diff --git a/[refs] b/[refs] index 7672f79605b0..2dd95540f252 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: b64ddf96456cde17be22bf74cafed381a29d58ba +refs/heads/master: 6ec129c3a2f8b38bc37e42348470ccfcb7460146 diff --git a/trunk/CREDITS b/trunk/CREDITS index c5f819bacda3..80e241304b8e 100644 --- a/trunk/CREDITS +++ b/trunk/CREDITS @@ -661,7 +661,7 @@ N: Kees Cook E: kees@outflux.net W: http://outflux.net/ P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D -D: Minor updates to SCSI code for the Communications type +D: Minor updates to SCSI types, added /proc/pid/maps protection S: (ask for current address) S: USA @@ -2580,10 +2580,9 @@ S: Australia N: Miguel Ojeda Sandonis E: maxextreme@gmail.com -D: Author: Auxiliary LCD Controller driver (ks0108) -D: Author: Auxiliary LCD driver (cfag12864b) -D: Author: Auxiliary LCD framebuffer driver (cfag12864bfb) -D: Maintainer: Auxiliary display drivers tree (drivers/auxdisplay/*) +W: http://maxextreme.googlepages.com/ +D: Author of the ks0108, cfag12864b and cfag12864bfb auxiliary display drivers. +D: Maintainer of the auxiliary display drivers tree (drivers/auxdisplay/*) S: C/ Mieses 20, 9-B S: Valladolid 47009 S: Spain diff --git a/trunk/Documentation/CodingStyle b/trunk/Documentation/CodingStyle index 9069189e78ef..afc286775891 100644 --- a/trunk/Documentation/CodingStyle +++ b/trunk/Documentation/CodingStyle @@ -160,6 +160,21 @@ supply of new-lines on your screen is not a renewable resource (think 25-line terminal screens here), you have more empty lines to put comments on. +Do not unnecessarily use braces where a single statement will do. + +if (condition) + action(); + +This does not apply if one branch of a conditional statement is a single +statement. Use braces in both branches. + +if (condition) { + do_this(); + do_that(); +} else { + otherwise(); +} + 3.1: Spaces Linux kernel style for use of spaces depends (mostly) on @@ -625,7 +640,7 @@ language. There appears to be a common misperception that gcc has a magic "make me faster" speedup option called "inline". While the use of inlines can be -appropriate (for example as a means of replacing macros, see Chapter 11), it +appropriate (for example as a means of replacing macros, see Chapter 12), it very often is not. Abundant use of the inline keyword leads to a much bigger kernel, which in turn slows the system as a whole down, due to a bigger icache footprint for the CPU and simply because there is less memory diff --git a/trunk/Documentation/DocBook/Makefile b/trunk/Documentation/DocBook/Makefile index 867608ab3ca0..6fd1646d3204 100644 --- a/trunk/Documentation/DocBook/Makefile +++ b/trunk/Documentation/DocBook/Makefile @@ -41,8 +41,9 @@ psdocs: $(PS) PDF := $(patsubst %.xml, %.pdf, $(BOOKS)) pdfdocs: $(PDF) -HTML := $(patsubst %.xml, %.html, $(BOOKS)) +HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS))) htmldocs: $(HTML) + $(call build_main_index) MAN := $(patsubst %.xml, %.9, $(BOOKS)) mandocs: $(MAN) @@ -132,10 +133,17 @@ quiet_cmd_db2pdf = PDF $@ %.pdf : %.xml $(call cmd,db2pdf) + +main_idx = Documentation/DocBook/index.html +build_main_index = rm -rf $(main_idx) && \ + echo '

Linux Kernel HTML Documentation

' >> $(main_idx) && \ + echo '

Kernel Version: $(KERNELVERSION)

' >> $(main_idx) && \ + cat $(HTML) >> $(main_idx) + quiet_cmd_db2html = HTML $@ cmd_db2html = xmlto xhtml $(XMLTOFLAGS) -o $(patsubst %.html,%,$@) $< && \ echo ' \ - Goto $(patsubst %.html,%,$(notdir $@))

' > $@ + $(patsubst %.html,%,$(notdir $@))

' > $@ %.html: %.xml @(which xmlto > /dev/null 2>&1) || \ @@ -152,6 +160,7 @@ quiet_cmd_db2man = MAN $@ @(which xmlto > /dev/null 2>&1) || \ (echo "*** You need to install xmlto ***"; \ exit 1) + $(Q)mkdir -p $(obj)/man $(call cmd,db2man) @touch $@ @@ -212,11 +221,7 @@ clean-files := $(DOCBOOKS) \ $(patsubst %.xml, %.9, $(DOCBOOKS)) \ $(C-procfs-example) -clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) - -#man put files in man subdir - traverse down -subdir- := man/ - +clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man # Declare the contents of the .PHONY variable as phony. We keep that # information in a variable se we can use it in if_changed and friends. diff --git a/trunk/Documentation/DocBook/kernel-api.tmpl b/trunk/Documentation/DocBook/kernel-api.tmpl index b61dfc79e1b8..a2b2b4d187c5 100644 --- a/trunk/Documentation/DocBook/kernel-api.tmpl +++ b/trunk/Documentation/DocBook/kernel-api.tmpl @@ -576,4 +576,67 @@ X!Idrivers/video/console/fonts.c !Edrivers/input/ff-core.c !Edrivers/input/ff-memless.c + + + Serial Peripheral Interface (SPI) + + SPI is the "Serial Peripheral Interface", widely used with + embedded systems because it is a simple and efficient + interface: basically a multiplexed shift register. + Its three signal wires hold a clock (SCK, often in the range + of 1-20 MHz), a "Master Out, Slave In" (MOSI) data line, and + a "Master In, Slave Out" (MISO) data line. + SPI is a full duplex protocol; for each bit shifted out the + MOSI line (one per clock) another is shifted in on the MISO line. + Those bits are assembled into words of various sizes on the + way to and from system memory. + An additional chipselect line is usually active-low (nCS); + four signals are normally used for each peripheral, plus + sometimes an interrupt. + + + The SPI bus facilities listed here provide a generalized + interface to declare SPI busses and devices, manage them + according to the standard Linux driver model, and perform + input/output operations. + At this time, only "master" side interfaces are supported, + where Linux talks to SPI peripherals and does not implement + such a peripheral itself. + (Interfaces to support implementing SPI slaves would + necessarily look different.) + + + The programming interface is structured around two kinds of driver, + and two kinds of device. + A "Controller Driver" abstracts the controller hardware, which may + be as simple as a set of GPIO pins or as complex as a pair of FIFOs + connected to dual DMA engines on the other side of the SPI shift + register (maximizing throughput). Such drivers bridge between + whatever bus they sit on (often the platform bus) and SPI, and + expose the SPI side of their device as a + struct spi_master. + SPI devices are children of that master, represented as a + struct spi_device and manufactured from + struct spi_board_info descriptors which + are usually provided by board-specific initialization code. + A struct spi_driver is called a + "Protocol Driver", and is bound to a spi_device using normal + driver model calls. + + + The I/O model is a set of queued messages. Protocol drivers + submit one or more struct spi_message + objects, which are processed and completed asynchronously. + (There are synchronous wrappers, however.) Messages are + built from one or more struct spi_transfer + objects, each of which wraps a full duplex SPI transfer. + A variety of protocol tweaking options are needed, because + different chips adopt very different policies for how they + use the bits transferred with SPI. + +!Iinclude/linux/spi/spi.h +!Fdrivers/spi/spi.c spi_register_board_info +!Edrivers/spi/spi.c + + diff --git a/trunk/Documentation/DocBook/librs.tmpl b/trunk/Documentation/DocBook/librs.tmpl index 3ff39bafc00e..94f21361e0ed 100644 --- a/trunk/Documentation/DocBook/librs.tmpl +++ b/trunk/Documentation/DocBook/librs.tmpl @@ -79,12 +79,12 @@ Usage - This chapter provides examples how to use the library. + This chapter provides examples of how to use the library. Initializing - The init function init_rs returns a pointer to a + The init function init_rs returns a pointer to an rs decoder structure, which holds the necessary information for encoding, decoding and error correction with the given polynomial. It either uses an existing @@ -98,10 +98,10 @@ static struct rs_control *rs_decoder; /* Symbolsize is 10 (bits) - * Primitve polynomial is x^10+x^3+1 + * Primitive polynomial is x^10+x^3+1 * first consecutive root is 0 - * primitve element to generate roots = 1 - * generator polinomial degree (number of roots) = 6 + * primitive element to generate roots = 1 + * generator polynomial degree (number of roots) = 6 */ rs_decoder = init_rs (10, 0x409, 0, 1, 6); @@ -116,12 +116,12 @@ rs_decoder = init_rs (10, 0x409, 0, 1, 6); The expanded data can be inverted on the fly by - providing a non zero inversion mask. The expanded data is + providing a non-zero inversion mask. The expanded data is XOR'ed with the mask. This is used e.g. for FLASH ECC, where the all 0xFF is inverted to an all 0x00. The Reed-Solomon code for all 0x00 is all 0x00. The code is inverted before storing to FLASH so it is 0xFF - too. This prevent's that reading from an erased FLASH + too. This prevents that reading from an erased FLASH results in ECC errors. @@ -273,7 +273,7 @@ free_rs(rs_decoder); May be used under the terms of the GNU General Public License (GPL) - The wrapper functions and interfaces are written by Thomas Gleixner + The wrapper functions and interfaces are written by Thomas Gleixner. Many users have provided bugfixes, improvements and helping hands for testing. diff --git a/trunk/Documentation/DocBook/man/Makefile b/trunk/Documentation/DocBook/man/Makefile deleted file mode 100644 index 4fb7ea0f7ac8..000000000000 --- a/trunk/Documentation/DocBook/man/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# Rules are put in Documentation/DocBook - -clean-files := *.9.gz *.sgml manpage.links manpage.refs diff --git a/trunk/Documentation/SubmittingDrivers b/trunk/Documentation/SubmittingDrivers index 58bead05eabb..d7e26427e426 100644 --- a/trunk/Documentation/SubmittingDrivers +++ b/trunk/Documentation/SubmittingDrivers @@ -87,6 +87,21 @@ Clarity: It helps if anyone can see how to fix the driver. It helps driver that intentionally obfuscates how the hardware works it will go in the bitbucket. +PM support: Since Linux is used on many portable and desktop systems, your + driver is likely to be used on such a system and therefore it + should support basic power management by implementing, if + necessary, the .suspend and .resume methods used during the + system-wide suspend and resume transitions. You should verify + that your driver correctly handles the suspend and resume, but + if you are unable to ensure that, please at least define the + .suspend method returning the -ENOSYS ("Function not + implemented") error. You should also try to make sure that your + driver uses as little power as possible when it's not doing + anything. For the driver testing instructions see + Documentation/power/drivers-testing.txt and for a relatively + complete overview of the power management issues related to + drivers see Documentation/power/devices.txt . + Control: In general if there is active maintainance of a driver by the author then patches will be redirected to them unless they are totally obvious and without need of checking. diff --git a/trunk/Documentation/accounting/getdelays.c b/trunk/Documentation/accounting/getdelays.c index e9126e794ed7..71acc28ed0d1 100644 --- a/trunk/Documentation/accounting/getdelays.c +++ b/trunk/Documentation/accounting/getdelays.c @@ -61,8 +61,6 @@ __u64 stime, utime; #define MAX_MSG_SIZE 1024 /* Maximum number of cpus expected to be specified in a cpumask */ #define MAX_CPUS 32 -/* Maximum length of pathname to log file */ -#define MAX_FILENAME 256 struct msgtemplate { struct nlmsghdr n; @@ -72,6 +70,16 @@ struct msgtemplate { char cpumask[100+6*MAX_CPUS]; +static void usage(void) +{ + fprintf(stderr, "getdelays [-dilv] [-w logfile] [-r bufsize] " + "[-m cpumask] [-t tgid] [-p pid]\n"); + fprintf(stderr, " -d: print delayacct stats\n"); + fprintf(stderr, " -i: print IO accounting (works only with -p)\n"); + fprintf(stderr, " -l: listen forever\n"); + fprintf(stderr, " -v: debug on\n"); +} + /* * Create a raw netlink socket and bind */ @@ -221,13 +229,13 @@ int main(int argc, char *argv[]) int count = 0; int write_file = 0; int maskset = 0; - char logfile[128]; + char *logfile = NULL; int loop = 0; struct msgtemplate msg; while (1) { - c = getopt(argc, argv, "diw:r:m:t:p:v:l"); + c = getopt(argc, argv, "diw:r:m:t:p:vl"); if (c < 0) break; @@ -241,7 +249,7 @@ int main(int argc, char *argv[]) print_io_accounting = 1; break; case 'w': - strncpy(logfile, optarg, MAX_FILENAME); + logfile = strdup(optarg); printf("write to file %s\n", logfile); write_file = 1; break; @@ -277,7 +285,7 @@ int main(int argc, char *argv[]) loop = 1; break; default: - printf("Unknown option %d\n", c); + usage(); exit(-1); } } diff --git a/trunk/Documentation/blackfin/00-INDEX b/trunk/Documentation/blackfin/00-INDEX new file mode 100644 index 000000000000..7cb3b356b249 --- /dev/null +++ b/trunk/Documentation/blackfin/00-INDEX @@ -0,0 +1,11 @@ +00-INDEX + - This file + +cache-lock.txt + - HOWTO for blackfin cache locking. + +cachefeatures.txt + - Supported cache features. + +Filesystems + - Requirements for mounting the root file system. diff --git a/trunk/Documentation/blackfin/Filesystems b/trunk/Documentation/blackfin/Filesystems new file mode 100644 index 000000000000..51260a1b8032 --- /dev/null +++ b/trunk/Documentation/blackfin/Filesystems @@ -0,0 +1,169 @@ +/* + * File: Documentation/blackfin/Filesystems + * Based on: + * Author: + * + * Created: + * Description: This file contains the simple DMA Implementation for Blackfin + * + * Rev: $Id: Filesystems 2384 2006-11-01 04:12:43Z magicyang $ + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + */ + + How to mount the root file system in uClinux/Blackfin + ----------------------------------------------------- + +1 Mounting EXT3 File system. + ------------------------ + + Creating an EXT3 File system for uClinux/Blackfin: + + +Please follow the steps to form the EXT3 File system and mount the same as root +file system. + +a Make an ext3 file system as large as you want the final root file + system. + + mkfs.ext3 /dev/ram0 + +b Mount this Empty file system on a free directory as: + + mount -t ext3 /dev/ram0 ./test + where ./test is the empty directory. + +c Copy your root fs directory that you have so carefully made over. + + cp -af /tmp/my_final_rootfs_files/* ./test + + (For ex: cp -af uClinux-dist/romfs/* ./test) + +d If you have done everything right till now you should be able to see + the required "root" dir's (that's etc, root, bin, lib, sbin...) + +e Now unmount the file system + + umount ./test + +f Create the root file system image. + + dd if=/dev/ram0 bs=1k count= \ + > ext3fs.img + + +Now you have to tell the kernel that will be mounting this file system as +rootfs. +So do a make menuconfig under kernel and select the Ext3 journaling file system +support under File system --> submenu. + + +2. Mounting EXT2 File system. + ------------------------- + +By default the ext2 file system image will be created if you invoke make from +the top uClinux-dist directory. + + +3. Mounting CRAMFS File System + ---------------------------- + +To create a CRAMFS file system image execute the command + + mkfs.cramfs ./test cramfs.img + + where ./test is the target directory. + + +4. Mounting ROMFS File System + -------------------------- + +To create a ROMFS file system image execute the command + + genromfs -v -V "ROMdisk" -f romfs.img -d ./test + + where ./test is the target directory + + +5. Mounting the JFFS2 Filesystem + ----------------------------- + +To create a compressed JFFS filesystem (JFFS2), please execute the command + + mkfs.jffs2 -d ./test -o jffs2.img + + where ./test is the target directory. + +However, please make sure the following is in your kernel config. + +/* + * RAM/ROM/Flash chip drivers + */ +#define CONFIG_MTD_CFI 1 +#define CONFIG_MTD_ROM 1 +/* + * Mapping drivers for chip access + */ +#define CONFIG_MTD_COMPLEX_MAPPINGS 1 +#define CONFIG_MTD_BF533 1 +#undef CONFIG_MTD_UCLINUX + +Through the u-boot boot loader, use the jffs2.img in the corresponding +partition made in linux-2.6.x/drivers/mtd/maps/bf533_flash.c. + +NOTE - Currently the Flash driver is available only for EZKIT. Watch out for a + STAMP driver soon. + + +6. Mounting the NFS File system + ----------------------------- + + For mounting the NFS please do the following in the kernel config. + + In Networking Support --> Networking options --> TCP/IP networking --> + IP: kernel level autoconfiguration + + Enable BOOTP Support. + + In Kernel hacking --> Compiled-in kernel boot parameter add the following + + root=/dev/nfs rw ip=bootp + + In File system --> Network File system, Enable + + NFS file system support --> NFSv3 client support + Root File system on NFS + + in uClibc menuconfig, do the following + In Networking Support + enable Remote Procedure Call (RPC) support + Full RPC Support + + On the Host side, ensure that /etc/dhcpd.conf looks something like this + + ddns-update-style ad-hoc; + allow bootp; + subnet 10.100.4.0 netmask 255.255.255.0 { + default-lease-time 122209600; + max-lease-time 31557600; + group { + host bf533 { + hardware ethernet 00:CF:52:49:C3:01; + fixed-address 10.100.4.50; + option root-path "/home/nfsmount"; + } + } + + ensure that /etc/exports looks something like this + /home/nfsmount *(rw,no_root_squash,no_all_squash) + + run the following commands as root (may differ depending on your + distribution) : + - service nfs start + - service portmap start + - service dhcpd start + - /usr/sbin/exportfs diff --git a/trunk/Documentation/blackfin/cache-lock.txt b/trunk/Documentation/blackfin/cache-lock.txt new file mode 100644 index 000000000000..88ba1e6c31c3 --- /dev/null +++ b/trunk/Documentation/blackfin/cache-lock.txt @@ -0,0 +1,48 @@ +/* + * File: Documentation/blackfin/cache-lock.txt + * Based on: + * Author: + * + * Created: + * Description: This file contains the simple DMA Implementation for Blackfin + * + * Rev: $Id: cache-lock.txt 2384 2006-11-01 04:12:43Z magicyang $ + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + */ + +How to lock your code in cache in uClinux/blackfin +-------------------------------------------------- + +There are only a few steps required to lock your code into the cache. +Currently you can lock the code by Way. + +Below are the interface provided for locking the cache. + + +1. cache_grab_lock(int Ways); + +This function grab the lock for locking your code into the cache specified +by Ways. + + +2. cache_lock(int Ways); + +This function should be called after your critical code has been executed. +Once the critical code exits, the code is now loaded into the cache. This +function locks the code into the cache. + + +So, the example sequence will be: + + cache_grab_lock(WAY0_L); /* Grab the lock */ + + critical_code(); /* Execute the code of interest */ + + cache_lock(WAY0_L); /* Lock the cache */ + +Where WAY0_L signifies WAY0 locking. diff --git a/trunk/Documentation/blackfin/cachefeatures.txt b/trunk/Documentation/blackfin/cachefeatures.txt new file mode 100644 index 000000000000..0fbec23becb5 --- /dev/null +++ b/trunk/Documentation/blackfin/cachefeatures.txt @@ -0,0 +1,65 @@ +/* + * File: Documentation/blackfin/cachefeatures.txt + * Based on: + * Author: + * + * Created: + * Description: This file contains the simple DMA Implementation for Blackfin + * + * Rev: $Id: cachefeatures.txt 2384 2006-11-01 04:12:43Z magicyang $ + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + */ + + - Instruction and Data cache initialization. + icache_init(); + dcache_init(); + + - Instruction and Data cache Invalidation Routines, when flushing the + same is not required. + _icache_invalidate(); + _dcache_invalidate(); + + Also, for invalidating the entire instruction and data cache, the below + routines are provided (another method for invalidation, refer page no 267 and 287 of + ADSP-BF533 Hardware Reference manual) + + invalidate_entire_dcache(); + invalidate_entire_icache(); + + -External Flushing of Instruction and data cache routines. + + flush_instruction_cache(); + flush_data_cache(); + + - Internal Flushing of Instruction and Data Cache. + + icplb_flush(); + dcplb_flush(); + + - Locking the cache. + + cache_grab_lock(); + cache_lock(); + + Please refer linux-2.6.x/Documentation/blackfin/cache-lock.txt for how to + lock the cache. + + Locking the cache is optional feature. + + - Miscellaneous cache functions. + + flush_cache_all(); + flush_cache_mm(); + invalidate_dcache_range(); + flush_dcache_range(); + flush_dcache_page(); + flush_cache_range(); + flush_cache_page(); + invalidate_dcache_range(); + flush_page_to_ram(); + diff --git a/trunk/Documentation/cciss.txt b/trunk/Documentation/cciss.txt index f74affe5c829..e65736c6b8bc 100644 --- a/trunk/Documentation/cciss.txt +++ b/trunk/Documentation/cciss.txt @@ -22,14 +22,21 @@ This driver is known to work with the following cards: * SA E200i * SA E500 -If nodes are not already created in the /dev/cciss directory, run as root: +Detecting drive failures: +------------------------- -# cd /dev -# ./MAKEDEV cciss +To get the status of logical volumes and to detect physical drive +failures, you can use the cciss_vol_status program found here: +http://cciss.sourceforge.net/#cciss_utils Device Naming: -------------- +If nodes are not already created in the /dev/cciss directory, run as root: + +# cd /dev +# ./MAKEDEV cciss + You need some entries in /dev for the cciss device. The MAKEDEV script can make device nodes for you automatically. Currently the device setup is as follows: diff --git a/trunk/Documentation/fb/deferred_io.txt b/trunk/Documentation/fb/deferred_io.txt new file mode 100644 index 000000000000..73cf9fb7cf60 --- /dev/null +++ b/trunk/Documentation/fb/deferred_io.txt @@ -0,0 +1,75 @@ +Deferred IO +----------- + +Deferred IO is a way to delay and repurpose IO. It uses host memory as a +buffer and the MMU pagefault as a pretrigger for when to perform the device +IO. The following example may be a useful explaination of how one such setup +works: + +- userspace app like Xfbdev mmaps framebuffer +- deferred IO and driver sets up nopage and page_mkwrite handlers +- userspace app tries to write to mmaped vaddress +- we get pagefault and reach nopage handler +- nopage handler finds and returns physical page +- we get page_mkwrite where we add this page to a list +- schedule a workqueue task to be run after a delay +- app continues writing to that page with no additional cost. this is + the key benefit. +- the workqueue task comes in and mkcleans the pages on the list, then + completes the work associated with updating the framebuffer. this is + the real work talking to the device. +- app tries to write to the address (that has now been mkcleaned) +- get pagefault and the above sequence occurs again + +As can be seen from above, one benefit is roughly to allow bursty framebuffer +writes to occur at minimum cost. Then after some time when hopefully things +have gone quiet, we go and really update the framebuffer which would be +a relatively more expensive operation. + +For some types of nonvolatile high latency displays, the desired image is +the final image rather than the intermediate stages which is why it's okay +to not update for each write that is occuring. + +It may be the case that this is useful in other scenarios as well. Paul Mundt +has mentioned a case where it is beneficial to use the page count to decide +whether to coalesce and issue SG DMA or to do memory bursts. + +Another one may be if one has a device framebuffer that is in an usual format, +say diagonally shifting RGB, this may then be a mechanism for you to allow +apps to pretend to have a normal framebuffer but reswizzle for the device +framebuffer at vsync time based on the touched pagelist. + +How to use it: (for applications) +--------------------------------- +No changes needed. mmap the framebuffer like normal and just use it. + +How to use it: (for fbdev drivers) +---------------------------------- +The following example may be helpful. + +1. Setup your structure. Eg: + +static struct fb_deferred_io hecubafb_defio = { + .delay = HZ, + .deferred_io = hecubafb_dpy_deferred_io, +}; + +The delay is the minimum delay between when the page_mkwrite trigger occurs +and when the deferred_io callback is called. The deferred_io callback is +explained below. + +2. Setup your deferred IO callback. Eg: +static void hecubafb_dpy_deferred_io(struct fb_info *info, + struct list_head *pagelist) + +The deferred_io callback is where you would perform all your IO to the display +device. You receive the pagelist which is the list of pages that were written +to during the delay. You must not modify this list. This callback is called +from a workqueue. + +3. Call init + info->fbdefio = &hecubafb_defio; + fb_deferred_io_init(info); + +4. Call cleanup + fb_deferred_io_cleanup(info); diff --git a/trunk/Documentation/fb/s3fb.txt b/trunk/Documentation/fb/s3fb.txt index 8a04c0da0c91..2c97770bdbaa 100644 --- a/trunk/Documentation/fb/s3fb.txt +++ b/trunk/Documentation/fb/s3fb.txt @@ -35,10 +35,12 @@ Supported Features * suspend/resume support * DPMS support -Text mode is supported even in higher resolutions, but there is limitation -to lower pixclocks (maximum between 50-60 MHz, depending on specific hardware). -This limitation is not enforced by driver. Text mode supports 8bit wide fonts -only (hardware limitation) and 16bit tall fonts (driver limitation). +Text mode is supported even in higher resolutions, but there is limitation to +lower pixclocks (maximum usually between 50-60 MHz, depending on specific +hardware, i get best results from plain S3 Trio32 card - about 75 MHz). This +limitation is not enforced by driver. Text mode supports 8bit wide fonts only +(hardware limitation) and 16bit tall fonts (driver limitation). Text mode +support is broken on S3 Trio64 V2/DX. There are two 4 bpp modes. First mode (selected if nonstd == 0) is mode with packed pixels, high nibble first. Second mode (selected if nonstd == 1) is mode @@ -73,6 +75,8 @@ Known bugs ========== * cursor disable in text mode doesn't work + * text mode broken on S3 Trio64 V2/DX + -- Ondrej Zajicek diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index 94fd03f25235..676b7981adb7 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -6,6 +6,14 @@ be removed from this file. --------------------------- +What: MXSER +When: December 2007 +Why: Old mxser driver is obsoleted by the mxser_new. Give it some time yet + and remove it. +Who: Jiri Slaby + +--------------------------- + What: V4L2 VIDIOC_G_MPEGCOMP and VIDIOC_S_MPEGCOMP When: October 2007 Why: Broken attempt to set MPEG compression parameters. These ioctls are @@ -126,18 +134,6 @@ Who: Adrian Bunk --------------------------- -What: Usage of invalid timevals in setitimer -When: March 2007 -Why: POSIX requires to validate timevals in the setitimer call. This - was never done by Linux. The invalid (e.g. negative timevals) were - silently converted to more or less random timeouts and intervals. - Until the removal a per boot limited number of warnings is printed - and the timevals are sanitized. - -Who: Thomas Gleixner - ---------------------------- - What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports (temporary transition config option provided until then) The transition config option will also be removed at the same time. @@ -165,7 +161,7 @@ Who: Greg Kroah-Hartman --------------------------- What: Interrupt only SA_* flags -When: Januar 2007 +When: September 2007 Why: The interrupt related SA_* flags are replaced by IRQF_* to move them out of the signal namespace. @@ -332,3 +328,11 @@ Why: Obsolete. The new i2c-gpio driver replaces all hardware-specific Who: Jean Delvare --------------------------- + +What: drivers depending on OSS_OBSOLETE +When: options in 2.6.23, code in 2.6.25 +Why: obsolete OSS drivers +Who: Adrian Bunk + +--------------------------- + diff --git a/trunk/Documentation/filesystems/Locking b/trunk/Documentation/filesystems/Locking index 28bfea75bcf2..59c14159cc47 100644 --- a/trunk/Documentation/filesystems/Locking +++ b/trunk/Documentation/filesystems/Locking @@ -15,6 +15,7 @@ prototypes: int (*d_delete)(struct dentry *); void (*d_release)(struct dentry *); void (*d_iput)(struct dentry *, struct inode *); + char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen); locking rules: none have BKL @@ -25,6 +26,7 @@ d_compare: no yes no no d_delete: yes no yes no d_release: no no no yes d_iput: no no no yes +d_dname: no no no no --------------------------- inode_operations --------------------------- prototypes: diff --git a/trunk/Documentation/filesystems/jfs.txt b/trunk/Documentation/filesystems/jfs.txt index bae128663748..26ebde77e821 100644 --- a/trunk/Documentation/filesystems/jfs.txt +++ b/trunk/Documentation/filesystems/jfs.txt @@ -29,7 +29,13 @@ errors=continue Keep going on a filesystem error. errors=remount-ro Default. Remount the filesystem read-only on an error. errors=panic Panic and halt the machine if an error occurs. -Please send bugs, comments, cards and letters to shaggy@austin.ibm.com. +uid=value Override on-disk uid with specified value +gid=value Override on-disk gid with specified value +umask=value Override on-disk umask with specified octal value. For + directories, the execute bit will be set if the corresponding + read bit is set. + +Please send bugs, comments, cards and letters to shaggy@linux.vnet.ibm.com. The JFS mailing list can be subscribed to by using the link labeled "Mail list Subscribe" at our web page http://jfs.sourceforge.net/ diff --git a/trunk/Documentation/filesystems/proc.txt b/trunk/Documentation/filesystems/proc.txt index 7aaf09b86a55..4f3e84c520a5 100644 --- a/trunk/Documentation/filesystems/proc.txt +++ b/trunk/Documentation/filesystems/proc.txt @@ -122,21 +122,22 @@ subdirectory has the entries listed in Table 1-1. Table 1-1: Process specific entries in /proc .............................................................................. - File Content - cmdline Command line arguments - cpu Current and last cpu in which it was executed (2.4)(smp) - cwd Link to the current working directory - environ Values of environment variables - exe Link to the executable of this process - fd Directory, which contains all file descriptors - maps Memory maps to executables and library files (2.4) - mem Memory held by this process - root Link to the root directory of this process - stat Process status - statm Process memory status information - status Process status in human readable form - wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan - smaps Extension based on maps, presenting the rss size for each mapped file + File Content + clear_refs Clears page referenced bits shown in smaps output + cmdline Command line arguments + cpu Current and last cpu in which it was executed (2.4)(smp) + cwd Link to the current working directory + environ Values of environment variables + exe Link to the executable of this process + fd Directory, which contains all file descriptors + maps Memory maps to executables and library files (2.4) + mem Memory held by this process + root Link to the root directory of this process + stat Process status + statm Process memory status information + status Process status in human readable form + wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan + smaps Extension based on maps, the rss size for each mapped file .............................................................................. For example, to get the status information of a process, all you have to do is @@ -1137,6 +1138,13 @@ determine whether or not they are still functioning properly. Because the NMI watchdog shares registers with oprofile, by disabling the NMI watchdog, oprofile may have more registers to utilize. +maps_protect +------------ + +Enables/Disables the protection of the per-process proc entries "maps" and +"smaps". When enabled, the contents of these files are visible only to +readers that are allowed to ptrace() the given process. + 2.4 /proc/sys/vm - The virtual memory subsystem ----------------------------------------------- diff --git a/trunk/Documentation/filesystems/vfat.txt b/trunk/Documentation/filesystems/vfat.txt index 069cb1094300..fcc123ffa252 100644 --- a/trunk/Documentation/filesystems/vfat.txt +++ b/trunk/Documentation/filesystems/vfat.txt @@ -57,6 +57,13 @@ nonumtail= -- When creating 8.3 aliases, normally the alias will currently exist in the directory, 'longfile.txt' will be the short alias instead of 'longfi~1.txt'. +usefree -- Use the "free clusters" value stored on FSINFO. It'll + be used to determine number of free clusters without + scanning disk. But it's not used by default, because + recent Windows don't update it correctly in some + case. If you are sure the "free clusters" on FSINFO is + correct, by this option you can avoid scanning disk. + quiet -- Stops printing certain warning messages. check=s|r|n -- Case sensitivity checking setting. diff --git a/trunk/Documentation/filesystems/vfs.txt b/trunk/Documentation/filesystems/vfs.txt index ea271f2d3954..a47cc819f37b 100644 --- a/trunk/Documentation/filesystems/vfs.txt +++ b/trunk/Documentation/filesystems/vfs.txt @@ -827,7 +827,7 @@ This describes how a filesystem can overload the standard dentry operations. Dentries and the dcache are the domain of the VFS and the individual filesystem implementations. Device drivers have no business here. These methods may be set to NULL, as they are either optional or -the VFS uses a default. As of kernel 2.6.13, the following members are +the VFS uses a default. As of kernel 2.6.22, the following members are defined: struct dentry_operations { @@ -837,6 +837,7 @@ struct dentry_operations { int (*d_delete)(struct dentry *); void (*d_release)(struct dentry *); void (*d_iput)(struct dentry *, struct inode *); + char *(*d_dname)(struct dentry *, char *, int); }; d_revalidate: called when the VFS needs to revalidate a dentry. This @@ -859,6 +860,26 @@ struct dentry_operations { VFS calls iput(). If you define this method, you must call iput() yourself + d_dname: called when the pathname of a dentry should be generated. + Usefull for some pseudo filesystems (sockfs, pipefs, ...) to delay + pathname generation. (Instead of doing it when dentry is created, + its done only when the path is needed.). Real filesystems probably + dont want to use it, because their dentries are present in global + dcache hash, so their hash should be an invariant. As no lock is + held, d_dname() should not try to modify the dentry itself, unless + appropriate SMP safety is used. CAUTION : d_path() logic is quite + tricky. The correct way to return for example "Hello" is to put it + at the end of the buffer, and returns a pointer to the first char. + dynamic_dname() helper function is provided to take care of this. + +Example : + +static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen) +{ + return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]", + dentry->d_inode->i_ino); +} + Each dentry has a pointer to its parent dentry, as well as a hash list of child dentries. Child dentries are basically like files in a directory. diff --git a/trunk/Documentation/hwmon/coretemp b/trunk/Documentation/hwmon/coretemp new file mode 100644 index 000000000000..870cda9416e9 --- /dev/null +++ b/trunk/Documentation/hwmon/coretemp @@ -0,0 +1,36 @@ +Kernel driver coretemp +====================== + +Supported chips: + * All Intel Core family + Prefix: 'coretemp' + CPUID: family 0x6, models 0xe, 0xf + Datasheet: Intel 64 and IA-32 Architectures Software Developer's Manual + Volume 3A: System Programming Guide + +Author: Rudolf Marek + +Description +----------- + +This driver permits reading temperature sensor embedded inside Intel Core CPU. +Temperature is measured in degrees Celsius and measurement resolution is +1 degree C. Valid temperatures are from 0 to TjMax degrees C, because +the actual value of temperature register is in fact a delta from TjMax. + +Temperature known as TjMax is the maximum junction temperature of processor. +Intel defines this temperature as 85C or 100C. At this temperature, protection +mechanism will perform actions to forcibly cool down the processor. Alarm +may be raised, if the temperature grows enough (more than TjMax) to trigger +the Out-Of-Spec bit. Following table summarizes the exported sysfs files: + +temp1_input - Core temperature (in millidegrees Celsius). +temp1_crit - Maximum junction temperature (in millidegrees Celsius). +temp1_crit_alarm - Set when Out-of-spec bit is set, never clears. + Correct CPU operation is no longer guaranteed. +temp1_label - Contains string "Core X", where X is processor + number. + +The TjMax temperature is set to 85 degrees C if undocumented model specific +register (UMSR) 0xee has bit 30 set. If not the TjMax is 100 degrees C as +(sometimes) documented in processor datasheet. diff --git a/trunk/Documentation/hwmon/max6650 b/trunk/Documentation/hwmon/max6650 new file mode 100644 index 000000000000..8be7beb9e3e8 --- /dev/null +++ b/trunk/Documentation/hwmon/max6650 @@ -0,0 +1,53 @@ +Kernel driver max6650 +===================== + +Supported chips: + * Maxim 6650 / 6651 + Prefix: 'max6650' + Addresses scanned: I2C 0x1b, 0x1f, 0x48, 0x4b + Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf + +Authors: + Hans J. Koch + John Morris + Claus Gindhart + +Description +----------- + +This driver implements support for the Maxim 6650/6651 + +The 2 devices are very similar, but the Maxim 6550 has a reduced feature +set, e.g. only one fan-input, instead of 4 for the 6651. + +The driver is not able to distinguish between the 2 devices. + +The driver provides the following sensor accesses in sysfs: + +fan1_input ro fan tachometer speed in RPM +fan2_input ro " +fan3_input ro " +fan4_input ro " +fan1_target rw desired fan speed in RPM (closed loop mode only) +pwm1_enable rw regulator mode, 0=full on, 1=open loop, 2=closed loop +pwm1 rw relative speed (0-255), 255=max. speed. + Used in open loop mode only. +fan1_div rw sets the speed range the inputs can handle. Legal + values are 1, 2, 4, and 8. Use lower values for + faster fans. + +Module parameters +----------------- + +If your board has a BIOS that initializes the MAX6650/6651 correctly, you can +simply load your module without parameters. It won't touch the configuration +registers then. If your board BIOS doesn't initialize the chip, or you want +different settings, you can set the following parameters: + +voltage_12V: 5=5V fan, 12=12V fan, 0=don't change +prescaler: Possible values are 1,2,4,8,16, or 0 for don't change +clock: The clock frequency in Hz of the chip the driver should assume [254000] + +Please have a look at the MAX6650/6651 data sheet and make sure that you fully +understand the meaning of these parameters before you attempt to change them. + diff --git a/trunk/Documentation/hwmon/smsc47m1 b/trunk/Documentation/hwmon/smsc47m1 index 04a11124f667..42c8431b3c9d 100644 --- a/trunk/Documentation/hwmon/smsc47m1 +++ b/trunk/Documentation/hwmon/smsc47m1 @@ -14,6 +14,10 @@ Supported chips: http://www.smsc.com/main/datasheets/47m14x.pdf http://www.smsc.com/main/tools/discontinued/47m15x.pdf http://www.smsc.com/main/datasheets/47m192.pdf + * SMSC LPC47M292 + Addresses scanned: none, address read from Super I/O config space + Prefix: 'smsc47m2' + Datasheet: Not public * SMSC LPC47M997 Addresses scanned: none, address read from Super I/O config space Prefix: 'smsc47m1' @@ -32,9 +36,10 @@ Description The Standard Microsystems Corporation (SMSC) 47M1xx Super I/O chips contain monitoring and PWM control circuitry for two fans. -The 47M15x and 47M192 chips contain a full 'hardware monitoring block' -in addition to the fan monitoring and control. The hardware monitoring -block is not supported by the driver. +The LPC47M15x, LPC47M192 and LPC47M292 chips contain a full 'hardware +monitoring block' in addition to the fan monitoring and control. The +hardware monitoring block is not supported by this driver, use the +smsc47m192 driver for that. No documentation is available for the 47M997, but it has the same device ID as the 47M15x and 47M192 chips and seems to be compatible. diff --git a/trunk/Documentation/hwmon/smsc47m192 b/trunk/Documentation/hwmon/smsc47m192 index 45d6453cd435..6d54ecb7b3f8 100644 --- a/trunk/Documentation/hwmon/smsc47m192 +++ b/trunk/Documentation/hwmon/smsc47m192 @@ -2,12 +2,13 @@ Kernel driver smsc47m192 ======================== Supported chips: - * SMSC LPC47M192 and LPC47M997 + * SMSC LPC47M192, LPC47M15x, LPC47M292 and LPC47M997 Prefix: 'smsc47m192' Addresses scanned: I2C 0x2c - 0x2d Datasheet: The datasheet for LPC47M192 is publicly available from http://www.smsc.com/ - The LPC47M997 is compatible for hardware monitoring. + The LPC47M15x, LPC47M292 and LPC47M997 are compatible for + hardware monitoring. Author: Hartmut Rick Special thanks to Jean Delvare for careful checking @@ -18,7 +19,7 @@ Description ----------- This driver implements support for the hardware sensor capabilities -of the SMSC LPC47M192 and LPC47M997 Super-I/O chips. +of the SMSC LPC47M192 and compatible Super-I/O chips. These chips support 3 temperature channels and 8 voltage inputs as well as CPU voltage VID input. diff --git a/trunk/Documentation/hwmon/sysfs-interface b/trunk/Documentation/hwmon/sysfs-interface index d73d2e8c7534..a9a18ad0d17a 100644 --- a/trunk/Documentation/hwmon/sysfs-interface +++ b/trunk/Documentation/hwmon/sysfs-interface @@ -152,6 +152,13 @@ fan[1-*]_div Fan divisor. Note that this is actually an internal clock divisor, which affects the measurable speed range, not the read value. +fan[1-*]_target + Desired fan speed + Unit: revolution/min (RPM) + RW + Only makes sense if the chip supports closed-loop fan speed + control based on the measured fan speed. + Also see the Alarms section for status flags associated with fans. diff --git a/trunk/Documentation/ia64/aliasing-test.c b/trunk/Documentation/ia64/aliasing-test.c new file mode 100644 index 000000000000..3153167b41c3 --- /dev/null +++ b/trunk/Documentation/ia64/aliasing-test.c @@ -0,0 +1,247 @@ +/* + * Exercise /dev/mem mmap cases that have been troublesome in the past + * + * (c) Copyright 2007 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int sum; + +int map_mem(char *path, off_t offset, size_t length, int touch) +{ + int fd, rc; + void *addr; + int *c; + + fd = open(path, O_RDWR); + if (fd == -1) { + perror(path); + return -1; + } + + addr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset); + if (addr == MAP_FAILED) + return 1; + + if (touch) { + c = (int *) addr; + while (c < (int *) (offset + length)) + sum += *c++; + } + + rc = munmap(addr, length); + if (rc == -1) { + perror("munmap"); + return -1; + } + + close(fd); + return 0; +} + +int scan_sysfs(char *path, char *file, off_t offset, size_t length, int touch) +{ + struct dirent **namelist; + char *name, *path2; + int i, n, r, rc, result = 0; + struct stat buf; + + n = scandir(path, &namelist, 0, alphasort); + if (n < 0) { + perror("scandir"); + return -1; + } + + for (i = 0; i < n; i++) { + name = namelist[i]->d_name; + + if (fnmatch(".", name, 0) == 0) + goto skip; + if (fnmatch("..", name, 0) == 0) + goto skip; + + path2 = malloc(strlen(path) + strlen(name) + 3); + strcpy(path2, path); + strcat(path2, "/"); + strcat(path2, name); + + if (fnmatch(file, name, 0) == 0) { + rc = map_mem(path2, offset, length, touch); + if (rc == 0) + fprintf(stderr, "PASS: %s 0x%lx-0x%lx is %s\n", path2, offset, offset + length, touch ? "readable" : "mappable"); + else if (rc > 0) + fprintf(stderr, "PASS: %s 0x%lx-0x%lx not mappable\n", path2, offset, offset + length); + else { + fprintf(stderr, "FAIL: %s 0x%lx-0x%lx not accessible\n", path2, offset, offset + length); + return rc; + } + } else { + r = lstat(path2, &buf); + if (r == 0 && S_ISDIR(buf.st_mode)) { + rc = scan_sysfs(path2, file, offset, length, touch); + if (rc < 0) + return rc; + } + } + + result |= rc; + free(path2); + +skip: + free(namelist[i]); + } + free(namelist); + return rc; +} + +char buf[1024]; + +int read_rom(char *path) +{ + int fd, rc; + size_t size = 0; + + fd = open(path, O_RDWR); + if (fd == -1) { + perror(path); + return -1; + } + + rc = write(fd, "1", 2); + if (rc <= 0) { + perror("write"); + return -1; + } + + do { + rc = read(fd, buf, sizeof(buf)); + if (rc > 0) + size += rc; + } while (rc > 0); + + close(fd); + return size; +} + +int scan_rom(char *path, char *file) +{ + struct dirent **namelist; + char *name, *path2; + int i, n, r, rc, result = 0; + struct stat buf; + + n = scandir(path, &namelist, 0, alphasort); + if (n < 0) { + perror("scandir"); + return -1; + } + + for (i = 0; i < n; i++) { + name = namelist[i]->d_name; + + if (fnmatch(".", name, 0) == 0) + goto skip; + if (fnmatch("..", name, 0) == 0) + goto skip; + + path2 = malloc(strlen(path) + strlen(name) + 3); + strcpy(path2, path); + strcat(path2, "/"); + strcat(path2, name); + + if (fnmatch(file, name, 0) == 0) { + rc = read_rom(path2); + + /* + * It's OK if the ROM is unreadable. Maybe there + * is no ROM, or some other error ocurred. The + * important thing is that no MCA happened. + */ + if (rc > 0) + fprintf(stderr, "PASS: %s read %ld bytes\n", path2, rc); + else { + fprintf(stderr, "PASS: %s not readable\n", path2); + return rc; + } + } else { + r = lstat(path2, &buf); + if (r == 0 && S_ISDIR(buf.st_mode)) { + rc = scan_rom(path2, file); + if (rc < 0) + return rc; + } + } + + result |= rc; + free(path2); + +skip: + free(namelist[i]); + } + free(namelist); + return rc; +} + +main() +{ + int rc; + + if (map_mem("/dev/mem", 0, 0xA0000, 1) == 0) + fprintf(stderr, "PASS: /dev/mem 0x0-0xa0000 is readable\n"); + else + fprintf(stderr, "FAIL: /dev/mem 0x0-0xa0000 not accessible\n"); + + /* + * It's not safe to blindly read the VGA frame buffer. If you know + * how to poke the card the right way, it should respond, but it's + * not safe in general. Many machines, e.g., Intel chipsets, cover + * up a non-responding card by just returning -1, but others will + * report the failure as a machine check. + */ + if (map_mem("/dev/mem", 0xA0000, 0x20000, 0) == 0) + fprintf(stderr, "PASS: /dev/mem 0xa0000-0xc0000 is mappable\n"); + else + fprintf(stderr, "FAIL: /dev/mem 0xa0000-0xc0000 not accessible\n"); + + if (map_mem("/dev/mem", 0xC0000, 0x40000, 1) == 0) + fprintf(stderr, "PASS: /dev/mem 0xc0000-0x100000 is readable\n"); + else + fprintf(stderr, "FAIL: /dev/mem 0xc0000-0x100000 not accessible\n"); + + /* + * Often you can map all the individual pieces above (0-0xA0000, + * 0xA0000-0xC0000, and 0xC0000-0x100000), but can't map the whole + * thing at once. This is because the individual pieces use different + * attributes, and there's no single attribute supported over the + * whole region. + */ + rc = map_mem("/dev/mem", 0, 1024*1024, 0); + if (rc == 0) + fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 is mappable\n"); + else if (rc > 0) + fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 not mappable\n"); + else + fprintf(stderr, "FAIL: /dev/mem 0x0-0x100000 not accessible\n"); + + scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1); + scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0); + scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1); + scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0); + + scan_rom("/sys/devices", "rom"); +} diff --git a/trunk/Documentation/ia64/aliasing.txt b/trunk/Documentation/ia64/aliasing.txt index 38f9a52d1820..9a431a7d0f5d 100644 --- a/trunk/Documentation/ia64/aliasing.txt +++ b/trunk/Documentation/ia64/aliasing.txt @@ -112,16 +112,6 @@ POTENTIAL ATTRIBUTE ALIASING CASES The /dev/mem mmap constraints apply. - However, since this is for mapping legacy MMIO space, WB access - does not make sense. This matters on machines without legacy - VGA support: these machines may have WB memory for the entire - first megabyte (or even the entire first granule). - - On these machines, we could mmap legacy_mem as WB, which would - be safe in terms of attribute aliasing, but X has no way of - knowing that it is accessing regular memory, not a frame buffer, - so the kernel should fail the mmap rather than doing it with WB. - read/write of /dev/mem This uses copy_from_user(), which implicitly uses a kernel @@ -138,14 +128,20 @@ POTENTIAL ATTRIBUTE ALIASING CASES ioremap() - This returns a kernel identity mapping for use inside the - kernel. + This returns a mapping for use inside the kernel. If the region is in kern_memmap, we should use the attribute - specified there. Otherwise, if the EFI memory map reports that - the entire granule supports WB, we should use that (granules - that are partially reserved or occupied by firmware do not appear - in kern_memmap). Otherwise, we should use a UC mapping. + specified there. + + If the EFI memory map reports that the entire granule supports + WB, we should use that (granules that are partially reserved + or occupied by firmware do not appear in kern_memmap). + + If the granule contains non-WB memory, but we can cover the + region safely with kernel page table mappings, we can use + ioremap_page_range() as most other architectures do. + + Failing all of the above, we have to fall back to a UC mapping. PAST PROBLEM CASES @@ -158,7 +154,7 @@ PAST PROBLEM CASES succeed. It may create either WB or UC user mappings, depending on whether the region is in kern_memmap or the EFI memory map. - mmap of 0x0-0xA0000 /dev/mem by "hwinfo" on HP sx1000 with VGA enabled + mmap of 0x0-0x9FFFF /dev/mem by "hwinfo" on HP sx1000 with VGA enabled See https://bugzilla.novell.com/show_bug.cgi?id=140858. @@ -171,28 +167,25 @@ PAST PROBLEM CASES so it is safe to use WB mappings. The kernel VGA driver may ioremap the VGA frame buffer at 0xA0000, - which will use a granule-sized UC mapping covering 0-0xFFFFF. This - granule covers some WB-only memory, but since UC is non-speculative, - the processor will never generate an uncacheable reference to the - WB-only areas unless the driver explicitly touches them. + which uses a granule-sized UC mapping. This granule will cover some + WB-only memory, but since UC is non-speculative, the processor will + never generate an uncacheable reference to the WB-only areas unless + the driver explicitly touches them. mmap of 0x0-0xFFFFF legacy_mem by "X" - If the EFI memory map reports this entire range as WB, there - is no VGA MMIO hole, and the mmap should fail or be done with - a WB mapping. + If the EFI memory map reports that the entire range supports the + same attributes, we can allow the mmap (and we will prefer WB if + supported, as is the case with HP sx[12]000 machines with VGA + disabled). - There's no easy way for X to determine whether the 0xA0000-0xBFFFF - region is a frame buffer or just memory, so I think it's best to - just fail this mmap request rather than using a WB mapping. As - far as I know, there's no need to map legacy_mem with WB - mappings. + If EFI reports the range as partly WB and partly UC (as on sx[12]000 + machines with VGA enabled), we must fail the mmap because there's no + safe attribute to use. - Otherwise, a UC mapping of the entire region is probably safe. - The VGA hole means the region will not be in kern_memmap. The - HP sx1000 chipset doesn't support UC access to the memory surrounding - the VGA hole, but X doesn't need that area anyway and should not - reference it. + If EFI reports some of the range but not all (as on Intel firmware + that doesn't report the VGA frame buffer at all), we should fail the + mmap and force the user to map just the specific region of interest. mmap of 0xA0000-0xBFFFF legacy_mem by "X" on HP sx1000 with VGA disabled @@ -202,6 +195,16 @@ PAST PROBLEM CASES This is a special case of the previous case, and the mmap should fail for the same reason as above. + read of /sys/devices/.../rom + + For VGA devices, this may cause an ioremap() of 0xC0000. This + used to be done with a UC mapping, because the VGA frame buffer + at 0xA0000 prevents use of a WB granule. The UC mapping causes + an MCA on HP sx[12]000 chipsets. + + We should use WB page table mappings to avoid covering the VGA + frame buffer. + NOTES [1] SDM rev 2.2, vol 2, sec 4.4.1. diff --git a/trunk/Documentation/ia64/err_inject.txt b/trunk/Documentation/ia64/err_inject.txt new file mode 100644 index 000000000000..6449a7090dbb --- /dev/null +++ b/trunk/Documentation/ia64/err_inject.txt @@ -0,0 +1,1068 @@ + +IPF Machine Check (MC) error inject tool +======================================== + +IPF Machine Check (MC) error inject tool is used to inject MC +errors from Linux. The tool is a test bed for IPF MC work flow including +hardware correctable error handling, OS recoverable error handling, MC +event logging, etc. + +The tool includes two parts: a kernel driver and a user application +sample. The driver provides interface to PAL to inject error +and query error injection capabilities. The driver code is in +arch/ia64/kernel/err_inject.c. The application sample (shown below) +provides a combination of various errors and calls the driver's interface +(sysfs interface) to inject errors or query error injection capabilities. + +The tool can be used to test Intel IPF machine MC handling capabilities. +It's especially useful for people who can not access hardware MC injection +tool to inject error. It's also very useful to integrate with other +software test suits to do stressful testing on IPF. + +Below is a sample application as part of the whole tool. The sample +can be used as a working test tool. Or it can be expanded to include +more features. It also can be a integrated into a libary or other user +application to have more thorough test. + +The sample application takes err.conf as error configuation input. Gcc +compiles the code. After you install err_inject driver, you can run +this sample application to inject errors. + +Errata: Itanium 2 Processors Specification Update lists some errata against +the pal_mc_error_inject PAL procedure. The following err.conf has been tested +on latest Montecito PAL. + +err.conf: + +#This is configuration file for err_inject_tool. +#The format of the each line is: +#cpu, loop, interval, err_type_info, err_struct_info, err_data_buffer +#where +# cpu: logical cpu number the error will be inject in. +# loop: times the error will be injected. +# interval: In second. every so often one error is injected. +# err_type_info, err_struct_info: PAL parameters. +# +#Note: All values are hex w/o or w/ 0x prefix. + + +#On cpu2, inject only total 0x10 errors, interval 5 seconds +#corrected, data cache, hier-2, physical addr(assigned by tool code). +#working on Montecito latest PAL. +2, 10, 5, 4101, 95 + +#On cpu4, inject and consume total 0x10 errors, interval 5 seconds +#corrected, data cache, hier-2, physical addr(assigned by tool code). +#working on Montecito latest PAL. +4, 10, 5, 4109, 95 + +#On cpu15, inject and consume total 0x10 errors, interval 5 seconds +#recoverable, DTR0, hier-2. +#working on Montecito latest PAL. +0xf, 0x10, 5, 4249, 15 + +The sample application source code: + +err_injection_tool.c: + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Copyright (C) 2006 Intel Co + * Fenghua Yu + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_FN_SIZE 256 +#define MAX_BUF_SIZE 256 +#define DATA_BUF_SIZE 256 +#define NR_CPUS 512 +#define MAX_TASK_NUM 2048 +#define MIN_INTERVAL 5 // seconds +#define ERR_DATA_BUFFER_SIZE 3 // Three 8-byte. +#define PARA_FIELD_NUM 5 +#define MASK_SIZE (NR_CPUS/64) +#define PATH_FORMAT "/sys/devices/system/cpu/cpu%d/err_inject/" + +int sched_setaffinity(pid_t pid, unsigned int len, unsigned long *mask); + +int verbose; +#define vbprintf if (verbose) printf + +int log_info(int cpu, const char *fmt, ...) +{ + FILE *log; + char fn[MAX_FN_SIZE]; + char buf[MAX_BUF_SIZE]; + va_list args; + + sprintf(fn, "%d.log", cpu); + log=fopen(fn, "a+"); + if (log==NULL) { + perror("Error open:"); + return -1; + } + + va_start(args, fmt); + vprintf(fmt, args); + memset(buf, 0, MAX_BUF_SIZE); + vsprintf(buf, fmt, args); + va_end(args); + + fwrite(buf, sizeof(buf), 1, log); + fclose(log); + + return 0; +} + +typedef unsigned long u64; +typedef unsigned int u32; + +typedef union err_type_info_u { + struct { + u64 mode : 3, /* 0-2 */ + err_inj : 3, /* 3-5 */ + err_sev : 2, /* 6-7 */ + err_struct : 5, /* 8-12 */ + struct_hier : 3, /* 13-15 */ + reserved : 48; /* 16-63 */ + } err_type_info_u; + u64 err_type_info; +} err_type_info_t; + +typedef union err_struct_info_u { + struct { + u64 siv : 1, /* 0 */ + c_t : 2, /* 1-2 */ + cl_p : 3, /* 3-5 */ + cl_id : 3, /* 6-8 */ + cl_dp : 1, /* 9 */ + reserved1 : 22, /* 10-31 */ + tiv : 1, /* 32 */ + trigger : 4, /* 33-36 */ + trigger_pl : 3, /* 37-39 */ + reserved2 : 24; /* 40-63 */ + } err_struct_info_cache; + struct { + u64 siv : 1, /* 0 */ + tt : 2, /* 1-2 */ + tc_tr : 2, /* 3-4 */ + tr_slot : 8, /* 5-12 */ + reserved1 : 19, /* 13-31 */ + tiv : 1, /* 32 */ + trigger : 4, /* 33-36 */ + trigger_pl : 3, /* 37-39 */ + reserved2 : 24; /* 40-63 */ + } err_struct_info_tlb; + struct { + u64 siv : 1, /* 0 */ + regfile_id : 4, /* 1-4 */ + reg_num : 7, /* 5-11 */ + reserved1 : 20, /* 12-31 */ + tiv : 1, /* 32 */ + trigger : 4, /* 33-36 */ + trigger_pl : 3, /* 37-39 */ + reserved2 : 24; /* 40-63 */ + } err_struct_info_register; + struct { + u64 reserved; + } err_struct_info_bus_processor_interconnect; + u64 err_struct_info; +} err_struct_info_t; + +typedef union err_data_buffer_u { + struct { + u64 trigger_addr; /* 0-63 */ + u64 inj_addr; /* 64-127 */ + u64 way : 5, /* 128-132 */ + index : 20, /* 133-152 */ + : 39; /* 153-191 */ + } err_data_buffer_cache; + struct { + u64 trigger_addr; /* 0-63 */ + u64 inj_addr; /* 64-127 */ + u64 way : 5, /* 128-132 */ + index : 20, /* 133-152 */ + reserved : 39; /* 153-191 */ + } err_data_buffer_tlb; + struct { + u64 trigger_addr; /* 0-63 */ + } err_data_buffer_register; + struct { + u64 reserved; /* 0-63 */ + } err_data_buffer_bus_processor_interconnect; + u64 err_data_buffer[ERR_DATA_BUFFER_SIZE]; +} err_data_buffer_t; + +typedef union capabilities_u { + struct { + u64 i : 1, + d : 1, + rv : 1, + tag : 1, + data : 1, + mesi : 1, + dp : 1, + reserved1 : 3, + pa : 1, + va : 1, + wi : 1, + reserved2 : 20, + trigger : 1, + trigger_pl : 1, + reserved3 : 30; + } capabilities_cache; + struct { + u64 d : 1, + i : 1, + rv : 1, + tc : 1, + tr : 1, + reserved1 : 27, + trigger : 1, + trigger_pl : 1, + reserved2 : 30; + } capabilities_tlb; + struct { + u64 gr_b0 : 1, + gr_b1 : 1, + fr : 1, + br : 1, + pr : 1, + ar : 1, + cr : 1, + rr : 1, + pkr : 1, + dbr : 1, + ibr : 1, + pmc : 1, + pmd : 1, + reserved1 : 3, + regnum : 1, + reserved2 : 15, + trigger : 1, + trigger_pl : 1, + reserved3 : 30; + } capabilities_register; + struct { + u64 reserved; + } capabilities_bus_processor_interconnect; +} capabilities_t; + +typedef struct resources_s { + u64 ibr0 : 1, + ibr2 : 1, + ibr4 : 1, + ibr6 : 1, + dbr0 : 1, + dbr2 : 1, + dbr4 : 1, + dbr6 : 1, + reserved : 48; +} resources_t; + + +long get_page_size(void) +{ + long page_size=sysconf(_SC_PAGESIZE); + return page_size; +} + +#define PAGE_SIZE (get_page_size()==-1?0x4000:get_page_size()) +#define SHM_SIZE (2*PAGE_SIZE*NR_CPUS) +#define SHM_VA 0x2000000100000000 + +int shmid; +void *shmaddr; + +int create_shm(void) +{ + key_t key; + char fn[MAX_FN_SIZE]; + + /* cpu0 is always existing */ + sprintf(fn, PATH_FORMAT, 0); + if ((key = ftok(fn, 's')) == -1) { + perror("ftok"); + return -1; + } + + shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT); + if (shmid == -1) { + if (errno==EEXIST) { + shmid = shmget(key, SHM_SIZE, 0); + if (shmid == -1) { + perror("shmget"); + return -1; + } + } + else { + perror("shmget"); + return -1; + } + } + vbprintf("shmid=%d", shmid); + + /* connect to the segment: */ + shmaddr = shmat(shmid, (void *)SHM_VA, 0); + if (shmaddr == (void*)-1) { + perror("shmat"); + return -1; + } + + memset(shmaddr, 0, SHM_SIZE); + mlock(shmaddr, SHM_SIZE); + + return 0; +} + +int free_shm() +{ + munlock(shmaddr, SHM_SIZE); + shmdt(shmaddr); + semctl(shmid, 0, IPC_RMID); + + return 0; +} + +#ifdef _SEM_SEMUN_UNDEFINED +union semun +{ + int val; + struct semid_ds *buf; + unsigned short int *array; + struct seminfo *__buf; +}; +#endif + +u32 mode=1; /* 1: physical mode; 2: virtual mode. */ +int one_lock=1; +key_t key[NR_CPUS]; +int semid[NR_CPUS]; + +int create_sem(int cpu) +{ + union semun arg; + char fn[MAX_FN_SIZE]; + int sid; + + sprintf(fn, PATH_FORMAT, cpu); + sprintf(fn, "%s/%s", fn, "err_type_info"); + if ((key[cpu] = ftok(fn, 'e')) == -1) { + perror("ftok"); + return -1; + } + + if (semid[cpu]!=0) + return 0; + + /* clear old semaphore */ + if ((sid = semget(key[cpu], 1, 0)) != -1) + semctl(sid, 0, IPC_RMID); + + /* get one semaphore */ + if ((semid[cpu] = semget(key[cpu], 1, IPC_CREAT | IPC_EXCL)) == -1) { + perror("semget"); + printf("Please remove semaphore with key=0x%lx, then run the tool.\n", + (u64)key[cpu]); + return -1; + } + + vbprintf("semid[%d]=0x%lx, key[%d]=%lx\n",cpu,(u64)semid[cpu],cpu, + (u64)key[cpu]); + /* initialize the semaphore to 1: */ + arg.val = 1; + if (semctl(semid[cpu], 0, SETVAL, arg) == -1) { + perror("semctl"); + return -1; + } + + return 0; +} + +static int lock(int cpu) +{ + struct sembuf lock; + + lock.sem_num = cpu; + lock.sem_op = 1; + semop(semid[cpu], &lock, 1); + + return 0; +} + +static int unlock(int cpu) +{ + struct sembuf unlock; + + unlock.sem_num = cpu; + unlock.sem_op = -1; + semop(semid[cpu], &unlock, 1); + + return 0; +} + +void free_sem(int cpu) +{ + semctl(semid[cpu], 0, IPC_RMID); +} + +int wr_multi(char *fn, unsigned long *data, int size) +{ + int fd; + char buf[MAX_BUF_SIZE]; + int ret; + + if (size==1) + sprintf(buf, "%lx", *data); + else if (size==3) + sprintf(buf, "%lx,%lx,%lx", data[0], data[1], data[2]); + else { + fprintf(stderr,"write to file with wrong size!\n"); + return -1; + } + + fd=open(fn, O_RDWR); + if (!fd) { + perror("Error:"); + return -1; + } + ret=write(fd, buf, sizeof(buf)); + close(fd); + return ret; +} + +int wr(char *fn, unsigned long data) +{ + return wr_multi(fn, &data, 1); +} + +int rd(char *fn, unsigned long *data) +{ + int fd; + char buf[MAX_BUF_SIZE]; + + fd=open(fn, O_RDONLY); + if (fd<0) { + perror("Error:"); + return -1; + } + read(fd, buf, MAX_BUF_SIZE); + *data=strtoul(buf, NULL, 16); + close(fd); + return 0; +} + +int rd_status(char *path, int *status) +{ + char fn[MAX_FN_SIZE]; + sprintf(fn, "%s/status", path); + if (rd(fn, (u64*)status)<0) { + perror("status reading error.\n"); + return -1; + } + + return 0; +} + +int rd_capabilities(char *path, u64 *capabilities) +{ + char fn[MAX_FN_SIZE]; + sprintf(fn, "%s/capabilities", path); + if (rd(fn, capabilities)<0) { + perror("capabilities reading error.\n"); + return -1; + } + + return 0; +} + +int rd_all(char *path) +{ + unsigned long err_type_info, err_struct_info, err_data_buffer; + int status; + unsigned long capabilities, resources; + char fn[MAX_FN_SIZE]; + + sprintf(fn, "%s/err_type_info", path); + if (rd(fn, &err_type_info)<0) { + perror("err_type_info reading error.\n"); + return -1; + } + printf("err_type_info=%lx\n", err_type_info); + + sprintf(fn, "%s/err_struct_info", path); + if (rd(fn, &err_struct_info)<0) { + perror("err_struct_info reading error.\n"); + return -1; + } + printf("err_struct_info=%lx\n", err_struct_info); + + sprintf(fn, "%s/err_data_buffer", path); + if (rd(fn, &err_data_buffer)<0) { + perror("err_data_buffer reading error.\n"); + return -1; + } + printf("err_data_buffer=%lx\n", err_data_buffer); + + sprintf(fn, "%s/status", path); + if (rd("status", (u64*)&status)<0) { + perror("status reading error.\n"); + return -1; + } + printf("status=%d\n", status); + + sprintf(fn, "%s/capabilities", path); + if (rd(fn,&capabilities)<0) { + perror("capabilities reading error.\n"); + return -1; + } + printf("capabilities=%lx\n", capabilities); + + sprintf(fn, "%s/resources", path); + if (rd(fn, &resources)<0) { + perror("resources reading error.\n"); + return -1; + } + printf("resources=%lx\n", resources); + + return 0; +} + +int query_capabilities(char *path, err_type_info_t err_type_info, + u64 *capabilities) +{ + char fn[MAX_FN_SIZE]; + err_struct_info_t err_struct_info; + err_data_buffer_t err_data_buffer; + + err_struct_info.err_struct_info=0; + memset(err_data_buffer.err_data_buffer, -1, ERR_DATA_BUFFER_SIZE*8); + + sprintf(fn, "%s/err_type_info", path); + wr(fn, err_type_info.err_type_info); + sprintf(fn, "%s/err_struct_info", path); + wr(fn, 0x0); + sprintf(fn, "%s/err_data_buffer", path); + wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE); + + // Fire pal_mc_error_inject procedure. + sprintf(fn, "%s/call_start", path); + wr(fn, mode); + + if (rd_capabilities(path, capabilities)<0) + return -1; + + return 0; +} + +int query_all_capabilities() +{ + int status; + err_type_info_t err_type_info; + int err_sev, err_struct, struct_hier; + int cap=0; + u64 capabilities; + char path[MAX_FN_SIZE]; + + err_type_info.err_type_info=0; // Initial + err_type_info.err_type_info_u.mode=0; // Query mode; + err_type_info.err_type_info_u.err_inj=0; + + printf("All capabilities implemented in pal_mc_error_inject:\n"); + sprintf(path, PATH_FORMAT ,0); + for (err_sev=0;err_sev<3;err_sev++) + for (err_struct=0;err_struct<5;err_struct++) + for (struct_hier=0;struct_hier<5;struct_hier++) + { + status=-1; + capabilities=0; + err_type_info.err_type_info_u.err_sev=err_sev; + err_type_info.err_type_info_u.err_struct=err_struct; + err_type_info.err_type_info_u.struct_hier=struct_hier; + + if (query_capabilities(path, err_type_info, &capabilities)<0) + continue; + + if (rd_status(path, &status)<0) + continue; + + if (status==0) { + cap=1; + printf("For err_sev=%d, err_struct=%d, struct_hier=%d: ", + err_sev, err_struct, struct_hier); + printf("capabilities 0x%lx\n", capabilities); + } + } + if (!cap) { + printf("No capabilities supported.\n"); + return 0; + } + + return 0; +} + +int err_inject(int cpu, char *path, err_type_info_t err_type_info, + err_struct_info_t err_struct_info, + err_data_buffer_t err_data_buffer) +{ + int status; + char fn[MAX_FN_SIZE]; + + log_info(cpu, "err_type_info=%lx, err_struct_info=%lx, ", + err_type_info.err_type_info, + err_struct_info.err_struct_info); + log_info(cpu,"err_data_buffer=[%lx,%lx,%lx]\n", + err_data_buffer.err_data_buffer[0], + err_data_buffer.err_data_buffer[1], + err_data_buffer.err_data_buffer[2]); + sprintf(fn, "%s/err_type_info", path); + wr(fn, err_type_info.err_type_info); + sprintf(fn, "%s/err_struct_info", path); + wr(fn, err_struct_info.err_struct_info); + sprintf(fn, "%s/err_data_buffer", path); + wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE); + + // Fire pal_mc_error_inject procedure. + sprintf(fn, "%s/call_start", path); + wr(fn,mode); + + if (rd_status(path, &status)<0) { + vbprintf("fail: read status\n"); + return -100; + } + + if (status!=0) { + log_info(cpu, "fail: status=%d\n", status); + return status; + } + + return status; +} + +static int construct_data_buf(char *path, err_type_info_t err_type_info, + err_struct_info_t err_struct_info, + err_data_buffer_t *err_data_buffer, + void *va1) +{ + char fn[MAX_FN_SIZE]; + u64 virt_addr=0, phys_addr=0; + + vbprintf("va1=%lx\n", (u64)va1); + memset(&err_data_buffer->err_data_buffer_cache, 0, ERR_DATA_BUFFER_SIZE*8); + + switch (err_type_info.err_type_info_u.err_struct) { + case 1: // Cache + switch (err_struct_info.err_struct_info_cache.cl_id) { + case 1: //Virtual addr + err_data_buffer->err_data_buffer_cache.inj_addr=(u64)va1; + break; + case 2: //Phys addr + sprintf(fn, "%s/virtual_to_phys", path); + virt_addr=(u64)va1; + if (wr(fn,virt_addr)<0) + return -1; + rd(fn, &phys_addr); + err_data_buffer->err_data_buffer_cache.inj_addr=phys_addr; + break; + default: + printf("Not supported cl_id\n"); + break; + } + break; + case 2: // TLB + break; + case 3: // Register file + break; + case 4: // Bus/system interconnect + default: + printf("Not supported err_struct\n"); + break; + } + + return 0; +} + +typedef struct { + u64 cpu; + u64 loop; + u64 interval; + u64 err_type_info; + u64 err_struct_info; + u64 err_data_buffer[ERR_DATA_BUFFER_SIZE]; +} parameters_t; + +parameters_t line_para; +int para; + +static int empty_data_buffer(u64 *err_data_buffer) +{ + int empty=1; + int i; + + for (i=0;iMIN_INTERVAL + ?interval:MIN_INTERVAL; + parameters[num].err_type_info=err_type_info_conf; + parameters[num].err_struct_info=err_struct_info_conf; + memcpy(parameters[num++].err_data_buffer, + err_data_buffer_conf,ERR_DATA_BUFFER_SIZE*8) ; + + if (num>=MAX_TASK_NUM) + break; + } + } + else { + parameters[0].cpu=line_para.cpu; + parameters[0].loop=line_para.loop; + parameters[0].interval= line_para.interval>MIN_INTERVAL + ?line_para.interval:MIN_INTERVAL; + parameters[0].err_type_info=line_para.err_type_info; + parameters[0].err_struct_info=line_para.err_struct_info; + memcpy(parameters[0].err_data_buffer, + line_para.err_data_buffer,ERR_DATA_BUFFER_SIZE*8) ; + + num=1; + } + + /* Create semaphore: If one_lock, one semaphore for all processors. + Otherwise, one sempaphore for each processor. */ + if (one_lock) { + if (create_sem(0)) { + printf("Can not create semaphore...exit\n"); + free_sem(0); + return -1; + } + } + else { + for (i=0;i diff --git a/trunk/Documentation/kbuild/modules.txt b/trunk/Documentation/kbuild/modules.txt index 769ee05ee4d1..1d247d59ad56 100644 --- a/trunk/Documentation/kbuild/modules.txt +++ b/trunk/Documentation/kbuild/modules.txt @@ -249,7 +249,7 @@ following files: --> filename: Makefile KERNELDIR := /lib/modules/`uname -r`/build all:: - $(MAKE) -C $KERNELDIR M=`pwd` $@ + $(MAKE) -C $(KERNELDIR) M=`pwd` $@ # Module specific targets genbin: diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index 38d7db3262c7..6b8ad06846c4 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -496,6 +496,30 @@ and is between 256 and 4096 characters. It is defined in the file Format: [,] See also Documentation/networking/decnet.txt. + default_blu= [VT] + Format: ,,,..., + Change the default blue palette of the console. + This is a 16-member array composed of values + ranging from 0-255. + + default_grn= [VT] + Format: ,,,..., + Change the default green palette of the console. + This is a 16-member array composed of values + ranging from 0-255. + + default_red= [VT] + Format: ,,,..., + Change the default red palette of the console. + This is a 16-member array composed of values + ranging from 0-255. + + default_utf8= [VT] + Format=<0|1> + Set system-wide default UTF-8 mode for all tty's. + Default is 0 and by setting to 1, it enables UTF-8 + mode for all newly opened or allocated terminals. + dhash_entries= [KNL] Set number of hash buckets for dentry cache. @@ -816,6 +840,11 @@ and is between 256 and 4096 characters. It is defined in the file lasi= [HW,SCSI] PARISC LASI driver for the 53c700 chip Format: addr:,irq: + legacy_serial.force [HW,IA-32,X86-64] + Probe for COM ports at legacy addresses even + if PNPBIOS or ACPI should describe them. This + is for working around firmware defects. + llsc*= [IA64] See function print_params() in arch/ia64/sn/kernel/llsc4.c. @@ -1578,6 +1607,17 @@ and is between 256 and 4096 characters. It is defined in the file smp-alt-once [IA-32,SMP] On a hotplug CPU system, only attempt to substitute SMP alternatives once at boot. + smsc-ircc2.nopnp [HW] Don't use PNP to discover SMC devices + smsc-ircc2.ircc_cfg= [HW] Device configuration I/O port + smsc-ircc2.ircc_sir= [HW] SIR base I/O port + smsc-ircc2.ircc_fir= [HW] FIR base I/O port + smsc-ircc2.ircc_irq= [HW] IRQ line + smsc-ircc2.ircc_dma= [HW] DMA channel + smsc-ircc2.ircc_transceiver= [HW] Transceiver type: + 0: Toshiba Satellite 1800 (GP data pin select) + 1: Fast pin select (default) + 2: ATC IRMode + snd-ad1816a= [HW,ALSA] snd-ad1848= [HW,ALSA] diff --git a/trunk/Documentation/kprobes.txt b/trunk/Documentation/kprobes.txt index d71fafffce90..da5404ab7569 100644 --- a/trunk/Documentation/kprobes.txt +++ b/trunk/Documentation/kprobes.txt @@ -14,6 +14,7 @@ CONTENTS 8. Kprobes Example 9. Jprobes Example 10. Kretprobes Example +Appendix A: The kprobes debugfs interface 1. Concepts: Kprobes, Jprobes, Return Probes @@ -349,9 +350,12 @@ for instrumentation and error reporting.) If the number of times a function is called does not match the number of times it returns, registering a return probe on that function may -produce undesirable results. We have the do_exit() case covered. -do_execve() and do_fork() are not an issue. We're unaware of other -specific cases where this could be a problem. +produce undesirable results. In such a case, a line: +kretprobe BUG!: Processing kretprobe d000000000041aa8 @ c00000000004f48c +gets printed. With this information, one will be able to correlate the +exact instance of the kretprobe that caused the problem. We have the +do_exit() case covered. do_execve() and do_fork() are not an issue. +We're unaware of other specific cases where this could be a problem. If, upon entry to or exit from a function, the CPU is running on a stack other than that of the current task, registering a return @@ -614,3 +618,27 @@ http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe http://www.redhat.com/magazine/005mar05/features/kprobes/ http://www-users.cs.umn.edu/~boutcher/kprobes/ http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115) + + +Appendix A: The kprobes debugfs interface + +With recent kernels (> 2.6.20) the list of registered kprobes is visible +under the /debug/kprobes/ directory (assuming debugfs is mounted at /debug). + +/debug/kprobes/list: Lists all registered probes on the system + +c015d71a k vfs_read+0x0 +c011a316 j do_fork+0x0 +c03dedc5 r tcp_v4_rcv+0x0 + +The first column provides the kernel address where the probe is inserted. +The second column identifies the type of probe (k - kprobe, r - kretprobe +and j - jprobe), while the third column specifies the symbol+offset of +the probe. If the probed function belongs to a module, the module name +is also specified. + +/debug/kprobes/enabled: Turn kprobes ON/OFF + +Provides a knob to globally turn registered kprobes ON or OFF. By default, +all kprobes are enabled. By echoing "0" to this file, all registered probes +will be disarmed, till such time a "1" is echoed to this file. diff --git a/trunk/Documentation/laptop-mode.txt b/trunk/Documentation/laptop-mode.txt index 6f639e3473af..eeedee11c8c2 100644 --- a/trunk/Documentation/laptop-mode.txt +++ b/trunk/Documentation/laptop-mode.txt @@ -33,7 +33,7 @@ or anything. Simply install all the files included in this document, and laptop mode will automatically be started when you're on battery. For your convenience, a tarball containing an installer can be downloaded at: -http://www.xs4all.nl/~bsamwel/laptop_mode/tools/ +http://www.samwel.tk/laptop_mode/laptop_mode/ To configure laptop mode, you need to edit the configuration file, which is located in /etc/default/laptop-mode on Debian-based systems, or in diff --git a/trunk/Documentation/oops-tracing.txt b/trunk/Documentation/oops-tracing.txt index ea55ea8bc8ef..7d5b60dea551 100644 --- a/trunk/Documentation/oops-tracing.txt +++ b/trunk/Documentation/oops-tracing.txt @@ -234,9 +234,6 @@ characters, each representing a particular tainted value. 6: 'B' if a page-release function has found a bad page reference or some unexpected page flags. - 7: 'U' if a user specifically requested that the Tainted flag be set, - ' ' otherwise. - 7: 'U' if a user or user application specifically requested that the Tainted flag be set, ' ' otherwise. diff --git a/trunk/Documentation/pcmcia/driver.txt b/trunk/Documentation/pcmcia/driver.txt new file mode 100644 index 000000000000..0ac167920778 --- /dev/null +++ b/trunk/Documentation/pcmcia/driver.txt @@ -0,0 +1,30 @@ +PCMCIA Driver +------------- + + +sysfs +----- + +New PCMCIA IDs may be added to a device driver pcmcia_device_id table at +runtime as shown below: + +echo "match_flags manf_id card_id func_id function device_no \ +prod_id_hash[0] prod_id_hash[1] prod_id_hash[2] prod_id_hash[3]" > \ +/sys/bus/pcmcia/drivers/{driver}/new_id + +All fields are passed in as hexadecimal values (no leading 0x). +The meaning is described in the PCMCIA specification, the match_flags is +a bitwise or-ed combination from PCMCIA_DEV_ID_MATCH_* constants +defined in include/linux/mod_devicetable.h. + +Once added, the driver probe routine will be invoked for any unclaimed +PCMCIA device listed in its (newly updated) pcmcia_device_id list. + +A common use-case is to add a new device according to the manufacturer ID +and the card ID (form the manf_id and card_id file in the device tree). +For this, just use: + +echo "0x3 manf_id card_id 0 0 0 0 0 0 0" > \ + /sys/bus/pcmcia/drivers/{driver}/new_id + +after loading the driver. diff --git a/trunk/Documentation/power/basic-pm-debugging.txt b/trunk/Documentation/power/basic-pm-debugging.txt new file mode 100644 index 000000000000..1a85e2b964dc --- /dev/null +++ b/trunk/Documentation/power/basic-pm-debugging.txt @@ -0,0 +1,106 @@ +Debugging suspend and resume + (C) 2007 Rafael J. Wysocki , GPL + +1. Testing suspend to disk (STD) + +To verify that the STD works, you can try to suspend in the "reboot" mode: + +# echo reboot > /sys/power/disk +# echo disk > /sys/power/state + +and the system should suspend, reboot, resume and get back to the command prompt +where you have started the transition. If that happens, the STD is most likely +to work correctly, but you need to repeat the test at least a couple of times in +a row for confidence. This is necessary, because some problems only show up on +a second attempt at suspending and resuming the system. You should also test +the "platform" and "shutdown" modes of suspend: + +# echo platform > /sys/power/disk +# echo disk > /sys/power/state + +or + +# echo shutdown > /sys/power/disk +# echo disk > /sys/power/state + +in which cases you will have to press the power button to make the system +resume. If that does not work, you will need to identify what goes wrong. + +a) Test mode of STD + +To verify if there are any drivers that cause problems you can run the STD +in the test mode: + +# echo test > /sys/power/disk +# echo disk > /sys/power/state + +in which case the system should freeze tasks, suspend devices, disable nonboot +CPUs (if any), wait for 5 seconds, enable nonboot CPUs, resume devices, thaw +tasks and return to your command prompt. If that fails, most likely there is +a driver that fails to either suspend or resume (in the latter case the system +may hang or be unstable after the test, so please take that into consideration). +To find this driver, you can carry out a binary search according to the rules: +- if the test fails, unload a half of the drivers currently loaded and repeat +(that would probably involve rebooting the system, so always note what drivers +have been loaded before the test), +- if the test succeeds, load a half of the drivers you have unloaded most +recently and repeat. + +Once you have found the failing driver (there can be more than just one of +them), you have to unload it every time before the STD transition. In that case +please make sure to report the problem with the driver. + +It is also possible that a cycle can still fail after you have unloaded +all modules. In that case, you would want to look in your kernel configuration +for the drivers that can be compiled as modules (testing again with them as +modules), and possibly also try boot time options such as "noapic" or "noacpi". + +b) Testing minimal configuration + +If the test mode of STD works, you can boot the system with "init=/bin/bash" +and attempt to suspend in the "reboot", "shutdown" and "platform" modes. If +that does not work, there probably is a problem with a driver statically +compiled into the kernel and you can try to compile more drivers as modules, +so that they can be tested individually. Otherwise, there is a problem with a +modular driver and you can find it by loading a half of the modules you normally +use and binary searching in accordance with the algorithm: +- if there are n modules loaded and the attempt to suspend and resume fails, +unload n/2 of the modules and try again (that would probably involve rebooting +the system), +- if there are n modules loaded and the attempt to suspend and resume succeeds, +load n/2 modules more and try again. + +Again, if you find the offending module(s), it(they) must be unloaded every time +before the STD transition, and please report the problem with it(them). + +c) Advanced debugging + +In case the STD does not work on your system even in the minimal configuration +and compiling more drivers as modules is not practical or some modules cannot +be unloaded, you can use one of the more advanced debugging techniques to find +the problem. First, if there is a serial port in your box, you can set the +CONFIG_DISABLE_CONSOLE_SUSPEND kernel configuration option and try to log kernel +messages using the serial console. This may provide you with some information +about the reasons of the suspend (resume) failure. Alternatively, it may be +possible to use a FireWire port for debugging with firescope +(ftp://ftp.firstfloor.org/pub/ak/firescope/). On i386 it is also possible to +use the PM_TRACE mechanism documented in Documentation/s2ram.txt . + +2. Testing suspend to RAM (STR) + +To verify that the STR works, it is generally more convenient to use the s2ram +tool available from http://suspend.sf.net and documented at +http://en.opensuse.org/s2ram . However, before doing that it is recommended to +carry out the procedure described in section 1. + +Assume you have resolved the problems with the STD and you have found some +failing drivers. These drivers are also likely to fail during the STR or +during the resume, so it is better to unload them every time before the STR +transition. Now, you can follow the instructions at +http://en.opensuse.org/s2ram to test the system, but if it does not work +"out of the box", you may need to boot it with "init=/bin/bash" and test +s2ram in the minimal configuration. In that case, you may be able to search +for failing drivers by following the procedure analogous to the one described in +1b). If you find some failing drivers, you will have to unload them every time +before the STR transition (ie. before you run s2ram), and please report the +problems with them. diff --git a/trunk/Documentation/power/drivers-testing.txt b/trunk/Documentation/power/drivers-testing.txt new file mode 100644 index 000000000000..33016c2f18dd --- /dev/null +++ b/trunk/Documentation/power/drivers-testing.txt @@ -0,0 +1,42 @@ +Testing suspend and resume support in device drivers + (C) 2007 Rafael J. Wysocki , GPL + +1. Preparing the test system + +Unfortunately, to effectively test the support for the system-wide suspend and +resume transitions in a driver, it is necessary to suspend and resume a fully +functional system with this driver loaded. Moreover, that should be done +several times, preferably several times in a row, and separately for the suspend +to disk (STD) and the suspend to RAM (STR) transitions, because each of these +cases involves different ordering of operations and different interactions with +the machine's BIOS. + +Of course, for this purpose the test system has to be known to suspend and +resume without the driver being tested. Thus, if possible, you should first +resolve all suspend/resume-related problems in the test system before you start +testing the new driver. Please see Documents/power/basic-pm-debugging.txt for +more information about the debugging of suspend/resume functionality. + +2. Testing the driver + +Once you have resolved the suspend/resume-related problems with your test system +without the new driver, you are ready to test it: + +a) Build the driver as a module, load it and try the STD in the test mode (see: +Documents/power/basic-pm-debugging.txt, 1a)). + +b) Load the driver and attempt to suspend to disk in the "reboot", "shutdown" +and "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1). + +c) Compile the driver directly into the kernel and try the STD in the test mode. + +d) Attempt to suspend to disk with the driver compiled directly into the kernel +in the "reboot", "shutdown" and "platform" modes. + +e) Attempt to suspend to RAM using the s2ram tool with the driver loaded (see: +Documents/power/basic-pm-debugging.txt, 2). As far as the STR tests are +concerned, it should not matter whether or not the driver is built as a module. + +Each of the above tests should be repeated several times and the STD tests +should be mixed with the STR tests. If any of them fails, the driver cannot be +regarded as suspend/resume-safe. diff --git a/trunk/Documentation/power/interface.txt b/trunk/Documentation/power/interface.txt index 8c5b41bf3f36..fd5192a8fa8a 100644 --- a/trunk/Documentation/power/interface.txt +++ b/trunk/Documentation/power/interface.txt @@ -34,8 +34,12 @@ for 5 seconds, resume devices, unfreeze tasks and enable nonboot CPUs. Then, we are able to look in the log messages and work out, for example, which code is being slow and which device drivers are misbehaving. -Reading from this file will display what the mode is currently set -to. Writing to this file will accept one of +Reading from this file will display all supported modes and the currently +selected one in brackets, for example + + [shutdown] reboot test testproc + +Writing to this file will accept one of 'platform' (only if the platform supports it) 'shutdown' diff --git a/trunk/Documentation/powerpc/booting-without-of.txt b/trunk/Documentation/powerpc/booting-without-of.txt index 033a3f3b3ab7..d4bfae75c946 100644 --- a/trunk/Documentation/powerpc/booting-without-of.txt +++ b/trunk/Documentation/powerpc/booting-without-of.txt @@ -1560,6 +1560,9 @@ platforms are moved over to use the flattened-device-tree model. network device. This is used by the bootwrapper to interpret MAC addresses passed by the firmware when no information other than indices is available to associate an address with a device. + - phy-connection-type : a string naming the controller/PHY interface type, + i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "tbi", + or "rtbi". Example: ucc@2000 { @@ -1574,6 +1577,7 @@ platforms are moved over to use the flattened-device-tree model. rx-clock = "none"; tx-clock = "clk9"; phy-handle = <212000>; + phy-connection-type = "gmii"; pio-handle = <140001>; }; diff --git a/trunk/Documentation/rtc.txt b/trunk/Documentation/rtc.txt index 1ef6bb88cd00..7c701b88d6d5 100644 --- a/trunk/Documentation/rtc.txt +++ b/trunk/Documentation/rtc.txt @@ -147,7 +147,7 @@ RTC class framework, but can't be supported by the older driver. * RTC_AIE_ON, RTC_AIE_OFF, RTC_ALM_SET, RTC_ALM_READ ... when the RTC is connected to an IRQ line, it can often issue an alarm IRQ up to - 24 hours in the future. + 24 hours in the future. (Use RTC_WKALM_* by preference.) * RTC_WKALM_SET, RTC_WKALM_RD ... RTCs that can issue alarms beyond the next 24 hours use a slightly more powerful API, which supports @@ -175,10 +175,7 @@ driver returns ENOIOCTLCMD. Some common examples: called with appropriate values. * RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: the - set_alarm/read_alarm functions will be called. To differentiate - between the ALM and WKALM, check the larger fields of the rtc_wkalrm - struct (like tm_year). These will be set to -1 when using ALM and - will be set to proper values when using WKALM. + set_alarm/read_alarm functions will be called. * RTC_IRQP_SET, RTC_IRQP_READ: the irq_set_freq function will be called to set the frequency while the framework will handle the read for you diff --git a/trunk/Documentation/sh/clk.txt b/trunk/Documentation/sh/clk.txt new file mode 100644 index 000000000000..9aef710e9a4b --- /dev/null +++ b/trunk/Documentation/sh/clk.txt @@ -0,0 +1,32 @@ +Clock framework on SuperH architecture + +The framework on SH extends existing API by the function clk_set_rate_ex, +which prototype is as follows: + + clk_set_rate_ex (struct clk *clk, unsigned long rate, int algo_id) + +The algo_id parameter is used to specify algorithm used to recalculate clocks, +adjanced to clock, specified as first argument. It is assumed that algo_id==0 +means no changes to adjanced clock + +Internally, the clk_set_rate_ex forwards request to clk->ops->set_rate method, +if it is present in ops structure. The method should set the clock rate and adjust +all needed clocks according to the passed algo_id. +Exact values for algo_id are machine-dependend. For the sh7722, the following +values are defined: + + NO_CHANGE = 0, + IUS_N1_N1, /* I:U = N:1, U:Sh = N:1 */ + IUS_322, /* I:U:Sh = 3:2:2 */ + IUS_522, /* I:U:Sh = 5:2:2 */ + IUS_N11, /* I:U:Sh = N:1:1 */ + SB_N1, /* Sh:B = N:1 */ + SB3_N1, /* Sh:B3 = N:1 */ + SB3_32, /* Sh:B3 = 3:2 */ + SB3_43, /* Sh:B3 = 4:3 */ + SB3_54, /* Sh:B3 = 5:4 */ + BP_N1, /* B:P = N:1 */ + IP_N1 /* I:P = N:1 */ + +Each of these constants means relation between clocks that can be set via the FRQCR +register diff --git a/trunk/Documentation/spi/pxa2xx b/trunk/Documentation/spi/pxa2xx index f9717fe9bd85..215e3b8e7266 100644 --- a/trunk/Documentation/spi/pxa2xx +++ b/trunk/Documentation/spi/pxa2xx @@ -62,7 +62,7 @@ static struct resource pxa_spi_nssp_resources[] = { static struct pxa2xx_spi_master pxa_nssp_master_info = { .ssp_type = PXA25x_NSSP, /* Type of SSP */ - .clock_enable = CKEN9_NSSP, /* NSSP Peripheral clock */ + .clock_enable = CKEN_NSSP, /* NSSP Peripheral clock */ .num_chipselect = 1, /* Matches the number of chips attached to NSSP */ .enable_dma = 1, /* Enables NSSP DMA */ }; diff --git a/trunk/Documentation/spi/spi-summary b/trunk/Documentation/spi/spi-summary index ecc7c9eb9f29..795fbb48ffa7 100644 --- a/trunk/Documentation/spi/spi-summary +++ b/trunk/Documentation/spi/spi-summary @@ -8,7 +8,7 @@ What is SPI? The "Serial Peripheral Interface" (SPI) is a synchronous four wire serial link used to connect microcontrollers to sensors, memory, and peripherals. -The three signal wires hold a clock (SCLK, often on the order of 10 MHz), +The three signal wires hold a clock (SCK, often on the order of 10 MHz), and parallel data lines with "Master Out, Slave In" (MOSI) or "Master In, Slave Out" (MISO) signals. (Other names are also used.) There are four clocking modes through which data is exchanged; mode-0 and mode-3 are most @@ -22,7 +22,7 @@ other signals, often including an interrupt to the master. Unlike serial busses like USB or SMBUS, even low level protocols for SPI slave functions are usually not interoperable between vendors -(except for cases like SPI memory chips). +(except for commodities like SPI memory chips). - SPI may be used for request/response style device protocols, as with touchscreen sensors and memory chips. @@ -77,8 +77,9 @@ cards without needing a special purpose MMC/SD/SDIO controller. How do these driver programming interfaces work? ------------------------------------------------ The header file includes kerneldoc, as does the -main source code, and you should certainly read that. This is just -an overview, so you get the big picture before the details. +main source code, and you should certainly read that chapter of the +kernel API document. This is just an overview, so you get the big +picture before those details. SPI requests always go into I/O queues. Requests for a given SPI device are always executed in FIFO order, and complete asynchronously through @@ -88,7 +89,7 @@ a command and then reading its response. There are two types of SPI driver, here called: - Controller drivers ... these are often built in to System-On-Chip + Controller drivers ... controllers may be built in to System-On-Chip processors, and often support both Master and Slave roles. These drivers touch hardware registers and may use DMA. Or they can be PIO bitbangers, needing just GPIO pins. @@ -108,18 +109,18 @@ those two types of driver. At this writing, Linux has no slave side programming interface. There is a minimal core of SPI programming interfaces, focussing on -using driver model to connect controller and protocol drivers using +using the driver model to connect controller and protocol drivers using device tables provided by board specific initialization code. SPI shows up in sysfs in several locations: - /sys/devices/.../CTLR/spiB.C ... spi_device for on bus "B", + /sys/devices/.../CTLR/spiB.C ... spi_device on bus "B", chipselect C, accessed through CTLR. /sys/devices/.../CTLR/spiB.C/modalias ... identifies the driver that should be used with this device (for hotplug/coldplug) /sys/bus/spi/devices/spiB.C ... symlink to the physical - spiB-C device + spiB.C device /sys/bus/spi/drivers/D ... driver for one or more spi*.* devices @@ -240,7 +241,7 @@ The board_info should provide enough information to let the system work without the chip's driver being loaded. The most troublesome aspect of that is likely the SPI_CS_HIGH bit in the spi_device.mode field, since sharing a bus with a device that interprets chipselect "backwards" is -not possible. +not possible until the infrastructure knows how to deselect it. Then your board initialization code would register that table with the SPI infrastructure, so that it's available later when the SPI master controller @@ -268,16 +269,14 @@ board info based on the board that was hotplugged. Of course, you'd later call at least spi_unregister_device() when that board is removed. When Linux includes support for MMC/SD/SDIO/DataFlash cards through SPI, those -configurations will also be dynamic. Fortunately, those devices all support -basic device identification probes, so that support should hotplug normally. +configurations will also be dynamic. Fortunately, such devices all support +basic device identification probes, so they should hotplug normally. How do I write an "SPI Protocol Driver"? ---------------------------------------- -All SPI drivers are currently kernel drivers. A userspace driver API -would just be another kernel driver, probably offering some lowlevel -access through aio_read(), aio_write(), and ioctl() calls and using the -standard userspace sysfs mechanisms to bind to a given SPI device. +Most SPI drivers are currently kernel drivers, but there's also support +for userspace drivers. Here we talk only about kernel drivers. SPI protocol drivers somewhat resemble platform device drivers: @@ -319,7 +318,8 @@ might look like this unless you're creating a class_device: As soon as it enters probe(), the driver may issue I/O requests to the SPI device using "struct spi_message". When remove() returns, -the driver guarantees that it won't submit any more such messages. +or after probe() fails, the driver guarantees that it won't submit +any more such messages. - An spi_message is a sequence of protocol operations, executed as one atomic sequence. SPI driver controls include: @@ -368,7 +368,8 @@ the driver guarantees that it won't submit any more such messages. Some drivers may need to modify spi_device characteristics like the transfer mode, wordsize, or clock rate. This is done with spi_setup(), which would normally be called from probe() before the first I/O is -done to the device. +done to the device. However, that can also be called at any time +that no message is pending for that device. While "spi_device" would be the bottom boundary of the driver, the upper boundaries might include sysfs (especially for sensor readings), @@ -445,11 +446,15 @@ SPI MASTER METHODS This sets up the device clock rate, SPI mode, and word sizes. Drivers may change the defaults provided by board_info, and then call spi_setup(spi) to invoke this routine. It may sleep. + Unless each SPI slave has its own configuration registers, don't + change them right away ... otherwise drivers could corrupt I/O + that's in progress for other SPI devices. master->transfer(struct spi_device *spi, struct spi_message *message) This must not sleep. Its responsibility is arrange that the - transfer happens and its complete() callback is issued; the two - will normally happen later, after other transfers complete. + transfer happens and its complete() callback is issued. The two + will normally happen later, after other transfers complete, and + if the controller is idle it will need to be kickstarted. master->cleanup(struct spi_device *spi) Your controller driver may use spi_device.controller_state to hold diff --git a/trunk/Documentation/spi/spidev b/trunk/Documentation/spi/spidev new file mode 100644 index 000000000000..5c8e1b988a08 --- /dev/null +++ b/trunk/Documentation/spi/spidev @@ -0,0 +1,307 @@ +SPI devices have a limited userspace API, supporting basic half-duplex +read() and write() access to SPI slave devices. Using ioctl() requests, +full duplex transfers and device I/O configuration are also available. + + #include + #include + #include + #include + #include + +Some reasons you might want to use this programming interface include: + + * Prototyping in an environment that's not crash-prone; stray pointers + in userspace won't normally bring down any Linux system. + + * Developing simple protocols used to talk to microcontrollers acting + as SPI slaves, which you may need to change quite often. + +Of course there are drivers that can never be written in userspace, because +they need to access kernel interfaces (such as IRQ handlers or other layers +of the driver stack) that are not accessible to userspace. + + +DEVICE CREATION, DRIVER BINDING +=============================== +The simplest way to arrange to use this driver is to just list it in the +spi_board_info for a device as the driver it should use: the "modalias" +entry is "spidev", matching the name of the driver exposing this API. +Set up the other device characteristics (bits per word, SPI clocking, +chipselect polarity, etc) as usual, so you won't always need to override +them later. + +(Sysfs also supports userspace driven binding/unbinding of drivers to +devices. That mechanism might be supported here in the future.) + +When you do that, the sysfs node for the SPI device will include a child +device node with a "dev" attribute that will be understood by udev or mdev. +(Larger systems will have "udev". Smaller ones may configure "mdev" into +busybox; it's less featureful, but often enough.) For a SPI device with +chipselect C on bus B, you should see: + + /dev/spidevB.C ... character special device, major number 153 with + a dynamically chosen minor device number. This is the node + that userspace programs will open, created by "udev" or "mdev". + + /sys/devices/.../spiB.C ... as usual, the SPI device node will + be a child of its SPI master controller. + + /sys/class/spidev/spidevB.C ... created when the "spidev" driver + binds to that device. (Directory or symlink, based on whether + or not you enabled the "deprecated sysfs files" Kconfig option.) + +Do not try to manage the /dev character device special file nodes by hand. +That's error prone, and you'd need to pay careful attention to system +security issues; udev/mdev should already be configured securely. + +If you unbind the "spidev" driver from that device, those two "spidev" nodes +(in sysfs and in /dev) should automatically be removed (respectively by the +kernel and by udev/mdev). You can unbind by removing the "spidev" driver +module, which will affect all devices using this driver. You can also unbind +by having kernel code remove the SPI device, probably by removing the driver +for its SPI controller (so its spi_master vanishes). + +Since this is a standard Linux device driver -- even though it just happens +to expose a low level API to userspace -- it can be associated with any number +of devices at a time. Just provide one spi_board_info record for each such +SPI device, and you'll get a /dev device node for each device. + + +BASIC CHARACTER DEVICE API +========================== +Normal open() and close() operations on /dev/spidevB.D files work as you +would expect. + +Standard read() and write() operations are obviously only half-duplex, and +the chipselect is deactivated between those operations. Full-duplex access, +and composite operation without chipselect de-activation, is available using +the SPI_IOC_MESSAGE(N) request. + +Several ioctl() requests let your driver read or override the device's current +settings for data transfer parameters: + + SPI_IOC_RD_MODE, SPI_IOC_WR_MODE ... pass a pointer to a byte which will + return (RD) or assign (WR) the SPI transfer mode. Use the constants + SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL + (clock polarity, idle high iff this is set) or SPI_CPHA (clock phase, + sample on trailing edge iff this is set) flags. + + SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte + which will return (RD) or assign (WR) the bit justification used to + transfer SPI words. Zero indicates MSB-first; other values indicate + the less common LSB-first encoding. In both cases the specified value + is right-justified in each word, so that unused (TX) or undefined (RX) + bits are in the MSBs. + + SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD ... pass a pointer to + a byte which will return (RD) or assign (WR) the number of bits in + each SPI transfer word. The value zero signifies eight bits. + + SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ ... pass a pointer to a + u32 which will return (RD) or assign (WR) the maximum SPI transfer + speed, in Hz. The controller can't necessarily assign that specific + clock speed. + +NOTES: + + - At this time there is no async I/O support; everything is purely + synchronous. + + - There's currently no way to report the actual bit rate used to + shift data to/from a given device. + + - From userspace, you can't currently change the chip select polarity; + that could corrupt transfers to other devices sharing the SPI bus. + Each SPI device is deselected when it's not in active use, allowing + other drivers to talk to other devices. + + - There's a limit on the number of bytes each I/O request can transfer + to the SPI device. It defaults to one page, but that can be changed + using a module parameter. + + - Because SPI has no low-level transfer acknowledgement, you usually + won't see any I/O errors when talking to a non-existent device. + + +FULL DUPLEX CHARACTER DEVICE API +================================ + +See the sample program below for one example showing the use of the full +duplex programming interface. (Although it doesn't perform a full duplex +transfer.) The model is the same as that used in the kernel spi_sync() +request; the individual transfers offer the same capabilities as are +available to kernel drivers (except that it's not asynchronous). + +The example shows one half-duplex RPC-style request and response message. +These requests commonly require that the chip not be deselected between +the request and response. Several such requests could be chained into +a single kernel request, even allowing the chip to be deselected after +each response. (Other protocol options include changing the word size +and bitrate for each transfer segment.) + +To make a full duplex request, provide both rx_buf and tx_buf for the +same transfer. It's even OK if those are the same buffer. + + +SAMPLE PROGRAM +============== + +-------------------------------- CUT HERE +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +static int verbose; + +static void do_read(int fd, int len) +{ + unsigned char buf[32], *bp; + int status; + + /* read at least 2 bytes, no more than 32 */ + if (len < 2) + len = 2; + else if (len > sizeof(buf)) + len = sizeof(buf); + memset(buf, 0, sizeof buf); + + status = read(fd, buf, len); + if (status < 0) { + perror("read"); + return; + } + if (status != len) { + fprintf(stderr, "short read\n"); + return; + } + + printf("read(%2d, %2d): %02x %02x,", len, status, + buf[0], buf[1]); + status -= 2; + bp = buf + 2; + while (status-- > 0) + printf(" %02x", *bp++); + printf("\n"); +} + +static void do_msg(int fd, int len) +{ + struct spi_ioc_transfer xfer[2]; + unsigned char buf[32], *bp; + int status; + + memset(xfer, 0, sizeof xfer); + memset(buf, 0, sizeof buf); + + if (len > sizeof buf) + len = sizeof buf; + + buf[0] = 0xaa; + xfer[0].tx_buf = (__u64) buf; + xfer[0].len = 1; + + xfer[1].rx_buf = (__u64) buf; + xfer[1].len = len; + + status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer); + if (status < 0) { + perror("SPI_IOC_MESSAGE"); + return; + } + + printf("response(%2d, %2d): ", len, status); + for (bp = buf; len; len--) + printf(" %02x", *bp++); + printf("\n"); +} + +static void dumpstat(const char *name, int fd) +{ + __u8 mode, lsb, bits; + __u32 speed; + + if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) { + perror("SPI rd_mode"); + return; + } + if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) { + perror("SPI rd_lsb_fist"); + return; + } + if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) { + perror("SPI bits_per_word"); + return; + } + if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) { + perror("SPI max_speed_hz"); + return; + } + + printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n", + name, mode, bits, lsb ? "(lsb first) " : "", speed); +} + +int main(int argc, char **argv) +{ + int c; + int readcount = 0; + int msglen = 0; + int fd; + const char *name; + + while ((c = getopt(argc, argv, "hm:r:v")) != EOF) { + switch (c) { + case 'm': + msglen = atoi(optarg); + if (msglen < 0) + goto usage; + continue; + case 'r': + readcount = atoi(optarg); + if (readcount < 0) + goto usage; + continue; + case 'v': + verbose++; + continue; + case 'h': + case '?': +usage: + fprintf(stderr, + "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n", + argv[0]); + return 1; + } + } + + if ((optind + 1) != argc) + goto usage; + name = argv[optind]; + + fd = open(name, O_RDWR); + if (fd < 0) { + perror("open"); + return 1; + } + + dumpstat(name, fd); + + if (msglen) + do_msg(fd, msglen); + + if (readcount) + do_read(fd, readcount); + + close(fd); + return 0; +} diff --git a/trunk/Documentation/sysctl/vm.txt b/trunk/Documentation/sysctl/vm.txt index e96a341eb7e4..1d192565e182 100644 --- a/trunk/Documentation/sysctl/vm.txt +++ b/trunk/Documentation/sysctl/vm.txt @@ -197,11 +197,22 @@ and may not be fast. panic_on_oom -This enables or disables panic on out-of-memory feature. If this is set to 1, -the kernel panics when out-of-memory happens. If this is set to 0, the kernel -will kill some rogue process, called oom_killer. Usually, oom_killer can kill -rogue processes and system will survive. If you want to panic the system -rather than killing rogue processes, set this to 1. +This enables or disables panic on out-of-memory feature. -The default value is 0. +If this is set to 0, the kernel will kill some rogue process, +called oom_killer. Usually, oom_killer can kill rogue processes and +system will survive. + +If this is set to 1, the kernel panics when out-of-memory happens. +However, if a process limits using nodes by mempolicy/cpusets, +and those nodes become memory exhaustion status, one process +may be killed by oom-killer. No panic occurs in this case. +Because other nodes' memory may be free. This means system total status +may be not fatal yet. +If this is set to 2, the kernel panics compulsorily even on the +above-mentioned. + +The default value is 0. +1 and 2 are for failover of clustering. Please select either +according to your policy of failover. diff --git a/trunk/Documentation/sysrq.txt b/trunk/Documentation/sysrq.txt index d43aa9d3c105..ba328f255417 100644 --- a/trunk/Documentation/sysrq.txt +++ b/trunk/Documentation/sysrq.txt @@ -1,6 +1,6 @@ Linux Magic System Request Key Hacks Documentation for sysrq.c -Last update: 2007-JAN-06 +Last update: 2007-MAR-14 * What is the magic SysRq key? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -75,7 +75,7 @@ On all - write a character to /proc/sysrq-trigger. e.g.: 'f' - Will call oom_kill to kill a memory hog process. -'g' - Used by kgdb on ppc platforms. +'g' - Used by kgdb on ppc and sh platforms. 'h' - Will display help (actually any other key than those listed above will display help. but 'h' is easy to remember :-) diff --git a/trunk/Documentation/tty.txt b/trunk/Documentation/tty.txt index 5f799e612e03..048a8762cfb5 100644 --- a/trunk/Documentation/tty.txt +++ b/trunk/Documentation/tty.txt @@ -108,7 +108,9 @@ hardware driver through the function pointers within the tty->driver structure: write() Write a block of characters to the tty device. - Returns the number of characters accepted. + Returns the number of characters accepted. The + character buffer passed to this method is already + in kernel space. put_char() Queues a character for writing to the tty device. If there is no room in the queue, the character is diff --git a/trunk/Documentation/vm/slabinfo.c b/trunk/Documentation/vm/slabinfo.c new file mode 100644 index 000000000000..41710ccf3a29 --- /dev/null +++ b/trunk/Documentation/vm/slabinfo.c @@ -0,0 +1,943 @@ +/* + * Slabinfo: Tool to get reports about slabs + * + * (C) 2007 sgi, Christoph Lameter + * + * Compile by: + * + * gcc -o slabinfo slabinfo.c + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_SLABS 500 +#define MAX_ALIASES 500 +#define MAX_NODES 1024 + +struct slabinfo { + char *name; + int alias; + int refs; + int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu; + int hwcache_align, object_size, objs_per_slab; + int sanity_checks, slab_size, store_user, trace; + int order, poison, reclaim_account, red_zone; + unsigned long partial, objects, slabs; + int numa[MAX_NODES]; + int numa_partial[MAX_NODES]; +} slabinfo[MAX_SLABS]; + +struct aliasinfo { + char *name; + char *ref; + struct slabinfo *slab; +} aliasinfo[MAX_ALIASES]; + +int slabs = 0; +int aliases = 0; +int alias_targets = 0; +int highest_node = 0; + +char buffer[4096]; + +int show_alias = 0; +int show_slab = 0; +int skip_zero = 1; +int show_numa = 0; +int show_track = 0; +int show_first_alias = 0; +int validate = 0; +int shrink = 0; +int show_inverted = 0; +int show_single_ref = 0; +int show_totals = 0; +int sort_size = 0; + +int page_size; + +regex_t pattern; + +void fatal(const char *x, ...) +{ + va_list ap; + + va_start(ap, x); + vfprintf(stderr, x, ap); + va_end(ap); + exit(1); +} + +void usage(void) +{ + printf("slabinfo [-ahnpvtsz] [slab-regexp]\n" + "-a|--aliases Show aliases\n" + "-h|--help Show usage information\n" + "-n|--numa Show NUMA information\n" + "-s|--shrink Shrink slabs\n" + "-v|--validate Validate slabs\n" + "-t|--tracking Show alloc/free information\n" + "-T|--Totals Show summary information\n" + "-l|--slabs Show slabs\n" + "-S|--Size Sort by size\n" + "-z|--zero Include empty slabs\n" + "-f|--first-alias Show first alias\n" + "-i|--inverted Inverted list\n" + "-1|--1ref Single reference\n" + ); +} + +unsigned long read_obj(char *name) +{ + FILE *f = fopen(name, "r"); + + if (!f) + buffer[0] = 0; + else { + if (!fgets(buffer,sizeof(buffer), f)) + buffer[0] = 0; + fclose(f); + if (buffer[strlen(buffer)] == '\n') + buffer[strlen(buffer)] = 0; + } + return strlen(buffer); +} + + +/* + * Get the contents of an attribute + */ +unsigned long get_obj(char *name) +{ + if (!read_obj(name)) + return 0; + + return atol(buffer); +} + +unsigned long get_obj_and_str(char *name, char **x) +{ + unsigned long result = 0; + char *p; + + *x = NULL; + + if (!read_obj(name)) { + x = NULL; + return 0; + } + result = strtoul(buffer, &p, 10); + while (*p == ' ') + p++; + if (*p) + *x = strdup(p); + return result; +} + +void set_obj(struct slabinfo *s, char *name, int n) +{ + char x[100]; + + sprintf(x, "%s/%s", s->name, name); + + FILE *f = fopen(x, "w"); + + if (!f) + fatal("Cannot write to %s\n", x); + + fprintf(f, "%d\n", n); + fclose(f); +} + +/* + * Put a size string together + */ +int store_size(char *buffer, unsigned long value) +{ + unsigned long divisor = 1; + char trailer = 0; + int n; + + if (value > 1000000000UL) { + divisor = 100000000UL; + trailer = 'G'; + } else if (value > 1000000UL) { + divisor = 100000UL; + trailer = 'M'; + } else if (value > 1000UL) { + divisor = 100; + trailer = 'K'; + } + + value /= divisor; + n = sprintf(buffer, "%ld",value); + if (trailer) { + buffer[n] = trailer; + n++; + buffer[n] = 0; + } + if (divisor != 1) { + memmove(buffer + n - 2, buffer + n - 3, 4); + buffer[n-2] = '.'; + n++; + } + return n; +} + +void decode_numa_list(int *numa, char *t) +{ + int node; + int nr; + + memset(numa, 0, MAX_NODES * sizeof(int)); + + while (*t == 'N') { + t++; + node = strtoul(t, &t, 10); + if (*t == '=') { + t++; + nr = strtoul(t, &t, 10); + numa[node] = nr; + if (node > highest_node) + highest_node = node; + } + while (*t == ' ') + t++; + } +} + +void slab_validate(struct slabinfo *s) +{ + set_obj(s, "validate", 1); +} + +void slab_shrink(struct slabinfo *s) +{ + set_obj(s, "shrink", 1); +} + +int line = 0; + +void first_line(void) +{ + printf("Name Objects Objsize Space " + "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); +} + +/* + * Find the shortest alias of a slab + */ +struct aliasinfo *find_one_alias(struct slabinfo *find) +{ + struct aliasinfo *a; + struct aliasinfo *best = NULL; + + for(a = aliasinfo;a < aliasinfo + aliases; a++) { + if (a->slab == find && + (!best || strlen(best->name) < strlen(a->name))) { + best = a; + if (strncmp(a->name,"kmall", 5) == 0) + return best; + } + } + if (best) + return best; + fatal("Cannot find alias for %s\n", find->name); + return NULL; +} + +unsigned long slab_size(struct slabinfo *s) +{ + return s->slabs * (page_size << s->order); +} + + +void slabcache(struct slabinfo *s) +{ + char size_str[20]; + char dist_str[40]; + char flags[20]; + char *p = flags; + + if (skip_zero && !s->slabs) + return; + + store_size(size_str, slab_size(s)); + sprintf(dist_str,"%lu/%lu/%d", s->slabs, s->partial, s->cpu_slabs); + + if (!line++) + first_line(); + + if (s->aliases) + *p++ = '*'; + if (s->cache_dma) + *p++ = 'd'; + if (s->hwcache_align) + *p++ = 'A'; + if (s->poison) + *p++ = 'P'; + if (s->reclaim_account) + *p++ = 'a'; + if (s->red_zone) + *p++ = 'Z'; + if (s->sanity_checks) + *p++ = 'F'; + if (s->store_user) + *p++ = 'U'; + if (s->trace) + *p++ = 'T'; + + *p = 0; + printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n", + s->name, s->objects, s->object_size, size_str, dist_str, + s->objs_per_slab, s->order, + s->slabs ? (s->partial * 100) / s->slabs : 100, + s->slabs ? (s->objects * s->object_size * 100) / + (s->slabs * (page_size << s->order)) : 100, + flags); +} + +void slab_numa(struct slabinfo *s) +{ + int node; + + if (!highest_node) + fatal("No NUMA information available.\n"); + + if (skip_zero && !s->slabs) + return; + + if (!line) { + printf("\nSlab Node "); + for(node = 0; node <= highest_node; node++) + printf(" %4d", node); + printf("\n----------------------"); + for(node = 0; node <= highest_node; node++) + printf("-----"); + printf("\n"); + } + printf("%-21s ", s->name); + for(node = 0; node <= highest_node; node++) { + char b[20]; + + store_size(b, s->numa[node]); + printf(" %4s", b); + } + printf("\n"); + line++; +} + +void show_tracking(struct slabinfo *s) +{ + printf("\n%s: Calls to allocate a slab object\n", s->name); + printf("---------------------------------------------------\n"); + if (read_obj("alloc_calls")) + printf(buffer); + + printf("%s: Calls to free a slab object\n", s->name); + printf("-----------------------------------------------\n"); + if (read_obj("free_calls")) + printf(buffer); + +} + +void totals(void) +{ + struct slabinfo *s; + + int used_slabs = 0; + char b1[20], b2[20], b3[20], b4[20]; + unsigned long long max = 1ULL << 63; + + /* Object size */ + unsigned long long min_objsize = max, max_objsize = 0, avg_objsize; + + /* Number of partial slabs in a slabcache */ + unsigned long long min_partial = max, max_partial = 0, + avg_partial, total_partial = 0; + + /* Number of slabs in a slab cache */ + unsigned long long min_slabs = max, max_slabs = 0, + avg_slabs, total_slabs = 0; + + /* Size of the whole slab */ + unsigned long long min_size = max, max_size = 0, + avg_size, total_size = 0; + + /* Bytes used for object storage in a slab */ + unsigned long long min_used = max, max_used = 0, + avg_used, total_used = 0; + + /* Waste: Bytes used for alignment and padding */ + unsigned long long min_waste = max, max_waste = 0, + avg_waste, total_waste = 0; + /* Number of objects in a slab */ + unsigned long long min_objects = max, max_objects = 0, + avg_objects, total_objects = 0; + /* Waste per object */ + unsigned long long min_objwaste = max, + max_objwaste = 0, avg_objwaste, + total_objwaste = 0; + + /* Memory per object */ + unsigned long long min_memobj = max, + max_memobj = 0, avg_memobj, + total_objsize = 0; + + /* Percentage of partial slabs per slab */ + unsigned long min_ppart = 100, max_ppart = 0, + avg_ppart, total_ppart = 0; + + /* Number of objects in partial slabs */ + unsigned long min_partobj = max, max_partobj = 0, + avg_partobj, total_partobj = 0; + + /* Percentage of partial objects of all objects in a slab */ + unsigned long min_ppartobj = 100, max_ppartobj = 0, + avg_ppartobj, total_ppartobj = 0; + + + for (s = slabinfo; s < slabinfo + slabs; s++) { + unsigned long long size; + unsigned long used; + unsigned long long wasted; + unsigned long long objwaste; + long long objects_in_partial_slabs; + unsigned long percentage_partial_slabs; + unsigned long percentage_partial_objs; + + if (!s->slabs || !s->objects) + continue; + + used_slabs++; + + size = slab_size(s); + used = s->objects * s->object_size; + wasted = size - used; + objwaste = s->slab_size - s->object_size; + + objects_in_partial_slabs = s->objects - + (s->slabs - s->partial - s ->cpu_slabs) * + s->objs_per_slab; + + if (objects_in_partial_slabs < 0) + objects_in_partial_slabs = 0; + + percentage_partial_slabs = s->partial * 100 / s->slabs; + if (percentage_partial_slabs > 100) + percentage_partial_slabs = 100; + + percentage_partial_objs = objects_in_partial_slabs * 100 + / s->objects; + + if (percentage_partial_objs > 100) + percentage_partial_objs = 100; + + if (s->object_size < min_objsize) + min_objsize = s->object_size; + if (s->partial < min_partial) + min_partial = s->partial; + if (s->slabs < min_slabs) + min_slabs = s->slabs; + if (size < min_size) + min_size = size; + if (wasted < min_waste) + min_waste = wasted; + if (objwaste < min_objwaste) + min_objwaste = objwaste; + if (s->objects < min_objects) + min_objects = s->objects; + if (used < min_used) + min_used = used; + if (objects_in_partial_slabs < min_partobj) + min_partobj = objects_in_partial_slabs; + if (percentage_partial_slabs < min_ppart) + min_ppart = percentage_partial_slabs; + if (percentage_partial_objs < min_ppartobj) + min_ppartobj = percentage_partial_objs; + if (s->slab_size < min_memobj) + min_memobj = s->slab_size; + + if (s->object_size > max_objsize) + max_objsize = s->object_size; + if (s->partial > max_partial) + max_partial = s->partial; + if (s->slabs > max_slabs) + max_slabs = s->slabs; + if (size > max_size) + max_size = size; + if (wasted > max_waste) + max_waste = wasted; + if (objwaste > max_objwaste) + max_objwaste = objwaste; + if (s->objects > max_objects) + max_objects = s->objects; + if (used > max_used) + max_used = used; + if (objects_in_partial_slabs > max_partobj) + max_partobj = objects_in_partial_slabs; + if (percentage_partial_slabs > max_ppart) + max_ppart = percentage_partial_slabs; + if (percentage_partial_objs > max_ppartobj) + max_ppartobj = percentage_partial_objs; + if (s->slab_size > max_memobj) + max_memobj = s->slab_size; + + total_partial += s->partial; + total_slabs += s->slabs; + total_size += size; + total_waste += wasted; + + total_objects += s->objects; + total_used += used; + total_partobj += objects_in_partial_slabs; + total_ppart += percentage_partial_slabs; + total_ppartobj += percentage_partial_objs; + + total_objwaste += s->objects * objwaste; + total_objsize += s->objects * s->slab_size; + } + + if (!total_objects) { + printf("No objects\n"); + return; + } + if (!used_slabs) { + printf("No slabs\n"); + return; + } + + /* Per slab averages */ + avg_partial = total_partial / used_slabs; + avg_slabs = total_slabs / used_slabs; + avg_size = total_size / used_slabs; + avg_waste = total_waste / used_slabs; + + avg_objects = total_objects / used_slabs; + avg_used = total_used / used_slabs; + avg_partobj = total_partobj / used_slabs; + avg_ppart = total_ppart / used_slabs; + avg_ppartobj = total_ppartobj / used_slabs; + + /* Per object object sizes */ + avg_objsize = total_used / total_objects; + avg_objwaste = total_objwaste / total_objects; + avg_partobj = total_partobj * 100 / total_objects; + avg_memobj = total_objsize / total_objects; + + printf("Slabcache Totals\n"); + printf("----------------\n"); + printf("Slabcaches : %3d Aliases : %3d->%-3d Active: %3d\n", + slabs, aliases, alias_targets, used_slabs); + + store_size(b1, total_size);store_size(b2, total_waste); + store_size(b3, total_waste * 100 / total_used); + printf("Memory used: %6s # Loss : %6s MRatio: %6s%%\n", b1, b2, b3); + + store_size(b1, total_objects);store_size(b2, total_partobj); + store_size(b3, total_partobj * 100 / total_objects); + printf("# Objects : %6s # PartObj: %6s ORatio: %6s%%\n", b1, b2, b3); + + printf("\n"); + printf("Per Cache Average Min Max Total\n"); + printf("---------------------------------------------------------\n"); + + store_size(b1, avg_objects);store_size(b2, min_objects); + store_size(b3, max_objects);store_size(b4, total_objects); + printf("#Objects %10s %10s %10s %10s\n", + b1, b2, b3, b4); + + store_size(b1, avg_slabs);store_size(b2, min_slabs); + store_size(b3, max_slabs);store_size(b4, total_slabs); + printf("#Slabs %10s %10s %10s %10s\n", + b1, b2, b3, b4); + + store_size(b1, avg_partial);store_size(b2, min_partial); + store_size(b3, max_partial);store_size(b4, total_partial); + printf("#PartSlab %10s %10s %10s %10s\n", + b1, b2, b3, b4); + store_size(b1, avg_ppart);store_size(b2, min_ppart); + store_size(b3, max_ppart); + store_size(b4, total_partial * 100 / total_slabs); + printf("%%PartSlab %10s%% %10s%% %10s%% %10s%%\n", + b1, b2, b3, b4); + + store_size(b1, avg_partobj);store_size(b2, min_partobj); + store_size(b3, max_partobj); + store_size(b4, total_partobj); + printf("PartObjs %10s %10s %10s %10s\n", + b1, b2, b3, b4); + + store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj); + store_size(b3, max_ppartobj); + store_size(b4, total_partobj * 100 / total_objects); + printf("%% PartObj %10s%% %10s%% %10s%% %10s%%\n", + b1, b2, b3, b4); + + store_size(b1, avg_size);store_size(b2, min_size); + store_size(b3, max_size);store_size(b4, total_size); + printf("Memory %10s %10s %10s %10s\n", + b1, b2, b3, b4); + + store_size(b1, avg_used);store_size(b2, min_used); + store_size(b3, max_used);store_size(b4, total_used); + printf("Used %10s %10s %10s %10s\n", + b1, b2, b3, b4); + + store_size(b1, avg_waste);store_size(b2, min_waste); + store_size(b3, max_waste);store_size(b4, total_waste); + printf("Loss %10s %10s %10s %10s\n", + b1, b2, b3, b4); + + printf("\n"); + printf("Per Object Average Min Max\n"); + printf("---------------------------------------------\n"); + + store_size(b1, avg_memobj);store_size(b2, min_memobj); + store_size(b3, max_memobj); + printf("Memory %10s %10s %10s\n", + b1, b2, b3); + store_size(b1, avg_objsize);store_size(b2, min_objsize); + store_size(b3, max_objsize); + printf("User %10s %10s %10s\n", + b1, b2, b3); + + store_size(b1, avg_objwaste);store_size(b2, min_objwaste); + store_size(b3, max_objwaste); + printf("Loss %10s %10s %10s\n", + b1, b2, b3); +} + +void sort_slabs(void) +{ + struct slabinfo *s1,*s2; + + for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) { + for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) { + int result; + + if (sort_size) + result = slab_size(s1) < slab_size(s2); + else + result = strcasecmp(s1->name, s2->name); + + if (show_inverted) + result = -result; + + if (result > 0) { + struct slabinfo t; + + memcpy(&t, s1, sizeof(struct slabinfo)); + memcpy(s1, s2, sizeof(struct slabinfo)); + memcpy(s2, &t, sizeof(struct slabinfo)); + } + } + } +} + +void sort_aliases(void) +{ + struct aliasinfo *a1,*a2; + + for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) { + for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) { + char *n1, *n2; + + n1 = a1->name; + n2 = a2->name; + if (show_alias && !show_inverted) { + n1 = a1->ref; + n2 = a2->ref; + } + if (strcasecmp(n1, n2) > 0) { + struct aliasinfo t; + + memcpy(&t, a1, sizeof(struct aliasinfo)); + memcpy(a1, a2, sizeof(struct aliasinfo)); + memcpy(a2, &t, sizeof(struct aliasinfo)); + } + } + } +} + +void link_slabs(void) +{ + struct aliasinfo *a; + struct slabinfo *s; + + for (a = aliasinfo; a < aliasinfo + aliases; a++) { + + for(s = slabinfo; s < slabinfo + slabs; s++) + if (strcmp(a->ref, s->name) == 0) { + a->slab = s; + s->refs++; + break; + } + if (s == slabinfo + slabs) + fatal("Unresolved alias %s\n", a->ref); + } +} + +void alias(void) +{ + struct aliasinfo *a; + char *active = NULL; + + sort_aliases(); + link_slabs(); + + for(a = aliasinfo; a < aliasinfo + aliases; a++) { + + if (!show_single_ref && a->slab->refs == 1) + continue; + + if (!show_inverted) { + if (active) { + if (strcmp(a->slab->name, active) == 0) { + printf(" %s", a->name); + continue; + } + } + printf("\n%-20s <- %s", a->slab->name, a->name); + active = a->slab->name; + } + else + printf("%-20s -> %s\n", a->name, a->slab->name); + } + if (active) + printf("\n"); +} + + +void rename_slabs(void) +{ + struct slabinfo *s; + struct aliasinfo *a; + + for (s = slabinfo; s < slabinfo + slabs; s++) { + if (*s->name != ':') + continue; + + if (s->refs > 1 && !show_first_alias) + continue; + + a = find_one_alias(s); + + s->name = a->name; + } +} + +int slab_mismatch(char *slab) +{ + return regexec(&pattern, slab, 0, NULL, 0); +} + +void read_slab_dir(void) +{ + DIR *dir; + struct dirent *de; + struct slabinfo *slab = slabinfo; + struct aliasinfo *alias = aliasinfo; + char *p; + char *t; + int count; + + dir = opendir("."); + while ((de = readdir(dir))) { + if (de->d_name[0] == '.' || + slab_mismatch(de->d_name)) + continue; + switch (de->d_type) { + case DT_LNK: + alias->name = strdup(de->d_name); + count = readlink(de->d_name, buffer, sizeof(buffer)); + + if (count < 0) + fatal("Cannot read symlink %s\n", de->d_name); + + buffer[count] = 0; + p = buffer + count; + while (p > buffer && p[-1] != '/') + p--; + alias->ref = strdup(p); + alias++; + break; + case DT_DIR: + if (chdir(de->d_name)) + fatal("Unable to access slab %s\n", slab->name); + slab->name = strdup(de->d_name); + slab->alias = 0; + slab->refs = 0; + slab->aliases = get_obj("aliases"); + slab->align = get_obj("align"); + slab->cache_dma = get_obj("cache_dma"); + slab->cpu_slabs = get_obj("cpu_slabs"); + slab->destroy_by_rcu = get_obj("destroy_by_rcu"); + slab->hwcache_align = get_obj("hwcache_align"); + slab->object_size = get_obj("object_size"); + slab->objects = get_obj("objects"); + slab->objs_per_slab = get_obj("objs_per_slab"); + slab->order = get_obj("order"); + slab->partial = get_obj("partial"); + slab->partial = get_obj_and_str("partial", &t); + decode_numa_list(slab->numa_partial, t); + slab->poison = get_obj("poison"); + slab->reclaim_account = get_obj("reclaim_account"); + slab->red_zone = get_obj("red_zone"); + slab->sanity_checks = get_obj("sanity_checks"); + slab->slab_size = get_obj("slab_size"); + slab->slabs = get_obj_and_str("slabs", &t); + decode_numa_list(slab->numa, t); + slab->store_user = get_obj("store_user"); + slab->trace = get_obj("trace"); + chdir(".."); + if (slab->name[0] == ':') + alias_targets++; + slab++; + break; + default : + fatal("Unknown file type %lx\n", de->d_type); + } + } + closedir(dir); + slabs = slab - slabinfo; + aliases = alias - aliasinfo; + if (slabs > MAX_SLABS) + fatal("Too many slabs\n"); + if (aliases > MAX_ALIASES) + fatal("Too many aliases\n"); +} + +void output_slabs(void) +{ + struct slabinfo *slab; + + for (slab = slabinfo; slab < slabinfo + slabs; slab++) { + + if (slab->alias) + continue; + + + if (show_numa) + slab_numa(slab); + else + if (show_track) + show_tracking(slab); + else + if (validate) + slab_validate(slab); + else + if (shrink) + slab_shrink(slab); + else { + if (show_slab) + slabcache(slab); + } + } +} + +struct option opts[] = { + { "aliases", 0, NULL, 'a' }, + { "slabs", 0, NULL, 'l' }, + { "numa", 0, NULL, 'n' }, + { "zero", 0, NULL, 'z' }, + { "help", 0, NULL, 'h' }, + { "validate", 0, NULL, 'v' }, + { "first-alias", 0, NULL, 'f' }, + { "shrink", 0, NULL, 's' }, + { "track", 0, NULL, 't'}, + { "inverted", 0, NULL, 'i'}, + { "1ref", 0, NULL, '1'}, + { NULL, 0, NULL, 0 } +}; + +int main(int argc, char *argv[]) +{ + int c; + int err; + char *pattern_source; + + page_size = getpagesize(); + if (chdir("/sys/slab")) + fatal("This kernel does not have SLUB support.\n"); + + while ((c = getopt_long(argc, argv, "afhil1npstvzTS", opts, NULL)) != -1) + switch(c) { + case '1': + show_single_ref = 1; + break; + case 'a': + show_alias = 1; + break; + case 'f': + show_first_alias = 1; + break; + case 'h': + usage(); + return 0; + case 'i': + show_inverted = 1; + break; + case 'n': + show_numa = 1; + break; + case 's': + shrink = 1; + break; + case 'l': + show_slab = 1; + break; + case 't': + show_track = 1; + break; + case 'v': + validate = 1; + break; + case 'z': + skip_zero = 0; + break; + case 'T': + show_totals = 1; + break; + case 'S': + sort_size = 1; + break; + + default: + fatal("%s: Invalid option '%c'\n", argv[0], optopt); + + } + + if (!show_slab && !show_alias && !show_track + && !validate && !shrink) + show_slab = 1; + + if (argc > optind) + pattern_source = argv[optind]; + else + pattern_source = ".*"; + + err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB); + if (err) + fatal("%s: Invalid pattern '%s' code %d\n", + argv[0], pattern_source, err); + read_slab_dir(); + if (show_alias) + alias(); + else + if (show_totals) + totals(); + else { + link_slabs(); + rename_slabs(); + sort_slabs(); + output_slabs(); + } + return 0; +} diff --git a/trunk/Documentation/vm/slub.txt b/trunk/Documentation/vm/slub.txt new file mode 100644 index 000000000000..727c8d81aeaf --- /dev/null +++ b/trunk/Documentation/vm/slub.txt @@ -0,0 +1,113 @@ +Short users guide for SLUB +-------------------------- + +First of all slub should transparently replace SLAB. If you enable +SLUB then everything should work the same (Note the word "should". +There is likely not much value in that word at this point). + +The basic philosophy of SLUB is very different from SLAB. SLAB +requires rebuilding the kernel to activate debug options for all +SLABS. SLUB always includes full debugging but its off by default. +SLUB can enable debugging only for selected slabs in order to avoid +an impact on overall system performance which may make a bug more +difficult to find. + +In order to switch debugging on one can add a option "slub_debug" +to the kernel command line. That will enable full debugging for +all slabs. + +Typically one would then use the "slabinfo" command to get statistical +data and perform operation on the slabs. By default slabinfo only lists +slabs that have data in them. See "slabinfo -h" for more options when +running the command. slabinfo can be compiled with + +gcc -o slabinfo Documentation/vm/slabinfo.c + +Some of the modes of operation of slabinfo require that slub debugging +be enabled on the command line. F.e. no tracking information will be +available without debugging on and validation can only partially +be performed if debugging was not switched on. + +Some more sophisticated uses of slub_debug: +------------------------------------------- + +Parameters may be given to slub_debug. If none is specified then full +debugging is enabled. Format: + +slub_debug= Enable options for all slabs +slub_debug=, + Enable options only for select slabs + +Possible debug options are + F Sanity checks on (enables SLAB_DEBUG_FREE. Sorry + SLAB legacy issues) + Z Red zoning + P Poisoning (object and padding) + U User tracking (free and alloc) + T Trace (please only use on single slabs) + +F.e. in order to boot just with sanity checks and red zoning one would specify: + + slub_debug=FZ + +Trying to find an issue in the dentry cache? Try + + slub_debug=,dentry_cache + +to only enable debugging on the dentry cache. + +Red zoning and tracking may realign the slab. We can just apply sanity checks +to the dentry cache with + + slub_debug=F,dentry_cache + +In case you forgot to enable debugging on the kernel command line: It is +possible to enable debugging manually when the kernel is up. Look at the +contents of: + +/sys/slab// + +Look at the writable files. Writing 1 to them will enable the +corresponding debug option. All options can be set on a slab that does +not contain objects. If the slab already contains objects then sanity checks +and tracing may only be enabled. The other options may cause the realignment +of objects. + +Careful with tracing: It may spew out lots of information and never stop if +used on the wrong slab. + +SLAB Merging +------------ + +If no debugging is specified then SLUB may merge similar slabs together +in order to reduce overhead and increase cache hotness of objects. +slabinfo -a displays which slabs were merged together. + +Getting more performance +------------------------ + +To some degree SLUB's performance is limited by the need to take the +list_lock once in a while to deal with partial slabs. That overhead is +governed by the order of the allocation for each slab. The allocations +can be influenced by kernel parameters: + +slub_min_objects=x (default 8) +slub_min_order=x (default 0) +slub_max_order=x (default 4) + +slub_min_objects allows to specify how many objects must at least fit +into one slab in order for the allocation order to be acceptable. +In general slub will be able to perform this number of allocations +on a slab without consulting centralized resources (list_lock) where +contention may occur. + +slub_min_order specifies a minim order of slabs. A similar effect like +slub_min_objects. + +slub_max_order specified the order at which slub_min_objects should no +longer be checked. This is useful to avoid SLUB trying to generate +super large order pages to fit slub_min_objects of a slab cache with +large object sizes into one high order page. + + +Christoph Lameter, , April 10, 2007 diff --git a/trunk/Kbuild b/trunk/Kbuild index 0451f69353ba..163f8cb020a4 100644 --- a/trunk/Kbuild +++ b/trunk/Kbuild @@ -2,6 +2,7 @@ # Kbuild for top-level directory of the kernel # This file takes care of the following: # 1) Generate asm-offsets.h +# 2) Check for missing system calls ##### # 1) Generate asm-offsets.h @@ -46,3 +47,13 @@ $(obj)/$(offsets-file): arch/$(ARCH)/kernel/asm-offsets.s Kbuild $(Q)mkdir -p $(dir $@) $(call cmd,offsets) +##### +# 2) Check for missing system calls +# + +quiet_cmd_syscalls = CALL $< + cmd_syscalls = $(CONFIG_SHELL) $< $(CC) $(c_flags) + +PHONY += missing-syscalls +missing-syscalls: scripts/checksyscalls.sh FORCE + $(call cmd,syscalls) diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 0492dd88e12a..41a4b477c576 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -382,6 +382,12 @@ L: linux-laptop@vger.kernel.org W: http://www.canb.auug.org.au/~sfr/ S: Supported +APPLE SMC DRIVER +P: Nicolas Boichat +M: nicolas@boichat.ch +L: mactel-linux-devel@lists.sourceforge.net +S: Maintained + APPLETALK NETWORK LAYER P: Arnaldo Carvalho de Melo M: acme@ghostprotocols.net @@ -673,6 +679,7 @@ AUXILIARY DISPLAY DRIVERS P: Miguel Ojeda Sandonis M: maxextreme@gmail.com L: linux-kernel@vger.kernel.org +W: http://auxdisplay.googlepages.com/ S: Maintained AVR32 ARCHITECTURE @@ -700,6 +707,44 @@ P: Richard Purdie M: rpurdie@rpsys.net S: Maintained +BLACKFIN ARCHITECTURE +P: Aubrey Li +M: aubrey.li@analog.com +P: Bernd Schmidt +M: bernd.schmidt@analog.com +P: Bryan Wu +M: bryan.wu@analog.com +P: Grace Pan +M: grace.pan@analog.com +P: Michael Hennerich +M: michael.hennerich@analog.com +P: Mike Frysinger +M: michael.frysinger@analog.com +P: Jane Lv +M: jane.lv@analog.com +P: Jerry Zeng +M: jerry.zeng@analog.com +P: Jie Zhang +M: jie.zhang@analog.com +P: Robin Getz +M: robin.getz@analog.com +P: Roy Huang +M: roy.huang@analog.com +P: Sonic Zhang +M: sonic.zhang@analog.com +P: Yi Li +M: yi.li@analog.com +L: uclinux-dist-devel@blackfin.uclinux.org +W: http://blackfin.uclinux.org +S: Supported + +BLACKFIN SERIAL DRIVER +P: Aubrey Li +M: aubrey.li@analog.com +L: uclinux-dist-devel@blackfin.uclinux.org +W: http://blackfin.uclinux.org +S: Supported + BAYCOM/HDLCDRV DRIVERS FOR AX.25 P: Thomas Sailer M: t.sailer@alumni.ethz.ch @@ -899,12 +944,14 @@ CFAG12864B LCD DRIVER P: Miguel Ojeda Sandonis M: maxextreme@gmail.com L: linux-kernel@vger.kernel.org +W: http://auxdisplay.googlepages.com/ S: Maintained CFAG12864BFB LCD FRAMEBUFFER DRIVER P: Miguel Ojeda Sandonis M: maxextreme@gmail.com L: linux-kernel@vger.kernel.org +W: http://auxdisplay.googlepages.com/ S: Maintained CFG80211 and NL80211 @@ -993,6 +1040,12 @@ P: Simon Arlott M: cxacru@fire.lp0.eu S: Maintained +CORETEMP HARDWARE MONITORING DRIVER +P: Rudolf Marek +M: r.marek@assembler.cz +L: lm-sensors@lm-sensors.org +S: Maintained + COSA/SRP SYNC SERIAL DRIVER P: Jan "Yenya" Kasprzak M: kas@fi.muni.cz @@ -1983,7 +2036,7 @@ P: Vivek Goyal M: vgoyal@in.ibm.com P: Haren Myneni M: hbabu@us.ibm.com -L: fastboot@lists.linux-foundation.org +L: kexec@lists.infradead.org L: linux-kernel@vger.kernel.org W: http://lse.sourceforge.net/kdump/ S: Maintained @@ -2033,7 +2086,7 @@ P: Eric Biederman M: ebiederm@xmission.com W: http://www.xmission.com/~ebiederm/files/kexec/ L: linux-kernel@vger.kernel.org -L: fastboot@lists.linux-foundation.org +L: kexec@lists.infradead.org S: Maintained KPROBES @@ -2052,6 +2105,7 @@ KS0108 LCD CONTROLLER DRIVER P: Miguel Ojeda Sandonis M: maxextreme@gmail.com L: linux-kernel@vger.kernel.org +W: http://auxdisplay.googlepages.com/ S: Maintained LAPB module @@ -2266,6 +2320,12 @@ M: vandrove@vc.cvut.cz L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only) S: Maintained +MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER +P: Hans J. Koch +M: hjk@linutronix.de +L: lm-sensors@lm-sensors.org +S: Maintained + MEGARAID SCSI DRIVERS P: Neela Syam Kolli M: Neela.Kolli@engenio.com @@ -3060,6 +3120,11 @@ L: selinux@tycho.nsa.gov (subscribers-only, general discussion) W: http://www.nsa.gov/selinux S: Supported +SENSABLE PHANTOM +P: Jiri Slaby +M: jirislaby@gmail.com +S: Maintained + SERIAL ATA (SATA) SUBSYSTEM: P: Jeff Garzik M: jgarzik@pobox.com diff --git a/trunk/Makefile b/trunk/Makefile index 387526b69d4f..dfe559c89fe6 100644 --- a/trunk/Makefile +++ b/trunk/Makefile @@ -576,7 +576,7 @@ libs-y := $(libs-y1) $(libs-y2) # --------------------------------------------------------------------------- # vmlinux is built from the objects selected by $(vmlinux-init) and # $(vmlinux-main). Most are built-in.o files from top-level directories -# in the kernel tree, others are specified in arch/$(ARCH)Makefile. +# in the kernel tree, others are specified in arch/$(ARCH)/Makefile. # Ordering when linking is important, and $(vmlinux-init) must be first. # # vmlinux @@ -603,6 +603,7 @@ vmlinux-init := $(head-y) $(init-y) vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y) vmlinux-all := $(vmlinux-init) $(vmlinux-main) vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds +export KBUILD_VMLINUX_OBJS := $(vmlinux-all) # Rule to link vmlinux - also used during CONFIG_KALLSYMS # May be overridden by arch/$(ARCH)/Makefile @@ -855,6 +856,7 @@ archprepare: prepare1 scripts_basic prepare0: archprepare FORCE $(Q)$(MAKE) $(build)=. + $(Q)$(MAKE) $(build)=. missing-syscalls # All the preparing.. prepare: prepare0 @@ -1277,10 +1279,7 @@ endif ALLSOURCE_ARCHS := $(ARCH) define find-sources - ( find $(__srctree) $(RCS_FIND_IGNORE) \ - \( -name include -o -name arch \) -prune -o \ - -name $1 -print; \ - for ARCH in $(ALLSOURCE_ARCHS) ; do \ + ( for ARCH in $(ALLSOURCE_ARCHS) ; do \ find $(__srctree)arch/$${ARCH} $(RCS_FIND_IGNORE) \ -name $1 -print; \ done ; \ @@ -1294,7 +1293,11 @@ define find-sources -name $1 -print; \ done ; \ find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \ - -name $1 -print ) + -name $1 -print; \ + find $(__srctree) $(RCS_FIND_IGNORE) \ + \( -name include -o -name arch \) -prune -o \ + -name $1 -print; \ + ) endef define all-sources diff --git a/trunk/arch/alpha/Kconfig.debug b/trunk/arch/alpha/Kconfig.debug index 36d0106c32eb..f45f28cc10da 100644 --- a/trunk/arch/alpha/Kconfig.debug +++ b/trunk/arch/alpha/Kconfig.debug @@ -16,14 +16,6 @@ config DEBUG_RWLOCK too many attempts. If you suspect a rwlock problem or a kernel hacker asks for this option then say Y. Otherwise say N. -config DEBUG_SEMAPHORE - bool "Semaphore debugging" - depends on DEBUG_KERNEL - help - If you say Y here then semaphore processing will issue lots of - verbose debugging messages. If you suspect a semaphore problem or a - kernel hacker asks for this option then say Y. Otherwise say N. - config ALPHA_LEGACY_START_ADDRESS bool "Legacy kernel start address" depends on ALPHA_GENERIC diff --git a/trunk/arch/alpha/boot/bootpz.c b/trunk/arch/alpha/boot/bootpz.c index 4307bde80a35..1036b515e20c 100644 --- a/trunk/arch/alpha/boot/bootpz.c +++ b/trunk/arch/alpha/boot/bootpz.c @@ -467,3 +467,9 @@ start_kernel(void) #endif runkernel(); } + + /* dummy function, should never be called. */ +void *__kmalloc(size_t size, gfp_t flags) +{ + return (void *)NULL; +} diff --git a/trunk/arch/alpha/boot/tools/objstrip.c b/trunk/arch/alpha/boot/tools/objstrip.c index 67beb1b45e4f..96154e768a20 100644 --- a/trunk/arch/alpha/boot/tools/objstrip.c +++ b/trunk/arch/alpha/boot/tools/objstrip.c @@ -25,7 +25,6 @@ #include #include #include -#include #ifdef __ELF__ # include #endif diff --git a/trunk/arch/alpha/kernel/osf_sys.c b/trunk/arch/alpha/kernel/osf_sys.c index be133f1f75a4..ce857158c1ea 100644 --- a/trunk/arch/alpha/kernel/osf_sys.c +++ b/trunk/arch/alpha/kernel/osf_sys.c @@ -93,7 +93,6 @@ osf_set_program_attributes(unsigned long text_start, unsigned long text_len, * offset differences aren't the same as "d_reclen"). */ #define NAME_OFFSET offsetof (struct osf_dirent, d_name) -#define ROUND_UP(x) (((x)+3) & ~3) struct osf_dirent { unsigned int d_ino; @@ -115,7 +114,7 @@ osf_filldir(void *__buf, const char *name, int namlen, loff_t offset, { struct osf_dirent __user *dirent; struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf; - unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1); + unsigned int reclen = ALIGN(NAME_OFFSET + namlen + 1, sizeof(u32)); unsigned int d_ino; buf->error = -EINVAL; /* only used if we fail */ @@ -174,7 +173,6 @@ osf_getdirentries(unsigned int fd, struct osf_dirent __user *dirent, return error; } -#undef ROUND_UP #undef NAME_OFFSET asmlinkage unsigned long @@ -955,15 +953,25 @@ osf_setitimer(int which, struct itimerval32 __user *in, struct itimerval32 __use asmlinkage int osf_utimes(char __user *filename, struct timeval32 __user *tvs) { - struct timeval ktvs[2]; + struct timespec tv[2]; if (tvs) { + struct timeval ktvs[2]; if (get_tv32(&ktvs[0], &tvs[0]) || get_tv32(&ktvs[1], &tvs[1])) return -EFAULT; + + if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 || + ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000) + return -EINVAL; + + tv[0].tv_sec = ktvs[0].tv_sec; + tv[0].tv_nsec = 1000 * ktvs[0].tv_usec; + tv[1].tv_sec = ktvs[1].tv_sec; + tv[1].tv_nsec = 1000 * ktvs[1].tv_usec; } - return do_utimes(AT_FDCWD, filename, tvs ? ktvs : NULL); + return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0); } #define MAX_SELECT_SECONDS \ @@ -1267,6 +1275,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, if (len > limit) return -ENOMEM; + if (flags & MAP_FIXED) + return addr; + /* First, see if the given suggestion fits. The OSF/1 loader (/sbin/loader) relies on us returning an diff --git a/trunk/arch/alpha/kernel/process.c b/trunk/arch/alpha/kernel/process.c index c15186390693..92b61629fe3f 100644 --- a/trunk/arch/alpha/kernel/process.c +++ b/trunk/arch/alpha/kernel/process.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/alpha/kernel/setup.c b/trunk/arch/alpha/kernel/setup.c index d352c2b05f1a..915f26345c45 100644 --- a/trunk/arch/alpha/kernel/setup.c +++ b/trunk/arch/alpha/kernel/setup.c @@ -744,15 +744,6 @@ setup_arch(char **cmdline_p) paging_init(); } -void __init -disable_early_printk(void) -{ - if (alpha_using_srm && srmcons_output) { - unregister_srm_console(); - srmcons_output = 0; - } -} - static char sys_unknown[] = "Unknown"; static char systype_names[][16] = { "0", diff --git a/trunk/arch/alpha/kernel/signal.c b/trunk/arch/alpha/kernel/signal.c index 741da0945dc4..7f64aa767d5a 100644 --- a/trunk/arch/alpha/kernel/signal.c +++ b/trunk/arch/alpha/kernel/signal.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/alpha/kernel/smp.c b/trunk/arch/alpha/kernel/smp.c index d1ec4f51df1a..80cfb758ee2b 100644 --- a/trunk/arch/alpha/kernel/smp.c +++ b/trunk/arch/alpha/kernel/smp.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/alpha/kernel/srmcons.c b/trunk/arch/alpha/kernel/srmcons.c index 756923203860..930cedc8be24 100644 --- a/trunk/arch/alpha/kernel/srmcons.c +++ b/trunk/arch/alpha/kernel/srmcons.c @@ -164,9 +164,9 @@ srmcons_get_private_struct(struct srmcons_private **ps) int retval = 0; if (srmconsp == NULL) { + srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL); spin_lock_irqsave(&srmconsp_lock, flags); - srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL); if (srmconsp == NULL) retval = -ENOMEM; else { @@ -300,7 +300,7 @@ static struct console srmcons = { .write = srm_console_write, .device = srm_console_device, .setup = srm_console_setup, - .flags = CON_PRINTBUFFER, + .flags = CON_PRINTBUFFER | CON_BOOT, .index = -1, }; diff --git a/trunk/arch/alpha/mm/fault.c b/trunk/arch/alpha/mm/fault.c index 8aa9db834c11..f5862792a167 100644 --- a/trunk/arch/alpha/mm/fault.c +++ b/trunk/arch/alpha/mm/fault.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index db00376aca15..0d8fac3b0371 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -29,6 +29,10 @@ config GENERIC_TIME bool default n +config GENERIC_CLOCKEVENTS + bool + default n + config MMU bool default y @@ -67,6 +71,14 @@ config GENERIC_HARDIRQS bool default y +config STACKTRACE_SUPPORT + bool + default y + +config LOCKDEP_SUPPORT + bool + default y + config TRACE_IRQFLAGS_SUPPORT bool default y @@ -162,6 +174,8 @@ config ARCH_VERSATILE select ARM_AMBA select ARM_VIC select ICST307 + select GENERIC_TIME + select GENERIC_CLOCKEVENTS help This enables support for ARM Ltd Versatile board. @@ -263,6 +277,7 @@ config ARCH_IXP4XX bool "IXP4xx-based" depends on MMU select GENERIC_TIME + select GENERIC_CLOCKEVENTS help Support for Intel's IXP4XX (XScale) family of processors. @@ -364,6 +379,7 @@ config ARCH_LH7A40X config ARCH_OMAP bool "TI OMAP" select GENERIC_GPIO + select GENERIC_TIME help Support for TI's OMAP platform (OMAP1 and OMAP2). @@ -514,6 +530,8 @@ endmenu menu "Kernel Features" +source "kernel/time/Kconfig" + config SMP bool "Symmetric Multi-Processing (EXPERIMENTAL)" depends on EXPERIMENTAL && REALVIEW_MPCORE @@ -573,6 +591,7 @@ config PREEMPT config NO_IDLE_HZ bool "Dynamic tick timer" + depends on !GENERIC_CLOCKEVENTS help Select this option if you want to disable continuous timer ticks and have them programmed to occur as required. This option saves @@ -670,6 +689,7 @@ config LEDS_TIMER bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \ MACH_OMAP_H2 || MACH_OMAP_PERSEUS2 depends on LEDS + depends on !GENERIC_CLOCKEVENTS default y if ARCH_EBSA110 help If you say Y here, one of the system LEDs (the green one on the diff --git a/trunk/arch/arm/boot/compressed/head-at91rm9200.S b/trunk/arch/arm/boot/compressed/head-at91rm9200.S index d68b9acd826e..11782ccd93a1 100644 --- a/trunk/arch/arm/boot/compressed/head-at91rm9200.S +++ b/trunk/arch/arm/boot/compressed/head-at91rm9200.S @@ -61,6 +61,12 @@ cmp r7, r3 beq 99f + @ picotux 200 : 963 + mov r3, #(MACH_TYPE_PICOTUX2XX & 0xff) + orr r3, r3, #(MACH_TYPE_PICOTUX2XX & 0xff00) + cmp r7, r3 + beq 99f + @ Ajeco 1ARM : 1075 mov r3, #(MACH_TYPE_ONEARM & 0xff) orr r3, r3, #(MACH_TYPE_ONEARM & 0xff00) diff --git a/trunk/arch/arm/common/sa1111.c b/trunk/arch/arm/common/sa1111.c index fe3f05901a23..798bbfccafb7 100644 --- a/trunk/arch/arm/common/sa1111.c +++ b/trunk/arch/arm/common/sa1111.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/arm/common/via82c505.c b/trunk/arch/arm/common/via82c505.c index ba2e62986a57..79a8206e62ac 100644 --- a/trunk/arch/arm/common/via82c505.c +++ b/trunk/arch/arm/common/via82c505.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include diff --git a/trunk/arch/arm/configs/ixp4xx_defconfig b/trunk/arch/arm/configs/ixp4xx_defconfig index fabf74c51a88..db850a5689eb 100644 --- a/trunk/arch/arm/configs/ixp4xx_defconfig +++ b/trunk/arch/arm/configs/ixp4xx_defconfig @@ -117,11 +117,13 @@ CONFIG_ARCH_ADI_COYOTE=y CONFIG_ARCH_IXDP425=y CONFIG_MACH_IXDPG425=y CONFIG_MACH_IXDP465=y +CONFIG_MACH_KIXRP435=y CONFIG_ARCH_IXCDP1100=y CONFIG_ARCH_PRPMC1100=y CONFIG_MACH_NAS100D=y CONFIG_ARCH_IXDP4XX=y CONFIG_CPU_IXP46X=y +CONFIG_CPU_IXP43X=y # CONFIG_MACH_GTWX5715 is not set # diff --git a/trunk/arch/arm/configs/picotux200_defconfig b/trunk/arch/arm/configs/picotux200_defconfig new file mode 100644 index 000000000000..339c48953a62 --- /dev/null +++ b/trunk/arch/arm/configs/picotux200_defconfig @@ -0,0 +1,1386 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.21-rc4 +# Wed Mar 28 16:19:50 2007 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_GENERIC_TIME is not set +CONFIG_MMU=y +# CONFIG_NO_IOPORT is not set +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_ZONE_DMA=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_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=m +CONFIG_IKCONFIG_PROC=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS 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 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=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_NS9XXX 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=y +# CONFIG_ARCH_AT91SAM9260 is not set +# CONFIG_ARCH_AT91SAM9261 is not set +# CONFIG_ARCH_AT91SAM9263 is not set + +# +# AT91RM9200 Board Type +# +# CONFIG_MACH_ONEARM is not set +# CONFIG_ARCH_AT91RM9200DK is not set +# CONFIG_MACH_AT91RM9200EK is not set +# CONFIG_MACH_CSB337 is not set +# CONFIG_MACH_CSB637 is not set +# CONFIG_MACH_CARMEVA is not set +# CONFIG_MACH_ATEB9200 is not set +# CONFIG_MACH_KB9200 is not set +CONFIG_MACH_PICOTUX2XX=y +# CONFIG_MACH_KAFA is not set + +# +# AT91 Board Options +# + +# +# AT91 Feature Selections +# +CONFIG_AT91_PROGRAMMABLE_CLOCKS=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM920T=y +CONFIG_CPU_32v4T=y +CONFIG_CPU_ABRT_EV4T=y +CONFIG_CPU_CACHE_V4WT=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=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_OUTER_CACHE 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=y +CONFIG_HZ=100 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +# 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_ZONE_DMA_FLAG=1 +# CONFIG_LEDS 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 +CONFIG_KEXEC=y + +# +# 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 + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=m + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_DIAG=m +CONFIG_INET_TCP_DIAG=m +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6_MULTIPLE_TABLES 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=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# 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=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=m +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# 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=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0x8000000 +CONFIG_MTD_PHYSMAP_LEN=0x0 +CONFIG_MTD_PHYSMAP_BANKWIDTH=2 +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND 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 +# +# CONFIG_PNPACPI is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +# 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 is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=m +# 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=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_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=m + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_ARM_AT91_ETHER=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=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLHC=m +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +# 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 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 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT 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 is not set + +# +# 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 +CONFIG_AT91RM9200_WATCHDOG=m + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_HW_RANDOM=m +# 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=m +CONFIG_I2C_CHARDEV=m + +# +# 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=m +CONFIG_I2C_ISA=m +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +# 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 is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=m +CONFIG_HWMON_VID=m +# CONFIG_SENSORS_ABITUGURU is not set +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +CONFIG_SENSORS_DS1621=m +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_MAX1619=m +# 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=m +# CONFIG_SENSORS_VT1211 is not set +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Misc devices +# + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 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_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# HID Devices +# +CONFIG_HID=m +# CONFIG_HID_DEBUG is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB_ARCH_HAS_EHCI is not set +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_SL811_HCD is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=m +# 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_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=m +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV 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 +# CONFIG_USB_GTCO is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Network Adapters +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET_MII=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +CONFIG_USB_NET_ZAURUS=m +# CONFIG_USB_MON is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_AIRPRIME is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP2101 is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +CONFIG_USB_SERIAL_PL2303=m +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_DEBUG 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_BERRY_CHARGE 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_IOWARRIOR is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=m +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=m +CONFIG_MMC_AT91=m + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=m + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=m +CONFIG_RTC_INTF_PROC=m +CONFIG_RTC_INTF_DEV=m +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set + +# +# RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_M48T86 is not set +CONFIG_RTC_DRV_AT91RM9200=m +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# File systems +# +CONFIG_EXT2_FS=m +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +# CONFIG_EXT3_FS_XATTR is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=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=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW 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=y +# CONFIG_JFFS2_FS_XATTR is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_EXPERIMENTAL 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=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +CONFIG_AMIGA_PARTITION=y +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=m +CONFIG_NLS_DEFAULT="utf-8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# 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_DEBUG_SHIRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# 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 is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_USER is not set +# 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=y +CONFIG_CRYPTO_ALGAPI=m +CONFIG_CRYPTO_BLKCIPHER=m +CONFIG_CRYPTO_HASH=m +CONFIG_CRYPTO_MANAGER=m +CONFIG_CRYPTO_HMAC=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_TEST=m + +# +# Hardware crypto devices +# + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=m +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/trunk/arch/arm/kernel/Makefile b/trunk/arch/arm/kernel/Makefile index bb28087bf818..593b56509f4f 100644 --- a/trunk/arch/arm/kernel/Makefile +++ b/trunk/arch/arm/kernel/Makefile @@ -7,8 +7,8 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) # Object file lists. obj-y := compat.o entry-armv.o entry-common.o irq.o \ - process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \ - time.o traps.o + process.o ptrace.o semaphore.o setup.o signal.o \ + sys_arm.o stacktrace.o time.o traps.o obj-$(CONFIG_ISA_DMA_API) += dma.o obj-$(CONFIG_ARCH_ACORN) += ecard.o diff --git a/trunk/arch/arm/kernel/ecard.c b/trunk/arch/arm/kernel/ecard.c index f1c0fb974177..bdbd7da99286 100644 --- a/trunk/arch/arm/kernel/ecard.c +++ b/trunk/arch/arm/kernel/ecard.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,8 @@ #include #include +#include "ecard.h" + #ifndef CONFIG_ARCH_RPC #define HAVE_EXPMASK #endif @@ -123,7 +126,7 @@ static void ecard_task_reset(struct ecard_request *req) res = ec->slot_no == 8 ? &ec->resource[ECARD_RES_MEMC] - : ec->type == ECARD_EASI + : ec->easi ? &ec->resource[ECARD_RES_EASI] : &ec->resource[ECARD_RES_IOCSYNC]; @@ -178,7 +181,7 @@ static void ecard_task_readbytes(struct ecard_request *req) index += 1; } } else { - unsigned long base = (ec->type == ECARD_EASI + unsigned long base = (ec->easi ? &ec->resource[ECARD_RES_EASI] : &ec->resource[ECARD_RES_IOCSYNC])->start; void __iomem *pbase = (void __iomem *)base; @@ -263,8 +266,6 @@ static int ecard_init_mm(void) static int ecard_task(void * unused) { - daemonize("kecardd"); - /* * Allocate a mm. We're not a lazy-TLB kernel task since we need * to set page table entries where the user space would be. Note @@ -727,7 +728,7 @@ static int ecard_prints(char *buffer, ecard_t *ec) char *start = buffer; buffer += sprintf(buffer, " %d: %s ", ec->slot_no, - ec->type == ECARD_EASI ? "EASI" : " "); + ec->easi ? "EASI" : " "); if (ec->cid.id == 0) { struct in_chunk_dir incd; @@ -814,7 +815,7 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot) } ec->slot_no = slot; - ec->type = type; + ec->easi = type == ECARD_EASI; ec->irq = NO_IRQ; ec->fiq = NO_IRQ; ec->dma = NO_DMA; @@ -825,6 +826,7 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot) ec->dev.bus = &ecard_bus_type; ec->dev.dma_mask = &ec->dma_mask; ec->dma_mask = (u64)0xffffffff; + ec->dev.coherent_dma_mask = ec->dma_mask; if (slot < 4) { ec_set_resource(ec, ECARD_RES_MEMC, @@ -907,7 +909,7 @@ static ssize_t ecard_show_device(struct device *dev, struct device_attribute *at static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); - return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC"); + return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC"); } static struct device_attribute ecard_dev_attrs[] = { @@ -1058,13 +1060,14 @@ ecard_probe(int slot, card_type_t type) */ static int __init ecard_init(void) { - int slot, irqhw, ret; - - ret = kernel_thread(ecard_task, NULL, CLONE_KERNEL); - if (ret < 0) { - printk(KERN_ERR "Ecard: unable to create kernel thread: %d\n", - ret); - return ret; + struct task_struct *task; + int slot, irqhw; + + task = kthread_run(ecard_task, NULL, "kecardd"); + if (IS_ERR(task)) { + printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n", + PTR_ERR(task)); + return PTR_ERR(task); } printk("Probing expansion cards\n"); diff --git a/trunk/arch/arm/kernel/ecard.h b/trunk/arch/arm/kernel/ecard.h new file mode 100644 index 000000000000..d7c2dacf935d --- /dev/null +++ b/trunk/arch/arm/kernel/ecard.h @@ -0,0 +1,56 @@ +/* + * ecard.h + * + * Copyright 2007 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Definitions internal to ecard.c - for it's use only!! + * + * External expansion card header as read from the card + */ +struct ex_ecid { + unsigned char r_irq:1; + unsigned char r_zero:1; + unsigned char r_fiq:1; + unsigned char r_id:4; + unsigned char r_a:1; + + unsigned char r_cd:1; + unsigned char r_is:1; + unsigned char r_w:2; + unsigned char r_r1:4; + + unsigned char r_r2:8; + + unsigned char r_prod[2]; + + unsigned char r_manu[2]; + + unsigned char r_country; + + unsigned char r_fiqmask; + unsigned char r_fiqoff[3]; + + unsigned char r_irqmask; + unsigned char r_irqoff[3]; +}; + +/* + * Chunk directory entry as read from the card + */ +struct ex_chunk_dir { + unsigned char r_id; + unsigned char r_len[3]; + unsigned long r_start; + union { + char string[256]; + char data[1]; + } d; +#define c_id(x) ((x)->r_id) +#define c_len(x) ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16)) +#define c_start(x) ((x)->r_start) +}; diff --git a/trunk/arch/arm/kernel/head.S b/trunk/arch/arm/kernel/head.S index 66db0a9bf0bc..1d35edacc011 100644 --- a/trunk/arch/arm/kernel/head.S +++ b/trunk/arch/arm/kernel/head.S @@ -257,7 +257,9 @@ __create_page_tables: * Map some ram to cover our .data and .bss areas. */ orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000) + .if (KERNEL_RAM_PADDR & 0x00f00000) orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000) + .endif add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18 str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]! ldr r6, =(_end - 1) @@ -274,7 +276,9 @@ __create_page_tables: */ add r0, r4, #PAGE_OFFSET >> 18 orr r6, r7, #(PHYS_OFFSET & 0xff000000) - orr r6, r6, #(PHYS_OFFSET & 0x00e00000) + .if (PHYS_OFFSET & 0x00f00000) + orr r6, r6, #(PHYS_OFFSET & 0x00f00000) + .endif str r6, [r0] #ifdef CONFIG_DEBUG_LL diff --git a/trunk/arch/arm/kernel/irq.c b/trunk/arch/arm/kernel/irq.c index e101846ab7dd..11dcd52e51be 100644 --- a/trunk/arch/arm/kernel/irq.c +++ b/trunk/arch/arm/kernel/irq.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -109,7 +108,7 @@ static struct irq_desc bad_irq_desc = { * come via this function. Instead, they should provide their * own 'handler' */ -asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) +asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); struct irq_desc *desc = irq_desc + irq; diff --git a/trunk/arch/arm/kernel/process.c b/trunk/arch/arm/kernel/process.c index 782af3cb213f..5d6e6523598b 100644 --- a/trunk/arch/arm/kernel/process.c +++ b/trunk/arch/arm/kernel/process.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -28,6 +27,7 @@ #include #include #include +#include #include #include @@ -160,9 +160,11 @@ void cpu_idle(void) if (!idle) idle = default_idle; leds_event(led_idle_start); + tick_nohz_stop_sched_tick(); while (!need_resched()) idle(); leds_event(led_idle_end); + tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); preempt_disable(); diff --git a/trunk/arch/arm/kernel/ptrace.c b/trunk/arch/arm/kernel/ptrace.c index 9254ba2f46fc..6f2f46c2e406 100644 --- a/trunk/arch/arm/kernel/ptrace.c +++ b/trunk/arch/arm/kernel/ptrace.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -457,13 +456,10 @@ void ptrace_cancel_bpt(struct task_struct *child) /* * Called by kernel/ptrace.c when detaching.. - * - * Make sure the single step bit is not set. */ void ptrace_disable(struct task_struct *child) { - child->ptrace &= ~PT_SINGLESTEP; - ptrace_cancel_bpt(child); + single_step_disable(child); } /* @@ -712,9 +708,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; - /* make sure single-step breakpoint is gone. */ - child->ptrace &= ~PT_SINGLESTEP; - ptrace_cancel_bpt(child); + single_step_disable(child); wake_up_process(child); ret = 0; break; @@ -725,9 +719,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) * exit. */ case PTRACE_KILL: - /* make sure single-step breakpoint is gone. */ - child->ptrace &= ~PT_SINGLESTEP; - ptrace_cancel_bpt(child); + single_step_disable(child); if (child->exit_state != EXIT_ZOMBIE) { child->exit_code = SIGKILL; wake_up_process(child); @@ -742,7 +734,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = -EIO; if (!valid_signal(data)) break; - child->ptrace |= PT_SINGLESTEP; + single_step_enable(child); clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; /* give it a chance to run. */ @@ -786,8 +778,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_SET_SYSCALL: + task_thread_info(child)->syscall = data; ret = 0; - child->ptrace_message = data; break; #ifdef CONFIG_CRUNCH @@ -824,7 +816,7 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) ip = regs->ARM_ip; regs->ARM_ip = why; - current->ptrace_message = scno; + current_thread_info()->syscall = scno; /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ @@ -841,5 +833,5 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) } regs->ARM_ip = ip; - return current->ptrace_message; + return current_thread_info()->syscall; } diff --git a/trunk/arch/arm/kernel/ptrace.h b/trunk/arch/arm/kernel/ptrace.h index f7cad13a22e9..def3b6184a79 100644 --- a/trunk/arch/arm/kernel/ptrace.h +++ b/trunk/arch/arm/kernel/ptrace.h @@ -7,6 +7,45 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include + extern void ptrace_cancel_bpt(struct task_struct *); extern void ptrace_set_bpt(struct task_struct *); extern void ptrace_break(struct task_struct *, struct pt_regs *); + +/* + * make sure single-step breakpoint is gone. + */ +static inline void single_step_disable(struct task_struct *task) +{ + task->ptrace &= ~PT_SINGLESTEP; + ptrace_cancel_bpt(task); +} + +static inline void single_step_enable(struct task_struct *task) +{ + task->ptrace |= PT_SINGLESTEP; +} + +/* + * Send SIGTRAP if we're single-stepping + */ +static inline void single_step_trap(struct task_struct *task) +{ + if (task->ptrace & PT_SINGLESTEP) { + ptrace_cancel_bpt(task); + send_sig(SIGTRAP, task, 1); + } +} + +static inline void single_step_clear(struct task_struct *task) +{ + if (task->ptrace & PT_SINGLESTEP) + ptrace_cancel_bpt(task); +} + +static inline void single_step_set(struct task_struct *task) +{ + if (task->ptrace & PT_SINGLESTEP) + ptrace_set_bpt(task); +} diff --git a/trunk/arch/arm/kernel/signal.c b/trunk/arch/arm/kernel/signal.c index 3843d3bab2dd..54cdf1aeefc3 100644 --- a/trunk/arch/arm/kernel/signal.c +++ b/trunk/arch/arm/kernel/signal.c @@ -9,7 +9,6 @@ */ #include #include -#include #include #include @@ -285,11 +284,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) if (restore_sigframe(regs, frame)) goto badframe; - /* Send SIGTRAP if we're single-stepping */ - if (current->ptrace & PT_SINGLESTEP) { - ptrace_cancel_bpt(current); - send_sig(SIGTRAP, current, 1); - } + single_step_trap(current); return regs->ARM_r0; @@ -324,11 +319,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) goto badframe; - /* Send SIGTRAP if we're single-stepping */ - if (current->ptrace & PT_SINGLESTEP) { - ptrace_cancel_bpt(current); - send_sig(SIGTRAP, current, 1); - } + single_step_trap(current); return regs->ARM_r0; @@ -644,14 +635,12 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) if (try_to_freeze()) goto no_signal; - if (current->ptrace & PT_SINGLESTEP) - ptrace_cancel_bpt(current); + single_step_clear(current); signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { handle_signal(signr, &ka, &info, oldset, regs, syscall); - if (current->ptrace & PT_SINGLESTEP) - ptrace_set_bpt(current); + single_step_set(current); return 1; } @@ -705,8 +694,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) restart_syscall(regs); } } - if (current->ptrace & PT_SINGLESTEP) - ptrace_set_bpt(current); + single_step_set(current); return 0; } diff --git a/trunk/arch/arm/kernel/stacktrace.c b/trunk/arch/arm/kernel/stacktrace.c new file mode 100644 index 000000000000..77ef35efaa8d --- /dev/null +++ b/trunk/arch/arm/kernel/stacktrace.c @@ -0,0 +1,73 @@ +#include +#include + +#include "stacktrace.h" + +int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, + int (*fn)(struct stackframe *, void *), void *data) +{ + struct stackframe *frame; + + do { + /* + * Check current frame pointer is within bounds + */ + if ((fp - 12) < low || fp + 4 >= high) + break; + + frame = (struct stackframe *)(fp - 12); + + if (fn(frame, data)) + break; + + /* + * Update the low bound - the next frame must always + * be at a higher address than the current frame. + */ + low = fp + 4; + fp = frame->fp; + } while (fp); + + return 0; +} + +#ifdef CONFIG_STACKTRACE +struct stack_trace_data { + struct stack_trace *trace; + unsigned int skip; +}; + +static int save_trace(struct stackframe *frame, void *d) +{ + struct stack_trace_data *data = d; + struct stack_trace *trace = data->trace; + + if (data->skip) { + data->skip--; + return 0; + } + + trace->entries[trace->nr_entries++] = frame->lr; + + return trace->nr_entries >= trace->max_entries; +} + +void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +{ + struct stack_trace_data data; + unsigned long fp, base; + + data.trace = trace; + data.skip = trace->skip; + + if (task) { + base = (unsigned long)task_stack_page(task); + fp = 0; /* FIXME */ + } else { + base = (unsigned long)task_stack_page(current); + asm("mov %0, fp" : "=r" (fp)); + } + + walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data); +} +#endif diff --git a/trunk/arch/arm/kernel/stacktrace.h b/trunk/arch/arm/kernel/stacktrace.h new file mode 100644 index 000000000000..e9fd20cb5662 --- /dev/null +++ b/trunk/arch/arm/kernel/stacktrace.h @@ -0,0 +1,9 @@ +struct stackframe { + unsigned long fp; + unsigned long sp; + unsigned long lr; + unsigned long pc; +}; + +int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, + int (*fn)(struct stackframe *, void *), void *data); diff --git a/trunk/arch/arm/kernel/time.c b/trunk/arch/arm/kernel/time.c index f61decb89ba2..d0540e4eaf5b 100644 --- a/trunk/arch/arm/kernel/time.c +++ b/trunk/arch/arm/kernel/time.c @@ -327,6 +327,7 @@ void restore_time_delta(struct timespec *delta, struct timespec *rtc) } EXPORT_SYMBOL(restore_time_delta); +#ifndef CONFIG_GENERIC_CLOCKEVENTS /* * Kernel system timer support. */ @@ -340,8 +341,9 @@ void timer_tick(void) update_process_times(user_mode(get_irq_regs())); #endif } +#endif -#ifdef CONFIG_PM +#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) static int timer_suspend(struct sys_device *dev, pm_message_t state) { struct sys_timer *timer = container_of(dev, struct sys_timer, dev); diff --git a/trunk/arch/arm/kernel/traps.c b/trunk/arch/arm/kernel/traps.c index 24095601359b..10ff36e4e414 100644 --- a/trunk/arch/arm/kernel/traps.c +++ b/trunk/arch/arm/kernel/traps.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -45,7 +44,18 @@ static int __init user_debug_setup(char *str) __setup("user_debug=", user_debug_setup); #endif -void dump_backtrace_entry(unsigned long where, unsigned long from) +static void dump_mem(const char *str, unsigned long bottom, unsigned long top); + +static inline int in_exception_text(unsigned long ptr) +{ + extern char __exception_text_start[]; + extern char __exception_text_end[]; + + return ptr >= (unsigned long)&__exception_text_start && + ptr < (unsigned long)&__exception_text_end; +} + +void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) { #ifdef CONFIG_KALLSYMS printk("[<%08lx>] ", where); @@ -55,6 +65,9 @@ void dump_backtrace_entry(unsigned long where, unsigned long from) #else printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); #endif + + if (in_exception_text(where)) + dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs)); } /* @@ -232,8 +245,8 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) do_exit(SIGSEGV); } -void notify_die(const char *str, struct pt_regs *regs, struct siginfo *info, - unsigned long err, unsigned long trap) +void arm_notify_die(const char *str, struct pt_regs *regs, + struct siginfo *info, unsigned long err, unsigned long trap) { if (user_mode(regs)) { current->thread.error_code = err; @@ -266,13 +279,14 @@ void unregister_undef_hook(struct undef_hook *hook) spin_unlock_irqrestore(&undef_lock, flags); } -asmlinkage void do_undefinstr(struct pt_regs *regs) +asmlinkage void __exception do_undefinstr(struct pt_regs *regs) { unsigned int correction = thumb_mode(regs) ? 2 : 4; unsigned int instr; struct undef_hook *hook; siginfo_t info; void __user *pc; + unsigned long flags; /* * According to the ARM ARM, PC is 2 or 4 bytes ahead, @@ -291,7 +305,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs) get_user(instr, (u32 __user *)pc); } - spin_lock_irq(&undef_lock); + spin_lock_irqsave(&undef_lock, flags); list_for_each_entry(hook, &undef_hook, node) { if ((instr & hook->instr_mask) == hook->instr_val && (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) { @@ -301,7 +315,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs) } } } - spin_unlock_irq(&undef_lock); + spin_unlock_irqrestore(&undef_lock, flags); #ifdef CONFIG_DEBUG_USER if (user_debug & UDBG_UNDEFINED) { @@ -316,7 +330,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs) info.si_code = ILL_ILLOPC; info.si_addr = pc; - notify_die("Oops - undefined instruction", regs, &info, 0, 6); + arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6); } asmlinkage void do_unexp_fiq (struct pt_regs *regs) @@ -370,7 +384,7 @@ static int bad_syscall(int n, struct pt_regs *regs) info.si_addr = (void __user *)instruction_pointer(regs) - (thumb_mode(regs) ? 2 : 4); - notify_die("Oops - bad syscall", regs, &info, n, 0); + arm_notify_die("Oops - bad syscall", regs, &info, n, 0); return regs->ARM_r0; } @@ -414,7 +428,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) info.si_code = SEGV_MAPERR; info.si_addr = NULL; - notify_die("branch through zero", regs, &info, 0, 0); + arm_notify_die("branch through zero", regs, &info, 0, 0); return 0; case NR(breakpoint): /* SWI BREAK_POINT */ @@ -550,7 +564,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) info.si_addr = (void __user *)instruction_pointer(regs) - (thumb_mode(regs) ? 2 : 4); - notify_die("Oops - bad syscall(2)", regs, &info, no, 0); + arm_notify_die("Oops - bad syscall(2)", regs, &info, no, 0); return 0; } @@ -624,7 +638,7 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) info.si_code = ILL_ILLOPC; info.si_addr = (void __user *)addr; - notify_die("unknown data abort code", regs, &info, instr, 0); + arm_notify_die("unknown data abort code", regs, &info, instr, 0); } void __attribute__((noreturn)) __bug(const char *file, int line) diff --git a/trunk/arch/arm/kernel/vmlinux.lds.S b/trunk/arch/arm/kernel/vmlinux.lds.S index d1a6a597ed9a..6be67296f333 100644 --- a/trunk/arch/arm/kernel/vmlinux.lds.S +++ b/trunk/arch/arm/kernel/vmlinux.lds.S @@ -83,6 +83,9 @@ SECTIONS .text : { /* Real text segment */ _text = .; /* Text and read-only data */ + __exception_text_start = .; + *(.exception.text) + __exception_text_end = .; *(.text) SCHED_TEXT LOCK_TEXT diff --git a/trunk/arch/arm/lib/backtrace.S b/trunk/arch/arm/lib/backtrace.S index 74230083cbf4..84dc890d2bf3 100644 --- a/trunk/arch/arm/lib/backtrace.S +++ b/trunk/arch/arm/lib/backtrace.S @@ -17,8 +17,8 @@ @ fp is 0 or stack frame #define frame r4 -#define next r5 -#define save r6 +#define sv_fp r5 +#define sv_pc r6 #define mask r7 #define offset r8 @@ -31,108 +31,106 @@ ENTRY(c_backtrace) #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) mov pc, lr #else - stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... - tst r1, #0x10 @ 26 or 32-bit? - moveq mask, #0xfc000003 - movne mask, #0 - tst mask, r0 - movne r0, #0 - movs frame, r0 -1: moveq r0, #-2 - ldmeqfd sp!, {r4 - r8, pc} - -2: stmfd sp!, {pc} @ calculate offset of PC in STMIA instruction - ldr r0, [sp], #4 - adr r1, 2b - 4 + movs frame, r0 @ if frame pointer is zero + beq no_frame @ we have no stack frames + + tst r1, #0x10 @ 26 or 32-bit mode? + moveq mask, #0xfc000003 @ mask for 26-bit + movne mask, #0 @ mask for 32-bit + +1: stmfd sp!, {pc} @ calculate offset of PC stored + ldr r0, [sp], #4 @ by stmfd for this CPU + adr r1, 1b sub offset, r0, r1 -3: tst frame, mask @ Check for address exceptions... - bne 1b +/* + * Stack frame layout: + * optionally saved caller registers (r4 - r10) + * saved fp + * saved sp + * saved lr + * frame => saved pc + * optionally saved arguments (r0 - r3) + * saved sp => + * + * Functions start with the following code sequence: + * mov ip, sp + * stmfd sp!, {r0 - r3} (optional) + * corrected pc => stmfd sp!, {..., fp, ip, lr, pc} + */ +for_each_frame: tst frame, mask @ Check for address exceptions + bne no_frame + +1001: ldr sv_pc, [frame, #0] @ get saved pc +1002: ldr sv_fp, [frame, #-12] @ get saved fp -1001: ldr next, [frame, #-12] @ get fp -1002: ldr r2, [frame, #-4] @ get lr -1003: ldr r3, [frame, #0] @ get pc - sub save, r3, offset @ Correct PC for prefetching - bic save, save, mask -1004: ldr r1, [save, #0] @ get instruction at function - mov r1, r1, lsr #10 - ldr r3, .Ldsi+4 - teq r1, r3 - subeq save, save, #4 - mov r0, save - bic r1, r2, mask + sub sv_pc, sv_pc, offset @ Correct PC for prefetching + bic sv_pc, sv_pc, mask @ mask PC/LR for the mode + +1003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists, + ldr r3, .Ldsi+4 @ adjust saved 'pc' back one + teq r3, r2, lsr #10 @ instruction + subne r0, sv_pc, #4 @ allow for mov + subeq r0, sv_pc, #8 @ allow for mov + stmia + + ldr r1, [frame, #-4] @ get saved lr + mov r2, frame + bic r1, r1, mask @ mask PC/LR for the mode bl dump_backtrace_entry - ldr r0, [frame, #-8] @ get sp - sub r0, r0, #4 -1005: ldr r1, [save, #4] @ get instruction at function+4 - mov r3, r1, lsr #10 - ldr r2, .Ldsi+4 - teq r3, r2 @ Check for stmia sp!, {args} - addeq save, save, #4 @ next instruction - bleq .Ldumpstm - - sub r0, frame, #16 -1006: ldr r1, [save, #4] @ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction - mov r3, r1, lsr #10 - ldr r2, .Ldsi - teq r3, r2 - bleq .Ldumpstm - - /* - * A zero next framepointer means we're done. - */ - teq next, #0 - ldmeqfd sp!, {r4 - r8, pc} - - /* - * The next framepointer must be above the - * current framepointer. - */ - cmp next, frame - mov frame, next - bhi 3b - b 1007f + ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists, + ldr r3, .Ldsi+4 + teq r3, r1, lsr #10 + ldreq r0, [frame, #-8] @ get sp + subeq r0, r0, #4 @ point at the last arg + bleq .Ldumpstm @ dump saved registers -/* - * Fixup for LDMDB. Note that this must not be in the fixup section. - */ -1007: ldr r0, =.Lbad +1004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc} + ldr r3, .Ldsi @ instruction exists, + teq r3, r1, lsr #10 + subeq r0, frame, #16 + bleq .Ldumpstm @ dump saved registers + + teq sv_fp, #0 @ zero saved fp means + beq no_frame @ no further frames + + cmp sv_fp, frame @ next frame must be + mov frame, sv_fp @ above the current frame + bhi for_each_frame + +1006: adr r0, .Lbad mov r1, frame bl printk - ldmfd sp!, {r4 - r8, pc} - .ltorg +no_frame: ldmfd sp!, {r4 - r8, pc} .section __ex_table,"a" .align 3 - .long 1001b, 1007b - .long 1002b, 1007b - .long 1003b, 1007b - .long 1004b, 1007b - .long 1005b, 1007b - .long 1006b, 1007b + .long 1001b, 1006b + .long 1002b, 1006b + .long 1003b, 1006b + .long 1004b, 1006b .previous #define instr r4 #define reg r5 #define stack r6 -.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, r8, lr} +.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, lr} mov stack, r0 mov instr, r1 - mov reg, #9 + mov reg, #10 mov r7, #0 1: mov r3, #1 tst instr, r3, lsl reg beq 2f add r7, r7, #1 - teq r7, #4 - moveq r7, #0 - moveq r3, #'\n' - movne r3, #' ' - ldr r2, [stack], #-4 - mov r1, reg + teq r7, #6 + moveq r7, #1 + moveq r1, #'\n' + movne r1, #' ' + ldr r3, [stack], #-4 + mov r2, reg adr r0, .Lfp bl printk 2: subs reg, reg, #1 @@ -140,14 +138,13 @@ ENTRY(c_backtrace) teq r7, #0 adrne r0, .Lcr blne printk - mov r0, stack - ldmfd sp!, {instr, reg, stack, r7, r8, pc} + ldmfd sp!, {instr, reg, stack, r7, pc} -.Lfp: .asciz " r%d = %08X%c" +.Lfp: .asciz "%cr%d:%08x" .Lcr: .asciz "\n" .Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" .align -.Ldsi: .word 0x00e92dd8 >> 2 - .word 0x00e92d00 >> 2 +.Ldsi: .word 0xe92dd800 >> 10 @ stmfd sp!, {... fp, ip, lr, pc} + .word 0xe92d0000 >> 10 @ stmfd sp!, {} #endif diff --git a/trunk/arch/arm/lib/getuser.S b/trunk/arch/arm/lib/getuser.S index c03ea8e666ba..1dd8ea4f9a9c 100644 --- a/trunk/arch/arm/lib/getuser.S +++ b/trunk/arch/arm/lib/getuser.S @@ -26,8 +26,6 @@ * Note that ADDR_LIMIT is either 0 or 0xc0000000. * Note also that it is intended that __get_user_bad is not global. */ -#include -#include #include .global __get_user_1 diff --git a/trunk/arch/arm/lib/putuser.S b/trunk/arch/arm/lib/putuser.S index 4593e9c07f05..8620afe54f72 100644 --- a/trunk/arch/arm/lib/putuser.S +++ b/trunk/arch/arm/lib/putuser.S @@ -26,8 +26,6 @@ * Note that ADDR_LIMIT is either 0 or 0xc0000000 * Note also that it is intended that __put_user_bad is not global. */ -#include -#include #include .global __put_user_1 diff --git a/trunk/arch/arm/mach-aaec2000/core.c b/trunk/arch/arm/mach-aaec2000/core.c index a950160fcfb6..0446ef2f5bd6 100644 --- a/trunk/arch/arm/mach-aaec2000/core.c +++ b/trunk/arch/arm/mach-aaec2000/core.c @@ -142,7 +142,7 @@ aaec2000_timer_interrupt(int irq, void *dev_id) static struct irqaction aaec2000_timer_irq = { .name = "AAEC-2000 Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = aaec2000_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-at91/Kconfig b/trunk/arch/arm/mach-at91/Kconfig index bf0d96272e3a..e238ad8cfd8f 100644 --- a/trunk/arch/arm/mach-at91/Kconfig +++ b/trunk/arch/arm/mach-at91/Kconfig @@ -81,6 +81,13 @@ config MACH_KB9200 Select this if you are using KwikByte's KB920x board. +config MACH_PICOTUX2XX + bool "picotux 200" + depends on ARCH_AT91RM9200 + help + Select this if you are using a picotux 200. + + config MACH_KAFA bool "Sperry-Sun KAFA board" depends on ARCH_AT91RM9200 diff --git a/trunk/arch/arm/mach-at91/Makefile b/trunk/arch/arm/mach-at91/Makefile index 05de6cdc88f1..a412ae18a421 100644 --- a/trunk/arch/arm/mach-at91/Makefile +++ b/trunk/arch/arm/mach-at91/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_MACH_CARMEVA) += board-carmeva.o obj-$(CONFIG_MACH_KB9200) += board-kb9202.o obj-$(CONFIG_MACH_ATEB9200) += board-eb9200.o obj-$(CONFIG_MACH_KAFA) += board-kafa.o +obj-$(CONFIG_MACH_PICOTUX2XX) += board-picotux200.o # AT91SAM9260 board-specific support obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o diff --git a/trunk/arch/arm/mach-at91/at91rm9200.c b/trunk/arch/arm/mach-at91/at91rm9200.c index 2ddcdd69df7d..2cad2bf864be 100644 --- a/trunk/arch/arm/mach-at91/at91rm9200.c +++ b/trunk/arch/arm/mach-at91/at91rm9200.c @@ -117,6 +117,21 @@ static struct clk pioD_clk = { .pmc_mask = 1 << AT91RM9200_ID_PIOD, .type = CLK_TYPE_PERIPHERAL, }; +static struct clk ssc0_clk = { + .name = "ssc0_clk", + .pmc_mask = 1 << AT91RM9200_ID_SSC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc1_clk = { + .name = "ssc1_clk", + .pmc_mask = 1 << AT91RM9200_ID_SSC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc2_clk = { + .name = "ssc2_clk", + .pmc_mask = 1 << AT91RM9200_ID_SSC2, + .type = CLK_TYPE_PERIPHERAL, +}; static struct clk tc0_clk = { .name = "tc0_clk", .pmc_mask = 1 << AT91RM9200_ID_TC0, @@ -161,7 +176,9 @@ static struct clk *periph_clocks[] __initdata = { &udc_clk, &twi_clk, &spi_clk, - // ssc 0 .. ssc2 + &ssc0_clk, + &ssc1_clk, + &ssc2_clk, &tc0_clk, &tc1_clk, &tc2_clk, diff --git a/trunk/arch/arm/mach-at91/at91rm9200_time.c b/trunk/arch/arm/mach-at91/at91rm9200_time.c index 949199a244c7..a6340357585d 100644 --- a/trunk/arch/arm/mach-at91/at91rm9200_time.c +++ b/trunk/arch/arm/mach-at91/at91rm9200_time.c @@ -87,7 +87,7 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id) static struct irqaction at91rm9200_timer_irq = { .name = "at91_tick", - .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = at91rm9200_timer_interrupt }; diff --git a/trunk/arch/arm/mach-at91/at91sam9260.c b/trunk/arch/arm/mach-at91/at91sam9260.c index 6ea41d8266cb..e47381e8aaba 100644 --- a/trunk/arch/arm/mach-at91/at91sam9260.c +++ b/trunk/arch/arm/mach-at91/at91sam9260.c @@ -119,6 +119,11 @@ static struct clk spi1_clk = { .pmc_mask = 1 << AT91SAM9260_ID_SPI1, .type = CLK_TYPE_PERIPHERAL, }; +static struct clk ssc_clk = { + .name = "ssc_clk", + .pmc_mask = 1 << AT91SAM9260_ID_SSC, + .type = CLK_TYPE_PERIPHERAL, +}; static struct clk tc0_clk = { .name = "tc0_clk", .pmc_mask = 1 << AT91SAM9260_ID_TC0, @@ -193,7 +198,7 @@ static struct clk *periph_clocks[] __initdata = { &twi_clk, &spi0_clk, &spi1_clk, - // ssc + &ssc_clk, &tc0_clk, &tc1_clk, &tc2_clk, diff --git a/trunk/arch/arm/mach-at91/at91sam9261.c b/trunk/arch/arm/mach-at91/at91sam9261.c index 784d1e682d6d..dfe8c39c9fb9 100644 --- a/trunk/arch/arm/mach-at91/at91sam9261.c +++ b/trunk/arch/arm/mach-at91/at91sam9261.c @@ -97,6 +97,21 @@ static struct clk spi1_clk = { .pmc_mask = 1 << AT91SAM9261_ID_SPI1, .type = CLK_TYPE_PERIPHERAL, }; +static struct clk ssc0_clk = { + .name = "ssc0_clk", + .pmc_mask = 1 << AT91SAM9261_ID_SSC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc1_clk = { + .name = "ssc1_clk", + .pmc_mask = 1 << AT91SAM9261_ID_SSC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc2_clk = { + .name = "ssc2_clk", + .pmc_mask = 1 << AT91SAM9261_ID_SSC2, + .type = CLK_TYPE_PERIPHERAL, +}; static struct clk tc0_clk = { .name = "tc0_clk", .pmc_mask = 1 << AT91SAM9261_ID_TC0, @@ -135,7 +150,9 @@ static struct clk *periph_clocks[] __initdata = { &twi_clk, &spi0_clk, &spi1_clk, - // ssc 0 .. ssc2 + &ssc0_clk, + &ssc1_clk, + &ssc2_clk, &tc0_clk, &tc1_clk, &tc2_clk, diff --git a/trunk/arch/arm/mach-at91/at91sam9261_devices.c b/trunk/arch/arm/mach-at91/at91sam9261_devices.c index e1504766fd64..8e781997716a 100644 --- a/trunk/arch/arm/mach-at91/at91sam9261_devices.c +++ b/trunk/arch/arm/mach-at91/at91sam9261_devices.c @@ -430,9 +430,9 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) * LCD Controller * -------------------------------------------------------------------- */ -#if defined(CONFIG_FB_AT91) || defined(CONFIG_FB_AT91_MODULE) +#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE) static u64 lcdc_dmamask = 0xffffffffUL; -static struct at91fb_info lcdc_data; +static struct atmel_lcdfb_info lcdc_data; static struct resource lcdc_resources[] = { [0] = { @@ -455,7 +455,7 @@ static struct resource lcdc_resources[] = { }; static struct platform_device at91_lcdc_device = { - .name = "at91-fb", + .name = "atmel_lcdfb", .id = 0, .dev = { .dma_mask = &lcdc_dmamask, @@ -466,7 +466,7 @@ static struct platform_device at91_lcdc_device = { .num_resources = ARRAY_SIZE(lcdc_resources), }; -void __init at91_add_device_lcdc(struct at91fb_info *data) +void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) { if (!data) { return; @@ -499,7 +499,7 @@ void __init at91_add_device_lcdc(struct at91fb_info *data) platform_device_register(&at91_lcdc_device); } #else -void __init at91_add_device_lcdc(struct at91fb_info *data) {} +void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {} #endif diff --git a/trunk/arch/arm/mach-at91/at91sam9263.c b/trunk/arch/arm/mach-at91/at91sam9263.c index 0e89a7fca3fa..00e27b177857 100644 --- a/trunk/arch/arm/mach-at91/at91sam9263.c +++ b/trunk/arch/arm/mach-at91/at91sam9263.c @@ -87,6 +87,11 @@ static struct clk mmc1_clk = { .pmc_mask = 1 << AT91SAM9263_ID_MCI1, .type = CLK_TYPE_PERIPHERAL, }; +static struct clk can_clk = { + .name = "can_clk", + .pmc_mask = 1 << AT91SAM9263_ID_CAN, + .type = CLK_TYPE_PERIPHERAL, +}; static struct clk twi_clk = { .name = "twi_clk", .pmc_mask = 1 << AT91SAM9263_ID_TWI, @@ -102,16 +107,46 @@ static struct clk spi1_clk = { .pmc_mask = 1 << AT91SAM9263_ID_SPI1, .type = CLK_TYPE_PERIPHERAL, }; +static struct clk ssc0_clk = { + .name = "ssc0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SSC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc1_clk = { + .name = "ssc1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SSC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ac97_clk = { + .name = "ac97_clk", + .pmc_mask = 1 << AT91SAM9263_ID_AC97C, + .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 pwmc_clk = { + .name = "pwmc_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PWMC, + .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 dma_clk = { + .name = "dma_clk", + .pmc_mask = 1 << AT91SAM9263_ID_DMA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twodge_clk = { + .name = "2dge_clk", + .pmc_mask = 1 << AT91SAM9263_ID_2DGE, + .type = CLK_TYPE_PERIPHERAL, +}; static struct clk udc_clk = { .name = "udc_clk", .pmc_mask = 1 << AT91SAM9263_ID_UDP, @@ -142,20 +177,21 @@ static struct clk *periph_clocks[] __initdata = { &usart2_clk, &mmc0_clk, &mmc1_clk, - // can + &can_clk, &twi_clk, &spi0_clk, &spi1_clk, - // ssc0 .. ssc1 - // ac97 + &ssc0_clk, + &ssc1_clk, + &ac97_clk, &tcb_clk, - // pwmc + &pwmc_clk, &macb_clk, - // 2dge + &twodge_clk, &udc_clk, &isi_clk, &lcdc_clk, - // dma + &dma_clk, &ohci_clk, // irq0 .. irq1 }; diff --git a/trunk/arch/arm/mach-at91/at91sam9263_devices.c b/trunk/arch/arm/mach-at91/at91sam9263_devices.c index b77121f27f34..2b2e18a67128 100644 --- a/trunk/arch/arm/mach-at91/at91sam9263_devices.c +++ b/trunk/arch/arm/mach-at91/at91sam9263_devices.c @@ -572,6 +572,130 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) #endif +/* -------------------------------------------------------------------- + * AC97 + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_SND_AT91_AC97) || defined(CONFIG_SND_AT91_AC97_MODULE) +static u64 ac97_dmamask = 0xffffffffUL; +static struct atmel_ac97_data ac97_data; + +static struct resource ac97_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_AC97C, + .end = AT91SAM9263_BASE_AC97C + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_AC97C, + .end = AT91SAM9263_ID_AC97C, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91sam9263_ac97_device = { + .name = "ac97c", + .id = 1, + .dev = { + .dma_mask = &ac97_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = &ac97_data, + }, + .resource = ac97_resources, + .num_resources = ARRAY_SIZE(ac97_resources), +}; + +void __init at91_add_device_ac97(struct atmel_ac97_data *data) +{ + if (!data) + return; + + at91_set_A_periph(AT91_PIN_PB0, 0); /* AC97FS */ + at91_set_A_periph(AT91_PIN_PB1, 0); /* AC97CK */ + at91_set_A_periph(AT91_PIN_PB2, 0); /* AC97TX */ + at91_set_A_periph(AT91_PIN_PB3, 0); /* AC97RX */ + + /* reset */ + if (data->reset_pin) + at91_set_gpio_output(data->reset_pin, 0); + + ac97_data = *ek_data; + platform_device_register(&at91sam9263_ac97_device); +} +#else +void __init at91_add_device_ac97(struct atmel_ac97_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * LCD Controller + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE) +static u64 lcdc_dmamask = 0xffffffffUL; +static struct atmel_lcdfb_info lcdc_data; + +static struct resource lcdc_resources[] = { + [0] = { + .start = AT91SAM9263_LCDC_BASE, + .end = AT91SAM9263_LCDC_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_ID_LCDC, + .end = AT91SAM9263_ID_LCDC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91_lcdc_device = { + .name = "atmel_lcdfb", + .id = 0, + .dev = { + .dma_mask = &lcdc_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = &lcdc_data, + }, + .resource = lcdc_resources, + .num_resources = ARRAY_SIZE(lcdc_resources), +}; + +void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) +{ + if (!data) + return; + + at91_set_A_periph(AT91_PIN_PC1, 0); /* LCDHSYNC */ + at91_set_A_periph(AT91_PIN_PC2, 0); /* LCDDOTCK */ + at91_set_A_periph(AT91_PIN_PC3, 0); /* LCDDEN */ + at91_set_B_periph(AT91_PIN_PB9, 0); /* LCDCC */ + at91_set_A_periph(AT91_PIN_PC6, 0); /* LCDD2 */ + at91_set_A_periph(AT91_PIN_PC7, 0); /* LCDD3 */ + at91_set_A_periph(AT91_PIN_PC8, 0); /* LCDD4 */ + at91_set_A_periph(AT91_PIN_PC9, 0); /* LCDD5 */ + at91_set_A_periph(AT91_PIN_PC10, 0); /* LCDD6 */ + at91_set_A_periph(AT91_PIN_PC11, 0); /* LCDD7 */ + at91_set_A_periph(AT91_PIN_PC14, 0); /* LCDD10 */ + at91_set_A_periph(AT91_PIN_PC15, 0); /* LCDD11 */ + at91_set_A_periph(AT91_PIN_PC16, 0); /* LCDD12 */ + at91_set_B_periph(AT91_PIN_PC12, 0); /* LCDD13 */ + at91_set_A_periph(AT91_PIN_PC18, 0); /* LCDD14 */ + at91_set_A_periph(AT91_PIN_PC19, 0); /* LCDD15 */ + at91_set_A_periph(AT91_PIN_PC22, 0); /* LCDD18 */ + at91_set_A_periph(AT91_PIN_PC23, 0); /* LCDD19 */ + at91_set_A_periph(AT91_PIN_PC24, 0); /* LCDD20 */ + at91_set_B_periph(AT91_PIN_PC17, 0); /* LCDD21 */ + at91_set_A_periph(AT91_PIN_PC26, 0); /* LCDD22 */ + at91_set_A_periph(AT91_PIN_PC27, 0); /* LCDD23 */ + + lcdc_data = *data; + platform_device_register(&at91_lcdc_device); +} +#else +void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {} +#endif + + /* -------------------------------------------------------------------- * LEDs * -------------------------------------------------------------------- */ diff --git a/trunk/arch/arm/mach-at91/at91sam926x_time.c b/trunk/arch/arm/mach-at91/at91sam926x_time.c index a4dded27fa16..5c090c9442f5 100644 --- a/trunk/arch/arm/mach-at91/at91sam926x_time.c +++ b/trunk/arch/arm/mach-at91/at91sam926x_time.c @@ -66,7 +66,7 @@ static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id) static struct irqaction at91sam926x_timer_irq = { .name = "at91_tick", - .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = at91sam926x_timer_interrupt }; diff --git a/trunk/arch/arm/mach-at91/board-picotux200.c b/trunk/arch/arm/mach-at91/board-picotux200.c new file mode 100644 index 000000000000..49cfe7ab4a85 --- /dev/null +++ b/trunk/arch/arm/mach-at91/board-picotux200.c @@ -0,0 +1,166 @@ +/* + * linux/arch/arm/mach-at91/board-picotux200.c + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2007 Kleinhenz Elektronik GmbH + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "generic.h" + + +/* + * Serial port configuration. + * 0 .. 3 = USART0 .. USART3 + * 4 = DBGU + */ +static struct at91_uart_config __initdata picotux200_uart_config = { + .console_tty = 0, /* ttyS0 */ + .nr_tty = 2, + .tty_map = { 4, 1, -1, -1, -1 } /* ttyS0, ..., ttyS4 */ +}; + +static void __init picotux200_map_io(void) +{ + /* Initialize processor: 18.432 MHz crystal */ + at91rm9200_initialize(18432000, AT91RM9200_BGA); + + /* Setup the serial ports and console */ + at91_init_serial(&picotux200_uart_config); +} + +static void __init picotux200_init_irq(void) +{ + at91rm9200_init_interrupts(NULL); +} + +static struct at91_eth_data __initdata picotux200_eth_data = { + .phy_irq_pin = AT91_PIN_PC4, + .is_rmii = 1, +}; + +static struct at91_usbh_data __initdata picotux200_usbh_data = { + .ports = 1, +}; + +// static struct at91_udc_data __initdata picotux200_udc_data = { +// .vbus_pin = AT91_PIN_PD4, +// .pullup_pin = AT91_PIN_PD5, +// }; + +static struct at91_mmc_data __initdata picotux200_mmc_data = { + .det_pin = AT91_PIN_PB27, + .slot_b = 0, + .wire4 = 1, + .wp_pin = AT91_PIN_PA17, +}; + +// static struct spi_board_info picotux200_spi_devices[] = { +// { /* DataFlash chip */ +// .modalias = "mtd_dataflash", +// .chip_select = 0, +// .max_speed_hz = 15 * 1000 * 1000, +// }, +// #ifdef CONFIG_MTD_AT91_DATAFLASH_CARD +// { /* DataFlash card */ +// .modalias = "mtd_dataflash", +// .chip_select = 3, +// .max_speed_hz = 15 * 1000 * 1000, +// }, +// #endif +// }; + +#define PICOTUX200_FLASH_BASE AT91_CHIPSELECT_0 +#define PICOTUX200_FLASH_SIZE 0x400000 + +static struct physmap_flash_data picotux200_flash_data = { + .width = 2, +}; + +static struct resource picotux200_flash_resource = { + .start = PICOTUX200_FLASH_BASE, + .end = PICOTUX200_FLASH_BASE + PICOTUX200_FLASH_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device picotux200_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &picotux200_flash_data, + }, + .resource = &picotux200_flash_resource, + .num_resources = 1, +}; + +static void __init picotux200_board_init(void) +{ + /* Serial */ + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&picotux200_eth_data); + /* USB Host */ + at91_add_device_usbh(&picotux200_usbh_data); + /* USB Device */ + // at91_add_device_udc(&picotux200_udc_data); + // at91_set_multi_drive(picotux200_udc_data.pullup_pin, 1); /* pullup_pin is connected to reset */ + /* I2C */ + at91_add_device_i2c(); + /* SPI */ + // at91_add_device_spi(picotux200_spi_devices, ARRAY_SIZE(picotux200_spi_devices)); +#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD + /* DataFlash card */ + at91_set_gpio_output(AT91_PIN_PB22, 0); +#else + /* MMC */ + at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ + at91_add_device_mmc(0, &picotux200_mmc_data); +#endif + /* NOR Flash */ + platform_device_register(&picotux200_flash); +} + +MACHINE_START(PICOTUX2XX, "picotux 200") + /* Maintainer: Kleinhenz Elektronik GmbH */ + .phys_io = AT91_BASE_SYS, + .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, + .boot_params = AT91_SDRAM_BASE + 0x100, + .timer = &at91rm9200_timer, + .map_io = picotux200_map_io, + .init_irq = picotux200_init_irq, + .init_machine = picotux200_board_init, +MACHINE_END diff --git a/trunk/arch/arm/mach-at91/board-sam9260ek.c b/trunk/arch/arm/mach-at91/board-sam9260ek.c index 57fb4499d969..65fa532bb4ac 100644 --- a/trunk/arch/arm/mach-at91/board-sam9260ek.c +++ b/trunk/arch/arm/mach-at91/board-sam9260ek.c @@ -104,9 +104,9 @@ static struct spi_board_info ek_spi_devices[] = { }, #endif #endif -#if defined(CONFIG_SND_AT73C213) +#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE) { /* AT73C213 DAC */ - .modalias = "snd_at73c213", + .modalias = "at73c213", .chip_select = 0, .max_speed_hz = 10 * 1000 * 1000, .bus_num = 1, @@ -118,7 +118,7 @@ static struct spi_board_info ek_spi_devices[] = { /* * MACB Ethernet device */ -static struct __initdata at91_eth_data ek_macb_data = { +static struct at91_eth_data __initdata ek_macb_data = { .phy_irq_pin = AT91_PIN_PA7, .is_rmii = 1, }; @@ -140,7 +140,7 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition *nand_partitions(int size, int *num_partitions) +static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) { *num_partitions = ARRAY_SIZE(ek_nand_partition); return ek_nand_partition; @@ -188,6 +188,8 @@ static void __init ek_board_init(void) at91_add_device_eth(&ek_macb_data); /* MMC */ at91_add_device_mmc(0, &ek_mmc_data); + /* I2C */ + at91_add_device_i2c(); } MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK") diff --git a/trunk/arch/arm/mach-at91/board-sam9261ek.c b/trunk/arch/arm/mach-at91/board-sam9261ek.c index b7e772467cf6..bcf71536cc6d 100644 --- a/trunk/arch/arm/mach-at91/board-sam9261ek.c +++ b/trunk/arch/arm/mach-at91/board-sam9261ek.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -194,6 +195,41 @@ static struct at91_nand_data __initdata ek_nand_data = { #endif }; +/* + * ADS7846 Touchscreen + */ +#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE) + +static int ads7843_pendown_state(void) +{ + return !at91_get_gpio_value(AT91_PIN_PC2); /* Touchscreen PENIRQ */ +} + +static struct ads7846_platform_data ads_info = { + .model = 7843, + .x_min = 150, + .x_max = 3830, + .y_min = 190, + .y_max = 3830, + .vref_delay_usecs = 100, + .x_plate_ohms = 450, + .y_plate_ohms = 250, + .pressure_max = 15000, + .debounce_max = 1, + .debounce_rep = 0, + .debounce_tol = (~0), + .get_pendown_state = ads7843_pendown_state, +}; + +static void __init ek_add_device_ts(void) +{ + at91_set_B_periph(AT91_PIN_PC2, 1); /* External IRQ0, with pullup */ + at91_set_gpio_input(AT91_PIN_PA11, 1); /* Touchscreen BUSY signal */ +} +#else +static void __init ek_add_device_ts(void) {} +#endif + /* * SPI devices */ @@ -204,6 +240,16 @@ static struct spi_board_info ek_spi_devices[] = { .max_speed_hz = 15 * 1000 * 1000, .bus_num = 0, }, +#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE) + { + .modalias = "ads7846", + .chip_select = 2, + .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */ + .bus_num = 0, + .platform_data = &ads_info, + .irq = AT91SAM9261_ID_IRQ0, + }, +#endif #if defined(CONFIG_MTD_AT91_DATAFLASH_CARD) { /* DataFlash card - jumper (J12) configurable to CS3 or CS0 */ .modalias = "mtd_dataflash", @@ -211,9 +257,9 @@ static struct spi_board_info ek_spi_devices[] = { .max_speed_hz = 15 * 1000 * 1000, .bus_num = 0, }, -#elif defined(CONFIG_SND_AT73C213) +#elif defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE) { /* AT73C213 DAC */ - .modalias = "snd_at73c213", + .modalias = "at73c213", .chip_select = 3, .max_speed_hz = 10 * 1000 * 1000, .bus_num = 0, @@ -241,6 +287,8 @@ static void __init ek_board_init(void) #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE) /* SPI */ at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices)); + /* Touchscreen */ + ek_add_device_ts(); #else /* MMC */ at91_add_device_mmc(0, &ek_mmc_data); diff --git a/trunk/arch/arm/mach-at91/board-sam9263ek.c b/trunk/arch/arm/mach-at91/board-sam9263ek.c index 8fdce11a880c..f57458559fb6 100644 --- a/trunk/arch/arm/mach-at91/board-sam9263ek.c +++ b/trunk/arch/arm/mach-at91/board-sam9263ek.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -85,6 +86,40 @@ static struct at91_udc_data __initdata ek_udc_data = { }; +/* + * ADS7846 Touchscreen + */ +#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE) +static int ads7843_pendown_state(void) +{ + return !at91_get_gpio_value(AT91_PIN_PA15); /* Touchscreen PENIRQ */ +} + +static struct ads7846_platform_data ads_info = { + .model = 7843, + .x_min = 150, + .x_max = 3830, + .y_min = 190, + .y_max = 3830, + .vref_delay_usecs = 100, + .x_plate_ohms = 450, + .y_plate_ohms = 250, + .pressure_max = 15000, + .debounce_max = 1, + .debounce_rep = 0, + .debounce_tol = (~0), + .get_pendown_state = ads7843_pendown_state, +}; + +static void __init ek_add_device_ts(void) +{ + at91_set_B_periph(AT91_PIN_PA15, 1); /* External IRQ1, with pullup */ + at91_set_gpio_input(AT91_PIN_PA31, 1); /* Touchscreen BUSY signal */ +} +#else +static void __init ek_add_device_ts(void) {} +#endif + /* * SPI devices. */ @@ -97,6 +132,16 @@ static struct spi_board_info ek_spi_devices[] = { .bus_num = 0, }, #endif +#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE) + { + .modalias = "ads7846", + .chip_select = 3, + .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */ + .bus_num = 0, + .platform_data = &ads_info, + .irq = AT91SAM9263_ID_IRQ1, + }, +#endif }; @@ -111,6 +156,14 @@ static struct at91_mmc_data __initdata ek_mmc_data = { }; +/* + * MACB Ethernet device + */ +static struct at91_eth_data __initdata ek_macb_data = { + .is_rmii = 1, +}; + + /* * NAND flash */ @@ -148,6 +201,14 @@ static struct at91_nand_data __initdata ek_nand_data = { }; +/* + * AC97 + */ +static struct atmel_ac97_data ek_ac97_data = { + .reset_pin = AT91_PIN_PA13, +}; + + static void __init ek_board_init(void) { /* Serial */ @@ -157,11 +218,20 @@ static void __init ek_board_init(void) /* USB Device */ at91_add_device_udc(&ek_udc_data); /* SPI */ + at91_set_gpio_output(AT91_PIN_PE20, 1); /* select spi0 clock */ at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices)); + /* Touchscreen */ + ek_add_device_ts(); /* MMC */ at91_add_device_mmc(1, &ek_mmc_data); + /* Ethernet */ + at91_add_device_eth(&ek_macb_data); /* NAND */ at91_add_device_nand(&ek_nand_data); + /* I2C */ + at91_add_device_i2c(); + /* AC97 */ + at91_add_device_ac97(&ek_ac97_data); } MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK") diff --git a/trunk/arch/arm/mach-clps711x/time.c b/trunk/arch/arm/mach-clps711x/time.c index 428493dd4687..f428af7545b4 100644 --- a/trunk/arch/arm/mach-clps711x/time.c +++ b/trunk/arch/arm/mach-clps711x/time.c @@ -58,7 +58,7 @@ p720t_timer_interrupt(int irq, void *dev_id) static struct irqaction clps711x_timer_irq = { .name = "CLPS711x Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = p720t_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-clps7500/core.c b/trunk/arch/arm/mach-clps7500/core.c index 231b90004736..4dde34f25e63 100644 --- a/trunk/arch/arm/mach-clps7500/core.c +++ b/trunk/arch/arm/mach-clps7500/core.c @@ -316,7 +316,7 @@ clps7500_timer_interrupt(int irq, void *dev_id) static struct irqaction clps7500_timer_irq = { .name = "CLPS7500 Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = clps7500_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-ebsa110/core.c b/trunk/arch/arm/mach-ebsa110/core.c index 8459431cfd71..8c1b5690dfe8 100644 --- a/trunk/arch/arm/mach-ebsa110/core.c +++ b/trunk/arch/arm/mach-ebsa110/core.c @@ -199,7 +199,7 @@ ebsa110_timer_interrupt(int irq, void *dev_id) static struct irqaction ebsa110_timer_irq = { .name = "EBSA110 Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = ebsa110_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-ebsa110/io.c b/trunk/arch/arm/mach-ebsa110/io.c index db38afb2aa88..bbf0d332407e 100644 --- a/trunk/arch/arm/mach-ebsa110/io.c +++ b/trunk/arch/arm/mach-ebsa110/io.c @@ -102,6 +102,26 @@ EXPORT_SYMBOL(__readb); EXPORT_SYMBOL(__readw); EXPORT_SYMBOL(__readl); +void readsw(void __iomem *addr, void *data, int len) +{ + void __iomem *a = __isamem_convert_addr(addr); + + BUG_ON((unsigned long)addr & 1); + + __raw_readsw(a, data, len); +} +EXPORT_SYMBOL(readsw); + +void readsl(void __iomem *addr, void *data, int len) +{ + void __iomem *a = __isamem_convert_addr(addr); + + BUG_ON((unsigned long)addr & 3); + + __raw_readsl(a, data, len); +} +EXPORT_SYMBOL(readsl); + void __writeb(u8 val, void __iomem *addr) { void __iomem *a = __isamem_convert_addr(addr); @@ -137,6 +157,26 @@ EXPORT_SYMBOL(__writeb); EXPORT_SYMBOL(__writew); EXPORT_SYMBOL(__writel); +void writesw(void __iomem *addr, void *data, int len) +{ + void __iomem *a = __isamem_convert_addr(addr); + + BUG_ON((unsigned long)addr & 1); + + __raw_writesw(a, data, len); +} +EXPORT_SYMBOL(writesw); + +void writesl(void __iomem *addr, void *data, int len) +{ + void __iomem *a = __isamem_convert_addr(addr); + + BUG_ON((unsigned long)addr & 3); + + __raw_writesl(a, data, len); +} +EXPORT_SYMBOL(writesl); + #define SUPERIO_PORT(p) \ (((p) >> 3) == (0x3f8 >> 3) || \ ((p) >> 3) == (0x2f8 >> 3) || \ diff --git a/trunk/arch/arm/mach-ep93xx/clock.c b/trunk/arch/arm/mach-ep93xx/clock.c index f174d1a3b11c..9d7515c36bff 100644 --- a/trunk/arch/arm/mach-ep93xx/clock.c +++ b/trunk/arch/arm/mach-ep93xx/clock.c @@ -27,6 +27,10 @@ struct clk { u32 enable_mask; }; +static struct clk clk_uart = { + .name = "UARTCLK", + .rate = 14745600, +}; static struct clk clk_pll1 = { .name = "pll1", }; @@ -50,6 +54,7 @@ static struct clk clk_usb_host = { static struct clk *clocks[] = { + &clk_uart, &clk_pll1, &clk_f, &clk_h, diff --git a/trunk/arch/arm/mach-ep93xx/core.c b/trunk/arch/arm/mach-ep93xx/core.c index 829aed696d98..851cc7158ca3 100644 --- a/trunk/arch/arm/mach-ep93xx/core.c +++ b/trunk/arch/arm/mach-ep93xx/core.c @@ -116,7 +116,7 @@ static int ep93xx_timer_interrupt(int irq, void *dev_id) static struct irqaction ep93xx_timer_irq = { .name = "ep93xx timer", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = ep93xx_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-footbridge/dc21285-timer.c b/trunk/arch/arm/mach-footbridge/dc21285-timer.c index fa6be870c6c2..3a63941d43be 100644 --- a/trunk/arch/arm/mach-footbridge/dc21285-timer.c +++ b/trunk/arch/arm/mach-footbridge/dc21285-timer.c @@ -44,7 +44,7 @@ timer1_interrupt(int irq, void *dev_id) static struct irqaction footbridge_timer_irq = { .name = "Timer1 timer tick", .handler = timer1_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, }; /* diff --git a/trunk/arch/arm/mach-footbridge/dc21285.c b/trunk/arch/arm/mach-footbridge/dc21285.c index 1463330ed8ee..d0dc51e81338 100644 --- a/trunk/arch/arm/mach-footbridge/dc21285.c +++ b/trunk/arch/arm/mach-footbridge/dc21285.c @@ -10,7 +10,6 @@ */ #include #include -#include #include #include #include diff --git a/trunk/arch/arm/mach-footbridge/isa-timer.c b/trunk/arch/arm/mach-footbridge/isa-timer.c index d884a3954fb4..d08d64139d00 100644 --- a/trunk/arch/arm/mach-footbridge/isa-timer.c +++ b/trunk/arch/arm/mach-footbridge/isa-timer.c @@ -73,7 +73,7 @@ isa_timer_interrupt(int irq, void *dev_id) static struct irqaction isa_timer_irq = { .name = "ISA timer tick", .handler = isa_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, }; static void __init isa_timer_init(void) diff --git a/trunk/arch/arm/mach-h720x/cpu-h7201.c b/trunk/arch/arm/mach-h720x/cpu-h7201.c index 13f76bdb3d9d..9107b8e2ad6e 100644 --- a/trunk/arch/arm/mach-h720x/cpu-h7201.c +++ b/trunk/arch/arm/mach-h720x/cpu-h7201.c @@ -41,7 +41,7 @@ h7201_timer_interrupt(int irq, void *dev_id) static struct irqaction h7201_timer_irq = { .name = "h7201 Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = h7201_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-h720x/cpu-h7202.c b/trunk/arch/arm/mach-h720x/cpu-h7202.c index 703870f30adf..82e420d6fd19 100644 --- a/trunk/arch/arm/mach-h720x/cpu-h7202.c +++ b/trunk/arch/arm/mach-h720x/cpu-h7202.c @@ -170,7 +170,7 @@ static struct irq_chip h7202_timerx_chip = { static struct irqaction h7202_timer_irq = { .name = "h7202 Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = h7202_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-imx/time.c b/trunk/arch/arm/mach-imx/time.c index 2703a730baf7..6960a9d04217 100644 --- a/trunk/arch/arm/mach-imx/time.c +++ b/trunk/arch/arm/mach-imx/time.c @@ -56,7 +56,7 @@ imx_timer_interrupt(int irq, void *dev_id) static struct irqaction imx_timer_irq = { .name = "i.MX Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = imx_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-integrator/core.c b/trunk/arch/arm/mach-integrator/core.c index 8d880cb9ba39..897c21c2fb5b 100644 --- a/trunk/arch/arm/mach-integrator/core.c +++ b/trunk/arch/arm/mach-integrator/core.c @@ -282,7 +282,7 @@ integrator_timer_interrupt(int irq, void *dev_id) static struct irqaction integrator_timer_irq = { .name = "Integrator Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = integrator_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-integrator/pci.c b/trunk/arch/arm/mach-integrator/pci.c index 394ec9261c4e..af7d3ff013ec 100644 --- a/trunk/arch/arm/mach-integrator/pci.c +++ b/trunk/arch/arm/mach-integrator/pci.c @@ -23,7 +23,6 @@ */ #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-integrator/pci_v3.c b/trunk/arch/arm/mach-integrator/pci_v3.c index fb8c6d97b22b..af9ebccac7c1 100644 --- a/trunk/arch/arm/mach-integrator/pci_v3.c +++ b/trunk/arch/arm/mach-integrator/pci_v3.c @@ -22,7 +22,6 @@ */ #include #include -#include #include #include #include diff --git a/trunk/arch/arm/mach-iop13xx/Makefile b/trunk/arch/arm/mach-iop13xx/Makefile index 4185e0586c33..da1609dc0dee 100644 --- a/trunk/arch/arm/mach-iop13xx/Makefile +++ b/trunk/arch/arm/mach-iop13xx/Makefile @@ -7,5 +7,6 @@ obj-$(CONFIG_ARCH_IOP13XX) += setup.o obj-$(CONFIG_ARCH_IOP13XX) += irq.o obj-$(CONFIG_ARCH_IOP13XX) += pci.o obj-$(CONFIG_ARCH_IOP13XX) += io.o +obj-$(CONFIG_ARCH_IOP13XX) += tpmi.o obj-$(CONFIG_MACH_IQ81340SC) += iq81340sc.o obj-$(CONFIG_MACH_IQ81340MC) += iq81340mc.o diff --git a/trunk/arch/arm/mach-iop13xx/io.c b/trunk/arch/arm/mach-iop13xx/io.c index e79a1b62600f..5b22fdeca52c 100644 --- a/trunk/arch/arm/mach-iop13xx/io.c +++ b/trunk/arch/arm/mach-iop13xx/io.c @@ -41,7 +41,7 @@ void * __iomem __iop13xx_io(unsigned long io_addr) EXPORT_SYMBOL(__iop13xx_io); void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size, - unsigned long flags) + unsigned int mtype) { void __iomem * retval; @@ -61,9 +61,9 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size, (cookie - IOP13XX_PCIE_LOWER_MEM_RA)); break; case IOP13XX_PBI_LOWER_MEM_RA ... IOP13XX_PBI_UPPER_MEM_RA: - retval = __ioremap(IOP13XX_PBI_LOWER_MEM_PA + - (cookie - IOP13XX_PBI_LOWER_MEM_RA), - size, flags); + retval = __arm_ioremap(IOP13XX_PBI_LOWER_MEM_PA + + (cookie - IOP13XX_PBI_LOWER_MEM_RA), + size, mtype); break; case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA: retval = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(cookie); @@ -75,7 +75,7 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size, retval = (void *) IOP13XX_PMMR_PHYS_TO_VIRT(cookie); break; default: - retval = __ioremap(cookie, size, flags); + retval = __arm_ioremap(cookie, size, mtype); } return retval; diff --git a/trunk/arch/arm/mach-iop13xx/iq81340mc.c b/trunk/arch/arm/mach-iop13xx/iq81340mc.c index a519d707571c..268a8d84999c 100644 --- a/trunk/arch/arm/mach-iop13xx/iq81340mc.c +++ b/trunk/arch/arm/mach-iop13xx/iq81340mc.c @@ -75,11 +75,14 @@ static void __init iq81340mc_init(void) { iop13xx_platform_init(); iq81340mc_pci_init(); + iop13xx_add_tpmi_devices(); } static void __init iq81340mc_timer_init(void) { - iop_init_time(400000000); + unsigned long bus_freq = iop13xx_core_freq() / iop13xx_xsi_bus_ratio(); + printk(KERN_DEBUG "%s: bus frequency: %lu\n", __FUNCTION__, bus_freq); + iop_init_time(bus_freq); } static struct sys_timer iq81340mc_timer = { diff --git a/trunk/arch/arm/mach-iop13xx/iq81340sc.c b/trunk/arch/arm/mach-iop13xx/iq81340sc.c index 0e71fbcabe00..a51ffd2683e5 100644 --- a/trunk/arch/arm/mach-iop13xx/iq81340sc.c +++ b/trunk/arch/arm/mach-iop13xx/iq81340sc.c @@ -77,11 +77,14 @@ static void __init iq81340sc_init(void) { iop13xx_platform_init(); iq81340sc_pci_init(); + iop13xx_add_tpmi_devices(); } static void __init iq81340sc_timer_init(void) { - iop_init_time(400000000); + unsigned long bus_freq = iop13xx_core_freq() / iop13xx_xsi_bus_ratio(); + printk(KERN_DEBUG "%s: bus frequency: %lu\n", __FUNCTION__, bus_freq); + iop_init_time(bus_freq); } static struct sys_timer iq81340sc_timer = { diff --git a/trunk/arch/arm/mach-iop13xx/pci.c b/trunk/arch/arm/mach-iop13xx/pci.c index 89ec70ea3187..d1d0d32ca77c 100644 --- a/trunk/arch/arm/mach-iop13xx/pci.c +++ b/trunk/arch/arm/mach-iop13xx/pci.c @@ -88,9 +88,9 @@ void iop13xx_map_pci_memory(void) if (end) { iop13xx_atux_mem_base = - (u32) __ioremap_pfn( + (u32) __arm_ioremap_pfn( __phys_to_pfn(IOP13XX_PCIX_LOWER_MEM_PA) - , 0, iop13xx_atux_mem_size, 0); + , 0, iop13xx_atux_mem_size, MT_DEVICE); if (!iop13xx_atux_mem_base) { printk("%s: atux allocation " "failed\n", __FUNCTION__); @@ -114,9 +114,9 @@ void iop13xx_map_pci_memory(void) if (end) { iop13xx_atue_mem_base = - (u32) __ioremap_pfn( + (u32) __arm_ioremap_pfn( __phys_to_pfn(IOP13XX_PCIE_LOWER_MEM_PA) - , 0, iop13xx_atue_mem_size, 0); + , 0, iop13xx_atue_mem_size, MT_DEVICE); if (!iop13xx_atue_mem_base) { printk("%s: atue allocation " "failed\n", __FUNCTION__); @@ -1023,7 +1023,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys) << IOP13XX_ATUX_PCIXSR_FUNC_NUM; __raw_writel(pcixsr, IOP13XX_ATUX_PCIXSR); - res[0].start = IOP13XX_PCIX_LOWER_IO_PA; + res[0].start = IOP13XX_PCIX_LOWER_IO_PA + IOP13XX_PCIX_IO_BUS_OFFSET; res[0].end = IOP13XX_PCIX_UPPER_IO_PA; res[0].name = "IQ81340 ATUX PCI I/O Space"; res[0].flags = IORESOURCE_IO; @@ -1033,7 +1033,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys) res[1].name = "IQ81340 ATUX PCI Memory Space"; res[1].flags = IORESOURCE_MEM; sys->mem_offset = IOP13XX_PCIX_MEM_OFFSET; - sys->io_offset = IOP13XX_PCIX_IO_OFFSET; + sys->io_offset = IOP13XX_PCIX_LOWER_IO_PA; break; case IOP13XX_INIT_ATU_ATUE: /* Note: the function number field in the PCSR is ro */ @@ -1044,7 +1044,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys) __raw_writel(pcsr, IOP13XX_ATUE_PCSR); - res[0].start = IOP13XX_PCIE_LOWER_IO_PA; + res[0].start = IOP13XX_PCIE_LOWER_IO_PA + IOP13XX_PCIE_IO_BUS_OFFSET; res[0].end = IOP13XX_PCIE_UPPER_IO_PA; res[0].name = "IQ81340 ATUE PCI I/O Space"; res[0].flags = IORESOURCE_IO; @@ -1054,7 +1054,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys) res[1].name = "IQ81340 ATUE PCI Memory Space"; res[1].flags = IORESOURCE_MEM; sys->mem_offset = IOP13XX_PCIE_MEM_OFFSET; - sys->io_offset = IOP13XX_PCIE_IO_OFFSET; + sys->io_offset = IOP13XX_PCIE_LOWER_IO_PA; sys->map_irq = iop13xx_pcie_map_irq; break; default: diff --git a/trunk/arch/arm/mach-iop13xx/setup.c b/trunk/arch/arm/mach-iop13xx/setup.c index 9a46bcd5f18e..bc4871553f6a 100644 --- a/trunk/arch/arm/mach-iop13xx/setup.c +++ b/trunk/arch/arm/mach-iop13xx/setup.c @@ -258,15 +258,11 @@ void __init iop13xx_platform_init(void) if (init_uart == IOP13XX_INIT_UART_DEFAULT) { switch (iop13xx_dev_id()) { - /* enable both uarts on iop341 and iop342 */ + /* enable both uarts on iop341 */ case 0x3380: case 0x3384: case 0x3388: case 0x338c: - case 0x3382: - case 0x3386: - case 0x338a: - case 0x338e: init_uart |= IOP13XX_INIT_UART_0; init_uart |= IOP13XX_INIT_UART_1; break; diff --git a/trunk/arch/arm/mach-iop13xx/tpmi.c b/trunk/arch/arm/mach-iop13xx/tpmi.c new file mode 100644 index 000000000000..d3dc278213da --- /dev/null +++ b/trunk/arch/arm/mach-iop13xx/tpmi.c @@ -0,0 +1,234 @@ +/* + * iop13xx tpmi device resources + * Copyright (c) 2005-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 +#include +#include +#include +#include +#include +#include + +/* assumes CONTROLLER_ONLY# is never asserted in the ESSR register */ +#define IOP13XX_TPMI_MMR(dev) IOP13XX_REG_ADDR32_PHYS(0x48000 + (dev << 12)) +#define IOP13XX_TPMI_MEM(dev) IOP13XX_REG_ADDR32_PHYS(0x60000 + (dev << 13)) +#define IOP13XX_TPMI_CTRL(dev) IOP13XX_REG_ADDR32_PHYS(0x50000 + (dev << 10)) +#define IOP13XX_TPMI_MMR_SIZE (SZ_4K - 1) +#define IOP13XX_TPMI_MEM_SIZE (255) +#define IOP13XX_TPMI_MEM_CTRL (SZ_1K - 1) +#define IOP13XX_TPMI_RESOURCE_MMR 0 +#define IOP13XX_TPMI_RESOURCE_MEM 1 +#define IOP13XX_TPMI_RESOURCE_CTRL 2 +#define IOP13XX_TPMI_RESOURCE_IRQ 3 + +static struct resource iop13xx_tpmi_0_resources[] = { + [IOP13XX_TPMI_RESOURCE_MMR] = { + .start = IOP13XX_TPMI_MMR(4), /* tpmi0 starts at dev == 4 */ + .end = IOP13XX_TPMI_MMR(4) + IOP13XX_TPMI_MMR_SIZE, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_MEM] = { + .start = IOP13XX_TPMI_MEM(0), + .end = IOP13XX_TPMI_MEM(0) + IOP13XX_TPMI_MEM_SIZE, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_CTRL] = { + .start = IOP13XX_TPMI_CTRL(0), + .end = IOP13XX_TPMI_CTRL(0) + IOP13XX_TPMI_MEM_CTRL, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_IRQ] = { + .start = IRQ_IOP13XX_TPMI0_OUT, + .end = IRQ_IOP13XX_TPMI0_OUT, + .flags = IORESOURCE_IRQ + } +}; + +static struct resource iop13xx_tpmi_1_resources[] = { + [IOP13XX_TPMI_RESOURCE_MMR] = { + .start = IOP13XX_TPMI_MMR(1), + .end = IOP13XX_TPMI_MMR(1) + IOP13XX_TPMI_MMR_SIZE, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_MEM] = { + .start = IOP13XX_TPMI_MEM(1), + .end = IOP13XX_TPMI_MEM(1) + IOP13XX_TPMI_MEM_SIZE, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_CTRL] = { + .start = IOP13XX_TPMI_CTRL(1), + .end = IOP13XX_TPMI_CTRL(1) + IOP13XX_TPMI_MEM_CTRL, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_IRQ] = { + .start = IRQ_IOP13XX_TPMI1_OUT, + .end = IRQ_IOP13XX_TPMI1_OUT, + .flags = IORESOURCE_IRQ + } +}; + +static struct resource iop13xx_tpmi_2_resources[] = { + [IOP13XX_TPMI_RESOURCE_MMR] = { + .start = IOP13XX_TPMI_MMR(2), + .end = IOP13XX_TPMI_MMR(2) + IOP13XX_TPMI_MMR_SIZE, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_MEM] = { + .start = IOP13XX_TPMI_MEM(2), + .end = IOP13XX_TPMI_MEM(2) + IOP13XX_TPMI_MEM_SIZE, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_CTRL] = { + .start = IOP13XX_TPMI_CTRL(2), + .end = IOP13XX_TPMI_CTRL(2) + IOP13XX_TPMI_MEM_CTRL, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_IRQ] = { + .start = IRQ_IOP13XX_TPMI2_OUT, + .end = IRQ_IOP13XX_TPMI2_OUT, + .flags = IORESOURCE_IRQ + } +}; + +static struct resource iop13xx_tpmi_3_resources[] = { + [IOP13XX_TPMI_RESOURCE_MMR] = { + .start = IOP13XX_TPMI_MMR(3), + .end = IOP13XX_TPMI_MMR(3) + IOP13XX_TPMI_MMR_SIZE, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_MEM] = { + .start = IOP13XX_TPMI_MEM(3), + .end = IOP13XX_TPMI_MEM(3) + IOP13XX_TPMI_MEM_SIZE, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_CTRL] = { + .start = IOP13XX_TPMI_CTRL(3), + .end = IOP13XX_TPMI_CTRL(3) + IOP13XX_TPMI_MEM_CTRL, + .flags = IORESOURCE_MEM, + }, + [IOP13XX_TPMI_RESOURCE_IRQ] = { + .start = IRQ_IOP13XX_TPMI3_OUT, + .end = IRQ_IOP13XX_TPMI3_OUT, + .flags = IORESOURCE_IRQ + } +}; + +u64 iop13xx_tpmi_mask = DMA_64BIT_MASK; +static struct platform_device iop13xx_tpmi_0_device = { + .name = "iop-tpmi", + .id = 0, + .num_resources = 4, + .resource = iop13xx_tpmi_0_resources, + .dev = { + .dma_mask = &iop13xx_tpmi_mask, + .coherent_dma_mask = DMA_64BIT_MASK, + }, +}; + +static struct platform_device iop13xx_tpmi_1_device = { + .name = "iop-tpmi", + .id = 1, + .num_resources = 4, + .resource = iop13xx_tpmi_1_resources, + .dev = { + .dma_mask = &iop13xx_tpmi_mask, + .coherent_dma_mask = DMA_64BIT_MASK, + }, +}; + +static struct platform_device iop13xx_tpmi_2_device = { + .name = "iop-tpmi", + .id = 2, + .num_resources = 4, + .resource = iop13xx_tpmi_2_resources, + .dev = { + .dma_mask = &iop13xx_tpmi_mask, + .coherent_dma_mask = DMA_64BIT_MASK, + }, +}; + +static struct platform_device iop13xx_tpmi_3_device = { + .name = "iop-tpmi", + .id = 3, + .num_resources = 4, + .resource = iop13xx_tpmi_3_resources, + .dev = { + .dma_mask = &iop13xx_tpmi_mask, + .coherent_dma_mask = DMA_64BIT_MASK, + }, +}; + +__init void iop13xx_add_tpmi_devices(void) +{ + unsigned short device_id; + + /* tpmi's not present on iop341 or iop342 */ + if (__raw_readl(IOP13XX_ESSR0) & IOP13XX_INTERFACE_SEL_PCIX) + /* ATUE must be present */ + device_id = __raw_readw(IOP13XX_ATUE_DID); + else + /* ATUX must be present */ + device_id = __raw_readw(IOP13XX_ATUX_DID); + + switch (device_id) { + /* iop34[1|2] 0-tpmi */ + case 0x3380: + case 0x3384: + case 0x3388: + case 0x338c: + case 0x3382: + case 0x3386: + case 0x338a: + case 0x338e: + return; + /* iop348 1-tpmi */ + case 0x3310: + case 0x3312: + case 0x3314: + case 0x3318: + case 0x331a: + case 0x331c: + case 0x33c0: + case 0x33c2: + case 0x33c4: + case 0x33c8: + case 0x33ca: + case 0x33cc: + case 0x33b0: + case 0x33b2: + case 0x33b4: + case 0x33b8: + case 0x33ba: + case 0x33bc: + case 0x3320: + case 0x3322: + case 0x3324: + case 0x3328: + case 0x332a: + case 0x332c: + platform_device_register(&iop13xx_tpmi_0_device); + return; + default: + platform_device_register(&iop13xx_tpmi_0_device); + platform_device_register(&iop13xx_tpmi_1_device); + platform_device_register(&iop13xx_tpmi_2_device); + platform_device_register(&iop13xx_tpmi_3_device); + return; + } +} diff --git a/trunk/arch/arm/mach-iop32x/Kconfig b/trunk/arch/arm/mach-iop32x/Kconfig index 9dd49cff21ff..9bb02b6d7ae1 100644 --- a/trunk/arch/arm/mach-iop32x/Kconfig +++ b/trunk/arch/arm/mach-iop32x/Kconfig @@ -34,6 +34,14 @@ config MACH_N2100 Say Y here if you want to run your kernel on the Thecus n2100 NAS appliance. +config IOP3XX_ATU + bool "Enable the PCI Controller" + default y + help + Say Y here if you want the IOP to initialize its PCI Controller. + Say N if the IOP is an add in card, the host system owns the PCI + bus in this case. + endmenu endif diff --git a/trunk/arch/arm/mach-iop32x/iq31244.c b/trunk/arch/arm/mach-iop32x/iq31244.c index 60e74309a458..7b21c6e13e59 100644 --- a/trunk/arch/arm/mach-iop32x/iq31244.c +++ b/trunk/arch/arm/mach-iop32x/iq31244.c @@ -178,9 +178,10 @@ static struct hw_pci iq31244_pci __initdata = { static int __init iq31244_pci_init(void) { - if (is_ep80219()) - pci_common_init(&ep80219_pci); - else if (machine_is_iq31244()) { + if (is_ep80219()) { + if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) + pci_common_init(&ep80219_pci); + } else if (machine_is_iq31244()) { if (is_80219()) { printk("note: iq31244 board type has been selected\n"); printk("note: to select ep80219 operation:\n"); @@ -189,7 +190,9 @@ static int __init iq31244_pci_init(void) printk("\t2/ update boot loader to pass" " the ep80219 id: %d\n", MACH_TYPE_EP80219); } - pci_common_init(&iq31244_pci); + + if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) + pci_common_init(&iq31244_pci); } return 0; diff --git a/trunk/arch/arm/mach-iop32x/iq80321.c b/trunk/arch/arm/mach-iop32x/iq80321.c index 361c70c0f64c..bc25fb91e7b9 100644 --- a/trunk/arch/arm/mach-iop32x/iq80321.c +++ b/trunk/arch/arm/mach-iop32x/iq80321.c @@ -113,7 +113,8 @@ static struct hw_pci iq80321_pci __initdata = { static int __init iq80321_pci_init(void) { - if (machine_is_iq80321()) + if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && + machine_is_iq80321()) pci_common_init(&iq80321_pci); return 0; diff --git a/trunk/arch/arm/mach-iop33x/Kconfig b/trunk/arch/arm/mach-iop33x/Kconfig index 9aa016bb18f9..45598e096898 100644 --- a/trunk/arch/arm/mach-iop33x/Kconfig +++ b/trunk/arch/arm/mach-iop33x/Kconfig @@ -16,6 +16,14 @@ config MACH_IQ80332 Say Y here if you want to run your kernel on the Intel IQ80332 evaluation kit for the IOP332 chipset. +config IOP3XX_ATU + bool "Enable the PCI Controller" + default y + help + Say Y here if you want the IOP to initialize its PCI Controller. + Say N if the IOP is an add in card, the host system owns the PCI + bus in this case. + endmenu endif diff --git a/trunk/arch/arm/mach-iop33x/iq80331.c b/trunk/arch/arm/mach-iop33x/iq80331.c index 1a9e36138d80..376c932830be 100644 --- a/trunk/arch/arm/mach-iop33x/iq80331.c +++ b/trunk/arch/arm/mach-iop33x/iq80331.c @@ -96,7 +96,8 @@ static struct hw_pci iq80331_pci __initdata = { static int __init iq80331_pci_init(void) { - if (machine_is_iq80331()) + if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && + machine_is_iq80331()) pci_common_init(&iq80331_pci); return 0; diff --git a/trunk/arch/arm/mach-iop33x/iq80332.c b/trunk/arch/arm/mach-iop33x/iq80332.c index 96d6f0f3cd21..58c81496c6f6 100644 --- a/trunk/arch/arm/mach-iop33x/iq80332.c +++ b/trunk/arch/arm/mach-iop33x/iq80332.c @@ -96,7 +96,8 @@ static struct hw_pci iq80332_pci __initdata = { static int __init iq80332_pci_init(void) { - if (machine_is_iq80332()) + if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && + machine_is_iq80332()) pci_common_init(&iq80332_pci); return 0; diff --git a/trunk/arch/arm/mach-ixp2000/core.c b/trunk/arch/arm/mach-ixp2000/core.c index 27b7480f4afe..cb6ad211887a 100644 --- a/trunk/arch/arm/mach-ixp2000/core.c +++ b/trunk/arch/arm/mach-ixp2000/core.c @@ -84,59 +84,59 @@ static struct map_desc ixp2000_io_desc[] __initdata = { .virtual = IXP2000_CAP_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_CAP_PHYS_BASE), .length = IXP2000_CAP_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, }, { .virtual = IXP2000_INTCTL_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_INTCTL_PHYS_BASE), .length = IXP2000_INTCTL_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, }, { .virtual = IXP2000_PCI_CREG_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CREG_PHYS_BASE), .length = IXP2000_PCI_CREG_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, }, { .virtual = IXP2000_PCI_CSR_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CSR_PHYS_BASE), .length = IXP2000_PCI_CSR_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, }, { .virtual = IXP2000_MSF_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_MSF_PHYS_BASE), .length = IXP2000_MSF_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, }, { .virtual = IXP2000_SCRATCH_RING_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_SCRATCH_RING_PHYS_BASE), .length = IXP2000_SCRATCH_RING_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, }, { .virtual = IXP2000_SRAM0_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_SRAM0_PHYS_BASE), .length = IXP2000_SRAM0_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, }, { .virtual = IXP2000_PCI_IO_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE), .length = IXP2000_PCI_IO_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, }, { .virtual = IXP2000_PCI_CFG0_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CFG0_PHYS_BASE), .length = IXP2000_PCI_CFG0_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, }, { .virtual = IXP2000_PCI_CFG1_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CFG1_PHYS_BASE), .length = IXP2000_PCI_CFG1_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, } }; void __init ixp2000_map_io(void) { /* - * On IXP2400 CPUs we need to use MT_IXP2000_DEVICE so that + * On IXP2400 CPUs we need to use MT_DEVICE_IXP2000 so that * XCB=101 (to avoid triggering erratum #66), and given that * this mode speeds up I/O accesses and we have write buffer * flushes in the right places anyway, it doesn't hurt to use @@ -224,7 +224,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id) static struct irqaction ixp2000_timer_irq = { .name = "IXP2000 Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = ixp2000_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-ixp2000/enp2611.c b/trunk/arch/arm/mach-ixp2000/enp2611.c index ac29298c5d3f..500e997ba7a4 100644 --- a/trunk/arch/arm/mach-ixp2000/enp2611.c +++ b/trunk/arch/arm/mach-ixp2000/enp2611.c @@ -70,17 +70,17 @@ static struct map_desc enp2611_io_desc[] __initdata = { .virtual = ENP2611_CALEB_VIRT_BASE, .pfn = __phys_to_pfn(ENP2611_CALEB_PHYS_BASE), .length = ENP2611_CALEB_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, }, { .virtual = ENP2611_PM3386_0_VIRT_BASE, .pfn = __phys_to_pfn(ENP2611_PM3386_0_PHYS_BASE), .length = ENP2611_PM3386_0_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, }, { .virtual = ENP2611_PM3386_1_VIRT_BASE, .pfn = __phys_to_pfn(ENP2611_PM3386_1_PHYS_BASE), .length = ENP2611_PM3386_1_SIZE, - .type = MT_IXP2000_DEVICE, + .type = MT_DEVICE_IXP2000, } }; diff --git a/trunk/arch/arm/mach-ixp23xx/core.c b/trunk/arch/arm/mach-ixp23xx/core.c index ce6ad635a00c..b644bbab7d0a 100644 --- a/trunk/arch/arm/mach-ixp23xx/core.c +++ b/trunk/arch/arm/mach-ixp23xx/core.c @@ -363,7 +363,7 @@ ixp23xx_timer_interrupt(int irq, void *dev_id) static struct irqaction ixp23xx_timer_irq = { .name = "IXP23xx Timer Tick", .handler = ixp23xx_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, }; void __init ixp23xx_init_timer(void) diff --git a/trunk/arch/arm/mach-ixp4xx/Kconfig b/trunk/arch/arm/mach-ixp4xx/Kconfig index 8a339cdfe222..9715ef506c24 100644 --- a/trunk/arch/arm/mach-ixp4xx/Kconfig +++ b/trunk/arch/arm/mach-ixp4xx/Kconfig @@ -62,6 +62,12 @@ config MACH_IXDP465 IXDP465 Development Platform (Also known as BMP). For more information on this platform, see . +config MACH_KIXRP435 + bool "KIXRP435" + help + Say 'Y' here if you want your kernel to support Intel's + KIXRP435 Reference Platform. + For more information on this platform, see . # # IXCDP1100 is the exact same HW as IXDP425, but with a different machine @@ -89,12 +95,21 @@ config MACH_NAS100D NAS 100d device. For more information on this platform, see http://www.nslu2-linux.org/wiki/NAS100d/HomePage +config MACH_DSMG600 + bool + prompt "D-Link DSM-G600 RevA" + select PCI + help + Say 'Y' here if you want your kernel to support D-Link's + DSM-G600 RevA device. For more information on this platform, + see http://www.nslu2-linux.org/wiki/DSMG600/HomePage + # # Avila and IXDP share the same source for now. Will change in future # config ARCH_IXDP4XX bool - depends on ARCH_IXDP425 || MACH_IXDP465 + depends on ARCH_IXDP425 || MACH_IXDP465 || MACH_KIXRP435 default y # @@ -105,6 +120,11 @@ config CPU_IXP46X depends on MACH_IXDP465 default y +config CPU_IXP43X + bool + depends on MACH_KIXRP435 + default y + config MACH_GTWX5715 bool "Gemtek WX5715 (Linksys WRV54G)" depends on ARCH_IXP4XX diff --git a/trunk/arch/arm/mach-ixp4xx/Makefile b/trunk/arch/arm/mach-ixp4xx/Makefile index 746e297284ed..3b87c47e06cf 100644 --- a/trunk/arch/arm/mach-ixp4xx/Makefile +++ b/trunk/arch/arm/mach-ixp4xx/Makefile @@ -12,6 +12,7 @@ obj-pci-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o obj-pci-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o obj-pci-$(CONFIG_MACH_NSLU2) += nslu2-pci.o obj-pci-$(CONFIG_MACH_NAS100D) += nas100d-pci.o +obj-pci-$(CONFIG_MACH_DSMG600) += dsmg600-pci.o obj-y += common.o @@ -22,5 +23,6 @@ obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-setup.o obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-setup.o obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.o nslu2-power.o obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o nas100d-power.o +obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o dsmg600-power.o obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o diff --git a/trunk/arch/arm/mach-ixp4xx/common-pci.c b/trunk/arch/arm/mach-ixp4xx/common-pci.c index 9562177b5fe1..bf04121d1a31 100644 --- a/trunk/arch/arm/mach-ixp4xx/common-pci.c +++ b/trunk/arch/arm/mach-ixp4xx/common-pci.c @@ -374,7 +374,7 @@ void __init ixp4xx_pci_preinit(void) * Determine which PCI read method to use. * Rev 0 IXP425 requires workaround. */ - if (!(processor_id & 0xf) && !cpu_is_ixp46x()) { + if (!(processor_id & 0xf) && cpu_is_ixp42x()) { printk("PCI: IXP42x A0 silicon detected - " "PCI Non-Prefetch Workaround Enabled\n"); ixp4xx_pci_read = ixp4xx_pci_read_errata; @@ -480,7 +480,7 @@ int ixp4xx_setup(int nr, struct pci_sys_data *sys) res[0].flags = IORESOURCE_IO; res[1].name = "PCI Memory Space"; - res[1].start = 0x48000000; + res[1].start = PCIBIOS_MIN_MEM; #ifndef CONFIG_IXP4XX_INDIRECT_PCI res[1].end = 0x4bffffff; #else diff --git a/trunk/arch/arm/mach-ixp4xx/common.c b/trunk/arch/arm/mach-ixp4xx/common.c index 45068c3d8dcc..64685da1462d 100644 --- a/trunk/arch/arm/mach-ixp4xx/common.c +++ b/trunk/arch/arm/mach-ixp4xx/common.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,8 @@ #include static int __init ixp4xx_clocksource_init(void); +static int __init ixp4xx_clockevent_init(void); +static struct clock_event_device clockevent_ixp4xx; /************************************************************************* * IXP4xx chipset I/O mapping @@ -102,6 +105,29 @@ static signed char irq2gpio[32] = { 7, 8, 9, 10, 11, 12, -1, -1, }; +int gpio_to_irq(int gpio) +{ + int irq; + + for (irq = 0; irq < 32; irq++) { + if (irq2gpio[irq] == gpio) + return irq; + } + return -EINVAL; +} +EXPORT_SYMBOL(gpio_to_irq); + +int irq_to_gpio(int irq) +{ + int gpio = (irq < 32) ? irq2gpio[irq] : -EINVAL; + + if (gpio == -1) + return -EINVAL; + + return gpio; +} +EXPORT_SYMBOL(irq_to_gpio); + static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type) { int line = irq2gpio[irq]; @@ -169,7 +195,7 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type) static void ixp4xx_irq_mask(unsigned int irq) { - if (cpu_is_ixp46x() && irq >= 32) + if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && irq >= 32) *IXP4XX_ICMR2 &= ~(1 << (irq - 32)); else *IXP4XX_ICMR &= ~(1 << irq); @@ -192,7 +218,7 @@ static void ixp4xx_irq_unmask(unsigned int irq) if (!(ixp4xx_irq_edge & (1 << irq))) ixp4xx_irq_ack(irq); - if (cpu_is_ixp46x() && irq >= 32) + if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && irq >= 32) *IXP4XX_ICMR2 |= (1 << (irq - 32)); else *IXP4XX_ICMR |= (1 << irq); @@ -216,7 +242,7 @@ void __init ixp4xx_init_irq(void) /* Disable all interrupt */ *IXP4XX_ICMR = 0x0; - if (cpu_is_ixp46x()) { + if (cpu_is_ixp46x() || cpu_is_ixp43x()) { /* Route upper 32 sources to IRQ instead of FIQ */ *IXP4XX_ICLR2 = 0x00; @@ -239,52 +265,40 @@ void __init ixp4xx_init_irq(void) * counter as a source of real clock ticks to account for missed jiffies. *************************************************************************/ -static unsigned volatile last_jiffy_time; - -#define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC) - static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id) { - write_seqlock(&xtime_lock); + struct clock_event_device *evt = &clockevent_ixp4xx; /* Clear Pending Interrupt by writing '1' to it */ *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; - /* - * Catch up with the real idea of time - */ - while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) { - timer_tick(); - last_jiffy_time += LATCH; - } - - write_sequnlock(&xtime_lock); + evt->event_handler(evt); return IRQ_HANDLED; } static struct irqaction ixp4xx_timer_irq = { - .name = "IXP4xx Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .name = "timer1", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = ixp4xx_timer_interrupt, }; static void __init ixp4xx_timer_init(void) { + /* Reset/disable counter */ + *IXP4XX_OSRT1 = 0; + /* Clear Pending Interrupt by writing '1' to it */ *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; - /* Setup the Timer counter value */ - *IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE; - /* Reset time-stamp counter */ *IXP4XX_OSTS = 0; - last_jiffy_time = 0; /* Connect the interrupt handler and enable the interrupt */ setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq); ixp4xx_clocksource_init(); + ixp4xx_clockevent_init(); } struct sys_timer ixp4xx_timer = { @@ -384,6 +398,9 @@ void __init ixp4xx_sys_init(void) ixp4xx_exp_bus_size >> 20); } +/* + * clocksource + */ cycle_t ixp4xx_get_cycles(void) { return *IXP4XX_OSTS; @@ -408,3 +425,64 @@ static int __init ixp4xx_clocksource_init(void) return 0; } + +/* + * clockevents + */ +static int ixp4xx_set_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + unsigned long opts = *IXP4XX_OSRT1 & IXP4XX_OST_RELOAD_MASK; + + *IXP4XX_OSRT1 = (evt & ~IXP4XX_OST_RELOAD_MASK) | opts; + + return 0; +} + +static void ixp4xx_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long opts, osrt = *IXP4XX_OSRT1 & ~IXP4XX_OST_RELOAD_MASK; + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + osrt = LATCH & ~IXP4XX_OST_RELOAD_MASK; + opts = IXP4XX_OST_ENABLE; + break; + case CLOCK_EVT_MODE_ONESHOT: + /* period set by 'set next_event' */ + osrt = 0; + opts = IXP4XX_OST_ENABLE | IXP4XX_OST_ONE_SHOT; + break; + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + default: + osrt = opts = 0; + break; + } + + *IXP4XX_OSRT1 = osrt | opts; +} + +static struct clock_event_device clockevent_ixp4xx = { + .name = "ixp4xx timer1", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .shift = 24, + .set_mode = ixp4xx_set_mode, + .set_next_event = ixp4xx_set_next_event, +}; + +static int __init ixp4xx_clockevent_init(void) +{ + clockevent_ixp4xx.mult = div_sc(FREQ, NSEC_PER_SEC, + clockevent_ixp4xx.shift); + clockevent_ixp4xx.max_delta_ns = + clockevent_delta2ns(0xfffffffe, &clockevent_ixp4xx); + clockevent_ixp4xx.min_delta_ns = + clockevent_delta2ns(0xf, &clockevent_ixp4xx); + clockevent_ixp4xx.cpumask = cpumask_of_cpu(0); + + clockevents_register_device(&clockevent_ixp4xx); + return 0; +} diff --git a/trunk/arch/arm/mach-ixp4xx/dsmg600-pci.c b/trunk/arch/arm/mach-ixp4xx/dsmg600-pci.c new file mode 100644 index 000000000000..9db7e1f42011 --- /dev/null +++ b/trunk/arch/arm/mach-ixp4xx/dsmg600-pci.c @@ -0,0 +1,74 @@ +/* + * DSM-G600 board-level PCI initialization + * + * Copyright (C) 2006 Tower Technologies + * Author: Alessandro Zummo + * + * based on ixdp425-pci.c: + * Copyright (C) 2002 Intel Corporation. + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * Maintainer: http://www.nslu2-linux.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. + * + */ + +#include +#include +#include + +#include +#include + +void __init dsmg600_pci_preinit(void) +{ + set_irq_type(IRQ_DSMG600_PCI_INTA, IRQT_LOW); + set_irq_type(IRQ_DSMG600_PCI_INTB, IRQT_LOW); + set_irq_type(IRQ_DSMG600_PCI_INTC, IRQT_LOW); + set_irq_type(IRQ_DSMG600_PCI_INTD, IRQT_LOW); + set_irq_type(IRQ_DSMG600_PCI_INTE, IRQT_LOW); + set_irq_type(IRQ_DSMG600_PCI_INTF, IRQT_LOW); + + ixp4xx_pci_preinit(); +} + +static int __init dsmg600_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + static int pci_irq_table[DSMG600_PCI_MAX_DEV][DSMG600_PCI_IRQ_LINES] = + { + { IRQ_DSMG600_PCI_INTE, -1, -1 }, + { IRQ_DSMG600_PCI_INTA, -1, -1 }, + { IRQ_DSMG600_PCI_INTB, IRQ_DSMG600_PCI_INTC, IRQ_DSMG600_PCI_INTD }, + { IRQ_DSMG600_PCI_INTF, -1, -1 }, + }; + + int irq = -1; + + if (slot >= 1 && slot <= DSMG600_PCI_MAX_DEV && + pin >= 1 && pin <= DSMG600_PCI_IRQ_LINES) + irq = pci_irq_table[slot-1][pin-1]; + + return irq; +} + +struct hw_pci __initdata dsmg600_pci = { + .nr_controllers = 1, + .preinit = dsmg600_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = dsmg600_map_irq, +}; + +int __init dsmg600_pci_init(void) +{ + if (machine_is_dsmg600()) + pci_common_init(&dsmg600_pci); + + return 0; +} + +subsys_initcall(dsmg600_pci_init); diff --git a/trunk/arch/arm/mach-ixp4xx/dsmg600-power.c b/trunk/arch/arm/mach-ixp4xx/dsmg600-power.c new file mode 100644 index 000000000000..34717872d076 --- /dev/null +++ b/trunk/arch/arm/mach-ixp4xx/dsmg600-power.c @@ -0,0 +1,125 @@ +/* + * arch/arm/mach-ixp4xx/dsmg600-power.c + * + * DSM-G600 Power/Reset driver + * Author: Michael Westerhof + * + * Based on nslu2-power.c + * Copyright (C) 2005 Tower Technologies + * Author: Alessandro Zummo + * + * which was based on nslu2-io.c + * Copyright (C) 2004 Karen Spearel + * + * Maintainers: http://www.nslu2-linux.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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +extern void ctrl_alt_del(void); + +/* This is used to make sure the power-button pusher is serious. The button + * must be held until the value of this counter reaches zero. + */ +static volatile int power_button_countdown; + +/* Must hold the button down for at least this many counts to be processed */ +#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */ + +static void dsmg600_power_handler(unsigned long data); +static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0); + +static void dsmg600_power_handler(unsigned long data) +{ + /* This routine is called twice per second to check the + * state of the power button. + */ + + if (*IXP4XX_GPIO_GPINR & DSMG600_PB_BM) { + + /* IO Pin is 1 (button pushed) */ + if (power_button_countdown == 0) { + /* Signal init to do the ctrlaltdel action, this will bypass + * init if it hasn't started and do a kernel_restart. + */ + ctrl_alt_del(); + + /* Change the state of the power LED to "blink" */ + gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW); + } + power_button_countdown--; + + } else { + power_button_countdown = PBUTTON_HOLDDOWN_COUNT; + } + + mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500)); +} + +static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id) +{ + /* This is the paper-clip reset, it shuts the machine down directly. */ + machine_power_off(); + + return IRQ_HANDLED; +} + +static int __init dsmg600_power_init(void) +{ + if (!(machine_is_dsmg600())) + return 0; + + if (request_irq(DSMG600_RB_IRQ, &dsmg600_reset_handler, + IRQF_DISABLED | IRQF_TRIGGER_LOW, "DSM-G600 reset button", + NULL) < 0) { + + printk(KERN_DEBUG "Reset Button IRQ %d not available\n", + DSMG600_RB_IRQ); + + return -EIO; + } + + /* The power button on the D-Link DSM-G600 is on GPIO 15, but + * it cannot handle interrupts on that GPIO line. So we'll + * have to poll it with a kernel timer. + */ + + /* Make sure that the power button GPIO is set up as an input */ + gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN); + + /* Set the initial value for the power button IRQ handler */ + power_button_countdown = PBUTTON_HOLDDOWN_COUNT; + + mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500)); + + return 0; +} + +static void __exit dsmg600_power_exit(void) +{ + if (!(machine_is_dsmg600())) + return; + + del_timer_sync(&dsmg600_power_timer); + + free_irq(DSMG600_RB_IRQ, NULL); +} + +module_init(dsmg600_power_init); +module_exit(dsmg600_power_exit); + +MODULE_AUTHOR("Michael Westerhof "); +MODULE_DESCRIPTION("DSM-G600 Power/Reset driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/arch/arm/mach-ixp4xx/dsmg600-setup.c b/trunk/arch/arm/mach-ixp4xx/dsmg600-setup.c new file mode 100644 index 000000000000..1caff65e22cc --- /dev/null +++ b/trunk/arch/arm/mach-ixp4xx/dsmg600-setup.c @@ -0,0 +1,175 @@ +/* + * DSM-G600 board-setup + * + * Copyright (C) 2006 Tower Technologies + * Author: Alessandro Zummo + * + * based ixdp425-setup.c: + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * Author: Alessandro Zummo + * Maintainers: http://www.nslu2-linux.org/ + */ + +#include +#include +#include + +#include +#include +#include + +static struct flash_platform_data dsmg600_flash_data = { + .map_name = "cfi_probe", + .width = 2, +}; + +static struct resource dsmg600_flash_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device dsmg600_flash = { + .name = "IXP4XX-Flash", + .id = 0, + .dev.platform_data = &dsmg600_flash_data, + .num_resources = 1, + .resource = &dsmg600_flash_resource, +}; + +static struct ixp4xx_i2c_pins dsmg600_i2c_gpio_pins = { + .sda_pin = DSMG600_SDA_PIN, + .scl_pin = DSMG600_SCL_PIN, +}; + +static struct platform_device dsmg600_i2c_controller = { + .name = "IXP4XX-I2C", + .id = 0, + .dev.platform_data = &dsmg600_i2c_gpio_pins, +}; + +#ifdef CONFIG_LEDS_CLASS +static struct resource dsmg600_led_resources[] = { + { + .name = "power", + .start = DSMG600_LED_PWR_GPIO, + .end = DSMG600_LED_PWR_GPIO, + .flags = IXP4XX_GPIO_HIGH, + }, + { + .name = "wlan", + .start = DSMG600_LED_WLAN_GPIO, + .end = DSMG600_LED_WLAN_GPIO, + .flags = IXP4XX_GPIO_LOW, + }, +}; + +static struct platform_device dsmg600_leds = { + .name = "IXP4XX-GPIO-LED", + .id = -1, + .num_resources = ARRAY_SIZE(dsmg600_led_resources), + .resource = dsmg600_led_resources, +}; +#endif + +static struct resource dsmg600_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 dsmg600_uart_data[] = { + { + .mapbase = IXP4XX_UART1_BASE_PHYS, + .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET, + .irq = IRQ_IXP4XX_UART1, + .flags = UPF_BOOT_AUTOCONF, + .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, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL, + }, + { } +}; + +static struct platform_device dsmg600_uart = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev.platform_data = dsmg600_uart_data, + .num_resources = ARRAY_SIZE(dsmg600_uart_resources), + .resource = dsmg600_uart_resources, +}; + +static struct platform_device *dsmg600_devices[] __initdata = { + &dsmg600_i2c_controller, + &dsmg600_flash, +}; + +static void dsmg600_power_off(void) +{ + /* enable the pwr cntl gpio */ + gpio_line_config(DSMG600_PO_GPIO, IXP4XX_GPIO_OUT); + + /* poweroff */ + gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH); +} + +static void __init dsmg600_init(void) +{ + ixp4xx_sys_init(); + + /* Make sure that GPIO14 and GPIO15 are not used as clocks */ + *IXP4XX_GPIO_GPCLKR = 0; + + dsmg600_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); + dsmg600_flash_resource.end = + IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + + pm_power_off = dsmg600_power_off; + + /* The UART is required on the DSM-G600 (Redboot cannot use the + * NIC) -- do it here so that it does *not* get removed if + * platform_add_devices fails! + */ + (void)platform_device_register(&dsmg600_uart); + + platform_add_devices(dsmg600_devices, ARRAY_SIZE(dsmg600_devices)); + +#ifdef CONFIG_LEDS_CLASS + /* We don't care whether or not this works. */ + (void)platform_device_register(&dsmg600_leds); +#endif +} + +static void __init dsmg600_fixup(struct machine_desc *desc, + struct tag *tags, char **cmdline, struct meminfo *mi) +{ + /* The xtal on this machine is non-standard. */ + ixp4xx_timer_freq = DSMG600_FREQ; +} + +MACHINE_START(DSMG600, "D-Link DSM-G600 RevA") + /* Maintainer: www.nslu2-linux.org */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC, + .boot_params = 0x00000100, + .fixup = dsmg600_fixup, + .map_io = ixp4xx_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .init_machine = dsmg600_init, +MACHINE_END diff --git a/trunk/arch/arm/mach-ixp4xx/ixdp425-pci.c b/trunk/arch/arm/mach-ixp4xx/ixdp425-pci.c index 99c1dc8033c8..408796004812 100644 --- a/trunk/arch/arm/mach-ixp4xx/ixdp425-pci.c +++ b/trunk/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_ixdp465()) + machine_is_ixdp465() || machine_is_kixrp435()) pci_common_init(&ixdp425_pci); return 0; } diff --git a/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c b/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c index 04b1d56396a0..ec4f07950ec6 100644 --- a/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -115,6 +115,11 @@ static void __init ixdp425_init(void) ixdp425_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + if (cpu_is_ixp43x()) { + ixdp425_uart.num_resources = 1; + ixdp425_uart_data[1].flags = 0; + } + platform_add_devices(ixdp425_devices, ARRAY_SIZE(ixdp425_devices)); } @@ -156,3 +161,16 @@ MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform") .init_machine = ixdp425_init, MACHINE_END #endif + +#ifdef CONFIG_MACH_KIXRP435 +MACHINE_START(KIXRP435, "Intel KIXRP435 Reference Platform") + /* Maintainer: MontaVista Software, Inc. */ + .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/trunk/arch/arm/mach-lh7a40x/irq-lh7a400.c b/trunk/arch/arm/mach-lh7a40x/irq-lh7a400.c index 0b938e8b4d98..9472bbebd8ab 100644 --- a/trunk/arch/arm/mach-lh7a40x/irq-lh7a400.c +++ b/trunk/arch/arm/mach-lh7a40x/irq-lh7a400.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-lh7a40x/irq-lh7a404.c b/trunk/arch/arm/mach-lh7a40x/irq-lh7a404.c index 5760f8c53e89..9b28389035e6 100644 --- a/trunk/arch/arm/mach-lh7a40x/irq-lh7a404.c +++ b/trunk/arch/arm/mach-lh7a40x/irq-lh7a404.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-lh7a40x/irq-lpd7a40x.c b/trunk/arch/arm/mach-lh7a40x/irq-lpd7a40x.c index 15b9577023c9..66e1ed3961ea 100644 --- a/trunk/arch/arm/mach-lh7a40x/irq-lpd7a40x.c +++ b/trunk/arch/arm/mach-lh7a40x/irq-lpd7a40x.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-lh7a40x/time.c b/trunk/arch/arm/mach-lh7a40x/time.c index bef3c4b68d3b..c25316d02537 100644 --- a/trunk/arch/arm/mach-lh7a40x/time.c +++ b/trunk/arch/arm/mach-lh7a40x/time.c @@ -53,7 +53,7 @@ lh7a40x_timer_interrupt(int irq, void *dev_id) static struct irqaction lh7a40x_timer_irq = { .name = "LHA740x Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = lh7a40x_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-netx/time.c b/trunk/arch/arm/mach-netx/time.c index 7e132fcccd47..4762e207b0bf 100644 --- a/trunk/arch/arm/mach-netx/time.c +++ b/trunk/arch/arm/mach-netx/time.c @@ -47,7 +47,7 @@ netx_timer_interrupt(int irq, void *dev_id) static struct irqaction netx_timer_irq = { .name = "NetX Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = netx_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-ns9xxx/Kconfig b/trunk/arch/arm/mach-ns9xxx/Kconfig index 8175ba92a2fa..8584ed107991 100644 --- a/trunk/arch/arm/mach-ns9xxx/Kconfig +++ b/trunk/arch/arm/mach-ns9xxx/Kconfig @@ -3,19 +3,30 @@ if ARCH_NS9XXX menu "NS9xxx Implementations" config MACH_CC9P9360DEV - bool "Connect Core 9P 9360 on an A9M9750 Devboard" + bool "ConnectCore 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 + Say Y here if you are using the Digi ConnectCore 9P 9360 on an A9M9750 Development Board. +config MACH_CC9P9360JS + bool "ConnectCore 9P 9360 on a JSCC9P9360 Devboard" + select PROCESSOR_NS9360 + select BOARD_JSCC9P9360 + help + Say Y here if you are using the Digi ConnectCore 9P 9360 + on an JSCC9P9360 Development Board. + config PROCESSOR_NS9360 bool config BOARD_A9M9750DEV bool +config BOARD_JSCC9P9360 + bool + endmenu endif diff --git a/trunk/arch/arm/mach-ns9xxx/Makefile b/trunk/arch/arm/mach-ns9xxx/Makefile index 91e945f5e16d..53213a69f601 100644 --- a/trunk/arch/arm/mach-ns9xxx/Makefile +++ b/trunk/arch/arm/mach-ns9xxx/Makefile @@ -3,3 +3,4 @@ obj-y := irq.o time.o generic.o obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o obj-$(CONFIG_BOARD_A9M9750DEV) += board-a9m9750dev.o +obj-$(CONFIG_BOARD_JSCC9P9360) += board-jscc9p9360.o diff --git a/trunk/arch/arm/mach-ns9xxx/board-jscc9p9360.c b/trunk/arch/arm/mach-ns9xxx/board-jscc9p9360.c new file mode 100644 index 000000000000..4bd3eec04bfe --- /dev/null +++ b/trunk/arch/arm/mach-ns9xxx/board-jscc9p9360.c @@ -0,0 +1,17 @@ +/* + * arch/arm/mach-ns9xxx/board-jscc9p9360.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 "board-jscc9p9360.h" + +void __init board_jscc9p9360_init_machine(void) +{ + /* TODO: reserve GPIOs for push buttons, etc pp */ +} + diff --git a/trunk/arch/arm/mach-ns9xxx/board-jscc9p9360.h b/trunk/arch/arm/mach-ns9xxx/board-jscc9p9360.h new file mode 100644 index 000000000000..1a81a074df45 --- /dev/null +++ b/trunk/arch/arm/mach-ns9xxx/board-jscc9p9360.h @@ -0,0 +1,13 @@ +/* + * arch/arm/mach-ns9xxx/board-jscc9p9360.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 + +void __init board_jscc9p9360_init_machine(void); diff --git a/trunk/arch/arm/mach-ns9xxx/mach-cc9p9360js.c b/trunk/arch/arm/mach-ns9xxx/mach-cc9p9360js.c new file mode 100644 index 000000000000..d09d5fa5620a --- /dev/null +++ b/trunk/arch/arm/mach-ns9xxx/mach-cc9p9360js.c @@ -0,0 +1,29 @@ +/* + * arch/arm/mach-ns9xxx/mach-cc9p9360js.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 +#include + +#include "board-jscc9p9360.h" +#include "generic.h" + +static void __init mach_cc9p9360js_init_machine(void) +{ + ns9xxx_init_machine(); + board_jscc9p9360_init_machine(); +} + +MACHINE_START(CC9P9360DEV, "Digi ConnectCore 9P 9360 on an JSCC9P9360 Devboard") + .map_io = ns9xxx_map_io, + .init_irq = ns9xxx_init_irq, + .init_machine = mach_cc9p9360js_init_machine, + .timer = &ns9xxx_timer, + .boot_params = 0x100, +MACHINE_END diff --git a/trunk/arch/arm/mach-ns9xxx/time.c b/trunk/arch/arm/mach-ns9xxx/time.c index eec05f18714a..dd257084441c 100644 --- a/trunk/arch/arm/mach-ns9xxx/time.c +++ b/trunk/arch/arm/mach-ns9xxx/time.c @@ -53,7 +53,7 @@ static unsigned long ns9xxx_timer_gettimeoffset(void) static struct irqaction ns9xxx_timer_irq = { .name = "NS9xxx Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = ns9xxx_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-omap1/irq.c b/trunk/arch/arm/mach-omap1/irq.c index 410d3e78dd0f..0733078940fa 100644 --- a/trunk/arch/arm/mach-omap1/irq.c +++ b/trunk/arch/arm/mach-omap1/irq.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-omap1/time.c b/trunk/arch/arm/mach-omap1/time.c index 1b7e4a506c26..3705d20c4e5c 100644 --- a/trunk/arch/arm/mach-omap1/time.c +++ b/trunk/arch/arm/mach-omap1/time.c @@ -39,6 +39,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -48,13 +52,7 @@ #include #include -struct sys_timer omap_timer; -/* - * --------------------------------------------------------------------------- - * MPU timer - * --------------------------------------------------------------------------- - */ #define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE #define OMAP_MPU_TIMER_OFFSET 0x100 @@ -88,21 +86,6 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc) return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR; } -/* - * MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs - * will break. On P2, the timer count rate is 6.5 MHz after programming PTV - * with 0. This divides the 13MHz input by 2, and is undocumented. - */ -#if defined(CONFIG_MACH_OMAP_PERSEUS2) || defined(CONFIG_MACH_OMAP_FSAMPLE) -/* REVISIT: This ifdef construct should be replaced by a query to clock - * framework to see if timer base frequency is 12.0, 13.0 or 19.2 MHz. - */ -#define MPU_TICKS_PER_SEC (13000000 / 2) -#else -#define MPU_TICKS_PER_SEC (12000000 / 2) -#endif - -#define MPU_TIMER_TICK_PERIOD ((MPU_TICKS_PER_SEC / HZ) - 1) typedef struct { u32 cntl; /* CNTL_TIMER, R/W */ @@ -120,98 +103,164 @@ static inline unsigned long omap_mpu_timer_read(int nr) return timer->read_tim; } -static inline void omap_mpu_timer_start(int nr, unsigned long load_val) +static inline void omap_mpu_set_autoreset(int nr) +{ + volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); + + timer->cntl = timer->cntl | MPU_TIMER_AR; +} + +static inline void omap_mpu_remove_autoreset(int nr) +{ + volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); + + timer->cntl = timer->cntl & ~MPU_TIMER_AR; +} + +static inline void omap_mpu_timer_start(int nr, unsigned long load_val, + int autoreset) { volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); + unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST); + + if (autoreset) timerflags |= MPU_TIMER_AR; timer->cntl = MPU_TIMER_CLOCK_ENABLE; udelay(1); timer->load_tim = load_val; udelay(1); - timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST); + timer->cntl = timerflags; } -unsigned long omap_mpu_timer_ticks_to_usecs(unsigned long nr_ticks) +/* + * --------------------------------------------------------------------------- + * MPU timer 1 ... count down to zero, interrupt, reload + * --------------------------------------------------------------------------- + */ +static int omap_mpu_set_next_event(unsigned long cycles, + struct clock_event_device *evt) { - unsigned long long nsec; + omap_mpu_timer_start(0, cycles, 0); + return 0; +} - nsec = cycles_2_ns((unsigned long long)nr_ticks); - return (unsigned long)nsec / 1000; +static void omap_mpu_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + omap_mpu_set_autoreset(0); + break; + case CLOCK_EVT_MODE_ONESHOT: + omap_mpu_remove_autoreset(0); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + break; + } } -/* - * Last processed system timer interrupt - */ -static unsigned long omap_mpu_timer_last = 0; +static struct clock_event_device clockevent_mpu_timer1 = { + .name = "mpu_timer1", + .features = CLOCK_EVT_FEAT_PERIODIC, CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .set_next_event = omap_mpu_set_next_event, + .set_mode = omap_mpu_set_mode, +}; -/* - * Returns elapsed usecs since last system timer interrupt - */ -static unsigned long omap_mpu_timer_gettimeoffset(void) +static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = &clockevent_mpu_timer1; + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static struct irqaction omap_mpu_timer1_irq = { + .name = "mpu_timer1", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = omap_mpu_timer1_interrupt, +}; + +static __init void omap_init_mpu_timer(unsigned long rate) { - unsigned long now = 0 - omap_mpu_timer_read(0); - unsigned long elapsed = now - omap_mpu_timer_last; + set_cyc2ns_scale(rate / 1000); + + setup_irq(INT_TIMER1, &omap_mpu_timer1_irq); + omap_mpu_timer_start(0, (rate / HZ) - 1, 1); + + clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC, + clockevent_mpu_timer1.shift); + clockevent_mpu_timer1.max_delta_ns = + clockevent_delta2ns(-1, &clockevent_mpu_timer1); + clockevent_mpu_timer1.min_delta_ns = + clockevent_delta2ns(1, &clockevent_mpu_timer1); - return omap_mpu_timer_ticks_to_usecs(elapsed); + clockevent_mpu_timer1.cpumask = cpumask_of_cpu(0); + clockevents_register_device(&clockevent_mpu_timer1); } + /* - * Elapsed time between interrupts is calculated using timer0. - * Latency during the interrupt is calculated using timer1. - * Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz). + * --------------------------------------------------------------------------- + * MPU timer 2 ... free running 32-bit clock source and scheduler clock + * --------------------------------------------------------------------------- */ -static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id) -{ - unsigned long now, latency; - write_seqlock(&xtime_lock); - now = 0 - omap_mpu_timer_read(0); - latency = MPU_TICKS_PER_SEC / HZ - omap_mpu_timer_read(1); - omap_mpu_timer_last = now - latency; - timer_tick(); - write_sequnlock(&xtime_lock); +static unsigned long omap_mpu_timer2_overflows; +static irqreturn_t omap_mpu_timer2_interrupt(int irq, void *dev_id) +{ + omap_mpu_timer2_overflows++; return IRQ_HANDLED; } -static struct irqaction omap_mpu_timer_irq = { - .name = "mpu timer", - .flags = IRQF_DISABLED | IRQF_TIMER, - .handler = omap_mpu_timer_interrupt, +static struct irqaction omap_mpu_timer2_irq = { + .name = "mpu_timer2", + .flags = IRQF_DISABLED, + .handler = omap_mpu_timer2_interrupt, }; -static unsigned long omap_mpu_timer1_overflows; -static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id) +static cycle_t mpu_read(void) { - omap_mpu_timer1_overflows++; - return IRQ_HANDLED; + return ~omap_mpu_timer_read(1); } -static struct irqaction omap_mpu_timer1_irq = { - .name = "mpu timer1 overflow", - .flags = IRQF_DISABLED, - .handler = omap_mpu_timer1_interrupt, +static struct clocksource clocksource_mpu = { + .name = "mpu_timer2", + .rating = 300, + .read = mpu_read, + .mask = CLOCKSOURCE_MASK(32), + .shift = 24, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static __init void omap_init_mpu_timer(void) +static void __init omap_init_clocksource(unsigned long rate) { - set_cyc2ns_scale(MPU_TICKS_PER_SEC / 1000); - omap_timer.offset = omap_mpu_timer_gettimeoffset; - setup_irq(INT_TIMER1, &omap_mpu_timer1_irq); - setup_irq(INT_TIMER2, &omap_mpu_timer_irq); - omap_mpu_timer_start(0, 0xffffffff); - omap_mpu_timer_start(1, MPU_TIMER_TICK_PERIOD); + static char err[] __initdata = KERN_ERR + "%s: can't register clocksource!\n"; + + clocksource_mpu.mult + = clocksource_khz2mult(rate/1000, clocksource_mpu.shift); + + setup_irq(INT_TIMER2, &omap_mpu_timer2_irq); + omap_mpu_timer_start(1, ~0, 1); + + if (clocksource_register(&clocksource_mpu)) + printk(err, clocksource_mpu.name); } + /* * Scheduler clock - returns current time in nanosec units. */ unsigned long long sched_clock(void) { - unsigned long ticks = 0 - omap_mpu_timer_read(0); + unsigned long ticks = 0 - omap_mpu_timer_read(1); unsigned long long ticks64; - ticks64 = omap_mpu_timer1_overflows; + ticks64 = omap_mpu_timer2_overflows; ticks64 <<= 32; ticks64 |= ticks; @@ -225,10 +274,21 @@ unsigned long long sched_clock(void) */ static void __init omap_timer_init(void) { - omap_init_mpu_timer(); + struct clk *ck_ref = clk_get(NULL, "ck_ref"); + unsigned long rate; + + BUG_ON(IS_ERR(ck_ref)); + + rate = clk_get_rate(ck_ref); + clk_put(ck_ref); + + /* PTV = 0 */ + rate /= 2; + + omap_init_mpu_timer(rate); + omap_init_clocksource(rate); } struct sys_timer omap_timer = { .init = omap_timer_init, - .offset = NULL, /* Initialized later */ }; diff --git a/trunk/arch/arm/mach-omap2/timer-gp.c b/trunk/arch/arm/mach-omap2/timer-gp.c index 45d1aaa51b57..62e801ef9ad9 100644 --- a/trunk/arch/arm/mach-omap2/timer-gp.c +++ b/trunk/arch/arm/mach-omap2/timer-gp.c @@ -52,7 +52,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) static struct irqaction omap2_gp_timer_irq = { .name = "gp timer", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = omap2_gp_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-pnx4008/time.c b/trunk/arch/arm/mach-pnx4008/time.c index 8621c206ac84..67e05f005a6b 100644 --- a/trunk/arch/arm/mach-pnx4008/time.c +++ b/trunk/arch/arm/mach-pnx4008/time.c @@ -82,7 +82,7 @@ static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id) static struct irqaction pnx4008_timer_irq = { .name = "PNX4008 Tick Timer", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = pnx4008_timer_interrupt }; diff --git a/trunk/arch/arm/mach-pxa/generic.c b/trunk/arch/arm/mach-pxa/generic.c index b8cb79f899d5..64b08b744f9f 100644 --- a/trunk/arch/arm/mach-pxa/generic.c +++ b/trunk/arch/arm/mach-pxa/generic.c @@ -164,9 +164,9 @@ void pxa_set_cken(int clock, int enable) local_irq_save(flags); if (enable) - CKEN |= clock; + CKEN |= (1 << clock); else - CKEN &= ~clock; + CKEN &= ~(1 << clock); local_irq_restore(flags); } diff --git a/trunk/arch/arm/mach-pxa/irq.c b/trunk/arch/arm/mach-pxa/irq.c index f815678a9d63..4619d5fe606c 100644 --- a/trunk/arch/arm/mach-pxa/irq.c +++ b/trunk/arch/arm/mach-pxa/irq.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -39,11 +38,33 @@ static void pxa_unmask_low_irq(unsigned int irq) ICMR |= (1 << (irq + PXA_IRQ_SKIP)); } +static int pxa_set_wake(unsigned int irq, unsigned int on) +{ + u32 mask; + + switch (irq) { + case IRQ_RTCAlrm: + mask = PWER_RTC; + break; +#ifdef CONFIG_PXA27x + /* REVISIT can handle USBH1, USBH2, USB, MSL, USIM, ... */ +#endif + default: + return -EINVAL; + } + if (on) + PWER |= mask; + else + PWER &= ~mask; + return 0; +} + static struct irq_chip pxa_internal_chip_low = { .name = "SC", .ack = pxa_mask_low_irq, .mask = pxa_mask_low_irq, .unmask = pxa_unmask_low_irq, + .set_wake = pxa_set_wake, }; #if PXA_INTERNAL_IRQS > 32 @@ -71,6 +92,26 @@ static struct irq_chip pxa_internal_chip_high = { #endif +/* Note that if an input/irq line ever gets changed to an output during + * suspend, the relevant PWER, PRER, and PFER bits should be cleared. + */ +#ifdef CONFIG_PXA27x + +/* PXA27x: Various gpios can issue wakeup events. This logic only + * handles the simple cases, not the WEMUX2 and WEMUX3 options + */ +#define PXA27x_GPIO_NOWAKE_MASK \ + ((1 << 8) | (1 << 7) | (1 << 6) | (1 << 5) | (1 << 2)) +#define WAKEMASK(gpio) \ + (((gpio) <= 15) \ + ? ((1 << (gpio)) & ~PXA27x_GPIO_NOWAKE_MASK) \ + : ((gpio == 35) ? (1 << 24) : 0)) +#else + +/* pxa 210, 250, 255, 26x: gpios 0..15 can issue wakeups */ +#define WAKEMASK(gpio) (((gpio) <= 15) ? (1 << (gpio)) : 0) +#endif + /* * PXA GPIO edge detection for IRQs: * IRQs are generated on Falling-Edge, Rising-Edge, or both. @@ -84,9 +125,11 @@ static long GPIO_IRQ_mask[4]; static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) { int gpio, idx; + u32 mask; gpio = IRQ_TO_GPIO(irq); idx = gpio >> 5; + mask = WAKEMASK(gpio); if (type == IRQT_PROBE) { /* Don't mess with enabled GPIOs using preconfigured edges or @@ -106,14 +149,20 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) if (type & __IRQT_RISEDGE) { /* printk("rising "); */ __set_bit (gpio, GPIO_IRQ_rising_edge); - } else + PRER |= mask; + } else { __clear_bit (gpio, GPIO_IRQ_rising_edge); + PRER &= ~mask; + } if (type & __IRQT_FALEDGE) { /* printk("falling "); */ __set_bit (gpio, GPIO_IRQ_falling_edge); - } else + PFER |= mask; + } else { __clear_bit (gpio, GPIO_IRQ_falling_edge); + PFER &= ~mask; + } /* printk("edges\n"); */ @@ -131,12 +180,29 @@ static void pxa_ack_low_gpio(unsigned int irq) GEDR0 = (1 << (irq - IRQ_GPIO0)); } +static int pxa_set_gpio_wake(unsigned int irq, unsigned int on) +{ + int gpio = IRQ_TO_GPIO(irq); + u32 mask = WAKEMASK(gpio); + + if (!mask) + return -EINVAL; + + if (on) + PWER |= mask; + else + PWER &= ~mask; + return 0; +} + + static struct irq_chip pxa_low_gpio_chip = { .name = "GPIO-l", .ack = pxa_ack_low_gpio, .mask = pxa_mask_low_irq, .unmask = pxa_unmask_low_irq, .set_type = pxa_gpio_irq_type, + .set_wake = pxa_set_gpio_wake, }; /* @@ -245,6 +311,7 @@ static struct irq_chip pxa_muxed_gpio_chip = { .mask = pxa_mask_muxed_gpio, .unmask = pxa_unmask_muxed_gpio, .set_type = pxa_gpio_irq_type, + .set_wake = pxa_set_gpio_wake, }; diff --git a/trunk/arch/arm/mach-pxa/lpd270.c b/trunk/arch/arm/mach-pxa/lpd270.c index 8e27a64fa9f4..e3097664ffe1 100644 --- a/trunk/arch/arm/mach-pxa/lpd270.c +++ b/trunk/arch/arm/mach-pxa/lpd270.c @@ -234,7 +234,7 @@ static void lpd270_backlight_power(int on) { if (on) { pxa_gpio_mode(GPIO16_PWM0_MD); - pxa_set_cken(CKEN0_PWM0, 1); + pxa_set_cken(CKEN_PWM0, 1); PWM_CTRL0 = 0; PWM_PWDUTY0 = 0x3ff; PWM_PERVAL0 = 0x3ff; @@ -242,7 +242,7 @@ static void lpd270_backlight_power(int on) PWM_CTRL0 = 0; PWM_PWDUTY0 = 0x0; PWM_PERVAL0 = 0x3FF; - pxa_set_cken(CKEN0_PWM0, 0); + pxa_set_cken(CKEN_PWM0, 0); } } diff --git a/trunk/arch/arm/mach-pxa/lubbock.c b/trunk/arch/arm/mach-pxa/lubbock.c index 055de7f4f00a..6377b2e29ff0 100644 --- a/trunk/arch/arm/mach-pxa/lubbock.c +++ b/trunk/arch/arm/mach-pxa/lubbock.c @@ -220,7 +220,7 @@ static struct resource pxa_ssp_resources[] = { static struct pxa2xx_spi_master pxa_ssp_master_info = { .ssp_type = PXA25x_SSP, - .clock_enable = CKEN3_SSP, + .clock_enable = CKEN_SSP, .num_chipselect = 0, }; diff --git a/trunk/arch/arm/mach-pxa/mainstone.c b/trunk/arch/arm/mach-pxa/mainstone.c index 56d94d88d5ca..ed99a81b98f3 100644 --- a/trunk/arch/arm/mach-pxa/mainstone.c +++ b/trunk/arch/arm/mach-pxa/mainstone.c @@ -266,7 +266,7 @@ static void mainstone_backlight_power(int on) { if (on) { pxa_gpio_mode(GPIO16_PWM0_MD); - pxa_set_cken(CKEN0_PWM0, 1); + pxa_set_cken(CKEN_PWM0, 1); PWM_CTRL0 = 0; PWM_PWDUTY0 = 0x3ff; PWM_PERVAL0 = 0x3ff; @@ -274,7 +274,7 @@ static void mainstone_backlight_power(int on) PWM_CTRL0 = 0; PWM_PWDUTY0 = 0x0; PWM_PERVAL0 = 0x3FF; - pxa_set_cken(CKEN0_PWM0, 0); + pxa_set_cken(CKEN_PWM0, 0); } } diff --git a/trunk/arch/arm/mach-pxa/pxa27x.c b/trunk/arch/arm/mach-pxa/pxa27x.c index 74eeada1e2fc..c64bab49efc4 100644 --- a/trunk/arch/arm/mach-pxa/pxa27x.c +++ b/trunk/arch/arm/mach-pxa/pxa27x.c @@ -140,9 +140,9 @@ void pxa_cpu_pm_enter(suspend_state_t state) extern void pxa_cpu_resume(void); if (state == PM_SUSPEND_STANDBY) - CKEN = CKEN22_MEMC | CKEN9_OSTIMER | CKEN16_LCD |CKEN0_PWM0; + CKEN = CKEN_MEMC | CKEN_OSTIMER | CKEN_LCD | CKEN_PWM0; else - CKEN = CKEN22_MEMC | CKEN9_OSTIMER; + CKEN = CKEN_MEMC | CKEN_OSTIMER; /* ensure voltage-change sequencer not initiated, which hangs */ PCFR &= ~PCFR_FVC; diff --git a/trunk/arch/arm/mach-pxa/ssp.c b/trunk/arch/arm/mach-pxa/ssp.c index 6cc202755fb4..71766ac0328b 100644 --- a/trunk/arch/arm/mach-pxa/ssp.c +++ b/trunk/arch/arm/mach-pxa/ssp.c @@ -52,13 +52,13 @@ struct ssp_info_ { */ static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = { #if defined (CONFIG_PXA27x) - {IRQ_SSP, CKEN23_SSP1}, - {IRQ_SSP2, CKEN3_SSP2}, - {IRQ_SSP3, CKEN4_SSP3}, + {IRQ_SSP, CKEN_SSP1}, + {IRQ_SSP2, CKEN_SSP2}, + {IRQ_SSP3, CKEN_SSP3}, #else - {IRQ_SSP, CKEN3_SSP}, - {IRQ_NSSP, CKEN9_NSSP}, - {IRQ_ASSP, CKEN10_ASSP}, + {IRQ_SSP, CKEN_SSP}, + {IRQ_NSSP, CKEN_NSSP}, + {IRQ_ASSP, CKEN_ASSP}, #endif }; diff --git a/trunk/arch/arm/mach-pxa/time.c b/trunk/arch/arm/mach-pxa/time.c index fc3b82a740a0..5248abe334d2 100644 --- a/trunk/arch/arm/mach-pxa/time.c +++ b/trunk/arch/arm/mach-pxa/time.c @@ -97,7 +97,7 @@ pxa_timer_interrupt(int irq, void *dev_id) static struct irqaction pxa_timer_irq = { .name = "PXA Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = pxa_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-realview/core.c b/trunk/arch/arm/mach-realview/core.c index 84d3fe76e94e..c7f1b44da40d 100644 --- a/trunk/arch/arm/mach-realview/core.c +++ b/trunk/arch/arm/mach-realview/core.c @@ -549,7 +549,7 @@ static irqreturn_t realview_timer_interrupt(int irq, void *dev_id) static struct irqaction realview_timer_irq = { .name = "RealView Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = realview_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-rpc/riscpc.c b/trunk/arch/arm/mach-rpc/riscpc.c index 208a2b5dba1b..570cf937e73b 100644 --- a/trunk/arch/arm/mach-rpc/riscpc.c +++ b/trunk/arch/arm/mach-rpc/riscpc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -159,11 +160,45 @@ static struct platform_device serial_device = { }, }; +static struct pata_platform_info pata_platform_data = { + .ioport_shift = 2, +}; + +static struct resource pata_resources[] = { + [0] = { + .start = 0x030107c0, + .end = 0x030107df, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0x03010fd8, + .end = 0x03010fdb, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = IRQ_HARDDISK, + .end = IRQ_HARDDISK, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device pata_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(pata_resources), + .resource = pata_resources, + .dev = { + .platform_data = &pata_platform_data, + .coherent_dma_mask = ~0, /* grumble */ + }, +}; + static struct platform_device *devs[] __initdata = { &iomd_device, &kbd_device, &serial_device, &acornfb_device, + &pata_device, }; static int __init rpc_init(void) diff --git a/trunk/arch/arm/mach-s3c2410/bast-irq.c b/trunk/arch/arm/mach-s3c2410/bast-irq.c index daeba427d781..76a7cb15f3be 100644 --- a/trunk/arch/arm/mach-s3c2410/bast-irq.c +++ b/trunk/arch/arm/mach-s3c2410/bast-irq.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-s3c2410/irq.c b/trunk/arch/arm/mach-s3c2410/irq.c index 53cbdaa43ac6..f5c5c53e1cc1 100644 --- a/trunk/arch/arm/mach-s3c2410/irq.c +++ b/trunk/arch/arm/mach-s3c2410/irq.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-s3c2410/mach-amlm5900.c b/trunk/arch/arm/mach-s3c2410/mach-amlm5900.c index 72f2cc4fcd03..bc308ceb91c3 100644 --- a/trunk/arch/arm/mach-s3c2410/mach-amlm5900.c +++ b/trunk/arch/arm/mach-s3c2410/mach-amlm5900.c @@ -160,17 +160,11 @@ static struct platform_device *amlm5900_devices[] __initdata = { #endif }; -static struct s3c24xx_board amlm5900_board __initdata = { - .devices = amlm5900_devices, - .devices_count = ARRAY_SIZE(amlm5900_devices) -}; - void __init amlm5900_map_io(void) { s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(amlm5900_uartcfgs, ARRAY_SIZE(amlm5900_uartcfgs)); - s3c24xx_set_board(&amlm5900_board); } #ifdef CONFIG_FB_S3C2410 @@ -247,6 +241,7 @@ static void __init amlm5900_init(void) #ifdef CONFIG_FB_S3C2410 s3c24xx_fb_set_platdata(&amlm5900_lcd_info); #endif + platform_add_devices(amlm5900_devices, ARRAY_SIZE(amlm5900_devices)); } MACHINE_START(AML_M5900, "AML_M5900") diff --git a/trunk/arch/arm/mach-s3c2410/mach-bast.c b/trunk/arch/arm/mach-s3c2410/mach-bast.c index 7b81296427eb..f01de807b72f 100644 --- a/trunk/arch/arm/mach-s3c2410/mach-bast.c +++ b/trunk/arch/arm/mach-s3c2410/mach-bast.c @@ -464,13 +464,6 @@ static struct clk *bast_clocks[] = { &s3c24xx_uclk, }; -static struct s3c24xx_board bast_board __initdata = { - .devices = bast_devices, - .devices_count = ARRAY_SIZE(bast_devices), - .clocks = bast_clocks, - .clocks_count = ARRAY_SIZE(bast_clocks), -}; - static void __init bast_map_io(void) { /* initialise the clocks */ @@ -486,19 +479,22 @@ static void __init bast_map_io(void) s3c24xx_uclk.parent = &s3c24xx_clkout1; + s3c24xx_register_clocks(bast_clocks, ARRAY_SIZE(bast_clocks)); + s3c_device_nand.dev.platform_data = &bast_nand_info; s3c_device_i2c.dev.platform_data = &bast_i2c_info; s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs)); - s3c24xx_set_board(&bast_board); + usb_simtec_init(); } static void __init bast_init(void) { s3c24xx_fb_set_platdata(&bast_lcd_info); + platform_add_devices(bast_devices, ARRAY_SIZE(bast_devices)); } MACHINE_START(BAST, "Simtec-BAST") diff --git a/trunk/arch/arm/mach-s3c2410/mach-h1940.c b/trunk/arch/arm/mach-s3c2410/mach-h1940.c index d052ab2d9377..5d5f00e9c462 100644 --- a/trunk/arch/arm/mach-s3c2410/mach-h1940.c +++ b/trunk/arch/arm/mach-s3c2410/mach-h1940.c @@ -129,7 +129,6 @@ static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = { }; - /** * Set lcd on or off **/ @@ -188,17 +187,11 @@ static struct platform_device *h1940_devices[] __initdata = { &s3c_device_leds, }; -static struct s3c24xx_board h1940_board __initdata = { - .devices = h1940_devices, - .devices_count = ARRAY_SIZE(h1940_devices) -}; - static void __init h1940_map_io(void) { s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs)); - s3c24xx_set_board(&h1940_board); /* setup PM */ @@ -232,6 +225,8 @@ static void __init h1940_init(void) | (0x02 << S3C2410_PLLCON_PDIVSHIFT) | (0x03 << S3C2410_PLLCON_SDIVSHIFT); writel(tmp, S3C2410_UPLLCON); + + platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices)); } MACHINE_START(H1940, "IPAQ-H1940") diff --git a/trunk/arch/arm/mach-s3c2410/mach-n30.c b/trunk/arch/arm/mach-s3c2410/mach-n30.c index 261aa4cc0770..412e50c3d28a 100644 --- a/trunk/arch/arm/mach-s3c2410/mach-n30.c +++ b/trunk/arch/arm/mach-s3c2410/mach-n30.c @@ -90,17 +90,11 @@ static struct s3c2410_platform_i2c n30_i2ccfg = { .max_freq = 10*1000, }; -static struct s3c24xx_board n30_board __initdata = { - .devices = n30_devices, - .devices_count = ARRAY_SIZE(n30_devices) -}; - static void __init n30_map_io(void) { s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs)); - s3c24xx_set_board(&n30_board); } static void __init n30_init_irq(void) @@ -120,6 +114,8 @@ static void __init n30_init(void) s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST | S3C2410_MISCCR_USBSUSPND0 | S3C2410_MISCCR_USBSUSPND1, 0x0); + + platform_add_devices(n30_devices, ARRAY_SIZE(n30_devices)); } MACHINE_START(N30, "Acer-N30") diff --git a/trunk/arch/arm/mach-s3c2410/mach-otom.c b/trunk/arch/arm/mach-s3c2410/mach-otom.c index c78ab75b44f3..1f899fa588df 100644 --- a/trunk/arch/arm/mach-s3c2410/mach-otom.c +++ b/trunk/arch/arm/mach-s3c2410/mach-otom.c @@ -100,20 +100,17 @@ static struct platform_device *otom11_devices[] __initdata = { &otom_device_nor, }; -static struct s3c24xx_board otom11_board __initdata = { - .devices = otom11_devices, - .devices_count = ARRAY_SIZE(otom11_devices) -}; - - static void __init otom11_map_io(void) { s3c24xx_init_io(otom11_iodesc, ARRAY_SIZE(otom11_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(otom11_uartcfgs, ARRAY_SIZE(otom11_uartcfgs)); - s3c24xx_set_board(&otom11_board); } +static void __init otom11_init(void) +{ + platform_add_devices(otom11_devices, ARRAY_SIZE(otom11_devices)); +} MACHINE_START(OTOM, "Nex Vision - Otom 1.1") /* Maintainer: Guillaume GOURAT */ @@ -121,6 +118,7 @@ MACHINE_START(OTOM, "Nex Vision - Otom 1.1") .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = otom11_map_io, + .init_machine = otom11_init, .init_irq = s3c24xx_init_irq, .timer = &s3c24xx_timer, MACHINE_END diff --git a/trunk/arch/arm/mach-s3c2410/mach-qt2410.c b/trunk/arch/arm/mach-s3c2410/mach-qt2410.c index c6a41593de21..9cc4253d7bbc 100644 --- a/trunk/arch/arm/mach-s3c2410/mach-qt2410.c +++ b/trunk/arch/arm/mach-s3c2410/mach-qt2410.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -331,11 +330,6 @@ static struct platform_device *qt2410_devices[] __initdata = { &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", @@ -405,7 +399,6 @@ 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) @@ -432,6 +425,7 @@ static void __init qt2410_machine_init(void) s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPIO_OUTPUT); + platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices)); s3c2410_pm_init(); } diff --git a/trunk/arch/arm/mach-s3c2410/mach-smdk2410.c b/trunk/arch/arm/mach-s3c2410/mach-smdk2410.c index 57b8a80f33d0..5852d300d52f 100644 --- a/trunk/arch/arm/mach-s3c2410/mach-smdk2410.c +++ b/trunk/arch/arm/mach-s3c2410/mach-smdk2410.c @@ -94,17 +94,17 @@ static struct platform_device *smdk2410_devices[] __initdata = { &s3c_device_iis, }; -static struct s3c24xx_board smdk2410_board __initdata = { - .devices = smdk2410_devices, - .devices_count = ARRAY_SIZE(smdk2410_devices) -}; - static void __init smdk2410_map_io(void) { s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs)); - s3c24xx_set_board(&smdk2410_board); +} + +static void __init smdk2410_init(void) +{ + platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices)); + smdk_machine_init(); } MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch @@ -115,7 +115,7 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = smdk2410_map_io, .init_irq = s3c24xx_init_irq, - .init_machine = smdk_machine_init, + .init_machine = smdk2410_init, .timer = &s3c24xx_timer, MACHINE_END diff --git a/trunk/arch/arm/mach-s3c2410/mach-vr1000.c b/trunk/arch/arm/mach-s3c2410/mach-vr1000.c index c947c75bcbf0..7b624bb00490 100644 --- a/trunk/arch/arm/mach-s3c2410/mach-vr1000.c +++ b/trunk/arch/arm/mach-s3c2410/mach-vr1000.c @@ -384,13 +384,6 @@ static struct clk *vr1000_clocks[] = { &s3c24xx_uclk, }; -static struct s3c24xx_board vr1000_board __initdata = { - .devices = vr1000_devices, - .devices_count = ARRAY_SIZE(vr1000_devices), - .clocks = vr1000_clocks, - .clocks_count = ARRAY_SIZE(vr1000_clocks), -}; - static void vr1000_power_off(void) { s3c2410_gpio_cfgpin(S3C2410_GPB9, S3C2410_GPB9_OUTP); @@ -412,15 +405,19 @@ static void __init vr1000_map_io(void) s3c24xx_uclk.parent = &s3c24xx_clkout1; + s3c24xx_register_clocks(vr1000_clocks, ARRAY_SIZE(vr1000_clocks)); + pm_power_off = vr1000_power_off; s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs)); - s3c24xx_set_board(&vr1000_board); - usb_simtec_init(); } +static void __init vr1000_init(void) +{ + platform_add_devices(vr1000_devices, ARRAY_SIZE(vr1000_devices)); +} MACHINE_START(VR1000, "Thorcom-VR1000") /* Maintainer: Ben Dooks */ @@ -428,6 +425,7 @@ MACHINE_START(VR1000, "Thorcom-VR1000") .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = vr1000_map_io, + .init_machine = vr1000_init, .init_irq = s3c24xx_init_irq, .timer = &s3c24xx_timer, MACHINE_END diff --git a/trunk/arch/arm/mach-s3c2412/Kconfig b/trunk/arch/arm/mach-s3c2412/Kconfig index befc5fdbb613..d5be5d053264 100644 --- a/trunk/arch/arm/mach-s3c2412/Kconfig +++ b/trunk/arch/arm/mach-s3c2412/Kconfig @@ -47,6 +47,15 @@ config MACH_S3C2413 machine_is_s3c2413() will work when MACH_SMDK2413 is selected +config MACH_SMDK2412 + bool "SMDK2412" + select MACH_SMDK2413 + help + Say Y here if you are using an SMDK2412 + + Note, this shares support with SMDK2413, so will automatically + select MACH_SMDK2413. + config MACH_VSTMS bool "VMSTMS" select CPU_S3C2412 diff --git a/trunk/arch/arm/mach-s3c2412/irq.c b/trunk/arch/arm/mach-s3c2412/irq.c index e89dbdcb1b7b..f0d66828f965 100644 --- a/trunk/arch/arm/mach-s3c2412/irq.c +++ b/trunk/arch/arm/mach-s3c2412/irq.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-s3c2412/mach-smdk2413.c b/trunk/arch/arm/mach-s3c2412/mach-smdk2413.c index b5befce6c8d3..063af09f899d 100644 --- a/trunk/arch/arm/mach-s3c2412/mach-smdk2413.c +++ b/trunk/arch/arm/mach-s3c2412/mach-smdk2413.c @@ -110,11 +110,6 @@ static struct platform_device *smdk2413_devices[] __initdata = { &s3c_device_usbgadget, }; -static struct s3c24xx_board smdk2413_board __initdata = { - .devices = smdk2413_devices, - .devices_count = ARRAY_SIZE(smdk2413_devices) -}; - static void __init smdk2413_fixup(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) @@ -132,7 +127,6 @@ static void __init smdk2413_map_io(void) s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs)); - s3c24xx_set_board(&smdk2413_board); } static void __init smdk2413_machine_init(void) @@ -149,6 +143,7 @@ static void __init smdk2413_machine_init(void) s3c24xx_udc_set_platdata(&smdk2413_udc_cfg); + platform_add_devices(smdk2413_devices, ARRAY_SIZE(smdk2413_devices)); smdk_machine_init(); } diff --git a/trunk/arch/arm/mach-s3c2412/mach-vstms.c b/trunk/arch/arm/mach-s3c2412/mach-vstms.c index 4231b549d797..f2fbd65956ac 100644 --- a/trunk/arch/arm/mach-s3c2412/mach-vstms.c +++ b/trunk/arch/arm/mach-s3c2412/mach-vstms.c @@ -129,11 +129,6 @@ static struct platform_device *vstms_devices[] __initdata = { &s3c_device_nand, }; -static struct s3c24xx_board vstms_board __initdata = { - .devices = vstms_devices, - .devices_count = ARRAY_SIZE(vstms_devices) -}; - static void __init vstms_fixup(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) @@ -153,7 +148,11 @@ static void __init vstms_map_io(void) s3c24xx_init_io(vstms_iodesc, ARRAY_SIZE(vstms_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(vstms_uartcfgs, ARRAY_SIZE(vstms_uartcfgs)); - s3c24xx_set_board(&vstms_board); +} + +static void __init vstms_init(void) +{ + platform_add_devices(vstms_devices, ARRAY_SIZE(vstms_devices)); } MACHINE_START(VSTMS, "VSTMS") @@ -163,6 +162,7 @@ MACHINE_START(VSTMS, "VSTMS") .fixup = vstms_fixup, .init_irq = s3c24xx_init_irq, + .init_machine = vstms_init, .map_io = vstms_map_io, .timer = &s3c24xx_timer, MACHINE_END diff --git a/trunk/arch/arm/mach-s3c2440/irq.c b/trunk/arch/arm/mach-s3c2440/irq.c index 1069d13d8c57..a87608bc1a03 100644 --- a/trunk/arch/arm/mach-s3c2440/irq.c +++ b/trunk/arch/arm/mach-s3c2440/irq.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-s3c2440/mach-anubis.c b/trunk/arch/arm/mach-s3c2440/mach-anubis.c index 3f0288eb1ed5..b5d387ef37e1 100644 --- a/trunk/arch/arm/mach-s3c2440/mach-anubis.c +++ b/trunk/arch/arm/mach-s3c2440/mach-anubis.c @@ -281,13 +281,6 @@ static struct clk *anubis_clocks[] = { &s3c24xx_uclk, }; -static struct s3c24xx_board anubis_board __initdata = { - .devices = anubis_devices, - .devices_count = ARRAY_SIZE(anubis_devices), - .clocks = anubis_clocks, - .clocks_count = ARRAY_SIZE(anubis_clocks), -}; - static void __init anubis_map_io(void) { /* initialise the clocks */ @@ -303,23 +296,31 @@ static void __init anubis_map_io(void) s3c24xx_uclk.parent = &s3c24xx_clkout1; + s3c24xx_register_clocks(anubis_clocks, ARRAY_SIZE(anubis_clocks)); + s3c_device_nand.dev.platform_data = &anubis_nand_info; s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs)); - s3c24xx_set_board(&anubis_board); /* ensure that the GPIO is setup */ s3c2410_gpio_setpin(S3C2410_GPA0, 1); } +static void __init anubis_init(void) +{ + platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices)); +} + + MACHINE_START(ANUBIS, "Simtec-Anubis") /* Maintainer: Ben Dooks */ .phys_io = S3C2410_PA_UART, .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = anubis_map_io, + .init_machine = anubis_init, .init_irq = s3c24xx_init_irq, .timer = &s3c24xx_timer, MACHINE_END diff --git a/trunk/arch/arm/mach-s3c2440/mach-nexcoder.c b/trunk/arch/arm/mach-s3c2440/mach-nexcoder.c index 6d551d88330b..5e61f2166c76 100644 --- a/trunk/arch/arm/mach-s3c2440/mach-nexcoder.c +++ b/trunk/arch/arm/mach-s3c2440/mach-nexcoder.c @@ -116,12 +116,6 @@ static struct platform_device *nexcoder_devices[] __initdata = { &nexcoder_device_nor, }; -static struct s3c24xx_board nexcoder_board __initdata = { - .devices = nexcoder_devices, - .devices_count = ARRAY_SIZE(nexcoder_devices), -}; - - static void __init nexcoder_sensorboard_init(void) { // Initialize SCCB bus @@ -142,10 +136,14 @@ static void __init nexcoder_map_io(void) s3c24xx_init_io(nexcoder_iodesc, ARRAY_SIZE(nexcoder_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(nexcoder_uartcfgs, ARRAY_SIZE(nexcoder_uartcfgs)); - s3c24xx_set_board(&nexcoder_board); + nexcoder_sensorboard_init(); } +static void __init nexcoder_init(void) +{ + platform_add_devices(nexcoder_devices, ARRAY_SIZE(nexcoder_devices)); +}; MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440") /* Maintainer: Guillaume GOURAT */ @@ -153,6 +151,7 @@ MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440") .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = nexcoder_map_io, + .init_machine = nexcoder_init, .init_irq = s3c24xx_init_irq, .timer = &s3c24xx_timer, MACHINE_END diff --git a/trunk/arch/arm/mach-s3c2440/mach-osiris.c b/trunk/arch/arm/mach-s3c2440/mach-osiris.c index 2ed8e51f20c8..324f5a237921 100644 --- a/trunk/arch/arm/mach-s3c2440/mach-osiris.c +++ b/trunk/arch/arm/mach-s3c2440/mach-osiris.c @@ -251,13 +251,6 @@ static struct clk *osiris_clocks[] = { &s3c24xx_uclk, }; -static struct s3c24xx_board osiris_board __initdata = { - .devices = osiris_devices, - .devices_count = ARRAY_SIZE(osiris_devices), - .clocks = osiris_clocks, - .clocks_count = ARRAY_SIZE(osiris_clocks), -}; - static void __init osiris_map_io(void) { unsigned long flags; @@ -275,12 +268,13 @@ static void __init osiris_map_io(void) s3c24xx_uclk.parent = &s3c24xx_clkout1; + s3c24xx_register_clocks(osiris_clocks, ARRAY_SIZE(osiris_clocks)); + s3c_device_nand.dev.platform_data = &osiris_nand_info; s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc)); s3c24xx_init_clocks(0); s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs)); - s3c24xx_set_board(&osiris_board); /* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */ @@ -292,12 +286,18 @@ static void __init osiris_map_io(void) s3c2410_gpio_setpin(S3C2410_GPA0, 1); } +static void __init osiris_init(void) +{ + platform_add_devices(osiris_devices, ARRAY_SIZE(osiris_devices)); +}; + MACHINE_START(OSIRIS, "Simtec-OSIRIS") /* Maintainer: Ben Dooks */ .phys_io = S3C2410_PA_UART, .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = osiris_map_io, + .init_machine = osiris_init, .init_irq = s3c24xx_init_irq, .timer = &s3c24xx_timer, MACHINE_END diff --git a/trunk/arch/arm/mach-s3c2440/mach-rx3715.c b/trunk/arch/arm/mach-s3c2440/mach-rx3715.c index ae1d0a81fd6a..c3cc4bf158f6 100644 --- a/trunk/arch/arm/mach-s3c2440/mach-rx3715.c +++ b/trunk/arch/arm/mach-s3c2440/mach-rx3715.c @@ -202,11 +202,6 @@ static struct platform_device *rx3715_devices[] __initdata = { &s3c_device_nand, }; -static struct s3c24xx_board rx3715_board __initdata = { - .devices = rx3715_devices, - .devices_count = ARRAY_SIZE(rx3715_devices) -}; - static void __init rx3715_map_io(void) { s3c_device_nand.dev.platform_data = &rx3715_nand_info; @@ -214,7 +209,6 @@ static void __init rx3715_map_io(void) s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc)); s3c24xx_init_clocks(16934000); s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs)); - s3c24xx_set_board(&rx3715_board); } static void __init rx3715_init_irq(void) @@ -230,9 +224,9 @@ static void __init rx3715_init_machine(void) s3c2410_pm_init(); s3c24xx_fb_set_platdata(&rx3715_lcdcfg); + platform_add_devices(rx3715_devices, ARRAY_SIZE(rx3715_devices)); } - MACHINE_START(RX3715, "IPAQ-RX3715") /* Maintainer: Ben Dooks */ .phys_io = S3C2410_PA_UART, diff --git a/trunk/arch/arm/mach-s3c2440/mach-smdk2440.c b/trunk/arch/arm/mach-s3c2440/mach-smdk2440.c index c17eb5b1f6b4..e167254e232e 100644 --- a/trunk/arch/arm/mach-s3c2440/mach-smdk2440.c +++ b/trunk/arch/arm/mach-s3c2440/mach-smdk2440.c @@ -174,23 +174,18 @@ static struct platform_device *smdk2440_devices[] __initdata = { &s3c_device_iis, }; -static struct s3c24xx_board smdk2440_board __initdata = { - .devices = smdk2440_devices, - .devices_count = ARRAY_SIZE(smdk2440_devices) -}; - static void __init smdk2440_map_io(void) { s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc)); s3c24xx_init_clocks(16934400); s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs)); - s3c24xx_set_board(&smdk2440_board); } static void __init smdk2440_machine_init(void) { s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg); + platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices)); smdk_machine_init(); } diff --git a/trunk/arch/arm/mach-s3c2443/irq.c b/trunk/arch/arm/mach-s3c2443/irq.c index 756573595b88..6cd4818f3f0d 100644 --- a/trunk/arch/arm/mach-s3c2443/irq.c +++ b/trunk/arch/arm/mach-s3c2443/irq.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-s3c2443/mach-smdk2443.c b/trunk/arch/arm/mach-s3c2443/mach-smdk2443.c index e82aaff7dee4..b71ee53c2865 100644 --- a/trunk/arch/arm/mach-s3c2443/mach-smdk2443.c +++ b/trunk/arch/arm/mach-s3c2443/mach-smdk2443.c @@ -106,21 +106,16 @@ static struct platform_device *smdk2443_devices[] __initdata = { &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) { + platform_add_devices(smdk2443_devices, ARRAY_SIZE(smdk2443_devices)); smdk_machine_init(); } diff --git a/trunk/arch/arm/mach-sa1100/clock.c b/trunk/arch/arm/mach-sa1100/clock.c index b1e8fd766c1a..fc97fe57ee6f 100644 --- a/trunk/arch/arm/mach-sa1100/clock.c +++ b/trunk/arch/arm/mach-sa1100/clock.c @@ -9,14 +9,17 @@ #include #include #include +#include #include -#include +/* + * Very simple clock implementation - we only have one clock to + * deal with at the moment, so we only match using the "name". + */ struct clk { struct list_head node; unsigned long rate; - struct module *owner; const char *name; unsigned int enabled; void (*enable)(void); @@ -24,21 +27,21 @@ struct clk { }; static LIST_HEAD(clocks); -static DECLARE_MUTEX(clocks_sem); +static DEFINE_MUTEX(clocks_mutex); static DEFINE_SPINLOCK(clocks_lock); struct clk *clk_get(struct device *dev, const char *id) { struct clk *p, *clk = ERR_PTR(-ENOENT); - down(&clocks_sem); + mutex_lock(&clocks_mutex); list_for_each_entry(p, &clocks, node) { - if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { + if (strcmp(id, p->name) == 0) { clk = p; break; } } - up(&clocks_sem); + mutex_unlock(&clocks_mutex); return clk; } @@ -46,7 +49,6 @@ EXPORT_SYMBOL(clk_get); void clk_put(struct clk *clk) { - module_put(clk->owner); } EXPORT_SYMBOL(clk_put); @@ -109,18 +111,18 @@ static struct clk clk_gpio27 = { int clk_register(struct clk *clk) { - down(&clocks_sem); + mutex_lock(&clocks_mutex); list_add(&clk->node, &clocks); - up(&clocks_sem); + mutex_unlock(&clocks_mutex); return 0; } EXPORT_SYMBOL(clk_register); void clk_unregister(struct clk *clk) { - down(&clocks_sem); + mutex_lock(&clocks_mutex); list_del(&clk->node); - up(&clocks_sem); + mutex_unlock(&clocks_mutex); } EXPORT_SYMBOL(clk_unregister); diff --git a/trunk/arch/arm/mach-sa1100/h3600.c b/trunk/arch/arm/mach-sa1100/h3600.c index b034ad69a324..b72fee0f2538 100644 --- a/trunk/arch/arm/mach-sa1100/h3600.c +++ b/trunk/arch/arm/mach-sa1100/h3600.c @@ -740,7 +740,7 @@ static void h3800_IRQ_demux(unsigned int irq, struct irq_desc *desc) static struct irqaction h3800_irq = { .name = "h3800_asic", .handler = h3800_IRQ_demux, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, }; u32 kpio_int_shadow = 0; diff --git a/trunk/arch/arm/mach-sa1100/irq.c b/trunk/arch/arm/mach-sa1100/irq.c index 5642aeca079e..edf3347d9c5b 100644 --- a/trunk/arch/arm/mach-sa1100/irq.c +++ b/trunk/arch/arm/mach-sa1100/irq.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-sa1100/neponset.c b/trunk/arch/arm/mach-sa1100/neponset.c index 075d4d1d63be..d7c038a0256b 100644 --- a/trunk/arch/arm/mach-sa1100/neponset.c +++ b/trunk/arch/arm/mach-sa1100/neponset.c @@ -4,7 +4,6 @@ */ #include #include -#include #include #include #include diff --git a/trunk/arch/arm/mach-sa1100/time.c b/trunk/arch/arm/mach-sa1100/time.c index 29c89f9eb2ce..416e277054c2 100644 --- a/trunk/arch/arm/mach-sa1100/time.c +++ b/trunk/arch/arm/mach-sa1100/time.c @@ -111,7 +111,7 @@ sa1100_timer_interrupt(int irq, void *dev_id) static struct irqaction sa1100_timer_irq = { .name = "SA11xx Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = sa1100_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-shark/core.c b/trunk/arch/arm/mach-shark/core.c index 0e480fae8ec5..a0545db2a34f 100644 --- a/trunk/arch/arm/mach-shark/core.c +++ b/trunk/arch/arm/mach-shark/core.c @@ -90,7 +90,7 @@ shark_timer_interrupt(int irq, void *dev_id) static struct irqaction shark_timer_irq = { .name = "Shark Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = shark_timer_interrupt, }; diff --git a/trunk/arch/arm/mach-shark/irq.c b/trunk/arch/arm/mach-shark/irq.c index 00a6c1466867..5b0c6af44ec6 100644 --- a/trunk/arch/arm/mach-shark/irq.c +++ b/trunk/arch/arm/mach-shark/irq.c @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/trunk/arch/arm/mach-versatile/core.c b/trunk/arch/arm/mach-versatile/core.c index bf71507c76fd..a7dd09436cbc 100644 --- a/trunk/arch/arm/mach-versatile/core.c +++ b/trunk/arch/arm/mach-versatile/core.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -828,69 +830,101 @@ void __init versatile_init(void) #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) #endif -/* - * Returns number of ms since last clock interrupt. Note that interrupts - * will have been disabled by do_gettimeoffset() - */ -static unsigned long versatile_gettimeoffset(void) +static void timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) { - unsigned long ticks1, ticks2, status; + unsigned long ctrl; - /* - * Get the current number of ticks. Note that there is a race - * condition between us reading the timer and checking for - * an interrupt. We get around this by ensuring that the - * counter has not reloaded between our two reads. - */ - ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; - do { - ticks1 = ticks2; - status = __raw_readl(VA_IC_BASE + VIC_RAW_STATUS); - ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; - } while (ticks2 > ticks1); + switch(mode) { + case CLOCK_EVT_MODE_PERIODIC: + writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); - /* - * Number of ticks since last interrupt. - */ - ticks1 = TIMER_RELOAD - ticks2; + ctrl = TIMER_CTRL_PERIODIC; + ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE; + break; + case CLOCK_EVT_MODE_ONESHOT: + /* period set, and timer enabled in 'next_event' hook */ + ctrl = TIMER_CTRL_ONESHOT; + ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE; + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + ctrl = 0; + } - /* - * Interrupt pending? If so, we've reloaded once already. - * - * FIXME: Need to check this is effectively timer 0 that expires - */ - if (status & IRQMASK_TIMERINT0_1) - ticks1 += TIMER_RELOAD; + writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL); +} - /* - * Convert the ticks to usecs - */ - return TICKS2USECS(ticks1); +static int timer_set_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL); + + writel(evt, TIMER0_VA_BASE + TIMER_LOAD); + writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL); + + return 0; } +static struct clock_event_device timer0_clockevent = { + .name = "timer0", + .shift = 32, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = timer_set_mode, + .set_next_event = timer_set_next_event, +}; + /* * IRQ handler for the timer */ static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id) { - write_seqlock(&xtime_lock); + struct clock_event_device *evt = &timer0_clockevent; - // ...clear the interrupt writel(1, TIMER0_VA_BASE + TIMER_INTCLR); - timer_tick(); - - write_sequnlock(&xtime_lock); + evt->event_handler(evt); return IRQ_HANDLED; } static struct irqaction versatile_timer_irq = { .name = "Versatile Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = versatile_timer_interrupt, }; +static cycle_t versatile_get_cycles(void) +{ + return ~readl(TIMER3_VA_BASE + TIMER_VALUE); +} + +static struct clocksource clocksource_versatile = { + .name = "timer3", + .rating = 200, + .read = versatile_get_cycles, + .mask = CLOCKSOURCE_MASK(32), + .shift = 20, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static int __init versatile_clocksource_init(void) +{ + /* setup timer3 as free-running clocksource */ + writel(0, TIMER3_VA_BASE + TIMER_CTRL); + writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD); + writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE); + writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, + TIMER3_VA_BASE + TIMER_CTRL); + + clocksource_versatile.mult = + clocksource_khz2mult(1000, clocksource_versatile.shift); + clocksource_register(&clocksource_versatile); + + return 0; +} + /* * Set up timer interrupt, and return the current time in seconds. */ @@ -918,18 +952,25 @@ static void __init versatile_timer_init(void) writel(0, TIMER2_VA_BASE + TIMER_CTRL); writel(0, TIMER3_VA_BASE + TIMER_CTRL); - writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); - writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE); - writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC | - TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL); - /* * Make irqs happen for the system timer */ setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq); + + versatile_clocksource_init(); + + timer0_clockevent.mult = + div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift); + timer0_clockevent.max_delta_ns = + clockevent_delta2ns(0xffffffff, &timer0_clockevent); + timer0_clockevent.min_delta_ns = + clockevent_delta2ns(0xf, &timer0_clockevent); + + timer0_clockevent.cpumask = cpumask_of_cpu(0); + clockevents_register_device(&timer0_clockevent); } struct sys_timer versatile_timer = { .init = versatile_timer_init, - .offset = versatile_gettimeoffset, }; + diff --git a/trunk/arch/arm/mach-versatile/pci.c b/trunk/arch/arm/mach-versatile/pci.c index 5cd0b5d9e7eb..ba58223f12be 100644 --- a/trunk/arch/arm/mach-versatile/pci.c +++ b/trunk/arch/arm/mach-versatile/pci.c @@ -16,7 +16,6 @@ */ #include #include -#include #include #include #include diff --git a/trunk/arch/arm/mm/alignment.c b/trunk/arch/arm/mm/alignment.c index aa109f074dd9..19ca333240ec 100644 --- a/trunk/arch/arm/mm/alignment.c +++ b/trunk/arch/arm/mm/alignment.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/mm/fault.c b/trunk/arch/arm/mm/fault.c index 9fd6d2eafb40..75d491448e45 100644 --- a/trunk/arch/arm/mm/fault.c +++ b/trunk/arch/arm/mm/fault.c @@ -10,7 +10,6 @@ */ #include #include -#include #include #include @@ -438,7 +437,7 @@ hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *) /* * Dispatch a data abort to the relevant handler. */ -asmlinkage void +asmlinkage void __exception do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6); @@ -454,10 +453,10 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) info.si_errno = 0; info.si_code = inf->code; info.si_addr = (void __user *)addr; - notify_die("", regs, &info, fsr, 0); + arm_notify_die("", regs, &info, fsr, 0); } -asmlinkage void +asmlinkage void __exception do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { do_translation_fault(addr, 0, regs); diff --git a/trunk/arch/arm/mm/init.c b/trunk/arch/arm/mm/init.c index 7760193e74cc..c0ad7c0fbae0 100644 --- a/trunk/arch/arm/mm/init.c +++ b/trunk/arch/arm/mm/init.c @@ -9,7 +9,6 @@ */ #include #include -#include #include #include #include diff --git a/trunk/arch/arm/mm/ioremap.c b/trunk/arch/arm/mm/ioremap.c index 0ac615c0f798..d6167ad4e011 100644 --- a/trunk/arch/arm/mm/ioremap.c +++ b/trunk/arch/arm/mm/ioremap.c @@ -32,6 +32,9 @@ #include #include +#include +#include "mm.h" + /* * Used by ioremap() and iounmap() code to mark (super)section-mapped * I/O regions in vm_struct->flags field. @@ -39,8 +42,9 @@ #define VM_ARM_SECTION_MAPPING 0x80000000 static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end, - unsigned long phys_addr, pgprot_t prot) + unsigned long phys_addr, const struct mem_type *type) { + pgprot_t prot = __pgprot(type->prot_pte); pte_t *pte; pte = pte_alloc_kernel(pmd, addr); @@ -51,7 +55,8 @@ static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end, if (!pte_none(*pte)) goto bad; - set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot), 0); + set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot), + type->prot_pte_ext); phys_addr += PAGE_SIZE; } while (pte++, addr += PAGE_SIZE, addr != end); return 0; @@ -63,7 +68,7 @@ static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end, static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr, unsigned long end, unsigned long phys_addr, - pgprot_t prot) + const struct mem_type *type) { unsigned long next; pmd_t *pmd; @@ -75,7 +80,7 @@ static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr, do { next = pmd_addr_end(addr, end); - ret = remap_area_pte(pmd, addr, next, phys_addr, prot); + ret = remap_area_pte(pmd, addr, next, phys_addr, type); if (ret) return ret; phys_addr += next - addr; @@ -84,13 +89,11 @@ static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr, } static int remap_area_pages(unsigned long start, unsigned long pfn, - unsigned long size, unsigned long flags) + size_t size, const struct mem_type *type) { unsigned long addr = start; unsigned long next, end = start + size; unsigned long phys_addr = __pfn_to_phys(pfn); - pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | - L_PTE_DIRTY | L_PTE_WRITE | flags); pgd_t *pgd; int err = 0; @@ -98,7 +101,7 @@ static int remap_area_pages(unsigned long start, unsigned long pfn, pgd = pgd_offset_k(addr); do { next = pgd_addr_end(addr, end); - err = remap_area_pmd(pgd, addr, next, phys_addr, prot); + err = remap_area_pmd(pgd, addr, next, phys_addr, type); if (err) break; phys_addr += next - addr; @@ -178,9 +181,9 @@ static void unmap_area_sections(unsigned long virt, unsigned long size) static int remap_area_sections(unsigned long virt, unsigned long pfn, - unsigned long size, unsigned long flags) + size_t size, const struct mem_type *type) { - unsigned long prot, addr = virt, end = virt + size; + unsigned long addr = virt, end = virt + size; pgd_t *pgd; /* @@ -189,23 +192,13 @@ remap_area_sections(unsigned long virt, unsigned long pfn, */ unmap_area_sections(virt, size); - prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO) | - (flags & (L_PTE_CACHEABLE | L_PTE_BUFFERABLE)); - - /* - * ARMv6 and above need XN set to prevent speculative prefetches - * hitting IO. - */ - if (cpu_architecture() >= CPU_ARCH_ARMv6) - prot |= PMD_SECT_XN; - pgd = pgd_offset_k(addr); do { pmd_t *pmd = pmd_offset(pgd, addr); - pmd[0] = __pmd(__pfn_to_phys(pfn) | prot); + pmd[0] = __pmd(__pfn_to_phys(pfn) | type->prot_sect); pfn += SZ_1M >> PAGE_SHIFT; - pmd[1] = __pmd(__pfn_to_phys(pfn) | prot); + pmd[1] = __pmd(__pfn_to_phys(pfn) | type->prot_sect); pfn += SZ_1M >> PAGE_SHIFT; flush_pmd_entry(pmd); @@ -218,9 +211,9 @@ remap_area_sections(unsigned long virt, unsigned long pfn, static int remap_area_supersections(unsigned long virt, unsigned long pfn, - unsigned long size, unsigned long flags) + size_t size, const struct mem_type *type) { - unsigned long prot, addr = virt, end = virt + size; + unsigned long addr = virt, end = virt + size; pgd_t *pgd; /* @@ -229,22 +222,12 @@ remap_area_supersections(unsigned long virt, unsigned long pfn, */ unmap_area_sections(virt, size); - prot = PMD_TYPE_SECT | PMD_SECT_SUPER | PMD_SECT_AP_WRITE | - PMD_DOMAIN(DOMAIN_IO) | - (flags & (L_PTE_CACHEABLE | L_PTE_BUFFERABLE)); - - /* - * ARMv6 and above need XN set to prevent speculative prefetches - * hitting IO. - */ - if (cpu_architecture() >= CPU_ARCH_ARMv6) - prot |= PMD_SECT_XN; - pgd = pgd_offset_k(virt); do { unsigned long super_pmd_val, i; - super_pmd_val = __pfn_to_phys(pfn) | prot; + super_pmd_val = __pfn_to_phys(pfn) | type->prot_sect | + PMD_SECT_SUPER; super_pmd_val |= ((pfn >> (32 - PAGE_SHIFT)) & 0xf) << 20; for (i = 0; i < 8; i++) { @@ -279,9 +262,10 @@ remap_area_supersections(unsigned long virt, unsigned long pfn, * mapping. See include/asm-arm/proc-armv/pgtable.h for more information. */ void __iomem * -__ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, - unsigned long flags) +__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, + unsigned int mtype) { + const struct mem_type *type; int err; unsigned long addr; struct vm_struct * area; @@ -292,6 +276,10 @@ __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK)) return NULL; + type = get_mem_type(mtype); + if (!type) + return NULL; + size = PAGE_ALIGN(size); area = get_vm_area(size, VM_IOREMAP); @@ -302,16 +290,16 @@ __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, #ifndef CONFIG_SMP if (DOMAIN_IO == 0 && (((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) || - cpu_is_xsc3()) && + cpu_is_xsc3()) && pfn >= 0x100000 && !((__pfn_to_phys(pfn) | size | addr) & ~SUPERSECTION_MASK)) { area->flags |= VM_ARM_SECTION_MAPPING; - err = remap_area_supersections(addr, pfn, size, flags); + err = remap_area_supersections(addr, pfn, size, type); } else if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) { area->flags |= VM_ARM_SECTION_MAPPING; - err = remap_area_sections(addr, pfn, size, flags); + err = remap_area_sections(addr, pfn, size, type); } else #endif - err = remap_area_pages(addr, pfn, size, flags); + err = remap_area_pages(addr, pfn, size, type); if (err) { vunmap((void *)addr); @@ -321,10 +309,10 @@ __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, flush_cache_vmap(addr, addr + size); return (void __iomem *) (offset + addr); } -EXPORT_SYMBOL(__ioremap_pfn); +EXPORT_SYMBOL(__arm_ioremap_pfn); void __iomem * -__ioremap(unsigned long phys_addr, size_t size, unsigned long flags) +__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) { unsigned long last_addr; unsigned long offset = phys_addr & ~PAGE_MASK; @@ -342,9 +330,9 @@ __ioremap(unsigned long phys_addr, size_t size, unsigned long flags) */ size = PAGE_ALIGN(last_addr + 1) - phys_addr; - return __ioremap_pfn(pfn, offset, size, flags); + return __arm_ioremap_pfn(pfn, offset, size, mtype); } -EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(__arm_ioremap); void __iounmap(volatile void __iomem *addr) { diff --git a/trunk/arch/arm/mm/mm.h b/trunk/arch/arm/mm/mm.h index a44e30970635..7647c597fc59 100644 --- a/trunk/arch/arm/mm/mm.h +++ b/trunk/arch/arm/mm/mm.h @@ -16,6 +16,16 @@ static inline pmd_t *pmd_off_k(unsigned long virt) return pmd_off(pgd_offset_k(virt), virt); } +struct mem_type { + unsigned int prot_pte; + unsigned int prot_pte_ext; + unsigned int prot_l1; + unsigned int prot_sect; + unsigned int domain; +}; + +const struct mem_type *get_mem_type(unsigned int type); + #endif struct map_desc; diff --git a/trunk/arch/arm/mm/mmap.c b/trunk/arch/arm/mm/mmap.c index b0b5f4694070..2c4c2422cd1e 100644 --- a/trunk/arch/arm/mm/mmap.c +++ b/trunk/arch/arm/mm/mmap.c @@ -49,8 +49,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, #endif /* - * We should enforce the MAP_FIXED case. However, currently - * the generic kernel code doesn't allow us to handle this. + * We enforce the MAP_FIXED case. */ if (flags & MAP_FIXED) { if (aliasing && flags & MAP_SHARED && addr & (SHMLBA - 1)) diff --git a/trunk/arch/arm/mm/mmu.c b/trunk/arch/arm/mm/mmu.c index 94fd4bf5cb9e..2ba1530d1ce1 100644 --- a/trunk/arch/arm/mm/mmu.c +++ b/trunk/arch/arm/mm/mmu.c @@ -176,28 +176,42 @@ void adjust_cr(unsigned long mask, unsigned long set) } #endif -struct mem_types { - unsigned int prot_pte; - unsigned int prot_l1; - unsigned int prot_sect; - unsigned int domain; -}; - -static struct mem_types mem_types[] __initdata = { - [MT_DEVICE] = { - .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | - L_PTE_WRITE, - .prot_l1 = PMD_TYPE_TABLE, - .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED | - PMD_SECT_AP_WRITE, - .domain = DOMAIN_IO, +#define PROT_PTE_DEVICE L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_WRITE +#define PROT_SECT_DEVICE PMD_TYPE_SECT|PMD_SECT_XN|PMD_SECT_AP_WRITE + +static struct mem_type mem_types[] = { + [MT_DEVICE] = { /* Strongly ordered / ARMv6 shared device */ + .prot_pte = PROT_PTE_DEVICE, + .prot_l1 = PMD_TYPE_TABLE, + .prot_sect = PROT_SECT_DEVICE | PMD_SECT_UNCACHED, + .domain = DOMAIN_IO, + }, + [MT_DEVICE_NONSHARED] = { /* ARMv6 non-shared device */ + .prot_pte = PROT_PTE_DEVICE, + .prot_pte_ext = PTE_EXT_TEX(2), + .prot_l1 = PMD_TYPE_TABLE, + .prot_sect = PROT_SECT_DEVICE | PMD_SECT_TEX(2), + .domain = DOMAIN_IO, + }, + [MT_DEVICE_CACHED] = { /* ioremap_cached */ + .prot_pte = PROT_PTE_DEVICE | L_PTE_CACHEABLE | L_PTE_BUFFERABLE, + .prot_l1 = PMD_TYPE_TABLE, + .prot_sect = PROT_SECT_DEVICE | PMD_SECT_WB, + .domain = DOMAIN_IO, + }, + [MT_DEVICE_IXP2000] = { /* IXP2400 requires XCB=101 for on-chip I/O */ + .prot_pte = PROT_PTE_DEVICE, + .prot_l1 = PMD_TYPE_TABLE, + .prot_sect = PROT_SECT_DEVICE | PMD_SECT_BUFFERABLE | + PMD_SECT_TEX(1), + .domain = DOMAIN_IO, }, [MT_CACHECLEAN] = { - .prot_sect = PMD_TYPE_SECT | PMD_BIT4, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, .domain = DOMAIN_KERNEL, }, [MT_MINICLEAN] = { - .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_MINICACHE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_MINICACHE, .domain = DOMAIN_KERNEL, }, [MT_LOW_VECTORS] = { @@ -213,30 +227,20 @@ static struct mem_types mem_types[] __initdata = { .domain = DOMAIN_USER, }, [MT_MEMORY] = { - .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_AP_WRITE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, .domain = DOMAIN_KERNEL, }, [MT_ROM] = { - .prot_sect = PMD_TYPE_SECT | PMD_BIT4, + .prot_sect = PMD_TYPE_SECT, .domain = DOMAIN_KERNEL, }, - [MT_IXP2000_DEVICE] = { /* IXP2400 requires XCB=101 for on-chip I/O */ - .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | - L_PTE_WRITE, - .prot_l1 = PMD_TYPE_TABLE, - .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED | - PMD_SECT_AP_WRITE | PMD_SECT_BUFFERABLE | - PMD_SECT_TEX(1), - .domain = DOMAIN_IO, - }, - [MT_NONSHARED_DEVICE] = { - .prot_l1 = PMD_TYPE_TABLE, - .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_NONSHARED_DEV | - PMD_SECT_AP_WRITE, - .domain = DOMAIN_IO, - } }; +const struct mem_type *get_mem_type(unsigned int type) +{ + return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL; +} + /* * Adjust the PMD section entries according to the CPU in use. */ @@ -262,20 +266,23 @@ static void __init build_mem_type_table(void) } /* - * Xscale must not have PMD bit 4 set for section mappings. + * ARMv5 and lower, bit 4 must be set for page tables. + * (was: cache "update-able on write" bit on ARM610) + * However, Xscale cores require this bit to be cleared. */ - if (cpu_is_xscale()) - for (i = 0; i < ARRAY_SIZE(mem_types); i++) + if (cpu_is_xscale()) { + for (i = 0; i < ARRAY_SIZE(mem_types); i++) { mem_types[i].prot_sect &= ~PMD_BIT4; - - /* - * ARMv5 and lower, excluding Xscale, bit 4 must be set for - * page tables. - */ - if (cpu_arch < CPU_ARCH_ARMv6 && !cpu_is_xscale()) - for (i = 0; i < ARRAY_SIZE(mem_types); i++) + mem_types[i].prot_l1 &= ~PMD_BIT4; + } + } else if (cpu_arch < CPU_ARCH_ARMv6) { + for (i = 0; i < ARRAY_SIZE(mem_types); i++) { if (mem_types[i].prot_l1) mem_types[i].prot_l1 |= PMD_BIT4; + if (mem_types[i].prot_sect) + mem_types[i].prot_sect |= PMD_BIT4; + } + } cp = &cache_policies[cachepolicy]; kern_pgprot = user_pgprot = cp->pte; @@ -295,13 +302,6 @@ static void __init build_mem_type_table(void) * ARMv6 and above have extended page tables. */ if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) { - /* - * bit 4 becomes XN which we must clear for the - * kernel memory mapping. - */ - mem_types[MT_MEMORY].prot_sect &= ~PMD_SECT_XN; - mem_types[MT_ROM].prot_sect &= ~PMD_SECT_XN; - /* * Mark cache clean areas and XIP ROM read only * from SVC mode and no access from userspace. @@ -368,64 +368,126 @@ static void __init build_mem_type_table(void) } printk("Memory policy: ECC %sabled, Data cache %s\n", ecc_mask ? "en" : "dis", cp->policy); + + for (i = 0; i < ARRAY_SIZE(mem_types); i++) { + struct mem_type *t = &mem_types[i]; + if (t->prot_l1) + t->prot_l1 |= PMD_DOMAIN(t->domain); + if (t->prot_sect) + t->prot_sect |= PMD_DOMAIN(t->domain); + } } #define vectors_base() (vectors_high() ? 0xffff0000 : 0) -/* - * Create a SECTION PGD between VIRT and PHYS in domain - * DOMAIN with protection PROT. This operates on half- - * pgdir entry increments. - */ -static inline void -alloc_init_section(unsigned long virt, unsigned long phys, int prot) +static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, + unsigned long end, unsigned long pfn, + const struct mem_type *type) { - pmd_t *pmdp = pmd_off_k(virt); + pte_t *pte; - if (virt & (1 << 20)) - pmdp++; + if (pmd_none(*pmd)) { + pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t)); + __pmd_populate(pmd, __pa(pte) | type->prot_l1); + } - *pmdp = __pmd(phys | prot); - flush_pmd_entry(pmdp); + pte = pte_offset_kernel(pmd, addr); + do { + set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), + type->prot_pte_ext); + pfn++; + } while (pte++, addr += PAGE_SIZE, addr != end); } -/* - * Create a SUPER SECTION PGD between VIRT and PHYS with protection PROT - */ -static inline void -alloc_init_supersection(unsigned long virt, unsigned long phys, int prot) +static void __init alloc_init_section(pgd_t *pgd, unsigned long addr, + unsigned long end, unsigned long phys, + const struct mem_type *type) { - int i; + pmd_t *pmd = pmd_offset(pgd, addr); + + /* + * Try a section mapping - end, addr and phys must all be aligned + * to a section boundary. Note that PMDs refer to the individual + * L1 entries, whereas PGDs refer to a group of L1 entries making + * up one logical pointer to an L2 table. + */ + if (((addr | end | phys) & ~SECTION_MASK) == 0) { + pmd_t *p = pmd; + + if (addr & SECTION_SIZE) + pmd++; - for (i = 0; i < 16; i += 1) { - alloc_init_section(virt, phys, prot | PMD_SECT_SUPER); + do { + *pmd = __pmd(phys | type->prot_sect); + phys += SECTION_SIZE; + } while (pmd++, addr += SECTION_SIZE, addr != end); - virt += (PGDIR_SIZE / 2); + flush_pmd_entry(p); + } else { + /* + * No need to loop; pte's aren't interested in the + * individual L1 entries. + */ + alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type); } } -/* - * Add a PAGE mapping between VIRT and PHYS in domain - * DOMAIN with protection PROT. Note that due to the - * way we map the PTEs, we must allocate two PTE_SIZE'd - * blocks - one for the Linux pte table, and one for - * the hardware pte table. - */ -static inline void -alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot) +static void __init create_36bit_mapping(struct map_desc *md, + const struct mem_type *type) { - pmd_t *pmdp = pmd_off_k(virt); - pte_t *ptep; + unsigned long phys, addr, length, end; + pgd_t *pgd; + + addr = md->virtual; + phys = (unsigned long)__pfn_to_phys(md->pfn); + length = PAGE_ALIGN(md->length); + + if (!(cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())) { + printk(KERN_ERR "MM: CPU does not support supersection " + "mapping for 0x%08llx at 0x%08lx\n", + __pfn_to_phys((u64)md->pfn), addr); + return; + } - if (pmd_none(*pmdp)) { - ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * - sizeof(pte_t)); + /* N.B. ARMv6 supersections are only defined to work with domain 0. + * Since domain assignments can in fact be arbitrary, the + * 'domain == 0' check below is required to insure that ARMv6 + * supersections are only allocated for domain 0 regardless + * of the actual domain assignments in use. + */ + if (type->domain) { + printk(KERN_ERR "MM: invalid domain in supersection " + "mapping for 0x%08llx at 0x%08lx\n", + __pfn_to_phys((u64)md->pfn), addr); + return; + } - __pmd_populate(pmdp, __pa(ptep) | prot_l1); + if ((addr | length | __pfn_to_phys(md->pfn)) & ~SUPERSECTION_MASK) { + printk(KERN_ERR "MM: cannot create mapping for " + "0x%08llx at 0x%08lx invalid alignment\n", + __pfn_to_phys((u64)md->pfn), addr); + return; } - ptep = pte_offset_kernel(pmdp, virt); - set_pte_ext(ptep, pfn_pte(phys >> PAGE_SHIFT, prot), 0); + /* + * Shift bits [35:32] of address into bits [23:20] of PMD + * (See ARMv6 spec). + */ + phys |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20); + + pgd = pgd_offset_k(addr); + end = addr + length; + do { + pmd_t *pmd = pmd_offset(pgd, addr); + int i; + + for (i = 0; i < 16; i++) + *pmd++ = __pmd(phys | type->prot_sect | PMD_SECT_SUPER); + + addr += SUPERSECTION_SIZE; + phys += SUPERSECTION_SIZE; + pgd += SUPERSECTION_SIZE >> PGDIR_SHIFT; + } while (addr != end); } /* @@ -437,10 +499,9 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg */ void __init create_mapping(struct map_desc *md) { - unsigned long virt, length; - int prot_sect, prot_l1, domain; - pgprot_t prot_pte; - unsigned long off = (u32)__pfn_to_phys(md->pfn); + unsigned long phys, addr, length, end; + const struct mem_type *type; + pgd_t *pgd; if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) { printk(KERN_WARNING "BUG: not creating mapping for " @@ -456,105 +517,37 @@ void __init create_mapping(struct map_desc *md) __pfn_to_phys((u64)md->pfn), md->virtual); } - domain = mem_types[md->type].domain; - prot_pte = __pgprot(mem_types[md->type].prot_pte); - prot_l1 = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain); - prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain); + type = &mem_types[md->type]; /* * Catch 36-bit addresses */ - if(md->pfn >= 0x100000) { - if(domain) { - printk(KERN_ERR "MM: invalid domain in supersection " - "mapping for 0x%08llx at 0x%08lx\n", - __pfn_to_phys((u64)md->pfn), md->virtual); - return; - } - if((md->virtual | md->length | __pfn_to_phys(md->pfn)) - & ~SUPERSECTION_MASK) { - printk(KERN_ERR "MM: cannot create mapping for " - "0x%08llx at 0x%08lx invalid alignment\n", - __pfn_to_phys((u64)md->pfn), md->virtual); - return; - } - - /* - * Shift bits [35:32] of address into bits [23:20] of PMD - * (See ARMv6 spec). - */ - off |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20); + if (md->pfn >= 0x100000) { + create_36bit_mapping(md, type); + return; } - virt = md->virtual; - off -= virt; - length = md->length; + addr = md->virtual; + phys = (unsigned long)__pfn_to_phys(md->pfn); + length = PAGE_ALIGN(md->length); - if (mem_types[md->type].prot_l1 == 0 && - (virt & 0xfffff || (virt + off) & 0xfffff || (virt + length) & 0xfffff)) { + if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) { printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not " "be mapped using pages, ignoring.\n", - __pfn_to_phys(md->pfn), md->virtual); + __pfn_to_phys(md->pfn), addr); return; } - while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) { - alloc_init_page(virt, virt + off, prot_l1, prot_pte); + pgd = pgd_offset_k(addr); + end = addr + length; + do { + unsigned long next = pgd_addr_end(addr, end); - virt += PAGE_SIZE; - length -= PAGE_SIZE; - } - - /* N.B. ARMv6 supersections are only defined to work with domain 0. - * Since domain assignments can in fact be arbitrary, the - * 'domain == 0' check below is required to insure that ARMv6 - * supersections are only allocated for domain 0 regardless - * of the actual domain assignments in use. - */ - if ((cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3()) - && domain == 0) { - /* - * Align to supersection boundary if !high pages. - * High pages have already been checked for proper - * alignment above and they will fail the SUPSERSECTION_MASK - * check because of the way the address is encoded into - * offset. - */ - if (md->pfn <= 0x100000) { - while ((virt & ~SUPERSECTION_MASK || - (virt + off) & ~SUPERSECTION_MASK) && - length >= (PGDIR_SIZE / 2)) { - alloc_init_section(virt, virt + off, prot_sect); - - virt += (PGDIR_SIZE / 2); - length -= (PGDIR_SIZE / 2); - } - } + alloc_init_section(pgd, addr, next, phys, type); - while (length >= SUPERSECTION_SIZE) { - alloc_init_supersection(virt, virt + off, prot_sect); - - virt += SUPERSECTION_SIZE; - length -= SUPERSECTION_SIZE; - } - } - - /* - * A section mapping covers half a "pgdir" entry. - */ - while (length >= (PGDIR_SIZE / 2)) { - alloc_init_section(virt, virt + off, prot_sect); - - virt += (PGDIR_SIZE / 2); - length -= (PGDIR_SIZE / 2); - } - - while (length >= PAGE_SIZE) { - alloc_init_page(virt, virt + off, prot_l1, prot_pte); - - virt += PAGE_SIZE; - length -= PAGE_SIZE; - } + phys += next - addr; + addr = next; + } while (pgd++, addr != end); } /* diff --git a/trunk/arch/arm/mm/nommu.c b/trunk/arch/arm/mm/nommu.c index 05818fc0c705..8cd3a60954f0 100644 --- a/trunk/arch/arm/mm/nommu.c +++ b/trunk/arch/arm/mm/nommu.c @@ -62,21 +62,21 @@ void flush_dcache_page(struct page *page) } EXPORT_SYMBOL(flush_dcache_page); -void __iomem *__ioremap_pfn(unsigned long pfn, unsigned long offset, - size_t size, unsigned long flags) +void __iomem *__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, + size_t size, unsigned int mtype) { if (pfn >= (0x100000000ULL >> PAGE_SHIFT)) return NULL; return (void __iomem *) (offset + (pfn << PAGE_SHIFT)); } -EXPORT_SYMBOL(__ioremap_pfn); +EXPORT_SYMBOL(__arm_ioremap_pfn); -void __iomem *__ioremap(unsigned long phys_addr, size_t size, - unsigned long flags) +void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size, + unsigned int mtype) { return (void __iomem *)phys_addr; } -EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(__arm_ioremap); void __iounmap(volatile void __iomem *addr) { diff --git a/trunk/arch/arm/mm/proc-xscale.S b/trunk/arch/arm/mm/proc-xscale.S index d29fe927ee9e..c156ddab9a2d 100644 --- a/trunk/arch/arm/mm/proc-xscale.S +++ b/trunk/arch/arm/mm/proc-xscale.S @@ -584,6 +584,11 @@ cpu_ixp42x_name: .asciz "XScale-IXP42x Family" .size cpu_ixp42x_name, . - cpu_ixp42x_name + .type cpu_ixp43x_name, #object +cpu_ixp43x_name: + .asciz "XScale-IXP43x Family" + .size cpu_ixp43x_name, . - cpu_ixp43x_name + .type cpu_ixp46x_name, #object cpu_ixp46x_name: .asciz "XScale-IXP46x Family" @@ -843,6 +848,29 @@ __ixp42x_proc_info: .long xscale_cache_fns .size __ixp42x_proc_info, . - __ixp42x_proc_info + .type __ixp43x_proc_info, #object +__ixp43x_proc_info: + .long 0x69054040 + .long 0xfffffff0 + .long PMD_TYPE_SECT | \ + PMD_SECT_BUFFERABLE | \ + PMD_SECT_CACHEABLE | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_ixp43x_name + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __ixp43x_proc_info, . - __ixp43x_proc_info + .type __ixp46x_proc_info, #object __ixp46x_proc_info: .long 0x69054200 diff --git a/trunk/arch/arm/oprofile/backtrace.c b/trunk/arch/arm/oprofile/backtrace.c index 7c22c12618cc..f5ebf30151fa 100644 --- a/trunk/arch/arm/oprofile/backtrace.c +++ b/trunk/arch/arm/oprofile/backtrace.c @@ -19,6 +19,19 @@ #include #include +#include "../kernel/stacktrace.h" + +static int report_trace(struct stackframe *frame, void *d) +{ + unsigned int *depth = d; + + if (*depth) { + oprofile_add_trace(frame->lr); + (*depth)--; + } + + return *depth == 0; +} /* * The registers we're interested in are at the end of the variable @@ -32,21 +45,6 @@ struct frame_tail { unsigned long lr; } __attribute__((packed)); - -#ifdef CONFIG_FRAME_POINTER -static struct frame_tail* kernel_backtrace(struct frame_tail *tail) -{ - oprofile_add_trace(tail->lr); - - /* frame pointers should strictly progress back up the stack - * (towards higher addresses) */ - if (tail >= tail->fp) - return NULL; - - return tail->fp-1; -} -#endif - static struct frame_tail* user_backtrace(struct frame_tail *tail) { struct frame_tail buftail[2]; @@ -67,47 +65,14 @@ static struct frame_tail* user_backtrace(struct frame_tail *tail) return buftail[0].fp-1; } -/* - * | | /\ Higher addresses - * | | - * --------------- stack base (address of current_thread_info) - * | thread info | - * . . - * | stack | - * --------------- saved regs->ARM_fp value if valid (frame_tail address) - * . . - * --------------- struct pt_regs stored on stack (struct pt_regs *) - * | | - * . . - * | | - * --------------- %esp - * | | - * | | \/ Lower addresses - * - * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values - */ -static int valid_kernel_stack(struct frame_tail *tail, struct pt_regs *regs) -{ - unsigned long tailaddr = (unsigned long)tail; - unsigned long stack = (unsigned long)regs; - unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE; - - return (tailaddr > stack) && (tailaddr < stack_base); -} - void arm_backtrace(struct pt_regs * const regs, unsigned int depth) { - struct frame_tail *tail; - - tail = ((struct frame_tail *) regs->ARM_fp) - 1; + struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1; if (!user_mode(regs)) { - -#ifdef CONFIG_FRAME_POINTER - while (depth-- && tail && valid_kernel_stack(tail, regs)) { - tail = kernel_backtrace(tail); - } -#endif + unsigned long base = ((unsigned long)regs) & ~(THREAD_SIZE - 1); + walk_stackframe(regs->ARM_fp, base, base + THREAD_SIZE, + report_trace, &depth); return; } diff --git a/trunk/arch/arm/plat-iop/io.c b/trunk/arch/arm/plat-iop/io.c index f7eccecf2e47..498675d028d0 100644 --- a/trunk/arch/arm/plat-iop/io.c +++ b/trunk/arch/arm/plat-iop/io.c @@ -22,7 +22,7 @@ #include void * __iomem __iop3xx_ioremap(unsigned long cookie, size_t size, - unsigned long flags) + unsigned int mtype) { void __iomem * retval; @@ -34,7 +34,7 @@ void * __iomem __iop3xx_ioremap(unsigned long cookie, size_t size, retval = (void *) IOP3XX_PMMR_PHYS_TO_VIRT(cookie); break; default: - retval = __ioremap(cookie, size, flags); + retval = __arm_ioremap(cookie, size, mtype); } return retval; diff --git a/trunk/arch/arm/plat-iop/pci.c b/trunk/arch/arm/plat-iop/pci.c index b5f6ec35aafb..e2744b7227c5 100644 --- a/trunk/arch/arm/plat-iop/pci.c +++ b/trunk/arch/arm/plat-iop/pci.c @@ -55,7 +55,7 @@ static u32 iop3xx_cfg_address(struct pci_bus *bus, int devfn, int where) * This routine checks the status of the last configuration cycle. If an error * was detected it returns a 1, else it returns a 0. The errors being checked * are parity, master abort, target abort (master and target). These types of - * errors occure during a config cycle where there is no device, like during + * errors occur during a config cycle where there is no device, like during * the discovery stage. */ static int iop3xx_pci_status(void) @@ -223,8 +223,111 @@ struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *sys) return pci_scan_bus(sys->busnr, &iop3xx_ops, sys); } +void __init iop3xx_atu_setup(void) +{ + /* BAR 0 ( Disabled ) */ + *IOP3XX_IAUBAR0 = 0x0; + *IOP3XX_IABAR0 = 0x0; + *IOP3XX_IATVR0 = 0x0; + *IOP3XX_IALR0 = 0x0; + + /* BAR 1 ( Disabled ) */ + *IOP3XX_IAUBAR1 = 0x0; + *IOP3XX_IABAR1 = 0x0; + *IOP3XX_IALR1 = 0x0; + + /* BAR 2 (1:1 mapping with Physical RAM) */ + /* Set limit and enable */ + *IOP3XX_IALR2 = ~((u32)IOP3XX_MAX_RAM_SIZE - 1) & ~0x1; + *IOP3XX_IAUBAR2 = 0x0; + + /* Align the inbound bar with the base of memory */ + *IOP3XX_IABAR2 = PHYS_OFFSET | + PCI_BASE_ADDRESS_MEM_TYPE_64 | + PCI_BASE_ADDRESS_MEM_PREFETCH; + + *IOP3XX_IATVR2 = PHYS_OFFSET; + + /* Outbound window 0 */ + *IOP3XX_OMWTVR0 = IOP3XX_PCI_LOWER_MEM_PA; + *IOP3XX_OUMWTVR0 = 0; + + /* Outbound window 1 */ + *IOP3XX_OMWTVR1 = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE; + *IOP3XX_OUMWTVR1 = 0; + + /* BAR 3 ( Disabled ) */ + *IOP3XX_IAUBAR3 = 0x0; + *IOP3XX_IABAR3 = 0x0; + *IOP3XX_IATVR3 = 0x0; + *IOP3XX_IALR3 = 0x0; + + /* Setup the I/O Bar + */ + *IOP3XX_OIOWTVR = IOP3XX_PCI_LOWER_IO_PA;; + + /* Enable inbound and outbound cycles + */ + *IOP3XX_ATUCMD |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_PARITY | PCI_COMMAND_SERR; + *IOP3XX_ATUCR |= IOP3XX_ATUCR_OUT_EN; +} + +void __init iop3xx_atu_disable(void) +{ + *IOP3XX_ATUCMD = 0; + *IOP3XX_ATUCR = 0; + + /* wait for cycles to quiesce */ + while (*IOP3XX_PCSR & (IOP3XX_PCSR_OUT_Q_BUSY | + IOP3XX_PCSR_IN_Q_BUSY)) + cpu_relax(); + + /* BAR 0 ( Disabled ) */ + *IOP3XX_IAUBAR0 = 0x0; + *IOP3XX_IABAR0 = 0x0; + *IOP3XX_IATVR0 = 0x0; + *IOP3XX_IALR0 = 0x0; + + /* BAR 1 ( Disabled ) */ + *IOP3XX_IAUBAR1 = 0x0; + *IOP3XX_IABAR1 = 0x0; + *IOP3XX_IALR1 = 0x0; + + /* BAR 2 ( Disabled ) */ + *IOP3XX_IAUBAR2 = 0x0; + *IOP3XX_IABAR2 = 0x0; + *IOP3XX_IATVR2 = 0x0; + *IOP3XX_IALR2 = 0x0; + + /* BAR 3 ( Disabled ) */ + *IOP3XX_IAUBAR3 = 0x0; + *IOP3XX_IABAR3 = 0x0; + *IOP3XX_IATVR3 = 0x0; + *IOP3XX_IALR3 = 0x0; + + /* Clear the outbound windows */ + *IOP3XX_OIOWTVR = 0; + + /* Outbound window 0 */ + *IOP3XX_OMWTVR0 = 0; + *IOP3XX_OUMWTVR0 = 0; + + /* Outbound window 1 */ + *IOP3XX_OMWTVR1 = 0; + *IOP3XX_OUMWTVR1 = 0; +} + +/* Flag to determine whether the ATU is initialized and the PCI bus scanned */ +int init_atu; + void iop3xx_pci_preinit(void) { + if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) { + iop3xx_atu_disable(); + iop3xx_atu_setup(); + } + DBG("PCI: Intel 803xx PCI init code.\n"); DBG("ATU: IOP3XX_ATUCMD=0x%04x\n", *IOP3XX_ATUCMD); DBG("ATU: IOP3XX_OMWTVR0=0x%04x, IOP3XX_OIOWTVR=0x%04x\n", @@ -245,3 +348,38 @@ void iop3xx_pci_preinit(void) hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, "imprecise external abort"); } + +/* allow init_atu to be user overridden */ +static int __init iop3xx_init_atu_setup(char *str) +{ + init_atu = IOP3XX_INIT_ATU_DEFAULT; + if (str) { + while (*str != '\0') { + switch (*str) { + case 'y': + case 'Y': + init_atu = IOP3XX_INIT_ATU_ENABLE; + break; + case 'n': + case 'N': + init_atu = IOP3XX_INIT_ATU_DISABLE; + break; + case ',': + case '=': + break; + default: + printk(KERN_DEBUG "\"%s\" malformed at " + "character: \'%c\'", + __FUNCTION__, + *str); + *(str + 1) = '\0'; + } + str++; + } + } + + return 1; +} + +__setup("iop3xx_init_atu", iop3xx_init_atu_setup); + diff --git a/trunk/arch/arm/plat-iop/time.c b/trunk/arch/arm/plat-iop/time.c index 16300adfb4de..100d57ad98ed 100644 --- a/trunk/arch/arm/plat-iop/time.c +++ b/trunk/arch/arm/plat-iop/time.c @@ -32,22 +32,22 @@ static unsigned long next_jiffy_time; unsigned long iop_gettimeoffset(void) { - unsigned long offset, temp1, temp2; + unsigned long offset, temp; /* enable cp6, if necessary, to avoid taking the overhead of an * undefined instruction trap */ asm volatile ( "mrc p15, 0, %0, c15, c1, 0\n\t" - "ands %1, %0, #(1 << 6)\n\t" + "tst %0, #(1 << 6)\n\t" "orreq %0, %0, #(1 << 6)\n\t" "mcreq p15, 0, %0, c15, c1, 0\n\t" -#ifdef CONFIG_XSCALE +#ifdef CONFIG_CPU_XSCALE "mrceq p15, 0, %0, c15, c1, 0\n\t" "moveq %0, %0\n\t" "subeq pc, pc, #4\n\t" #endif - : "=r"(temp1), "=r"(temp2) : : "cc"); + : "=r"(temp) : : "cc"); offset = next_jiffy_time - read_tcr1(); @@ -75,7 +75,7 @@ iop_timer_interrupt(int irq, void *dev_id) static struct irqaction iop_timer_irq = { .name = "IOP Timer Tick", .handler = iop_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, }; void __init iop_init_time(unsigned long tick_rate) diff --git a/trunk/arch/arm/plat-omap/Kconfig b/trunk/arch/arm/plat-omap/Kconfig index f2dc363de66b..9e8d21eca4ec 100644 --- a/trunk/arch/arm/plat-omap/Kconfig +++ b/trunk/arch/arm/plat-omap/Kconfig @@ -11,6 +11,7 @@ choice config ARCH_OMAP1 bool "TI OMAP1" + select GENERIC_CLOCKEVENTS config ARCH_OMAP2 bool "TI OMAP2" diff --git a/trunk/arch/arm/plat-omap/common.c b/trunk/arch/arm/plat-omap/common.c index 57b7b93674a4..fecd3d625995 100644 --- a/trunk/arch/arm/plat-omap/common.c +++ b/trunk/arch/arm/plat-omap/common.c @@ -156,3 +156,53 @@ static int __init omap_add_serial_console(void) return add_preferred_console("ttyS", line, opt); } console_initcall(omap_add_serial_console); + + +/* + * 32KHz clocksource ... always available, on pretty most chips except + * OMAP 730 and 1510. Other timers could be used as clocksources, with + * higher resolution in free-running counter modes (e.g. 12 MHz xtal), + * but systems won't necessarily want to spend resources that way. + */ + +#if defined(CONFIG_ARCH_OMAP16XX) +#define TIMER_32K_SYNCHRONIZED 0xfffbc410 +#elif defined(CONFIG_ARCH_OMAP24XX) +#define TIMER_32K_SYNCHRONIZED 0x48004010 +#endif + +#ifdef TIMER_32K_SYNCHRONIZED + +#include + +static cycle_t omap_32k_read(void) +{ + return omap_readl(TIMER_32K_SYNCHRONIZED); +} + +static struct clocksource clocksource_32k = { + .name = "32k_counter", + .rating = 250, + .read = omap_32k_read, + .mask = CLOCKSOURCE_MASK(32), + .shift = 10, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static int __init omap_init_clocksource_32k(void) +{ + static char err[] __initdata = KERN_ERR + "%s: can't register clocksource!\n"; + + if (cpu_is_omap16xx() || cpu_is_omap24xx()) { + clocksource_32k.mult = clocksource_hz2mult(32768, + clocksource_32k.shift); + + if (clocksource_register(&clocksource_32k)) + printk(err, clocksource_32k.name); + } + return 0; +} +arch_initcall(omap_init_clocksource_32k); + +#endif /* TIMER_32K_SYNCHRONIZED */ diff --git a/trunk/arch/arm/plat-omap/devices.c b/trunk/arch/arm/plat-omap/devices.c index dbc3f44e07a6..eeb33fed6f7c 100644 --- a/trunk/arch/arm/plat-omap/devices.c +++ b/trunk/arch/arm/plat-omap/devices.c @@ -429,6 +429,10 @@ static inline void omap_init_rng(void) {} */ static int __init omap_init_devices(void) { +/* + * Need to enable relevant once for 2430 SDP + */ +#ifndef CONFIG_MACH_OMAP_2430SDP /* please keep these calls, and their implementations above, * in alphabetical order so they're easier to sort through. */ @@ -438,7 +442,7 @@ static int __init omap_init_devices(void) omap_init_uwire(); omap_init_wdt(); omap_init_rng(); - +#endif return 0; } arch_initcall(omap_init_devices); diff --git a/trunk/arch/arm/plat-omap/dmtimer.c b/trunk/arch/arm/plat-omap/dmtimer.c index 45f0439bffba..659619f235ca 100644 --- a/trunk/arch/arm/plat-omap/dmtimer.c +++ b/trunk/arch/arm/plat-omap/dmtimer.c @@ -506,6 +506,8 @@ int omap_dm_timer_init(void) BUG_ON(dm_source_clocks[i] == NULL); } #endif + if (cpu_is_omap243x()) + dm_timers[0].phys_base = 0x49018000; for (i = 0; i < dm_timer_count; i++) { #ifdef CONFIG_ARCH_OMAP2 diff --git a/trunk/arch/arm/plat-omap/gpio.c b/trunk/arch/arm/plat-omap/gpio.c index b8c01de208b4..9dc6d3617bdb 100644 --- a/trunk/arch/arm/plat-omap/gpio.c +++ b/trunk/arch/arm/plat-omap/gpio.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -86,10 +85,17 @@ /* * omap24xx specific GPIO registers */ -#define OMAP24XX_GPIO1_BASE (void __iomem *)0x48018000 -#define OMAP24XX_GPIO2_BASE (void __iomem *)0x4801a000 -#define OMAP24XX_GPIO3_BASE (void __iomem *)0x4801c000 -#define OMAP24XX_GPIO4_BASE (void __iomem *)0x4801e000 +#define OMAP242X_GPIO1_BASE (void __iomem *)0x48018000 +#define OMAP242X_GPIO2_BASE (void __iomem *)0x4801a000 +#define OMAP242X_GPIO3_BASE (void __iomem *)0x4801c000 +#define OMAP242X_GPIO4_BASE (void __iomem *)0x4801e000 + +#define OMAP243X_GPIO1_BASE (void __iomem *)0x4900C000 +#define OMAP243X_GPIO2_BASE (void __iomem *)0x4900E000 +#define OMAP243X_GPIO3_BASE (void __iomem *)0x49010000 +#define OMAP243X_GPIO4_BASE (void __iomem *)0x49012000 +#define OMAP243X_GPIO5_BASE (void __iomem *)0x480B6000 + #define OMAP24XX_GPIO_REVISION 0x0000 #define OMAP24XX_GPIO_SYSCONFIG 0x0010 #define OMAP24XX_GPIO_SYSSTATUS 0x0014 @@ -118,8 +124,18 @@ struct gpio_bank { u16 virtual_irq_start; int method; u32 reserved_map; +#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_ARCH_OMAP24XX) u32 suspend_wakeup; u32 saved_wakeup; +#endif +#ifdef CONFIG_ARCH_OMAP24XX + u32 non_wakeup_gpios; + u32 enabled_non_wakeup_gpios; + + u32 saved_datain; + u32 saved_fallingdetect; + u32 saved_risingdetect; +#endif spinlock_t lock; }; @@ -159,12 +175,22 @@ static struct gpio_bank gpio_bank_730[7] = { #endif #ifdef CONFIG_ARCH_OMAP24XX -static struct gpio_bank gpio_bank_24xx[4] = { - { OMAP24XX_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX }, - { OMAP24XX_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX }, - { OMAP24XX_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX }, - { OMAP24XX_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX }, + +static struct gpio_bank gpio_bank_242x[4] = { + { OMAP242X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX }, + { OMAP242X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX }, + { OMAP242X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX }, + { OMAP242X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX }, +}; + +static struct gpio_bank gpio_bank_243x[5] = { + { OMAP243X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX }, + { OMAP243X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX }, + { OMAP243X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX }, + { OMAP243X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX }, + { OMAP243X_GPIO5_BASE, INT_24XX_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_24XX }, }; + #endif static struct gpio_bank *gpio_bank; @@ -258,21 +284,34 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) u32 l; switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: reg += OMAP_MPUIO_IO_CNTL; break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_DIR_CONTROL; break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: reg += OMAP1610_GPIO_DIRECTION; break; +#endif +#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_DIR_CONTROL; break; +#endif +#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_OE; break; +#endif + default: + WARN_ON(1); + return; } l = __raw_readl(reg); if (is_input) @@ -300,6 +339,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) u32 l = 0; switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: reg += OMAP_MPUIO_OUTPUT; l = __raw_readl(reg); @@ -308,6 +348,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) else l &= ~(1 << gpio); break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_DATA_OUTPUT; l = __raw_readl(reg); @@ -316,6 +358,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) else l &= ~(1 << gpio); break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: if (enable) reg += OMAP1610_GPIO_SET_DATAOUT; @@ -323,6 +367,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) reg += OMAP1610_GPIO_CLEAR_DATAOUT; l = 1 << gpio; break; +#endif +#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_DATA_OUTPUT; l = __raw_readl(reg); @@ -331,6 +377,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) else l &= ~(1 << gpio); break; +#endif +#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: if (enable) reg += OMAP24XX_GPIO_SETDATAOUT; @@ -338,8 +386,9 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) reg += OMAP24XX_GPIO_CLEARDATAOUT; l = 1 << gpio; break; +#endif default: - BUG(); + WARN_ON(1); return; } __raw_writel(l, reg); @@ -363,28 +412,37 @@ int omap_get_gpio_datain(int gpio) void __iomem *reg; if (check_gpio(gpio) < 0) - return -1; + return -EINVAL; bank = get_gpio_bank(gpio); reg = bank->base; switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: reg += OMAP_MPUIO_INPUT_LATCH; break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_DATA_INPUT; break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: reg += OMAP1610_GPIO_DATAIN; break; +#endif +#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_DATA_INPUT; break; +#endif +#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_DATAIN; break; +#endif default: - BUG(); - return -1; + return -EINVAL; } return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0; @@ -398,8 +456,10 @@ do { \ __raw_writel(l, base + reg); \ } while(0) -static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int trigger) +#ifdef CONFIG_ARCH_OMAP24XX +static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) { + void __iomem *base = bank->base; u32 gpio_bit = 1 << gpio; MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit, @@ -410,9 +470,21 @@ static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int tr trigger & __IRQT_RISEDGE); MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit, trigger & __IRQT_FALEDGE); + if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { + if (trigger != 0) + __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_SETWKUENA); + else + __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_CLEARWKUENA); + } else { + if (trigger != 0) + bank->enabled_non_wakeup_gpios |= gpio_bit; + else + bank->enabled_non_wakeup_gpios &= ~gpio_bit; + } /* FIXME: Possibly do 'set_irq_handler(j, handle_level_irq)' if only level * triggering requested. */ } +#endif static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) { @@ -420,6 +492,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) u32 l = 0; switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_INT_EDGE; l = __raw_readl(reg); @@ -430,6 +503,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) else goto bad; break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_CONTROL; l = __raw_readl(reg); @@ -440,22 +515,28 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) else goto bad; break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: if (gpio & 0x08) reg += OMAP1610_GPIO_EDGE_CTRL2; else reg += OMAP1610_GPIO_EDGE_CTRL1; gpio &= 0x07; - /* We allow only edge triggering, i.e. two lowest bits */ - if (trigger & (__IRQT_LOWLVL | __IRQT_HIGHLVL)) - BUG(); l = __raw_readl(reg); l &= ~(3 << (gpio << 1)); if (trigger & __IRQT_RISEDGE) l |= 2 << (gpio << 1); if (trigger & __IRQT_FALEDGE) l |= 1 << (gpio << 1); + if (trigger) + /* Enable wake-up during idle for dynamic tick */ + __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_SET_WAKEUPENA); + else + __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA); break; +#endif +#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_CONTROL; l = __raw_readl(reg); @@ -466,11 +547,13 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) else goto bad; break; +#endif +#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: - set_24xx_gpio_triggering(reg, gpio, trigger); + set_24xx_gpio_triggering(bank, gpio, trigger); break; +#endif default: - BUG(); goto bad; } __raw_writel(l, reg); @@ -485,7 +568,7 @@ static int gpio_irq_type(unsigned irq, unsigned type) unsigned gpio; int retval; - if (irq > IH_MPUIO_BASE) + if (!cpu_is_omap24xx() && irq > IH_MPUIO_BASE) gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); else gpio = irq - IH_GPIO_BASE; @@ -493,14 +576,21 @@ static int gpio_irq_type(unsigned irq, unsigned type) if (check_gpio(gpio) < 0) return -EINVAL; - if (type & IRQT_PROBE) + if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; - if (!cpu_is_omap24xx() && (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL))) + + /* OMAP1 allows only only edge triggering */ + if (!cpu_is_omap24xx() + && (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) return -EINVAL; - bank = get_gpio_bank(gpio); + bank = get_irq_chip_data(irq); spin_lock(&bank->lock); retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type); + if (retval == 0) { + irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK; + irq_desc[irq].status |= type; + } spin_unlock(&bank->lock); return retval; } @@ -510,24 +600,34 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) void __iomem *reg = bank->base; switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: /* MPUIO irqstatus is reset by reading the status register, * so do nothing here */ return; +#endif +#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_STATUS; break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: reg += OMAP1610_GPIO_IRQSTATUS1; break; +#endif +#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_STATUS; break; +#endif +#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_IRQSTATUS1; break; +#endif default: - BUG(); + WARN_ON(1); return; } __raw_writel(gpio_mask, reg); @@ -550,31 +650,41 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) u32 mask; switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_MASKIT; mask = 0xffff; inv = 1; break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_MASK; mask = 0xffff; inv = 1; break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: reg += OMAP1610_GPIO_IRQENABLE1; mask = 0xffff; break; +#endif +#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_MASK; mask = 0xffffffff; inv = 1; break; +#endif +#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_IRQENABLE1; mask = 0xffffffff; break; +#endif default: - BUG(); + WARN_ON(1); return 0; } @@ -591,6 +701,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab u32 l; switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP1 case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_MASKIT; l = __raw_readl(reg); @@ -599,6 +710,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab else l |= gpio_mask; break; +#endif +#ifdef CONFIG_ARCH_OMAP15XX case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_MASK; l = __raw_readl(reg); @@ -607,6 +720,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab else l |= gpio_mask; break; +#endif +#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: if (enable) reg += OMAP1610_GPIO_SET_IRQENABLE1; @@ -614,6 +729,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab reg += OMAP1610_GPIO_CLEAR_IRQENABLE1; l = gpio_mask; break; +#endif +#ifdef CONFIG_ARCH_OMAP730 case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_MASK; l = __raw_readl(reg); @@ -622,6 +739,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab else l |= gpio_mask; break; +#endif +#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: if (enable) reg += OMAP24XX_GPIO_SETIRQENABLE1; @@ -629,8 +748,9 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab reg += OMAP24XX_GPIO_CLEARIRQENABLE1; l = gpio_mask; break; +#endif default: - BUG(); + WARN_ON(1); return; } __raw_writel(l, reg); @@ -652,15 +772,39 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) { switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP16XX + case METHOD_MPUIO: case METHOD_GPIO_1610: + spin_lock(&bank->lock); + if (enable) { + bank->suspend_wakeup |= (1 << gpio); + enable_irq_wake(bank->irq); + } else { + disable_irq_wake(bank->irq); + bank->suspend_wakeup &= ~(1 << gpio); + } + spin_unlock(&bank->lock); + return 0; +#endif +#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: + if (bank->non_wakeup_gpios & (1 << gpio)) { + printk(KERN_ERR "Unable to modify wakeup on " + "non-wakeup GPIO%d\n", + (bank - gpio_bank) * 32 + gpio); + return -EINVAL; + } spin_lock(&bank->lock); - if (enable) + if (enable) { bank->suspend_wakeup |= (1 << gpio); - else + enable_irq_wake(bank->irq); + } else { + disable_irq_wake(bank->irq); bank->suspend_wakeup &= ~(1 << gpio); + } spin_unlock(&bank->lock); return 0; +#endif default: printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n", bank->method); @@ -685,7 +829,7 @@ static int gpio_wake_enable(unsigned int irq, unsigned int enable) if (check_gpio(gpio) < 0) return -ENODEV; - bank = get_gpio_bank(gpio); + bank = get_irq_chip_data(irq); retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable); return retval; @@ -721,20 +865,6 @@ int omap_request_gpio(int gpio) reg = bank->base + OMAP1510_GPIO_PIN_CONTROL; __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg); } -#endif -#ifdef CONFIG_ARCH_OMAP16XX - if (bank->method == METHOD_GPIO_1610) { - /* Enable wake-up during idle for dynamic tick */ - void __iomem *reg = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; - __raw_writel(1 << get_gpio_index(gpio), reg); - } -#endif -#ifdef CONFIG_ARCH_OMAP24XX - if (bank->method == METHOD_GPIO_24XX) { - /* Enable wake-up during idle for dynamic tick */ - void __iomem *reg = bank->base + OMAP24XX_GPIO_SETWKUENA; - __raw_writel(1 << get_gpio_index(gpio), reg); - } #endif spin_unlock(&bank->lock); @@ -795,8 +925,10 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) desc->chip->ack(irq); bank = get_irq_data(irq); +#ifdef CONFIG_ARCH_OMAP1 if (bank->method == METHOD_MPUIO) isr_reg = bank->base + OMAP_MPUIO_GPIO_INT; +#endif #ifdef CONFIG_ARCH_OMAP15XX if (bank->method == METHOD_GPIO_1510) isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS; @@ -912,7 +1044,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) static void gpio_irq_shutdown(unsigned int irq) { unsigned int gpio = irq - IH_GPIO_BASE; - struct gpio_bank *bank = get_gpio_bank(gpio); + struct gpio_bank *bank = get_irq_chip_data(irq); _reset_gpio(bank, gpio); } @@ -920,7 +1052,7 @@ static void gpio_irq_shutdown(unsigned int irq) static void gpio_ack_irq(unsigned int irq) { unsigned int gpio = irq - IH_GPIO_BASE; - struct gpio_bank *bank = get_gpio_bank(gpio); + struct gpio_bank *bank = get_irq_chip_data(irq); _clear_gpio_irqstatus(bank, gpio); } @@ -928,7 +1060,7 @@ static void gpio_ack_irq(unsigned int irq) static void gpio_mask_irq(unsigned int irq) { unsigned int gpio = irq - IH_GPIO_BASE; - struct gpio_bank *bank = get_gpio_bank(gpio); + struct gpio_bank *bank = get_irq_chip_data(irq); _set_gpio_irqenable(bank, gpio, 0); } @@ -937,11 +1069,27 @@ static void gpio_unmask_irq(unsigned int irq) { unsigned int gpio = irq - IH_GPIO_BASE; unsigned int gpio_idx = get_gpio_index(gpio); - struct gpio_bank *bank = get_gpio_bank(gpio); + struct gpio_bank *bank = get_irq_chip_data(irq); _set_gpio_irqenable(bank, gpio_idx, 1); } +static struct irq_chip gpio_irq_chip = { + .name = "GPIO", + .shutdown = gpio_irq_shutdown, + .ack = gpio_ack_irq, + .mask = gpio_mask_irq, + .unmask = gpio_unmask_irq, + .set_type = gpio_irq_type, + .set_wake = gpio_wake_enable, +}; + +/*---------------------------------------------------------------------*/ + +#ifdef CONFIG_ARCH_OMAP1 + +/* MPUIO uses the always-on 32k clock */ + static void mpuio_ack_irq(unsigned int irq) { /* The ISR is reset automatically, so do nothing here. */ @@ -950,7 +1098,7 @@ static void mpuio_ack_irq(unsigned int irq) static void mpuio_mask_irq(unsigned int irq) { unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); - struct gpio_bank *bank = get_gpio_bank(gpio); + struct gpio_bank *bank = get_irq_chip_data(irq); _set_gpio_irqenable(bank, gpio, 0); } @@ -958,33 +1106,108 @@ static void mpuio_mask_irq(unsigned int irq) static void mpuio_unmask_irq(unsigned int irq) { unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); - struct gpio_bank *bank = get_gpio_bank(gpio); + struct gpio_bank *bank = get_irq_chip_data(irq); _set_gpio_irqenable(bank, gpio, 1); } -static struct irq_chip gpio_irq_chip = { - .name = "GPIO", - .shutdown = gpio_irq_shutdown, - .ack = gpio_ack_irq, - .mask = gpio_mask_irq, - .unmask = gpio_unmask_irq, +static struct irq_chip mpuio_irq_chip = { + .name = "MPUIO", + .ack = mpuio_ack_irq, + .mask = mpuio_mask_irq, + .unmask = mpuio_unmask_irq, .set_type = gpio_irq_type, +#ifdef CONFIG_ARCH_OMAP16XX + /* REVISIT: assuming only 16xx supports MPUIO wake events */ .set_wake = gpio_wake_enable, +#endif }; -static struct irq_chip mpuio_irq_chip = { - .name = "MPUIO", - .ack = mpuio_ack_irq, - .mask = mpuio_mask_irq, - .unmask = mpuio_unmask_irq, - .set_type = gpio_irq_type, + +#define bank_is_mpuio(bank) ((bank)->method == METHOD_MPUIO) + + +#ifdef CONFIG_ARCH_OMAP16XX + +#include + +static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t mesg) +{ + struct gpio_bank *bank = platform_get_drvdata(pdev); + void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT; + + spin_lock(&bank->lock); + bank->saved_wakeup = __raw_readl(mask_reg); + __raw_writel(0xffff & ~bank->suspend_wakeup, mask_reg); + spin_unlock(&bank->lock); + + return 0; +} + +static int omap_mpuio_resume_early(struct platform_device *pdev) +{ + struct gpio_bank *bank = platform_get_drvdata(pdev); + void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT; + + spin_lock(&bank->lock); + __raw_writel(bank->saved_wakeup, mask_reg); + spin_unlock(&bank->lock); + + return 0; +} + +/* use platform_driver for this, now that there's no longer any + * point to sys_device (other than not disturbing old code). + */ +static struct platform_driver omap_mpuio_driver = { + .suspend_late = omap_mpuio_suspend_late, + .resume_early = omap_mpuio_resume_early, + .driver = { + .name = "mpuio", + }, +}; + +static struct platform_device omap_mpuio_device = { + .name = "mpuio", + .id = -1, + .dev = { + .driver = &omap_mpuio_driver.driver, + } + /* could list the /proc/iomem resources */ }; +static inline void mpuio_init(void) +{ + platform_set_drvdata(&omap_mpuio_device, &gpio_bank_1610[0]); + + if (platform_driver_register(&omap_mpuio_driver) == 0) + (void) platform_device_register(&omap_mpuio_device); +} + +#else +static inline void mpuio_init(void) {} +#endif /* 16xx */ + +#else + +extern struct irq_chip mpuio_irq_chip; + +#define bank_is_mpuio(bank) 0 +static inline void mpuio_init(void) {} + +#endif + +/*---------------------------------------------------------------------*/ + static int initialized; static struct clk * gpio_ick; static struct clk * gpio_fck; +#ifdef CONFIG_ARCH_OMAP2430 +static struct clk * gpio5_ick; +static struct clk * gpio5_fck; +#endif + static int __init _omap_gpio_init(void) { int i; @@ -1010,7 +1233,25 @@ static int __init _omap_gpio_init(void) printk("Could not get gpios_fck\n"); else clk_enable(gpio_fck); - } + + /* + * On 2430 GPIO 5 uses CORE L4 ICLK + */ +#ifdef CONFIG_ARCH_OMAP2430 + if (cpu_is_omap2430()) { + gpio5_ick = clk_get(NULL, "gpio5_ick"); + if (IS_ERR(gpio5_ick)) + printk("Could not get gpio5_ick\n"); + else + clk_enable(gpio5_ick); + gpio5_fck = clk_get(NULL, "gpio5_fck"); + if (IS_ERR(gpio5_fck)) + printk("Could not get gpio5_fck\n"); + else + clk_enable(gpio5_fck); + } +#endif +} #ifdef CONFIG_ARCH_OMAP15XX if (cpu_is_omap15xx()) { @@ -1037,14 +1278,24 @@ static int __init _omap_gpio_init(void) gpio_bank = gpio_bank_730; } #endif + #ifdef CONFIG_ARCH_OMAP24XX - if (cpu_is_omap24xx()) { + if (cpu_is_omap242x()) { int rev; gpio_bank_count = 4; - gpio_bank = gpio_bank_24xx; + gpio_bank = gpio_bank_242x; + rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION); + printk(KERN_INFO "OMAP242x GPIO hardware version %d.%d\n", + (rev >> 4) & 0x0f, rev & 0x0f); + } + if (cpu_is_omap243x()) { + int rev; + + gpio_bank_count = 5; + gpio_bank = gpio_bank_243x; rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION); - printk(KERN_INFO "OMAP24xx GPIO hardware version %d.%d\n", + printk(KERN_INFO "OMAP243x GPIO hardware version %d.%d\n", (rev >> 4) & 0x0f, rev & 0x0f); } #endif @@ -1055,9 +1306,8 @@ static int __init _omap_gpio_init(void) bank->reserved_map = 0; bank->base = IO_ADDRESS(bank->base); spin_lock_init(&bank->lock); - if (bank->method == METHOD_MPUIO) { + if (bank_is_mpuio(bank)) omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT); - } #ifdef CONFIG_ARCH_OMAP15XX if (bank->method == METHOD_GPIO_1510) { __raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK); @@ -1081,15 +1331,25 @@ static int __init _omap_gpio_init(void) #endif #ifdef CONFIG_ARCH_OMAP24XX if (bank->method == METHOD_GPIO_24XX) { + static const u32 non_wakeup_gpios[] = { + 0xe203ffc0, 0x08700040 + }; + __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1); __raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1); + __raw_writew(0x0015, bank->base + OMAP24XX_GPIO_SYSCONFIG); + /* Initialize interface clock ungated, module enabled */ + __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL); + if (i < ARRAY_SIZE(non_wakeup_gpios)) + bank->non_wakeup_gpios = non_wakeup_gpios[i]; gpio_count = 32; } #endif for (j = bank->virtual_irq_start; j < bank->virtual_irq_start + gpio_count; j++) { - if (bank->method == METHOD_MPUIO) + set_irq_chip_data(j, bank); + if (bank_is_mpuio(bank)) set_irq_chip(j, &mpuio_irq_chip); else set_irq_chip(j, &gpio_irq_chip); @@ -1105,6 +1365,12 @@ static int __init _omap_gpio_init(void) if (cpu_is_omap16xx()) omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL); +#ifdef CONFIG_ARCH_OMAP24XX + /* Enable autoidle for the OCP interface */ + if (cpu_is_omap24xx()) + omap_writel(1 << 0, 0x48019010); +#endif + return 0; } @@ -1123,16 +1389,20 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) void __iomem *wake_set; switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE; wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; break; +#endif +#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: wake_status = bank->base + OMAP24XX_GPIO_SETWKUENA; wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA; break; +#endif default: continue; } @@ -1160,14 +1430,18 @@ static int omap_gpio_resume(struct sys_device *dev) void __iomem *wake_set; switch (bank->method) { +#ifdef CONFIG_ARCH_OMAP16XX case METHOD_GPIO_1610: wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; break; +#endif +#ifdef CONFIG_ARCH_OMAP24XX case METHOD_GPIO_24XX: wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA; break; +#endif default: continue; } @@ -1191,6 +1465,80 @@ static struct sys_device omap_gpio_device = { .id = 0, .cls = &omap_gpio_sysclass, }; + +#endif + +#ifdef CONFIG_ARCH_OMAP24XX + +static int workaround_enabled; + +void omap2_gpio_prepare_for_retention(void) +{ + int i, c = 0; + + /* Remove triggering for all non-wakeup GPIOs. Otherwise spurious + * IRQs will be generated. See OMAP2420 Errata item 1.101. */ + for (i = 0; i < gpio_bank_count; i++) { + struct gpio_bank *bank = &gpio_bank[i]; + u32 l1, l2; + + if (!(bank->enabled_non_wakeup_gpios)) + continue; + bank->saved_datain = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); + l1 = __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT); + l2 = __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT); + bank->saved_fallingdetect = l1; + bank->saved_risingdetect = l2; + l1 &= ~bank->enabled_non_wakeup_gpios; + l2 &= ~bank->enabled_non_wakeup_gpios; + __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT); + __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT); + c++; + } + if (!c) { + workaround_enabled = 0; + return; + } + workaround_enabled = 1; +} + +void omap2_gpio_resume_after_retention(void) +{ + int i; + + if (!workaround_enabled) + return; + for (i = 0; i < gpio_bank_count; i++) { + struct gpio_bank *bank = &gpio_bank[i]; + u32 l; + + if (!(bank->enabled_non_wakeup_gpios)) + continue; + __raw_writel(bank->saved_fallingdetect, + bank->base + OMAP24XX_GPIO_FALLINGDETECT); + __raw_writel(bank->saved_risingdetect, + bank->base + OMAP24XX_GPIO_RISINGDETECT); + /* Check if any of the non-wakeup interrupt GPIOs have changed + * state. If so, generate an IRQ by software. This is + * horribly racy, but it's the best we can do to work around + * this silicon bug. */ + l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN); + l ^= bank->saved_datain; + l &= bank->non_wakeup_gpios; + if (l) { + u32 old0, old1; + + old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0); + old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); + __raw_writel(old0 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT0); + __raw_writel(old1 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT1); + __raw_writel(old0, bank->base + OMAP24XX_GPIO_LEVELDETECT0); + __raw_writel(old1, bank->base + OMAP24XX_GPIO_LEVELDETECT1); + } + } + +} + #endif /* @@ -1212,6 +1560,8 @@ static int __init omap_gpio_sysinit(void) if (!initialized) ret = _omap_gpio_init(); + mpuio_init(); + #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) if (cpu_is_omap16xx() || cpu_is_omap24xx()) { if (ret == 0) { @@ -1232,3 +1582,128 @@ EXPORT_SYMBOL(omap_set_gpio_dataout); EXPORT_SYMBOL(omap_get_gpio_datain); arch_initcall(omap_gpio_sysinit); + + +#ifdef CONFIG_DEBUG_FS + +#include +#include + +static int gpio_is_input(struct gpio_bank *bank, int mask) +{ + void __iomem *reg = bank->base; + + switch (bank->method) { + case METHOD_MPUIO: + reg += OMAP_MPUIO_IO_CNTL; + break; + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_DIR_CONTROL; + break; + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_DIRECTION; + break; + case METHOD_GPIO_730: + reg += OMAP730_GPIO_DIR_CONTROL; + break; + case METHOD_GPIO_24XX: + reg += OMAP24XX_GPIO_OE; + break; + } + return __raw_readl(reg) & mask; +} + + +static int dbg_gpio_show(struct seq_file *s, void *unused) +{ + unsigned i, j, gpio; + + for (i = 0, gpio = 0; i < gpio_bank_count; i++) { + struct gpio_bank *bank = gpio_bank + i; + unsigned bankwidth = 16; + u32 mask = 1; + + if (bank_is_mpuio(bank)) + gpio = OMAP_MPUIO(0); + else if (cpu_is_omap24xx() || cpu_is_omap730()) + bankwidth = 32; + + for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) { + unsigned irq, value, is_in, irqstat; + + if (!(bank->reserved_map & mask)) + continue; + + irq = bank->virtual_irq_start + j; + value = omap_get_gpio_datain(gpio); + is_in = gpio_is_input(bank, mask); + + if (bank_is_mpuio(bank)) + seq_printf(s, "MPUIO %2d: ", j); + else + seq_printf(s, "GPIO %3d: ", gpio); + seq_printf(s, "%s %s", + is_in ? "in " : "out", + value ? "hi" : "lo"); + + irqstat = irq_desc[irq].status; + if (is_in && ((bank->suspend_wakeup & mask) + || irqstat & IRQ_TYPE_SENSE_MASK)) { + char *trigger = NULL; + + switch (irqstat & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_FALLING: + trigger = "falling"; + break; + case IRQ_TYPE_EDGE_RISING: + trigger = "rising"; + break; + case IRQ_TYPE_EDGE_BOTH: + trigger = "bothedge"; + break; + case IRQ_TYPE_LEVEL_LOW: + trigger = "low"; + break; + case IRQ_TYPE_LEVEL_HIGH: + trigger = "high"; + break; + case IRQ_TYPE_NONE: + trigger = "(unspecified)"; + break; + } + seq_printf(s, ", irq-%d %s%s", + irq, trigger, + (bank->suspend_wakeup & mask) + ? " wakeup" : ""); + } + seq_printf(s, "\n"); + } + + if (bank_is_mpuio(bank)) { + seq_printf(s, "\n"); + gpio = 0; + } + } + return 0; +} + +static int dbg_gpio_open(struct inode *inode, struct file *file) +{ + return single_open(file, dbg_gpio_show, &inode->i_private); +} + +static const struct file_operations debug_fops = { + .open = dbg_gpio_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init omap_gpio_debuginit(void) +{ + (void) debugfs_create_file("omap_gpio", S_IRUGO, + NULL, NULL, &debug_fops); + return 0; +} +late_initcall(omap_gpio_debuginit); +#endif diff --git a/trunk/arch/arm/plat-omap/mcbsp.c b/trunk/arch/arm/plat-omap/mcbsp.c index b8d6f17ff58f..f7b9ccdaacbc 100644 --- a/trunk/arch/arm/plat-omap/mcbsp.c +++ b/trunk/arch/arm/plat-omap/mcbsp.c @@ -225,11 +225,16 @@ static void omap_mcbsp_dsp_free(void) #ifdef CONFIG_ARCH_OMAP2 static void omap2_mcbsp2_mux_setup(void) { - omap_cfg_reg(Y15_24XX_MCBSP2_CLKX); - omap_cfg_reg(R14_24XX_MCBSP2_FSX); - omap_cfg_reg(W15_24XX_MCBSP2_DR); - omap_cfg_reg(V15_24XX_MCBSP2_DX); - omap_cfg_reg(V14_24XX_GPIO117); + if (cpu_is_omap2420()) { + omap_cfg_reg(Y15_24XX_MCBSP2_CLKX); + omap_cfg_reg(R14_24XX_MCBSP2_FSX); + omap_cfg_reg(W15_24XX_MCBSP2_DR); + omap_cfg_reg(V15_24XX_MCBSP2_DX); + omap_cfg_reg(V14_24XX_GPIO117); + } + /* + * Need to add MUX settings for OMAP 2430 SDP + */ } #endif diff --git a/trunk/arch/arm/plat-omap/timer32k.c b/trunk/arch/arm/plat-omap/timer32k.c index 265310601161..2feceec8eccd 100644 --- a/trunk/arch/arm/plat-omap/timer32k.c +++ b/trunk/arch/arm/plat-omap/timer32k.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include @@ -80,13 +82,13 @@ struct sys_timer omap_timer; #define OMAP1_32K_TIMER_TVR 0x00 #define OMAP1_32K_TIMER_TCR 0x04 -#define OMAP_32K_TICKS_PER_HZ (32768 / HZ) +#define OMAP_32K_TICKS_PER_SEC (32768) /* * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1 * so with HZ = 128, TVR = 255. */ -#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1) +#define OMAP_32K_TIMER_TICK_PERIOD ((OMAP_32K_TICKS_PER_SEC / HZ) - 1) #define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ (((nr_jiffies) * (clock_rate)) / HZ) @@ -142,6 +144,28 @@ static inline void omap_32k_timer_ack_irq(void) #endif +static void omap_32k_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_PERIODIC: + omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + omap_32k_timer_stop(); + break; + } +} + +static struct clock_event_device clockevent_32k_timer = { + .name = "32k-timer", + .features = CLOCK_EVT_FEAT_PERIODIC, + .shift = 32, + .set_mode = omap_32k_timer_set_mode, +}; + /* * The 32KHz synchronized timer is an additional timer on 16xx. * It is always running. @@ -170,15 +194,6 @@ omap_32k_ticks_to_nsecs(unsigned long ticks_32k) static unsigned long omap_32k_last_tick = 0; -/* - * Returns elapsed usecs since last 32k timer interrupt - */ -static unsigned long omap_32k_timer_gettimeoffset(void) -{ - unsigned long now = omap_32k_sync_timer_read(); - return omap_32k_ticks_to_usecs(now - omap_32k_last_tick); -} - /* * Returns current time from boot in nsecs. It's OK for this to wrap * around for now, as it's just a relative time stamp. @@ -188,110 +203,26 @@ unsigned long long sched_clock(void) return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read()); } -/* - * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this - * function is also called from other interrupts to remove latency - * issues with dynamic tick. In the dynamic tick case, we need to lock - * with irqsave. - */ -static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id) -{ - unsigned long now; - - omap_32k_timer_ack_irq(); - now = omap_32k_sync_timer_read(); - - while ((signed long)(now - omap_32k_last_tick) - >= OMAP_32K_TICKS_PER_HZ) { - omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ; - timer_tick(); - } - - /* Restart timer so we don't drift off due to modulo or dynamic tick. - * By default we program the next timer to be continuous to avoid - * latencies during high system load. During dynamic tick operation the - * continuous timer can be overridden from pm_idle to be longer. - */ - omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now); - - return IRQ_HANDLED; -} - -static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id) -{ - return _omap_32k_timer_interrupt(irq, dev_id); -} - static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id) { - unsigned long flags; + struct clock_event_device *evt = &clockevent_32k_timer; + omap_32k_timer_ack_irq(); - write_seqlock_irqsave(&xtime_lock, flags); - _omap_32k_timer_interrupt(irq, dev_id); - write_sequnlock_irqrestore(&xtime_lock, flags); + evt->event_handler(evt); return IRQ_HANDLED; } -#ifdef CONFIG_NO_IDLE_HZ -/* - * Programs the next timer interrupt needed. Called when dynamic tick is - * enabled, and to reprogram the ticks to skip from pm_idle. Note that - * we can keep the timer continuous, and don't need to set it to run in - * one-shot mode. This is because the timer will get reprogrammed again - * after next interrupt. - */ -void omap_32k_timer_reprogram(unsigned long next_tick) -{ - unsigned long ticks = JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1; - unsigned long now = omap_32k_sync_timer_read(); - unsigned long idled = now - omap_32k_last_tick; - - if (idled + 1 < ticks) - ticks -= idled; - else - ticks = 1; - omap_32k_timer_start(ticks); -} - -static struct irqaction omap_32k_timer_irq; -extern struct timer_update_handler timer_update; - -static int omap_32k_timer_enable_dyn_tick(void) -{ - /* No need to reprogram timer, just use the next interrupt */ - return 0; -} - -static int omap_32k_timer_disable_dyn_tick(void) -{ - omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); - return 0; -} - -static struct dyn_tick_timer omap_dyn_tick_timer = { - .enable = omap_32k_timer_enable_dyn_tick, - .disable = omap_32k_timer_disable_dyn_tick, - .reprogram = omap_32k_timer_reprogram, - .handler = omap_32k_timer_handler, -}; -#endif /* CONFIG_NO_IDLE_HZ */ - static struct irqaction omap_32k_timer_irq = { .name = "32KHz timer", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = omap_32k_timer_interrupt, }; static __init void omap_init_32k_timer(void) { -#ifdef CONFIG_NO_IDLE_HZ - omap_timer.dyn_tick = &omap_dyn_tick_timer; -#endif - if (cpu_class_is_omap1()) setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); - omap_timer.offset = omap_32k_timer_gettimeoffset; omap_32k_last_tick = omap_32k_sync_timer_read(); #ifdef CONFIG_ARCH_OMAP2 @@ -308,7 +239,16 @@ static __init void omap_init_32k_timer(void) } #endif - omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); + clockevent_32k_timer.mult = div_sc(OMAP_32K_TICKS_PER_SEC, + NSEC_PER_SEC, + clockevent_32k_timer.shift); + clockevent_32k_timer.max_delta_ns = + clockevent_delta2ns(0xfffffffe, &clockevent_32k_timer); + clockevent_32k_timer.min_delta_ns = + clockevent_delta2ns(1, &clockevent_32k_timer); + + clockevent_32k_timer.cpumask = cpumask_of_cpu(0); + clockevents_register_device(&clockevent_32k_timer); } /* @@ -326,5 +266,4 @@ static void __init omap_timer_init(void) struct sys_timer omap_timer = { .init = omap_timer_init, - .offset = NULL, /* Initialized later */ }; diff --git a/trunk/arch/arm/plat-s3c24xx/clock.c b/trunk/arch/arm/plat-s3c24xx/clock.c index d3dc03a7383a..79cda0faec86 100644 --- a/trunk/arch/arm/plat-s3c24xx/clock.c +++ b/trunk/arch/arm/plat-s3c24xx/clock.c @@ -404,6 +404,18 @@ int s3c24xx_register_clock(struct clk *clk) return 0; } +int s3c24xx_register_clocks(struct clk **clks, int nr_clks) +{ + int fails = 0; + + for (; nr_clks > 0; nr_clks--, clks++) { + if (s3c24xx_register_clock(*clks) < 0) + fails++; + } + + return fails; +} + /* initalise all the clocks */ int __init s3c24xx_setup_clocks(unsigned long xtal, diff --git a/trunk/arch/arm/plat-s3c24xx/cpu.c b/trunk/arch/arm/plat-s3c24xx/cpu.c index 6a2d1070e5a0..8ce4904d3131 100644 --- a/trunk/arch/arm/plat-s3c24xx/cpu.c +++ b/trunk/arch/arm/plat-s3c24xx/cpu.c @@ -181,24 +181,6 @@ s3c_lookup_cpu(unsigned long idcode) return NULL; } -/* board information */ - -static struct s3c24xx_board *board; - -void s3c24xx_set_board(struct s3c24xx_board *b) -{ - int i; - - board = b; - - if (b->clocks_count != 0) { - struct clk **ptr = b->clocks; - - for (i = b->clocks_count; i > 0; i--, ptr++) - s3c24xx_register_clock(*ptr); - } -} - /* cpu information */ static struct cpu_table *cpu; @@ -342,26 +324,6 @@ static int __init s3c_arch_init(void) return ret; ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts); - if (ret != 0) - return ret; - - if (board != NULL) { - struct platform_device **ptr = board->devices; - int i; - - for (i = 0; i < board->devices_count; i++, ptr++) { - ret = platform_device_register(*ptr); - - if (ret) { - printk(KERN_ERR "s3c24xx: failed to add board device %s (%d) @%p\n", (*ptr)->name, ret, *ptr); - } - } - - /* mask any error, we may not need all these board - * devices */ - ret = 0; - } - return ret; } diff --git a/trunk/arch/arm/plat-s3c24xx/dma.c b/trunk/arch/arm/plat-s3c24xx/dma.c index 4540a806f522..6f03c9370979 100644 --- a/trunk/arch/arm/plat-s3c24xx/dma.c +++ b/trunk/arch/arm/plat-s3c24xx/dma.c @@ -44,7 +44,7 @@ static struct kmem_cache *dma_kmem; static int dma_channels; -struct s3c24xx_dma_selection dma_sel; +static struct s3c24xx_dma_selection dma_sel; /* dma channel state information */ struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS]; @@ -880,7 +880,7 @@ static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan) return 0; } -void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan) +static void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan) { unsigned long tmp; unsigned int timeout = 0x10000; @@ -957,8 +957,7 @@ static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan) return 0; } -int -s3c2410_dma_started(struct s3c2410_dma_chan *chan) +static int s3c2410_dma_started(struct s3c2410_dma_chan *chan) { unsigned long flags; @@ -1280,7 +1279,7 @@ static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long /* initialisation code */ -int __init s3c24xx_dma_sysclass_init(void) +static int __init s3c24xx_dma_sysclass_init(void) { int ret = sysdev_class_register(&dma_sysclass); @@ -1292,7 +1291,7 @@ int __init s3c24xx_dma_sysclass_init(void) core_initcall(s3c24xx_dma_sysclass_init); -int __init s3c24xx_dma_sysdev_register(void) +static int __init s3c24xx_dma_sysdev_register(void) { struct s3c2410_dma_chan *cp = s3c2410_chans; int channel, ret; @@ -1396,7 +1395,7 @@ static struct s3c24xx_dma_order *dma_order; * channel */ -struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel) +static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel) { struct s3c24xx_dma_order_ch *ord = NULL; struct s3c24xx_dma_map *ch_map; diff --git a/trunk/arch/arm/plat-s3c24xx/irq.c b/trunk/arch/arm/plat-s3c24xx/irq.c index ce186398e3fd..8fbc88470261 100644 --- a/trunk/arch/arm/plat-s3c24xx/irq.c +++ b/trunk/arch/arm/plat-s3c24xx/irq.c @@ -54,7 +54,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/plat-s3c24xx/s3c244x-irq.c b/trunk/arch/arm/plat-s3c24xx/s3c244x-irq.c index a0e39d894014..2dbb2606d448 100644 --- a/trunk/arch/arm/plat-s3c24xx/s3c244x-irq.c +++ b/trunk/arch/arm/plat-s3c24xx/s3c244x-irq.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm/plat-s3c24xx/time.c b/trunk/arch/arm/plat-s3c24xx/time.c index c523d1c9cce5..b7667375bcec 100644 --- a/trunk/arch/arm/plat-s3c24xx/time.c +++ b/trunk/arch/arm/plat-s3c24xx/time.c @@ -138,7 +138,7 @@ s3c2410_timer_interrupt(int irq, void *dev_id) static struct irqaction s3c2410_timer_irq = { .name = "S3C2410 Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = s3c2410_timer_interrupt, }; diff --git a/trunk/arch/arm/vfp/vfpdouble.c b/trunk/arch/arm/vfp/vfpdouble.c index e44b9ed0f81f..74e89f8fb3ab 100644 --- a/trunk/arch/arm/vfp/vfpdouble.c +++ b/trunk/arch/arm/vfp/vfpdouble.c @@ -34,7 +34,6 @@ #include #include -#include #include #include "vfpinstr.h" diff --git a/trunk/arch/arm/vfp/vfpsingle.c b/trunk/arch/arm/vfp/vfpsingle.c index 0221ba3bc799..b252631b406b 100644 --- a/trunk/arch/arm/vfp/vfpsingle.c +++ b/trunk/arch/arm/vfp/vfpsingle.c @@ -34,7 +34,6 @@ #include #include -#include #include #include "vfpinstr.h" diff --git a/trunk/arch/arm26/Kconfig b/trunk/arch/arm26/Kconfig index 989113dce415..20688bc13e9b 100644 --- a/trunk/arch/arm26/Kconfig +++ b/trunk/arch/arm26/Kconfig @@ -57,9 +57,6 @@ config GENERIC_CALIBRATE_DELAY bool default y -config GENERIC_BUST_SPINLOCK - bool - config ZONE_DMA bool default y diff --git a/trunk/arch/arm26/kernel/armksyms.c b/trunk/arch/arm26/kernel/armksyms.c index 93293d04b303..f735d7e018e4 100644 --- a/trunk/arch/arm26/kernel/armksyms.c +++ b/trunk/arch/arm26/kernel/armksyms.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/arm26/kernel/ptrace.c b/trunk/arch/arm26/kernel/ptrace.c index 9343889b27fe..416927956721 100644 --- a/trunk/arch/arm26/kernel/ptrace.c +++ b/trunk/arch/arm26/kernel/ptrace.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/arm26/kernel/signal.c b/trunk/arch/arm26/kernel/signal.c index 6a8ef8da6dab..379b82dc645f 100644 --- a/trunk/arch/arm26/kernel/signal.c +++ b/trunk/arch/arm26/kernel/signal.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/arm26/mm/memc.c b/trunk/arch/arm26/mm/memc.c index f2901581d4da..42505541a9b1 100644 --- a/trunk/arch/arm26/mm/memc.c +++ b/trunk/arch/arm26/mm/memc.c @@ -176,13 +176,9 @@ void __init pgtable_cache_init(void) { pte_cache = kmem_cache_create("pte-cache", sizeof(pte_t) * PTRS_PER_PTE, - 0, 0, pte_cache_ctor, NULL); - if (!pte_cache) - BUG(); + 0, SLAB_PANIC, pte_cache_ctor, NULL); pgd_cache = kmem_cache_create("pgd-cache", MEMC_TABLE_SIZE + sizeof(pgd_t) * PTRS_PER_PGD, - 0, 0, pgd_cache_ctor, NULL); - if (!pgd_cache) - BUG(); + 0, SLAB_PANIC, pgd_cache_ctor, NULL); } diff --git a/trunk/arch/avr32/kernel/kprobes.c b/trunk/arch/avr32/kernel/kprobes.c index d0abbcaf1c1e..004c94b6fc1d 100644 --- a/trunk/arch/avr32/kernel/kprobes.c +++ b/trunk/arch/avr32/kernel/kprobes.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include DEFINE_PER_CPU(struct kprobe *, current_kprobe); diff --git a/trunk/arch/avr32/kernel/ptrace.c b/trunk/arch/avr32/kernel/ptrace.c index 6f4388f7c20b..8ac74dddbbde 100644 --- a/trunk/arch/avr32/kernel/ptrace.c +++ b/trunk/arch/avr32/kernel/ptrace.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -21,7 +20,7 @@ #include #include #include -#include +#include static struct pt_regs *get_user_regs(struct task_struct *tsk) { @@ -300,7 +299,7 @@ asmlinkage void do_debug_priv(struct pt_regs *regs) else die_val = DIE_BREAKPOINT; - if (notify_die(die_val, regs, 0, SIGTRAP) == NOTIFY_STOP) + if (notify_die(die_val, "ptrace", regs, 0, 0, SIGTRAP) == NOTIFY_STOP) return; if (likely(ds & DS_SSS)) { diff --git a/trunk/arch/avr32/kernel/traps.c b/trunk/arch/avr32/kernel/traps.c index 4f0382d8483f..4de9edf96ed2 100644 --- a/trunk/arch/avr32/kernel/traps.c +++ b/trunk/arch/avr32/kernel/traps.c @@ -20,20 +20,6 @@ #include #include -ATOMIC_NOTIFIER_HEAD(avr32_die_chain); - -int register_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&avr32_die_chain, nb); -} -EXPORT_SYMBOL(register_die_notifier); - -int unregister_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&avr32_die_chain, nb); -} -EXPORT_SYMBOL(unregister_die_notifier); - static DEFINE_SPINLOCK(die_lock); void NORET_TYPE die(const char *str, struct pt_regs *regs, long err) diff --git a/trunk/arch/avr32/mm/fault.c b/trunk/arch/avr32/mm/fault.c index 146ebdbdc302..88b00b15970f 100644 --- a/trunk/arch/avr32/mm/fault.c +++ b/trunk/arch/avr32/mm/fault.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include diff --git a/trunk/arch/blackfin/Kconfig b/trunk/arch/blackfin/Kconfig new file mode 100644 index 000000000000..1a4930509325 --- /dev/null +++ b/trunk/arch/blackfin/Kconfig @@ -0,0 +1,989 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# + +mainmenu "uClinux/Blackfin (w/o MMU) Kernel Configuration" + +config MMU + bool + default n + +config FPU + bool + default n + +config RWSEM_GENERIC_SPINLOCK + bool + default y + +config RWSEM_XCHGADD_ALGORITHM + bool + default n + +config BLACKFIN + bool + default y + +config BFIN + bool + default y + +config SEMAPHORE_SLEEPERS + bool + default y + +config GENERIC_FIND_NEXT_BIT + bool + default y + +config GENERIC_HWEIGHT + bool + default y + +config GENERIC_HARDIRQS + bool + default y + +config GENERIC_IRQ_PROBE + bool + default y + +config GENERIC_TIME + bool + default n + +config GENERIC_CALIBRATE_DELAY + bool + default y + +config FORCE_MAX_ZONEORDER + int + default "14" + +config GENERIC_CALIBRATE_DELAY + bool + default y + +config IRQCHIP_DEMUX_GPIO + bool + default y + +source "init/Kconfig" +source "kernel/Kconfig.preempt" + +menu "Blackfin Processor Options" + +comment "Processor and Board Settings" + +choice + prompt "CPU" + default BF533 + +config BF531 + bool "BF531" + help + BF531 Processor Support. + +config BF532 + bool "BF532" + help + BF532 Processor Support. + +config BF533 + bool "BF533" + help + BF533 Processor Support. + +config BF534 + bool "BF534" + help + BF534 Processor Support. + +config BF536 + bool "BF536" + help + BF536 Processor Support. + +config BF537 + bool "BF537" + help + BF537 Processor Support. + +config BF561 + bool "BF561" + help + Not Supported Yet - Work in progress - BF561 Processor Support. + +endchoice + +choice + prompt "Silicon Rev" + default BF_REV_0_2 if BF537 + default BF_REV_0_3 if BF533 + +config BF_REV_0_2 + bool "0.2" + depends on (BF537 || BF536 || BF534) + +config BF_REV_0_3 + bool "0.3" + depends on (BF561 || BF537 || BF536 || BF534 || BF533 || BF532 || BF531) + +config BF_REV_0_4 + bool "0.4" + depends on (BF561 || BF533 || BF532 || BF531) + +config BF_REV_0_5 + bool "0.5" + depends on (BF561 || BF533 || BF532 || BF531) + +endchoice + +config BFIN_DUAL_CORE + bool + depends on (BF561) + default y + +config BFIN_SINGLE_CORE + bool + depends on !BFIN_DUAL_CORE + default y + +choice + prompt "System type" + default BFIN533_STAMP + help + Do NOT change the board here. Please use the top level + configuration to ensure that all the other settings are + correct. + +config BFIN533_EZKIT + bool "BF533-EZKIT" + depends on (BF533 || BF532 || BF531) + help + BF533-EZKIT-LITE board Support. + +config BFIN533_STAMP + bool "BF533-STAMP" + depends on (BF533 || BF532 || BF531) + help + BF533-STAMP board Support. + +config BFIN537_STAMP + bool "BF537-STAMP" + depends on (BF537 || BF536 || BF534) + help + BF537-STAMP board Support. + +config BFIN533_BLUETECHNIX_CM + bool "Bluetechnix CM-BF533" + depends on (BF533) + help + CM-BF533 support for EVAL- and DEV-Board. + +config BFIN537_BLUETECHNIX_CM + bool "Bluetechnix CM-BF537" + depends on (BF537) + help + CM-BF537 support for EVAL- and DEV-Board. + +config BFIN561_BLUETECHNIX_CM + bool "BF561-CM" + depends on (BF561) + help + CM-BF561 support for EVAL- and DEV-Board. + +config BFIN561_EZKIT + bool "BF561-EZKIT" + depends on (BF561) + help + BF561-EZKIT-LITE board Support. + +config PNAV10 + bool "PNAV 1.0 board" + depends on (BF537) + help + PNAV 1.0 board Support. + +config GENERIC_BOARD + bool "Custom" + depends on (BF537 || BF536 \ + || BF534 || BF561 || BF535 || BF533 || BF532 || BF531) + help + GENERIC or Custom board Support. + +endchoice + +config MEM_GENERIC_BOARD + bool + depends on GENERIC_BOARD + default y + +config MEM_MT48LC64M4A2FB_7E + bool + depends on (BFIN533_STAMP) + default y + +config MEM_MT48LC16M16A2TG_75 + bool + depends on (BFIN533_EZKIT || BFIN561_EZKIT \ + || BFIN533_BLUETECHNIX_CM || BFIN537_BLUETECHNIX_CM) + default y + +config MEM_MT48LC32M8A2_75 + bool + depends on (BFIN537_STAMP || PNAV10) + default y + +config MEM_MT48LC8M32B2B5_7 + bool + depends on (BFIN561_BLUETECHNIX_CM) + default y + +config BFIN_SHARED_FLASH_ENET + bool + depends on (BFIN533_STAMP) + default y + +source "arch/blackfin/mach-bf533/Kconfig" +source "arch/blackfin/mach-bf561/Kconfig" +source "arch/blackfin/mach-bf537/Kconfig" + +menu "Board customizations" + +config CMDLINE_BOOL + bool "Default bootloader kernel arguments" + +config CMDLINE + string "Initial kernel command string" + depends on CMDLINE_BOOL + default "console=ttyBF0,57600" + help + If you don't have a boot loader capable of passing a command line string + to the kernel, you may specify one here. As a minimum, you should specify + the memory size and the root device (e.g., mem=8M, root=/dev/nfs). + +comment "Board Setup" + +config CLKIN_HZ + int "Crystal Frequency in Hz" + default "11059200" if BFIN533_STAMP + default "27000000" if BFIN533_EZKIT + default "25000000" if BFIN537_STAMP + default "30000000" if BFIN561_EZKIT + default "24576000" if PNAV10 + help + The frequency of CLKIN crystal oscillator on the board in Hz. + +config MEM_SIZE + int "SDRAM Memory Size in MBytes" + default 32 if BFIN533_EZKIT + default 64 if BFIN537_STAMP + default 64 if BFIN561_EZKIT + default 128 if BFIN533_STAMP + default 64 if PNAV10 + +config MEM_ADD_WIDTH + int "SDRAM Memory Address Width" + default 9 if BFIN533_EZKIT + default 9 if BFIN561_EZKIT + default 10 if BFIN537_STAMP + default 11 if BFIN533_STAMP + default 10 if PNAV10 + +config ENET_FLASH_PIN + int "PF port/pin used for flash and ethernet sharing" + depends on (BFIN533_STAMP) + default 0 + help + PF port/pin used for flash and ethernet sharing to allow other PF + pins to be used on other platforms without having to touch common + code. + For example: PF0 --> 0,PF1 --> 1,PF2 --> 2, etc. + +config BOOT_LOAD + hex "Kernel load address for booting" + default "0x1000" + help + This option allows you to set the load address of the kernel. + This can be useful if you are on a board which has a small amount + of memory or you wish to reserve some memory at the beginning of + the address space. + + Note that you generally want to keep this value at or above 4k + (0x1000) as this will allow the kernel to capture NULL pointer + references. + +comment "LED Status Indicators" + depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM) + +config BFIN_ALIVE_LED + bool "Enable Board Alive" + depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM) + default n + help + Blink the LEDs you select when the kernel is running. Helps detect + a hung kernel. + +config BFIN_ALIVE_LED_NUM + int "LED" + depends on BFIN_ALIVE_LED + range 1 3 if BFIN533_STAMP + default "3" if BFIN533_STAMP + help + Select the LED (marked on the board) for you to blink. + +config BFIN_IDLE_LED + bool "Enable System Load/Idle LED" + depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM) + default n + help + Blinks the LED you select when to determine kernel load. + +config BFIN_IDLE_LED_NUM + int "LED" + depends on BFIN_IDLE_LED + range 1 3 if BFIN533_STAMP + default "2" if BFIN533_STAMP + help + Select the LED (marked on the board) for you to blink. + +# +# Sorry - but you need to put the hex address here - +# + +# Flag Data register +config BFIN_ALIVE_LED_PORT + hex + default 0xFFC00700 if (BFIN533_STAMP) + +# Peripheral Flag Direction Register +config BFIN_ALIVE_LED_DPORT + hex + default 0xFFC00730 if (BFIN533_STAMP) + +config BFIN_ALIVE_LED_PIN + hex + default 0x04 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 1) + default 0x08 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 2) + default 0x10 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 3) + +config BFIN_IDLE_LED_PORT + hex + default 0xFFC00700 if (BFIN533_STAMP) + +# Peripheral Flag Direction Register +config BFIN_IDLE_LED_DPORT + hex + default 0xFFC00730 if (BFIN533_STAMP) + +config BFIN_IDLE_LED_PIN + hex + default 0x04 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 1) + default 0x08 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 2) + default 0x10 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 3) + +comment "Console UART Setup" + +choice + prompt "Baud Rate" + default BAUD_57600 +config BAUD_9600 + bool "9600" +config BAUD_19200 + bool "19200" +config BAUD_38400 + bool "38400" +config BAUD_57600 + bool "57600" +config BAUD_115200 + bool "115200" +endchoice + +choice + prompt "Parity" + default BAUD_NO_PARITY +config BAUD_NO_PARITY + bool "No Parity" +config BAUD_PARITY + bool "Parity" +endchoice + +choice + prompt "Stop Bits" + default BAUD_1_STOPBIT +config BAUD_1_STOPBIT + bool "1" +config BAUD_2_STOPBIT + bool "2" +endchoice + +endmenu + + +menu "Blackfin Kernel Optimizations" + +comment "Timer Tick" + +source kernel/Kconfig.hz + +comment "Memory Optimizations" + +config I_ENTRY_L1 + bool "Locate interrupt entry code in L1 Memory" + default y + help + If enabled interrupt entry code (STORE/RESTORE CONTEXT) is linked + into L1 instruction memory.(less latency) + +config EXCPT_IRQ_SYSC_L1 + bool "Locate entire ASM lowlevel excepetion / interrupt - Syscall and CPLB handler code in L1 Memory" + default y + help + If enabled entire ASM lowlevel exception and interrupt entry code (STORE/RESTORE CONTEXT) is linked + into L1 instruction memory.(less latency) + +config DO_IRQ_L1 + bool "Locate frequently called do_irq dispatcher function in L1 Memory" + default y + help + If enabled frequently called do_irq dispatcher function is linked + into L1 instruction memory.(less latency) + +config CORE_TIMER_IRQ_L1 + bool "Locate frequently called timer_interrupt() function in L1 Memory" + default y + help + If enabled frequently called timer_interrupt() function is linked + into L1 instruction memory.(less latency) + +config IDLE_L1 + bool "Locate frequently idle function in L1 Memory" + default y + help + If enabled frequently called idle function is linked + into L1 instruction memory.(less latency) + +config SCHEDULE_L1 + bool "Locate kernel schedule function in L1 Memory" + default y + help + If enabled frequently called kernel schedule is linked + into L1 instruction memory.(less latency) + +config ARITHMETIC_OPS_L1 + bool "Locate kernel owned arithmetic functions in L1 Memory" + default y + help + If enabled arithmetic functions are linked + into L1 instruction memory.(less latency) + +config ACCESS_OK_L1 + bool "Locate access_ok function in L1 Memory" + default y + help + If enabled access_ok function is linked + into L1 instruction memory.(less latency) + +config MEMSET_L1 + bool "Locate memset function in L1 Memory" + default y + help + If enabled memset function is linked + into L1 instruction memory.(less latency) + +config MEMCPY_L1 + bool "Locate memcpy function in L1 Memory" + default y + help + If enabled memcpy function is linked + into L1 instruction memory.(less latency) + +config SYS_BFIN_SPINLOCK_L1 + bool "Locate sys_bfin_spinlock function in L1 Memory" + default y + help + If enabled sys_bfin_spinlock function is linked + into L1 instruction memory.(less latency) + +config IP_CHECKSUM_L1 + bool "Locate IP Checksum function in L1 Memory" + default n + help + If enabled IP Checksum function is linked + into L1 instruction memory.(less latency) + +config CACHELINE_ALIGNED_L1 + bool "Locate cacheline_aligned data to L1 Data Memory" + default y + depends on !BF531 + help + If enabled cacheline_anligned data is linked + into L1 data memory.(less latency) + +config SYSCALL_TAB_L1 + bool "Locate Syscall Table L1 Data Memory" + default n + depends on !BF531 + help + If enabled the Syscall LUT is linked + into L1 data memory.(less latency) + +config CPLB_SWITCH_TAB_L1 + bool "Locate CPLB Switch Tables L1 Data Memory" + default n + depends on !BF531 + help + If enabled the CPLB Switch Tables are linked + into L1 data memory.(less latency) + +endmenu + + +choice + prompt "Kernel executes from" + help + Choose the memory type that the kernel will be running in. + +config RAMKERNEL + bool "RAM" + help + The kernel will be resident in RAM when running. + +config ROMKERNEL + bool "ROM" + help + The kernel will be resident in FLASH/ROM when running. + +endchoice + +source "mm/Kconfig" + +config LARGE_ALLOCS + bool "Allow allocating large blocks (> 1MB) of memory" + help + Allow the slab memory allocator to keep chains for very large + memory sizes - upto 32MB. You may need this if your system has + a lot of RAM, and you need to able to allocate very large + contiguous chunks. If unsure, say N. + +config BFIN_DMA_5XX + bool "Enable DMA Support" + depends on (BF533 || BF532 || BF531 || BF537 || BF536 || BF534 || BF561) + default y + help + DMA driver for BF5xx. + +choice + prompt "Uncached SDRAM region" + default DMA_UNCACHED_1M + depends BFIN_DMA_5XX +config DMA_UNCACHED_2M + bool "Enable 2M DMA region" +config DMA_UNCACHED_1M + bool "Enable 1M DMA region" +config DMA_UNCACHED_NONE + bool "Disable DMA region" +endchoice + + +comment "Cache Support" +config BLKFIN_CACHE + bool "Enable ICACHE" +config BLKFIN_DCACHE + bool "Enable DCACHE" +config BLKFIN_DCACHE_BANKA + bool "Enable only 16k BankA DCACHE - BankB is SRAM" + depends on BLKFIN_DCACHE && !BF531 + default n +config BLKFIN_CACHE_LOCK + bool "Enable Cache Locking" + +choice + prompt "Policy" + depends on BLKFIN_DCACHE + default BLKFIN_WB +config BLKFIN_WB + bool "Write back" + help + Write Back Policy: + Cached data will be written back to SDRAM only when needed. + This can give a nice increase in performance, but beware of + broken drivers that do not properly invalidate/flush their + cache. + + Write Through Policy: + Cached data will always be written back to SDRAM when the + cache is updated. This is a completely safe setting, but + performance is worse than Write Back. + + If you are unsure of the options and you want to be safe, + then go with Write Through. + +config BLKFIN_WT + bool "Write through" + help + Write Back Policy: + Cached data will be written back to SDRAM only when needed. + This can give a nice increase in performance, but beware of + broken drivers that do not properly invalidate/flush their + cache. + + Write Through Policy: + Cached data will always be written back to SDRAM when the + cache is updated. This is a completely safe setting, but + performance is worse than Write Back. + + If you are unsure of the options and you want to be safe, + then go with Write Through. + +endchoice + +config L1_MAX_PIECE + int "Set the max L1 SRAM pieces" + default 16 + help + Set the max memory pieces for the L1 SRAM allocation algorithm. + Min value is 16. Max value is 1024. + +menu "Clock Settings" + + +config BFIN_KERNEL_CLOCK + bool "Re-program Clocks while Kernel boots?" + default n + help + This option decides if kernel clocks are re-programed from the + bootloader settings. If the clocks are not set, the SDRAM settings + are also not changed, and the Bootloader does 100% of the hardware + configuration. + +config VCO_MULT + int "VCO Multiplier" + depends on BFIN_KERNEL_CLOCK + default "22" if BFIN533_EZKIT + default "45" if BFIN533_STAMP + default "20" if BFIN537_STAMP + default "22" if BFIN533_BLUETECHNIX_CM + default "20" if BFIN537_BLUETECHNIX_CM + default "20" if BFIN561_BLUETECHNIX_CM + default "20" if BFIN561_EZKIT + +config CCLK_DIV + int "Core Clock Divider" + depends on BFIN_KERNEL_CLOCK + default 1 if BFIN533_EZKIT + default 1 if BFIN533_STAMP + default 1 if BFIN537_STAMP + default 1 if BFIN533_BLUETECHNIX_CM + default 1 if BFIN537_BLUETECHNIX_CM + default 1 if BFIN561_BLUETECHNIX_CM + default 1 if BFIN561_EZKIT + +config SCLK_DIV + int "System Clock Divider" + depends on BFIN_KERNEL_CLOCK + default 5 if BFIN533_EZKIT + default 5 if BFIN533_STAMP + default 4 if BFIN537_STAMP + default 5 if BFIN533_BLUETECHNIX_CM + default 4 if BFIN537_BLUETECHNIX_CM + default 4 if BFIN561_BLUETECHNIX_CM + default 5 if BFIN561_EZKIT + +config CLKIN_HALF + bool "Half ClockIn" + depends on BFIN_KERNEL_CLOCK + default n + +config PLL_BYPASS + bool "Bypass PLL" + depends on BFIN_KERNEL_CLOCK + default n + +endmenu + +comment "Asynchonous Memory Configuration" + +menu "EBIU_AMBCTL Global Control" +config C_AMCKEN + bool "Enable CLKOUT" + default y + +config C_CDPRIO + bool "DMA has priority over core for ext. accesses" + default n + +config C_B0PEN + depends on BF561 + bool "Bank 0 16 bit packing enable" + default y + +config C_B1PEN + depends on BF561 + bool "Bank 1 16 bit packing enable" + default y + +config C_B2PEN + depends on BF561 + bool "Bank 2 16 bit packing enable" + default y + +config C_B3PEN + depends on BF561 + bool "Bank 3 16 bit packing enable" + default n + +choice + prompt"Enable Asynchonous Memory Banks" + default C_AMBEN_ALL + +config C_AMBEN + bool "Disable All Banks" + +config C_AMBEN_B0 + bool "Enable Bank 0" + +config C_AMBEN_B0_B1 + bool "Enable Bank 0 & 1" + +config C_AMBEN_B0_B1_B2 + bool "Enable Bank 0 & 1 & 2" + +config C_AMBEN_ALL + bool "Enable All Banks" +endchoice +endmenu + +menu "EBIU_AMBCTL Control" +config BANK_0 + hex "Bank 0" + default 0x7BB0 + +config BANK_1 + hex "Bank 1" + default 0x7BB0 + +config BANK_2 + hex "Bank 2" + default 0x7BB0 + +config BANK_3 + hex "Bank 3" + default 0x99B3 +endmenu + +endmenu + +############################################################################# +menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" + +config PCI + bool "PCI support" + help + Support for PCI bus. + +source "drivers/pci/Kconfig" + +config HOTPLUG + bool "Support for hot-pluggable device" + help + Say Y here if you want to plug devices into your computer while + the system is running, and be able to use them quickly. In many + cases, the devices can likewise be unplugged at any time too. + + One well known example of this is PCMCIA- or PC-cards, credit-card + size devices such as network cards, modems or hard drives which are + plugged into slots found on all modern laptop computers. Another + example, used on modern desktops as well as laptops, is USB. + + Enable HOTPLUG and KMOD, and build a modular kernel. Get agent + software (at ) and install it. + Then your kernel will automatically call out to a user mode "policy + agent" (/sbin/hotplug) to load modules and set up software needed + to use devices as you hotplug them. + +source "drivers/pcmcia/Kconfig" + +source "drivers/pci/hotplug/Kconfig" + +endmenu + +menu "Executable file formats" + +source "fs/Kconfig.binfmt" + +endmenu + +menu "Power management options" +source "kernel/power/Kconfig" + +choice + prompt "Select PM Wakeup Event Source" + default PM_WAKEUP_GPIO_BY_SIC_IWR + depends on PM + help + If you have a GPIO already configured as input with the corresponding PORTx_MASK + bit set - "Specify Wakeup Event by SIC_IWR value" + +config PM_WAKEUP_GPIO_BY_SIC_IWR + bool "Specify Wakeup Event by SIC_IWR value" +config PM_WAKEUP_BY_GPIO + bool "Cause Wakeup Event by GPIO" +config PM_WAKEUP_GPIO_API + bool "Configure Wakeup Event by PM GPIO API" + +endchoice + +config PM_WAKEUP_SIC_IWR + hex "Wakeup Events (SIC_IWR)" + depends on PM_WAKEUP_GPIO_BY_SIC_IWR + default 0x80000000 if (BF537 || BF536 || BF534) + default 0x100000 if (BF533 || BF532 || BF531) + +config PM_WAKEUP_GPIO_NUMBER + int "Wakeup GPIO number" + range 0 47 + depends on PM_WAKEUP_BY_GPIO + default 2 if BFIN537_STAMP + +choice + prompt "GPIO Polarity" + depends on PM_WAKEUP_BY_GPIO + default PM_WAKEUP_GPIO_POLAR_H +config PM_WAKEUP_GPIO_POLAR_H + bool "Active High" +config PM_WAKEUP_GPIO_POLAR_L + bool "Active Low" +config PM_WAKEUP_GPIO_POLAR_EDGE_F + bool "Falling EDGE" +config PM_WAKEUP_GPIO_POLAR_EDGE_R + bool "Rising EDGE" +config PM_WAKEUP_GPIO_POLAR_EDGE_B + bool "Both EDGE" +endchoice + +endmenu + +if (BF537 || BF533) + +menu "CPU Frequency scaling" + +source "drivers/cpufreq/Kconfig" + +config CPU_FREQ + bool + default n + help + If you want to enable this option, you should select the + DPMC driver from Character Devices. +endmenu + +endif + +source "net/Kconfig" + +source "drivers/Kconfig" + +source "fs/Kconfig" + +source "arch/blackfin/oprofile/Kconfig" + +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config DEBUG_HWERR + bool "Hardware error interrupt debugging" + depends on DEBUG_KERNEL + help + When enabled, the hardware error interrupt is never disabled, and + will happen immediately when an error condition occurs. This comes + at a slight cost in code size, but is necessary if you are getting + hardware error interrupts and need to know where they are coming + from. + +config DEBUG_ICACHE_CHECK + bool "Check Instruction cache coherancy" + depends on DEBUG_KERNEL + depends on DEBUG_HWERR + help + Say Y here if you are getting wierd unexplained errors. This will + ensure that icache is what SDRAM says it should be, by doing a + byte wise comparision between SDRAM and instruction cache. This + also relocates the irq_panic() function to L1 memory, (which is + un-cached). + +config DEBUG_KERNEL_START + bool "Debug Kernel Startup" + depends on DEBUG_KERNEL + help + Say Y here to put in an mini-execption handler before the kernel + replaces the bootloader exception handler. This will stop kernels + from dieing at startup with no visible error messages. + +config DEBUG_SERIAL_EARLY_INIT + bool "Initialize serial driver early" + default n + depends on SERIAL_BFIN + help + Say Y here if you want to get kernel output early when kernel + crashes before the normal console initialization. If this option + is enable, console output will always go to the ttyBF0, no matter + what kernel boot paramters you set. + +config DEBUG_HUNT_FOR_ZERO + bool "Catch NULL pointer reads/writes" + default y + help + Say Y here to catch reads/writes to anywhere in the memory range + from 0x0000 - 0x0FFF (the first 4k) of memory. This is useful in + catching common programming errors such as NULL pointer dereferences. + + Misbehaving applications will be killed (generate a SEGV) while the + kernel will trigger a panic. + + Enabling this option will take up an extra entry in CPLB table. + Otherwise, there is no extra overhead. + +config DEBUG_BFIN_NO_KERN_HWTRACE + bool "Trace user apps (turn off hwtrace in kernel)" + default n + help + Some pieces of the kernel contain a lot of flow changes which can + quickly fill up the hardware trace buffer. When debugging crashes, + the hardware trace may indicate that the problem lies in kernel + space when in reality an application is buggy. + + Say Y here to disable hardware tracing in some known "jumpy" pieces + of code so that the trace buffer will extend further back. + +config DUAL_CORE_TEST_MODULE + tristate "Dual Core Test Module" + depends on (BF561) + default n + help + Say Y here to build-in dual core test module for dual core test. + +config CPLB_INFO + bool "Display the CPLB information" + help + Display the CPLB information. + +config ACCESS_CHECK + bool "Check the user pointer address" + default y + help + Usually the pointer transfer from user space is checked to see if its + address is in the kernel space. + + Say N here to disable that check to improve the performance. + +endmenu + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" diff --git a/trunk/arch/blackfin/Makefile b/trunk/arch/blackfin/Makefile new file mode 100644 index 000000000000..52d4dbdb2b1a --- /dev/null +++ b/trunk/arch/blackfin/Makefile @@ -0,0 +1,80 @@ +# +# arch/blackfin/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + + +CROSS_COMPILE ?= bfin-uclinux- +LDFLAGS_vmlinux := -X +OBJCOPYFLAGS := -O binary -R .note -R .comment -S +GZFLAGS := -9 + +CFLAGS_MODULE += -mlong-calls +KALLSYMS += --symbol-prefix=_ + + +# setup the machine name and the machine dependent settings +machine-$(CONFIG_BF531) := bf533 +machine-$(CONFIG_BF532) := bf533 +machine-$(CONFIG_BF533) := bf533 +machine-$(CONFIG_BF534) := bf537 +machine-$(CONFIG_BF536) := bf537 +machine-$(CONFIG_BF537) := bf537 +machine-$(CONFIG_BF561) := bf561 +MACHINE := $(machine-y) +export MACHINE + + +head-y := arch/$(ARCH)/mach-$(MACHINE)/head.o arch/$(ARCH)/kernel/init_task.o + +core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/ arch/$(ARCH)/mach-common/ + +# If we have a machine-specific directory, then include it in the build. +ifneq ($(machine-y),) +core-y += arch/$(ARCH)/mach-$(MACHINE)/ +core-y += arch/$(ARCH)/mach-$(MACHINE)/boards/ +endif + +libs-y += arch/$(ARCH)/lib/ + +drivers-$(CONFIG_OPROFILE) += arch/$(ARCH)/oprofile/ + + + +# Update machine arch symlinks if something which affects +# them changed. We use .mach to indicate when they were updated +# last, otherwise make uses the target directory mtime. + +include/asm-blackfin/.mach: $(wildcard include/config/arch/*.h) include/config/auto.conf + @echo ' SYMLINK include/asm-$(ARCH)/mach-$(MACHINE) -> include/asm-$(ARCH)/mach' +ifneq ($(KBUILD_SRC),) + $(Q)mkdir -p include/asm-$(ARCH) + $(Q)ln -fsn $(srctree)/include/asm-$(ARCH)/mach-$(MACHINE) include/asm-$(ARCH)/mach +else + $(Q)ln -fsn mach-$(MACHINE) include/asm-$(ARCH)/mach +endif + @touch $@ + +CLEAN_FILES += \ + include/asm-$(ARCH)/asm-offsets.h \ + arch/$(ARCH)/kernel/asm-offsets.s \ + include/asm-$(ARCH)/mach \ + include/asm-$(ARCH)/.mach + +archprepare: include/asm-blackfin/.mach +archclean: + $(Q)$(MAKE) $(clean)=$(boot) + + +all: vmImage +boot := arch/$(ARCH)/boot +BOOT_TARGETS = vmImage +.PHONY: $(BOOT_TARGETS) +$(BOOT_TARGETS): vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ +define archhelp + echo '* vmImage - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage)' +endef diff --git a/trunk/arch/blackfin/boot/Makefile b/trunk/arch/blackfin/boot/Makefile new file mode 100644 index 000000000000..49e8098d4c21 --- /dev/null +++ b/trunk/arch/blackfin/boot/Makefile @@ -0,0 +1,27 @@ +# +# arch/blackfin/boot/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + +MKIMAGE := $(srctree)/scripts/mkuboot.sh + +targets := vmImage +extra-y += vmlinux.bin vmlinux.gz + +quiet_cmd_uimage = UIMAGE $@ + cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \ + -C gzip -a $(CONFIG_BOOT_LOAD) -e $(CONFIG_BOOT_LOAD) -n 'Linux-$(KERNELRELEASE)' \ + -d $< $@ + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +$(obj)/vmImage: $(obj)/vmlinux.gz + $(call if_changed,uimage) + @echo 'Kernel: $@ is ready' diff --git a/trunk/arch/blackfin/defconfig b/trunk/arch/blackfin/defconfig new file mode 100644 index 000000000000..d5904ca994cf --- /dev/null +++ b/trunk/arch/blackfin/defconfig @@ -0,0 +1,1314 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.20 +# +# CONFIG_MMU is not set +# CONFIG_FPU is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_BFIN=y +CONFIG_SEMAPHORE_SLEEPERS=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_UCLINUX=y +CONFIG_FORCE_MAX_ZONEORDER=14 +CONFIG_IRQCHIP_DEMUX_GPIO=y +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_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 is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +# CONFIG_LIMIT_PAGECACHE is not set +CONFIG_BUDDY=y +# CONFIG_NP2 is not set +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +CONFIG_TINY_SHMEM=y +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=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Blackfin Processor Options +# + +# +# Processor and Board Settings +# +# CONFIG_BF531 is not set +# CONFIG_BF532 is not set +# CONFIG_BF533 is not set +# CONFIG_BF534 is not set +# CONFIG_BF535 is not set +# CONFIG_BF536 is not set +CONFIG_BF537=y +# CONFIG_BF561 is not set +CONFIG_BF_REV_0_2=y +# CONFIG_BF_REV_0_3 is not set +# CONFIG_BF_REV_0_4 is not set +# CONFIG_BF_REV_0_5 is not set +CONFIG_BLACKFIN=y +CONFIG_BFIN_SINGLE_CORE=y +# CONFIG_BFIN533_EZKIT is not set +# CONFIG_BFIN533_STAMP is not set +CONFIG_BFIN537_STAMP=y +# CONFIG_BFIN533_BLUETECHNIX_CM is not set +# CONFIG_BFIN537_BLUETECHNIX_CM is not set +# CONFIG_BFIN561_BLUETECHNIX_CM is not set +# CONFIG_BFIN561_EZKIT is not set +# CONFIG_PNAV10 is not set +# CONFIG_GENERIC_BOARD is not set +CONFIG_MEM_MT48LC32M8A2_75=y +CONFIG_IRQ_PLL_WAKEUP=7 + +# +# BF537 Specific Configuration +# + +# +# PORT F/G Selection +# +CONFIG_BF537_PORT_F=y +# CONFIG_BF537_PORT_G is not set +# CONFIG_BF537_PORT_H is not set + +# +# Interrupt Priority Assignment +# + +# +# Priority +# +CONFIG_IRQ_DMA_ERROR=7 +CONFIG_IRQ_ERROR=7 +CONFIG_IRQ_RTC=8 +CONFIG_IRQ_PPI=8 +CONFIG_IRQ_SPORT0_RX=9 +CONFIG_IRQ_SPORT0_TX=9 +CONFIG_IRQ_SPORT1_RX=9 +CONFIG_IRQ_SPORT1_TX=9 +CONFIG_IRQ_TWI=10 +CONFIG_IRQ_SPI=10 +CONFIG_IRQ_UART0_RX=10 +CONFIG_IRQ_UART0_TX=10 +CONFIG_IRQ_UART1_RX=10 +CONFIG_IRQ_UART1_TX=10 +CONFIG_IRQ_CAN_RX=11 +CONFIG_IRQ_CAN_TX=11 +CONFIG_IRQ_MAC_RX=11 +CONFIG_IRQ_MAC_TX=11 +CONFIG_IRQ_TMR0=12 +CONFIG_IRQ_TMR1=12 +CONFIG_IRQ_TMR2=12 +CONFIG_IRQ_TMR3=12 +CONFIG_IRQ_TMR4=12 +CONFIG_IRQ_TMR5=12 +CONFIG_IRQ_TMR6=12 +CONFIG_IRQ_TMR7=12 +CONFIG_IRQ_PROG_INTA=12 +CONFIG_IRQ_PORTG_INTB=12 +CONFIG_IRQ_MEM_DMA0=13 +CONFIG_IRQ_MEM_DMA1=13 +CONFIG_IRQ_WATCH=13 + +# +# Board customizations +# + +# +# Board Setup +# +CONFIG_CLKIN_HZ=25000000 +CONFIG_MEM_SIZE=64 +CONFIG_MEM_ADD_WIDTH=10 +CONFIG_BOOT_LOAD=0x1000 + +# +# Console UART Setup +# +# CONFIG_BAUD_9600 is not set +# CONFIG_BAUD_19200 is not set +# CONFIG_BAUD_38400 is not set +CONFIG_BAUD_57600=y +# CONFIG_BAUD_115200 is not set +CONFIG_BAUD_NO_PARITY=y +# CONFIG_BAUD_PARITY is not set +CONFIG_BAUD_1_STOPBIT=y +# CONFIG_BAUD_2_STOPBIT is not set + +# +# Blackfin Kernel Optimizations +# + +# +# Timer Tick +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 + +# +# Memory Optimizations +# +CONFIG_I_ENTRY_L1=y +CONFIG_RAMKERNEL=y +# CONFIG_ROMKERNEL 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=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_LARGE_ALLOCS=y +CONFIG_BFIN_DMA_5XX=y +# CONFIG_DMA_UNCACHED_2M is not set +CONFIG_DMA_UNCACHED_1M=y +# CONFIG_DMA_UNCACHED_NONE is not set + +# +# Cache Support +# +CONFIG_BLKFIN_CACHE=y +CONFIG_BLKFIN_DCACHE=y +# CONFIG_BLKFIN_CACHE_LOCK is not set +# CONFIG_BLKFIN_WB is not set +CONFIG_BLKFIN_WT=y +CONFIG_L1_MAX_PIECE=16 + +# +# Clock Settings +# +# CONFIG_BFIN_KERNEL_CLOCK is not set + +# +# Asynchonous Memory Configuration +# + +# +# EBIU_AMBCTL Global Control +# +CONFIG_C_AMCKEN=y +CONFIG_C_CDPRIO=y +# CONFIG_C_AMBEN is not set +# CONFIG_C_AMBEN_B0 is not set +# CONFIG_C_AMBEN_B0_B1 is not set +# CONFIG_C_AMBEN_B0_B1_B2 is not set +CONFIG_C_AMBEN_ALL=y + +# +# EBIU_AMBCTL Control +# +CONFIG_BANK_0=0x7BB0 +CONFIG_BANK_1=0x7BB0 +CONFIG_BANK_2=0x7BB0 +CONFIG_BANK_3=0x99B3 + +# +# Bus options (PCI, PCMCIA, EISA, MCA, ISA) +# +# CONFIG_PCI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF_FDPIC=y +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_ZFLAT=y +# CONFIG_BINFMT_SHARED_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_PM=y +CONFIG_PM_LEGACY=y +# CONFIG_PM_DEBUG is not set +# CONFIG_PM_SYSFS_DEPRECATED is not set +CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y +# CONFIG_PM_WAKEUP_BY_GPIO is not set +# CONFIG_PM_WAKEUP_GPIO_API is not set +CONFIG_PM_WAKEUP_SIC_IWR=0x80000000 + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ 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_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETLABEL 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=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +# CONFIG_IRDA_FAST_RR is not set +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# Old SIR device drivers +# +# CONFIG_IRPORT_SIR is not set + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +# 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_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 is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +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=m +CONFIG_MTD_GEN_PROBE=m +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_MW320D=m +CONFIG_MTD_RAM=y +CONFIG_MTD_ROM=m +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_BF5xx=m +CONFIG_BFIN_FLASH_SIZE=0x400000 +CONFIG_EBIU_FLASH_BASE=0x20000000 + +# +# FLASH_EBIU_AMBCTL Control +# +CONFIG_BFIN_FLASH_BANK_0=0x7BB0 +CONFIG_BFIN_FLASH_BANK_1=0x7BB0 +CONFIG_BFIN_FLASH_BANK_2=0x7BB0 +CONFIG_BFIN_FLASH_BANK_3=0x7BB0 +CONFIG_MTD_UCLINUX=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# 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=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_BFIN=m +CONFIG_BFIN_NAND_BASE=0x20212000 +CONFIG_BFIN_NAND_CLE=2 +CONFIG_BFIN_NAND_ALE=1 +CONFIG_BFIN_NAND_READY=3 +CONFIG_MTD_NAND_IDS=m +# CONFIG_MTD_NAND_DISKONCHIP is not set +# 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 is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE 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 +# + +# +# 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_BFIN_MAC=y +CONFIG_BFIN_MAC_USE_L1=y +CONFIG_BFIN_TX_DESC_NUM=10 +CONFIG_BFIN_RX_DESC_NUM=20 +# CONFIG_BFIN_MAC_RMII 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 + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# 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=m +# 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=y +# CONFIG_INPUT_UINPUT is not set +# CONFIG_BF53X_PFBUTTONS is not set +CONFIG_TWI_KEYPAD=m +CONFIG_BFIN_TWIKEYPAD_IRQ_PFX=72 + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_AD9960 is not set +# CONFIG_SPI_ADC_BF533 is not set +# CONFIG_BF533_PFLAGS is not set +# CONFIG_BF5xx_PPIFCD is not set +# CONFIG_BF5xx_TIMERS is not set +# CONFIG_BF5xx_PPI is not set +CONFIG_BFIN_SPORT=y +# CONFIG_BFIN_TIMER_LATENCY is not set +CONFIG_TWI_LCD=m +CONFIG_TWI_LCD_SLAVE_ADDR=34 +# CONFIG_AD5304 is not set +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_BFIN=y +CONFIG_SERIAL_BFIN_CONSOLE=y +CONFIG_SERIAL_BFIN_DMA=y +# CONFIG_SERIAL_BFIN_PIO is not set +CONFIG_SERIAL_BFIN_UART0=y +# CONFIG_BFIN_UART0_CTSRTS is not set +# CONFIG_SERIAL_BFIN_UART1 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_BFIN_SPORT is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# CAN, the car bus and industrial fieldbus +# +CONFIG_CAN4LINUX=y + +# +# linux embedded drivers +# +# CONFIG_CAN_MCF5282 is not set +# CONFIG_CAN_UNCTWINCAN is not set +CONFIG_CAN_BLACKFIN=m + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_GEN_RTC is not set +CONFIG_BLACKFIN_DPMC=y +# 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=m +CONFIG_I2C_CHARDEV=m + +# +# 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_BFIN_GPIO is not set +CONFIG_I2C_BFIN_TWI=m +CONFIG_TWICLK_KHZ=50 +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_STUB 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_AD5252=m +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8575 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_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +CONFIG_SPI_BFIN=y + +# +# SPI Protocol Masters +# + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_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 +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FIRMWARE_EDID=y +CONFIG_FB=m +CONFIG_FB_CFB_FILLRECT=m +CONFIG_FB_CFB_COPYAREA=m +CONFIG_FB_CFB_IMAGEBLIT=m +# 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_BFIN_7171=m +CONFIG_FB_BFIN_7393=m +CONFIG_NTSC=y +# CONFIG_PAL is not set +# CONFIG_NTSC_640x480 is not set +# CONFIG_PAL_640x480 is not set +# CONFIG_NTSC_YCBCR is not set +# CONFIG_PAL_YCBCR is not set +CONFIG_ADV7393_1XMEM=y +# CONFIG_ADV7393_2XMEM is not set +CONFIG_FB_BF537_LQ035=m +CONFIG_LQ035_SLAVE_ADDR=0x58 +# CONFIG_FB_BFIN_LANDSCAPE is not set +# CONFIG_FB_BFIN_BGR is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=m +CONFIG_BACKLIGHT_DEVICE=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_DEVICE=y + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +# CONFIG_SND_SEQUENCER is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME 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_SPI_MMC is not set +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set + +# +# RTC drivers +# +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_V3020 is not set +CONFIG_RTC_DRV_BFIN=y + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Virtualization +# + +# +# PBX support +# +# CONFIG_PBX is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS 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_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 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_YAFFS_FS=m +CONFIG_YAFFS_YAFFS1=y +# CONFIG_YAFFS_DOES_ECC is not set +CONFIG_YAFFS_YAFFS2=y +CONFIG_YAFFS_AUTO_YAFFS2=y +# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set +CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 +# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set +# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set +CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y +CONFIG_JFFS2_FS=m +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 is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT 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=m +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 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 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Profiling support +# +# CONFIG_PROFILING 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 is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_HUNT_FOR_ZERO=y +# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set +# CONFIG_BOOTPARAM is not set +# CONFIG_NO_KERNEL_MSG is not set +CONFIG_CPLB_INFO=y +# CONFIG_NO_ACCESS_CHECK is not set + +# +# Security options +# +# CONFIG_KEYS is not set +CONFIG_SECURITY=y +# CONFIG_SECURITY_NETWORK is not set +CONFIG_SECURITY_CAPABILITIES=y + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_PLIST=y +CONFIG_IOMAP_COPY=y diff --git a/trunk/arch/blackfin/kernel/Makefile b/trunk/arch/blackfin/kernel/Makefile new file mode 100644 index 000000000000..f3b7d2f9d49c --- /dev/null +++ b/trunk/arch/blackfin/kernel/Makefile @@ -0,0 +1,14 @@ +# +# arch/blackfin/kernel/Makefile +# + +extra-y := init_task.o vmlinux.lds + +obj-y := \ + entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \ + sys_bfin.o time.o traps.o irqchip.o dma-mapping.o bfin_gpio.o \ + flat.o + +obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o +obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o diff --git a/trunk/arch/blackfin/kernel/asm-offsets.c b/trunk/arch/blackfin/kernel/asm-offsets.c new file mode 100644 index 000000000000..41d9a9f89700 --- /dev/null +++ b/trunk/arch/blackfin/kernel/asm-offsets.c @@ -0,0 +1,136 @@ +/* + * File: arch/blackfin/kernel/asm-offsets.c + * Based on: + * Author: + * + * Created: + * Description: generate definitions needed by assembly language modules. + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +int main(void) +{ + /* offsets into the task struct */ + DEFINE(TASK_STATE, offsetof(struct task_struct, state)); + DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); + DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); + DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked)); + DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); + DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info)); + DEFINE(TASK_MM, offsetof(struct task_struct, mm)); + DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); + DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending)); + + /* offsets into the irq_cpustat_t struct */ + DEFINE(CPUSTAT_SOFTIRQ_PENDING, + offsetof(irq_cpustat_t, __softirq_pending)); + + /* offsets into the thread struct */ + DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); + DEFINE(THREAD_USP, offsetof(struct thread_struct, usp)); + DEFINE(THREAD_SR, offsetof(struct thread_struct, seqstat)); + DEFINE(PT_SR, offsetof(struct thread_struct, seqstat)); + DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0)); + DEFINE(THREAD_PC, offsetof(struct thread_struct, pc)); + DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE); + + /* offsets into the pt_regs */ + DEFINE(PT_ORIG_P0, offsetof(struct pt_regs, orig_p0)); + DEFINE(PT_ORIG_PC, offsetof(struct pt_regs, orig_pc)); + DEFINE(PT_R0, offsetof(struct pt_regs, r0)); + DEFINE(PT_R1, offsetof(struct pt_regs, r1)); + DEFINE(PT_R2, offsetof(struct pt_regs, r2)); + DEFINE(PT_R3, offsetof(struct pt_regs, r3)); + DEFINE(PT_R4, offsetof(struct pt_regs, r4)); + DEFINE(PT_R5, offsetof(struct pt_regs, r5)); + DEFINE(PT_R6, offsetof(struct pt_regs, r6)); + DEFINE(PT_R7, offsetof(struct pt_regs, r7)); + + DEFINE(PT_P0, offsetof(struct pt_regs, p0)); + DEFINE(PT_P1, offsetof(struct pt_regs, p1)); + DEFINE(PT_P2, offsetof(struct pt_regs, p2)); + DEFINE(PT_P3, offsetof(struct pt_regs, p3)); + DEFINE(PT_P4, offsetof(struct pt_regs, p4)); + DEFINE(PT_P5, offsetof(struct pt_regs, p5)); + + DEFINE(PT_FP, offsetof(struct pt_regs, fp)); + DEFINE(PT_USP, offsetof(struct pt_regs, usp)); + DEFINE(PT_I0, offsetof(struct pt_regs, i0)); + DEFINE(PT_I1, offsetof(struct pt_regs, i1)); + DEFINE(PT_I2, offsetof(struct pt_regs, i2)); + DEFINE(PT_I3, offsetof(struct pt_regs, i3)); + DEFINE(PT_M0, offsetof(struct pt_regs, m0)); + DEFINE(PT_M1, offsetof(struct pt_regs, m1)); + DEFINE(PT_M2, offsetof(struct pt_regs, m2)); + DEFINE(PT_M3, offsetof(struct pt_regs, m3)); + DEFINE(PT_L0, offsetof(struct pt_regs, l0)); + DEFINE(PT_L1, offsetof(struct pt_regs, l1)); + DEFINE(PT_L2, offsetof(struct pt_regs, l2)); + DEFINE(PT_L3, offsetof(struct pt_regs, l3)); + DEFINE(PT_B0, offsetof(struct pt_regs, b0)); + DEFINE(PT_B1, offsetof(struct pt_regs, b1)); + DEFINE(PT_B2, offsetof(struct pt_regs, b2)); + DEFINE(PT_B3, offsetof(struct pt_regs, b3)); + DEFINE(PT_A0X, offsetof(struct pt_regs, a0x)); + DEFINE(PT_A0W, offsetof(struct pt_regs, a0w)); + DEFINE(PT_A1X, offsetof(struct pt_regs, a1x)); + DEFINE(PT_A1W, offsetof(struct pt_regs, a1w)); + DEFINE(PT_LC0, offsetof(struct pt_regs, lc0)); + DEFINE(PT_LC1, offsetof(struct pt_regs, lc1)); + DEFINE(PT_LT0, offsetof(struct pt_regs, lt0)); + DEFINE(PT_LT1, offsetof(struct pt_regs, lt1)); + DEFINE(PT_LB0, offsetof(struct pt_regs, lb0)); + DEFINE(PT_LB1, offsetof(struct pt_regs, lb1)); + DEFINE(PT_ASTAT, offsetof(struct pt_regs, astat)); + DEFINE(PT_RESERVED, offsetof(struct pt_regs, reserved)); + DEFINE(PT_RETS, offsetof(struct pt_regs, rets)); + DEFINE(PT_PC, offsetof(struct pt_regs, pc)); + DEFINE(PT_RETX, offsetof(struct pt_regs, retx)); + DEFINE(PT_RETN, offsetof(struct pt_regs, retn)); + DEFINE(PT_RETE, offsetof(struct pt_regs, rete)); + DEFINE(PT_SEQSTAT, offsetof(struct pt_regs, seqstat)); + DEFINE(PT_SYSCFG, offsetof(struct pt_regs, syscfg)); + DEFINE(PT_IPEND, offsetof(struct pt_regs, ipend)); + DEFINE(SIZEOF_PTREGS, sizeof(struct pt_regs)); + DEFINE(PT_TEXT_ADDR, sizeof(struct pt_regs)); /* Needed by gdb */ + DEFINE(PT_TEXT_END_ADDR, 4 + sizeof(struct pt_regs));/* Needed by gdb */ + DEFINE(PT_DATA_ADDR, 8 + sizeof(struct pt_regs)); /* Needed by gdb */ + DEFINE(PT_FDPIC_EXEC, 12 + sizeof(struct pt_regs)); /* Needed by gdb */ + DEFINE(PT_FDPIC_INTERP, 16 + sizeof(struct pt_regs));/* Needed by gdb */ + + /* signal defines */ + DEFINE(SIGSEGV, SIGSEGV); + DEFINE(SIGTRAP, SIGTRAP); + + return 0; +} diff --git a/trunk/arch/blackfin/kernel/bfin_dma_5xx.c b/trunk/arch/blackfin/kernel/bfin_dma_5xx.c new file mode 100644 index 000000000000..8ea079ebecb5 --- /dev/null +++ b/trunk/arch/blackfin/kernel/bfin_dma_5xx.c @@ -0,0 +1,742 @@ +/* + * File: arch/blackfin/kernel/bfin_dma_5xx.c + * Based on: + * Author: + * + * Created: + * Description: This file contains the simple DMA Implementation for Blackfin + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Remove unused code not exported by symbol or internally called */ +#define REMOVE_DEAD_CODE + +/************************************************************************** + * Global Variables +***************************************************************************/ + +static struct dma_channel dma_ch[MAX_BLACKFIN_DMA_CHANNEL]; +#if defined (CONFIG_BF561) +static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = { + (struct dma_register *) DMA1_0_NEXT_DESC_PTR, + (struct dma_register *) DMA1_1_NEXT_DESC_PTR, + (struct dma_register *) DMA1_2_NEXT_DESC_PTR, + (struct dma_register *) DMA1_3_NEXT_DESC_PTR, + (struct dma_register *) DMA1_4_NEXT_DESC_PTR, + (struct dma_register *) DMA1_5_NEXT_DESC_PTR, + (struct dma_register *) DMA1_6_NEXT_DESC_PTR, + (struct dma_register *) DMA1_7_NEXT_DESC_PTR, + (struct dma_register *) DMA1_8_NEXT_DESC_PTR, + (struct dma_register *) DMA1_9_NEXT_DESC_PTR, + (struct dma_register *) DMA1_10_NEXT_DESC_PTR, + (struct dma_register *) DMA1_11_NEXT_DESC_PTR, + (struct dma_register *) DMA2_0_NEXT_DESC_PTR, + (struct dma_register *) DMA2_1_NEXT_DESC_PTR, + (struct dma_register *) DMA2_2_NEXT_DESC_PTR, + (struct dma_register *) DMA2_3_NEXT_DESC_PTR, + (struct dma_register *) DMA2_4_NEXT_DESC_PTR, + (struct dma_register *) DMA2_5_NEXT_DESC_PTR, + (struct dma_register *) DMA2_6_NEXT_DESC_PTR, + (struct dma_register *) DMA2_7_NEXT_DESC_PTR, + (struct dma_register *) DMA2_8_NEXT_DESC_PTR, + (struct dma_register *) DMA2_9_NEXT_DESC_PTR, + (struct dma_register *) DMA2_10_NEXT_DESC_PTR, + (struct dma_register *) DMA2_11_NEXT_DESC_PTR, + (struct dma_register *) MDMA1_D0_NEXT_DESC_PTR, + (struct dma_register *) MDMA1_S0_NEXT_DESC_PTR, + (struct dma_register *) MDMA1_D1_NEXT_DESC_PTR, + (struct dma_register *) MDMA1_S1_NEXT_DESC_PTR, + (struct dma_register *) MDMA2_D0_NEXT_DESC_PTR, + (struct dma_register *) MDMA2_S0_NEXT_DESC_PTR, + (struct dma_register *) MDMA2_D1_NEXT_DESC_PTR, + (struct dma_register *) MDMA2_S1_NEXT_DESC_PTR, + (struct dma_register *) IMDMA_D0_NEXT_DESC_PTR, + (struct dma_register *) IMDMA_S0_NEXT_DESC_PTR, + (struct dma_register *) IMDMA_D1_NEXT_DESC_PTR, + (struct dma_register *) IMDMA_S1_NEXT_DESC_PTR, +}; +#else +static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = { + (struct dma_register *) DMA0_NEXT_DESC_PTR, + (struct dma_register *) DMA1_NEXT_DESC_PTR, + (struct dma_register *) DMA2_NEXT_DESC_PTR, + (struct dma_register *) DMA3_NEXT_DESC_PTR, + (struct dma_register *) DMA4_NEXT_DESC_PTR, + (struct dma_register *) DMA5_NEXT_DESC_PTR, + (struct dma_register *) DMA6_NEXT_DESC_PTR, + (struct dma_register *) DMA7_NEXT_DESC_PTR, +#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536)) + (struct dma_register *) DMA8_NEXT_DESC_PTR, + (struct dma_register *) DMA9_NEXT_DESC_PTR, + (struct dma_register *) DMA10_NEXT_DESC_PTR, + (struct dma_register *) DMA11_NEXT_DESC_PTR, +#endif + (struct dma_register *) MDMA_D0_NEXT_DESC_PTR, + (struct dma_register *) MDMA_S0_NEXT_DESC_PTR, + (struct dma_register *) MDMA_D1_NEXT_DESC_PTR, + (struct dma_register *) MDMA_S1_NEXT_DESC_PTR, +}; +#endif + +/*------------------------------------------------------------------------------ + * Set the Buffer Clear bit in the Configuration register of specific DMA + * channel. This will stop the descriptor based DMA operation. + *-----------------------------------------------------------------------------*/ +static void clear_dma_buffer(unsigned int channel) +{ + dma_ch[channel].regs->cfg |= RESTART; + SSYNC(); + dma_ch[channel].regs->cfg &= ~RESTART; + SSYNC(); +} + +int __init blackfin_dma_init(void) +{ + int i; + + printk(KERN_INFO "Blackfin DMA Controller\n"); + + for (i = 0; i < MAX_BLACKFIN_DMA_CHANNEL; i++) { + dma_ch[i].chan_status = DMA_CHANNEL_FREE; + dma_ch[i].regs = base_addr[i]; + mutex_init(&(dma_ch[i].dmalock)); + } + + return 0; +} + +arch_initcall(blackfin_dma_init); + +/* + * Form the channel find the irq number for that channel. + */ +#if !defined(CONFIG_BF561) + +static int bf533_channel2irq(unsigned int channel) +{ + int ret_irq = -1; + + switch (channel) { + case CH_PPI: + ret_irq = IRQ_PPI; + break; + +#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536)) + case CH_EMAC_RX: + ret_irq = IRQ_MAC_RX; + break; + + case CH_EMAC_TX: + ret_irq = IRQ_MAC_TX; + break; + + case CH_UART1_RX: + ret_irq = IRQ_UART1_RX; + break; + + case CH_UART1_TX: + ret_irq = IRQ_UART1_TX; + break; +#endif + + case CH_SPORT0_RX: + ret_irq = IRQ_SPORT0_RX; + break; + + case CH_SPORT0_TX: + ret_irq = IRQ_SPORT0_TX; + break; + + case CH_SPORT1_RX: + ret_irq = IRQ_SPORT1_RX; + break; + + case CH_SPORT1_TX: + ret_irq = IRQ_SPORT1_TX; + break; + + case CH_SPI: + ret_irq = IRQ_SPI; + break; + + case CH_UART_RX: + ret_irq = IRQ_UART_RX; + break; + + case CH_UART_TX: + ret_irq = IRQ_UART_TX; + break; + + case CH_MEM_STREAM0_SRC: + case CH_MEM_STREAM0_DEST: + ret_irq = IRQ_MEM_DMA0; + break; + + case CH_MEM_STREAM1_SRC: + case CH_MEM_STREAM1_DEST: + ret_irq = IRQ_MEM_DMA1; + break; + } + return ret_irq; +} + +# define channel2irq(channel) bf533_channel2irq(channel) + +#else + +static int bf561_channel2irq(unsigned int channel) +{ + int ret_irq = -1; + + switch (channel) { + case CH_PPI0: + ret_irq = IRQ_PPI0; + break; + case CH_PPI1: + ret_irq = IRQ_PPI1; + break; + case CH_SPORT0_RX: + ret_irq = IRQ_SPORT0_RX; + break; + case CH_SPORT0_TX: + ret_irq = IRQ_SPORT0_TX; + break; + case CH_SPORT1_RX: + ret_irq = IRQ_SPORT1_RX; + break; + case CH_SPORT1_TX: + ret_irq = IRQ_SPORT1_TX; + break; + case CH_SPI: + ret_irq = IRQ_SPI; + break; + case CH_UART_RX: + ret_irq = IRQ_UART_RX; + break; + case CH_UART_TX: + ret_irq = IRQ_UART_TX; + break; + + case CH_MEM_STREAM0_SRC: + case CH_MEM_STREAM0_DEST: + ret_irq = IRQ_MEM_DMA0; + break; + case CH_MEM_STREAM1_SRC: + case CH_MEM_STREAM1_DEST: + ret_irq = IRQ_MEM_DMA1; + break; + case CH_MEM_STREAM2_SRC: + case CH_MEM_STREAM2_DEST: + ret_irq = IRQ_MEM_DMA2; + break; + case CH_MEM_STREAM3_SRC: + case CH_MEM_STREAM3_DEST: + ret_irq = IRQ_MEM_DMA3; + break; + + case CH_IMEM_STREAM0_SRC: + case CH_IMEM_STREAM0_DEST: + ret_irq = IRQ_IMEM_DMA0; + break; + case CH_IMEM_STREAM1_SRC: + case CH_IMEM_STREAM1_DEST: + ret_irq = IRQ_IMEM_DMA1; + break; + } + return ret_irq; +} + +# define channel2irq(channel) bf561_channel2irq(channel) + +#endif + +/*------------------------------------------------------------------------------ + * Request the specific DMA channel from the system. + *-----------------------------------------------------------------------------*/ +int request_dma(unsigned int channel, char *device_id) +{ + + pr_debug("request_dma() : BEGIN \n"); + mutex_lock(&(dma_ch[channel].dmalock)); + + if ((dma_ch[channel].chan_status == DMA_CHANNEL_REQUESTED) + || (dma_ch[channel].chan_status == DMA_CHANNEL_ENABLED)) { + mutex_unlock(&(dma_ch[channel].dmalock)); + pr_debug("DMA CHANNEL IN USE \n"); + return -EBUSY; + } else { + dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED; + pr_debug("DMA CHANNEL IS ALLOCATED \n"); + } + + mutex_unlock(&(dma_ch[channel].dmalock)); + + dma_ch[channel].device_id = device_id; + dma_ch[channel].irq_callback = NULL; + + /* This is to be enabled by putting a restriction - + * you have to request DMA, before doing any operations on + * descriptor/channel + */ + pr_debug("request_dma() : END \n"); + return channel; +} +EXPORT_SYMBOL(request_dma); + +int set_dma_callback(unsigned int channel, dma_interrupt_t callback, void *data) +{ + int ret_irq = 0; + + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + if (callback != NULL) { + int ret_val; + ret_irq = channel2irq(channel); + + dma_ch[channel].data = data; + + ret_val = + request_irq(ret_irq, (void *)callback, IRQF_DISABLED, + dma_ch[channel].device_id, data); + if (ret_val) { + printk(KERN_NOTICE + "Request irq in DMA engine failed.\n"); + return -EPERM; + } + dma_ch[channel].irq_callback = callback; + } + return 0; +} +EXPORT_SYMBOL(set_dma_callback); + +void free_dma(unsigned int channel) +{ + int ret_irq; + + pr_debug("freedma() : BEGIN \n"); + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + /* Halt the DMA */ + disable_dma(channel); + clear_dma_buffer(channel); + + if (dma_ch[channel].irq_callback != NULL) { + ret_irq = channel2irq(channel); + free_irq(ret_irq, dma_ch[channel].data); + } + + /* Clear the DMA Variable in the Channel */ + mutex_lock(&(dma_ch[channel].dmalock)); + dma_ch[channel].chan_status = DMA_CHANNEL_FREE; + mutex_unlock(&(dma_ch[channel].dmalock)); + + pr_debug("freedma() : END \n"); +} +EXPORT_SYMBOL(free_dma); + +void dma_enable_irq(unsigned int channel) +{ + int ret_irq; + + pr_debug("dma_enable_irq() : BEGIN \n"); + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + ret_irq = channel2irq(channel); + enable_irq(ret_irq); +} +EXPORT_SYMBOL(dma_enable_irq); + +void dma_disable_irq(unsigned int channel) +{ + int ret_irq; + + pr_debug("dma_disable_irq() : BEGIN \n"); + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + ret_irq = channel2irq(channel); + disable_irq(ret_irq); +} +EXPORT_SYMBOL(dma_disable_irq); + +int dma_channel_active(unsigned int channel) +{ + if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE) { + return 0; + } else { + return 1; + } +} +EXPORT_SYMBOL(dma_channel_active); + +/*------------------------------------------------------------------------------ +* stop the specific DMA channel. +*-----------------------------------------------------------------------------*/ +void disable_dma(unsigned int channel) +{ + pr_debug("stop_dma() : BEGIN \n"); + + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->cfg &= ~DMAEN; /* Clean the enable bit */ + SSYNC(); + dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED; + /* Needs to be enabled Later */ + pr_debug("stop_dma() : END \n"); + return; +} +EXPORT_SYMBOL(disable_dma); + +void enable_dma(unsigned int channel) +{ + pr_debug("enable_dma() : BEGIN \n"); + + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED; + dma_ch[channel].regs->curr_x_count = 0; + dma_ch[channel].regs->curr_y_count = 0; + + dma_ch[channel].regs->cfg |= DMAEN; /* Set the enable bit */ + SSYNC(); + pr_debug("enable_dma() : END \n"); + return; +} +EXPORT_SYMBOL(enable_dma); + +/*------------------------------------------------------------------------------ +* Set the Start Address register for the specific DMA channel +* This function can be used for register based DMA, +* to setup the start address +* addr: Starting address of the DMA Data to be transferred. +*-----------------------------------------------------------------------------*/ +void set_dma_start_addr(unsigned int channel, unsigned long addr) +{ + pr_debug("set_dma_start_addr() : BEGIN \n"); + + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->start_addr = addr; + SSYNC(); + pr_debug("set_dma_start_addr() : END\n"); +} +EXPORT_SYMBOL(set_dma_start_addr); + +void set_dma_next_desc_addr(unsigned int channel, unsigned long addr) +{ + pr_debug("set_dma_next_desc_addr() : BEGIN \n"); + + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->next_desc_ptr = addr; + SSYNC(); + pr_debug("set_dma_start_addr() : END\n"); +} +EXPORT_SYMBOL(set_dma_next_desc_addr); + +void set_dma_x_count(unsigned int channel, unsigned short x_count) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->x_count = x_count; + SSYNC(); +} +EXPORT_SYMBOL(set_dma_x_count); + +void set_dma_y_count(unsigned int channel, unsigned short y_count) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->y_count = y_count; + SSYNC(); +} +EXPORT_SYMBOL(set_dma_y_count); + +void set_dma_x_modify(unsigned int channel, short x_modify) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->x_modify = x_modify; + SSYNC(); +} +EXPORT_SYMBOL(set_dma_x_modify); + +void set_dma_y_modify(unsigned int channel, short y_modify) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->y_modify = y_modify; + SSYNC(); +} +EXPORT_SYMBOL(set_dma_y_modify); + +void set_dma_config(unsigned int channel, unsigned short config) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->cfg = config; + SSYNC(); +} +EXPORT_SYMBOL(set_dma_config); + +unsigned short +set_bfin_dma_config(char direction, char flow_mode, + char intr_mode, char dma_mode, char width) +{ + unsigned short config; + + config = + ((direction << 1) | (width << 2) | (dma_mode << 4) | + (intr_mode << 6) | (flow_mode << 12) | RESTART); + return config; +} +EXPORT_SYMBOL(set_bfin_dma_config); + +void set_dma_sg(unsigned int channel, struct dmasg * sg, int nr_sg) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->cfg |= ((nr_sg & 0x0F) << 8); + + dma_ch[channel].regs->next_desc_ptr = (unsigned int)sg; + + SSYNC(); +} +EXPORT_SYMBOL(set_dma_sg); + +/*------------------------------------------------------------------------------ + * Get the DMA status of a specific DMA channel from the system. + *-----------------------------------------------------------------------------*/ +unsigned short get_dma_curr_irqstat(unsigned int channel) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + return dma_ch[channel].regs->irq_status; +} +EXPORT_SYMBOL(get_dma_curr_irqstat); + +/*------------------------------------------------------------------------------ + * Clear the DMA_DONE bit in DMA status. Stop the DMA completion interrupt. + *-----------------------------------------------------------------------------*/ +void clear_dma_irqstat(unsigned int channel) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + dma_ch[channel].regs->irq_status |= 3; +} +EXPORT_SYMBOL(clear_dma_irqstat); + +/*------------------------------------------------------------------------------ + * Get current DMA xcount of a specific DMA channel from the system. + *-----------------------------------------------------------------------------*/ +unsigned short get_dma_curr_xcount(unsigned int channel) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + return dma_ch[channel].regs->curr_x_count; +} +EXPORT_SYMBOL(get_dma_curr_xcount); + +/*------------------------------------------------------------------------------ + * Get current DMA ycount of a specific DMA channel from the system. + *-----------------------------------------------------------------------------*/ +unsigned short get_dma_curr_ycount(unsigned int channel) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + return dma_ch[channel].regs->curr_y_count; +} +EXPORT_SYMBOL(get_dma_curr_ycount); + +void *dma_memcpy(void *dest, const void *src, size_t size) +{ + int direction; /* 1 - address decrease, 0 - address increase */ + int flag_align; /* 1 - address aligned, 0 - address unaligned */ + int flag_2D; /* 1 - 2D DMA needed, 0 - 1D DMA needed */ + + if (size <= 0) + return NULL; + + if ((unsigned long)src < memory_end) + blackfin_dcache_flush_range((unsigned int)src, + (unsigned int)(src + size)); + + bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); + + if ((unsigned long)src < (unsigned long)dest) + direction = 1; + else + direction = 0; + + if ((((unsigned long)dest % 2) == 0) && (((unsigned long)src % 2) == 0) + && ((size % 2) == 0)) + flag_align = 1; + else + flag_align = 0; + + if (size > 0x10000) /* size > 64K */ + flag_2D = 1; + else + flag_2D = 0; + + /* Setup destination and source start address */ + if (direction) { + if (flag_align) { + bfin_write_MDMA_D0_START_ADDR(dest + size - 2); + bfin_write_MDMA_S0_START_ADDR(src + size - 2); + } else { + bfin_write_MDMA_D0_START_ADDR(dest + size - 1); + bfin_write_MDMA_S0_START_ADDR(src + size - 1); + } + } else { + bfin_write_MDMA_D0_START_ADDR(dest); + bfin_write_MDMA_S0_START_ADDR(src); + } + + /* Setup destination and source xcount */ + if (flag_2D) { + if (flag_align) { + bfin_write_MDMA_D0_X_COUNT(1024 / 2); + bfin_write_MDMA_S0_X_COUNT(1024 / 2); + } else { + bfin_write_MDMA_D0_X_COUNT(1024); + bfin_write_MDMA_S0_X_COUNT(1024); + } + bfin_write_MDMA_D0_Y_COUNT(size >> 10); + bfin_write_MDMA_S0_Y_COUNT(size >> 10); + } else { + if (flag_align) { + bfin_write_MDMA_D0_X_COUNT(size / 2); + bfin_write_MDMA_S0_X_COUNT(size / 2); + } else { + bfin_write_MDMA_D0_X_COUNT(size); + bfin_write_MDMA_S0_X_COUNT(size); + } + } + + /* Setup destination and source xmodify and ymodify */ + if (direction) { + if (flag_align) { + bfin_write_MDMA_D0_X_MODIFY(-2); + bfin_write_MDMA_S0_X_MODIFY(-2); + if (flag_2D) { + bfin_write_MDMA_D0_Y_MODIFY(-2); + bfin_write_MDMA_S0_Y_MODIFY(-2); + } + } else { + bfin_write_MDMA_D0_X_MODIFY(-1); + bfin_write_MDMA_S0_X_MODIFY(-1); + if (flag_2D) { + bfin_write_MDMA_D0_Y_MODIFY(-1); + bfin_write_MDMA_S0_Y_MODIFY(-1); + } + } + } else { + if (flag_align) { + bfin_write_MDMA_D0_X_MODIFY(2); + bfin_write_MDMA_S0_X_MODIFY(2); + if (flag_2D) { + bfin_write_MDMA_D0_Y_MODIFY(2); + bfin_write_MDMA_S0_Y_MODIFY(2); + } + } else { + bfin_write_MDMA_D0_X_MODIFY(1); + bfin_write_MDMA_S0_X_MODIFY(1); + if (flag_2D) { + bfin_write_MDMA_D0_Y_MODIFY(1); + bfin_write_MDMA_S0_Y_MODIFY(1); + } + } + } + + /* Enable source DMA */ + if (flag_2D) { + if (flag_align) { + bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D | WDSIZE_16); + bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D | WDSIZE_16); + } else { + bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D); + bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D); + } + } else { + if (flag_align) { + bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16); + bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16); + } else { + bfin_write_MDMA_S0_CONFIG(DMAEN); + bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN); + } + } + + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)) + ; + + bfin_write_MDMA_D0_IRQ_STATUS(bfin_read_MDMA_D0_IRQ_STATUS() | + (DMA_DONE | DMA_ERR)); + + bfin_write_MDMA_S0_CONFIG(0); + bfin_write_MDMA_D0_CONFIG(0); + + if ((unsigned long)dest < memory_end) + blackfin_dcache_invalidate_range((unsigned int)dest, + (unsigned int)(dest + size)); + + return dest; +} +EXPORT_SYMBOL(dma_memcpy); + +void *safe_dma_memcpy(void *dest, const void *src, size_t size) +{ + int flags = 0; + void *addr; + local_irq_save(flags); + addr = dma_memcpy(dest, src, size); + local_irq_restore(flags); + return addr; +} +EXPORT_SYMBOL(safe_dma_memcpy); diff --git a/trunk/arch/blackfin/kernel/bfin_gpio.c b/trunk/arch/blackfin/kernel/bfin_gpio.c new file mode 100644 index 000000000000..e9f24a9a46ba --- /dev/null +++ b/trunk/arch/blackfin/kernel/bfin_gpio.c @@ -0,0 +1,637 @@ +/* + * File: arch/blackfin/kernel/bfin_gpio.c + * Based on: + * Author: Michael Hennerich (hennerich@blackfin.uclinux.org) + * + * Created: + * Description: GPIO Abstraction Layer + * + * Modified: + * Copyright 2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* +* Number BF537/6/4 BF561 BF533/2/1 +* +* GPIO_0 PF0 PF0 PF0 +* GPIO_1 PF1 PF1 PF1 +* GPIO_2 PF2 PF2 PF2 +* GPIO_3 PF3 PF3 PF3 +* GPIO_4 PF4 PF4 PF4 +* GPIO_5 PF5 PF5 PF5 +* GPIO_6 PF6 PF6 PF6 +* GPIO_7 PF7 PF7 PF7 +* GPIO_8 PF8 PF8 PF8 +* GPIO_9 PF9 PF9 PF9 +* GPIO_10 PF10 PF10 PF10 +* GPIO_11 PF11 PF11 PF11 +* GPIO_12 PF12 PF12 PF12 +* GPIO_13 PF13 PF13 PF13 +* GPIO_14 PF14 PF14 PF14 +* GPIO_15 PF15 PF15 PF15 +* GPIO_16 PG0 PF16 +* GPIO_17 PG1 PF17 +* GPIO_18 PG2 PF18 +* GPIO_19 PG3 PF19 +* GPIO_20 PG4 PF20 +* GPIO_21 PG5 PF21 +* GPIO_22 PG6 PF22 +* GPIO_23 PG7 PF23 +* GPIO_24 PG8 PF24 +* GPIO_25 PG9 PF25 +* GPIO_26 PG10 PF26 +* GPIO_27 PG11 PF27 +* GPIO_28 PG12 PF28 +* GPIO_29 PG13 PF29 +* GPIO_30 PG14 PF30 +* GPIO_31 PG15 PF31 +* GPIO_32 PH0 PF32 +* GPIO_33 PH1 PF33 +* GPIO_34 PH2 PF34 +* GPIO_35 PH3 PF35 +* GPIO_36 PH4 PF36 +* GPIO_37 PH5 PF37 +* GPIO_38 PH6 PF38 +* GPIO_39 PH7 PF39 +* GPIO_40 PH8 PF40 +* GPIO_41 PH9 PF41 +* GPIO_42 PH10 PF42 +* GPIO_43 PH11 PF43 +* GPIO_44 PH12 PF44 +* GPIO_45 PH13 PF45 +* GPIO_46 PH14 PF46 +* GPIO_47 PH15 PF47 +*/ + +#include +#include +#include +#include +#include + +#ifdef BF533_FAMILY +static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = { + (struct gpio_port_t *) FIO_FLAG_D, +}; +#endif + +#ifdef BF537_FAMILY +static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = { + (struct gpio_port_t *) PORTFIO, + (struct gpio_port_t *) PORTGIO, + (struct gpio_port_t *) PORTHIO, +}; + +static unsigned short *port_fer[gpio_bank(MAX_BLACKFIN_GPIOS)] = { + (unsigned short *) PORTF_FER, + (unsigned short *) PORTG_FER, + (unsigned short *) PORTH_FER, +}; + +#endif + +#ifdef BF561_FAMILY +static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = { + (struct gpio_port_t *) FIO0_FLAG_D, + (struct gpio_port_t *) FIO1_FLAG_D, + (struct gpio_port_t *) FIO2_FLAG_D, +}; +#endif + +static unsigned short reserved_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; + +#ifdef CONFIG_PM +static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; +static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS]; +static struct gpio_port_s gpio_bank_saved[gpio_bank(MAX_BLACKFIN_GPIOS)]; + +#ifdef BF533_FAMILY +static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB}; +#endif + +#ifdef BF537_FAMILY +static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX}; +#endif + +#ifdef BF561_FAMILY +static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INTB, IRQ_PROG1_INTB, IRQ_PROG2_INTB}; +#endif + +#endif /* CONFIG_PM */ + +inline int check_gpio(unsigned short gpio) +{ + if (gpio > MAX_BLACKFIN_GPIOS) + return -EINVAL; + return 0; +} + +#ifdef BF537_FAMILY +void port_setup(unsigned short gpio, unsigned short usage) +{ + if (usage == GPIO_USAGE) { + if (*port_fer[gpio_bank(gpio)] & gpio_bit(gpio)) + printk(KERN_WARNING "bfin-gpio: Possible Conflict with Peripheral " + "usage and GPIO %d detected!\n", gpio); + *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio); + } else + *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio); + SSYNC(); +} +#else +# define port_setup(...) do { } while (0) +#endif + + +void default_gpio(unsigned short gpio) +{ + unsigned short bank,bitmask; + + bank = gpio_bank(gpio); + bitmask = gpio_bit(gpio); + + gpio_bankb[bank]->maska_clear = bitmask; + gpio_bankb[bank]->maskb_clear = bitmask; + SSYNC(); + gpio_bankb[bank]->inen &= ~bitmask; + gpio_bankb[bank]->dir &= ~bitmask; + gpio_bankb[bank]->polar &= ~bitmask; + gpio_bankb[bank]->both &= ~bitmask; + gpio_bankb[bank]->edge &= ~bitmask; +} + + +int __init bfin_gpio_init(void) +{ + int i; + + printk(KERN_INFO "Blackfin GPIO Controller\n"); + + for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) + reserved_map[gpio_bank(i)] = 0; + +#if defined(BF537_FAMILY) && (defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)) +# if defined(CONFIG_BFIN_MAC_RMII) + reserved_map[PORT_H] = 0xC373; +# else + reserved_map[PORT_H] = 0xFFFF; +# endif +#endif + + return 0; +} + +arch_initcall(bfin_gpio_init); + + +/*********************************************************** +* +* FUNCTIONS: Blackfin General Purpose Ports Access Functions +* +* INPUTS/OUTPUTS: +* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS +* +* +* DESCRIPTION: These functions abstract direct register access +* to Blackfin processor General Purpose +* Ports Regsiters +* +* CAUTION: These functions do not belong to the GPIO Driver API +************************************************************* +* MODIFICATION HISTORY : +**************************************************************/ + +/* Set a specific bit */ + +#define SET_GPIO(name) \ +void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \ +{ \ + unsigned long flags; \ + BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \ + local_irq_save(flags); \ + if (arg) \ + gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \ + else \ + gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \ + local_irq_restore(flags); \ +} \ +EXPORT_SYMBOL(set_gpio_ ## name); + +SET_GPIO(dir) +SET_GPIO(inen) +SET_GPIO(polar) +SET_GPIO(edge) +SET_GPIO(both) + + +#define SET_GPIO_SC(name) \ +void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \ +{ \ + BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \ + if (arg) \ + gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \ + else \ + gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \ +} \ +EXPORT_SYMBOL(set_gpio_ ## name); + +SET_GPIO_SC(maska) +SET_GPIO_SC(maskb) + +#if defined(ANOMALY_05000311) +void set_gpio_data(unsigned short gpio, unsigned short arg) +{ + unsigned long flags; + BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); + local_irq_save(flags); + if (arg) + gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio); + else + gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio); + bfin_read_CHIPID(); + local_irq_restore(flags); +} +EXPORT_SYMBOL(set_gpio_data); +#else +SET_GPIO_SC(data) +#endif + + +#if defined(ANOMALY_05000311) +void set_gpio_toggle(unsigned short gpio) +{ + unsigned long flags; + BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); + local_irq_save(flags); + gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio); + bfin_read_CHIPID(); + local_irq_restore(flags); +} +#else +void set_gpio_toggle(unsigned short gpio) +{ + BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); + gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio); +} +#endif +EXPORT_SYMBOL(set_gpio_toggle); + + +/*Set current PORT date (16-bit word)*/ + +#define SET_GPIO_P(name) \ +void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \ +{ \ + gpio_bankb[gpio_bank(gpio)]->name = arg; \ +} \ +EXPORT_SYMBOL(set_gpiop_ ## name); + +SET_GPIO_P(dir) +SET_GPIO_P(inen) +SET_GPIO_P(polar) +SET_GPIO_P(edge) +SET_GPIO_P(both) +SET_GPIO_P(maska) +SET_GPIO_P(maskb) + + +#if defined(ANOMALY_05000311) +void set_gpiop_data(unsigned short gpio, unsigned short arg) +{ + unsigned long flags; + local_irq_save(flags); + gpio_bankb[gpio_bank(gpio)]->data = arg; + bfin_read_CHIPID(); + local_irq_restore(flags); +} +EXPORT_SYMBOL(set_gpiop_data); +#else +SET_GPIO_P(data) +#endif + + + +/* Get a specific bit */ + +#define GET_GPIO(name) \ +unsigned short get_gpio_ ## name(unsigned short gpio) \ +{ \ + return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \ +} \ +EXPORT_SYMBOL(get_gpio_ ## name); + +GET_GPIO(dir) +GET_GPIO(inen) +GET_GPIO(polar) +GET_GPIO(edge) +GET_GPIO(both) +GET_GPIO(maska) +GET_GPIO(maskb) + + +#if defined(ANOMALY_05000311) +unsigned short get_gpio_data(unsigned short gpio) +{ + unsigned long flags; + unsigned short ret; + BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); + local_irq_save(flags); + ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >> gpio_sub_n(gpio)); + bfin_read_CHIPID(); + local_irq_restore(flags); + return ret; +} +EXPORT_SYMBOL(get_gpio_data); +#else +GET_GPIO(data) +#endif + +/*Get current PORT date (16-bit word)*/ + +#define GET_GPIO_P(name) \ +unsigned short get_gpiop_ ## name(unsigned short gpio) \ +{ \ + return (gpio_bankb[gpio_bank(gpio)]->name);\ +} \ +EXPORT_SYMBOL(get_gpiop_ ## name); + +GET_GPIO_P(dir) +GET_GPIO_P(inen) +GET_GPIO_P(polar) +GET_GPIO_P(edge) +GET_GPIO_P(both) +GET_GPIO_P(maska) +GET_GPIO_P(maskb) + +#if defined(ANOMALY_05000311) +unsigned short get_gpiop_data(unsigned short gpio) +{ + unsigned long flags; + unsigned short ret; + local_irq_save(flags); + ret = gpio_bankb[gpio_bank(gpio)]->data; + bfin_read_CHIPID(); + local_irq_restore(flags); + return ret; +} +EXPORT_SYMBOL(get_gpiop_data); +#else +GET_GPIO_P(data) +#endif + +#ifdef CONFIG_PM +/*********************************************************** +* +* FUNCTIONS: Blackfin PM Setup API +* +* INPUTS/OUTPUTS: +* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS +* type - +* PM_WAKE_RISING +* PM_WAKE_FALLING +* PM_WAKE_HIGH +* PM_WAKE_LOW +* PM_WAKE_BOTH_EDGES +* +* DESCRIPTION: Blackfin PM Driver API +* +* CAUTION: +************************************************************* +* MODIFICATION HISTORY : +**************************************************************/ +int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type) +{ + unsigned long flags; + + if ((check_gpio(gpio) < 0) || !type) + return -EINVAL; + + local_irq_save(flags); + + wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio); + wakeup_flags_map[gpio] = type; + local_irq_restore(flags); + + return 0; +} +EXPORT_SYMBOL(gpio_pm_wakeup_request); + +void gpio_pm_wakeup_free(unsigned short gpio) +{ + unsigned long flags; + + if (check_gpio(gpio) < 0) + return; + + local_irq_save(flags); + + wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); + + local_irq_restore(flags); +} +EXPORT_SYMBOL(gpio_pm_wakeup_free); + +static int bfin_gpio_wakeup_type(unsigned short gpio, unsigned char type) +{ + port_setup(gpio, GPIO_USAGE); + set_gpio_dir(gpio, 0); + set_gpio_inen(gpio, 1); + + if (type & (PM_WAKE_RISING | PM_WAKE_FALLING)) + set_gpio_edge(gpio, 1); + else + set_gpio_edge(gpio, 0); + + if ((type & (PM_WAKE_BOTH_EDGES)) == (PM_WAKE_BOTH_EDGES)) + set_gpio_both(gpio, 1); + else + set_gpio_both(gpio, 0); + + if ((type & (PM_WAKE_FALLING | PM_WAKE_LOW))) + set_gpio_polar(gpio, 1); + else + set_gpio_polar(gpio, 0); + + SSYNC(); + + return 0; +} + +u32 gpio_pm_setup(void) +{ + u32 sic_iwr = 0; + u16 bank, mask, i, gpio; + + for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) { + mask = wakeup_map[gpio_bank(i)]; + bank = gpio_bank(i); + + gpio_bank_saved[bank].maskb = gpio_bankb[bank]->maskb; + gpio_bankb[bank]->maskb = 0; + + if (mask) { +#ifdef BF537_FAMILY + gpio_bank_saved[bank].fer = *port_fer[bank]; +#endif + gpio_bank_saved[bank].inen = gpio_bankb[bank]->inen; + gpio_bank_saved[bank].polar = gpio_bankb[bank]->polar; + gpio_bank_saved[bank].dir = gpio_bankb[bank]->dir; + gpio_bank_saved[bank].edge = gpio_bankb[bank]->edge; + gpio_bank_saved[bank].both = gpio_bankb[bank]->both; + + gpio = i; + + while (mask) { + if (mask & 1) { + bfin_gpio_wakeup_type(gpio, wakeup_flags_map[gpio]); + set_gpio_data(gpio, 0); /*Clear*/ + } + gpio++; + mask >>= 1; + } + + sic_iwr |= 1 << (sic_iwr_irqs[bank] - (IRQ_CORETMR + 1)); + gpio_bankb[bank]->maskb_set = wakeup_map[gpio_bank(i)]; + } + } + + if (sic_iwr) + return sic_iwr; + else + return IWR_ENABLE_ALL; +} + + +void gpio_pm_restore(void) +{ + u16 bank, mask, i; + + for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) { + mask = wakeup_map[gpio_bank(i)]; + bank = gpio_bank(i); + + if (mask) { +#ifdef BF537_FAMILY + *port_fer[bank] = gpio_bank_saved[bank].fer; +#endif + gpio_bankb[bank]->inen = gpio_bank_saved[bank].inen; + gpio_bankb[bank]->dir = gpio_bank_saved[bank].dir; + gpio_bankb[bank]->polar = gpio_bank_saved[bank].polar; + gpio_bankb[bank]->edge = gpio_bank_saved[bank].edge; + gpio_bankb[bank]->both = gpio_bank_saved[bank].both; + } + + gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb; + } +} + +#endif + +/*********************************************************** +* +* FUNCTIONS: Blackfin GPIO Driver +* +* INPUTS/OUTPUTS: +* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS +* +* +* DESCRIPTION: Blackfin GPIO Driver API +* +* CAUTION: +************************************************************* +* MODIFICATION HISTORY : +**************************************************************/ + +int gpio_request(unsigned short gpio, const char *label) +{ + unsigned long flags; + + if (check_gpio(gpio) < 0) + return -EINVAL; + + local_irq_save(flags); + + if (unlikely(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio); + dump_stack(); + local_irq_restore(flags); + return -EBUSY; + } + reserved_map[gpio_bank(gpio)] |= gpio_bit(gpio); + + local_irq_restore(flags); + + port_setup(gpio, GPIO_USAGE); + + return 0; +} +EXPORT_SYMBOL(gpio_request); + + +void gpio_free(unsigned short gpio) +{ + unsigned long flags; + + if (check_gpio(gpio) < 0) + return; + + local_irq_save(flags); + + if (unlikely(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { + printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio); + dump_stack(); + local_irq_restore(flags); + return; + } + + default_gpio(gpio); + + reserved_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); + + local_irq_restore(flags); +} +EXPORT_SYMBOL(gpio_free); + + +void gpio_direction_input(unsigned short gpio) +{ + unsigned long flags; + + BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); + + local_irq_save(flags); + gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio); + gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio); + local_irq_restore(flags); +} +EXPORT_SYMBOL(gpio_direction_input); + +void gpio_direction_output(unsigned short gpio) +{ + unsigned long flags; + + BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); + + local_irq_save(flags); + gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio); + gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio); + local_irq_restore(flags); +} +EXPORT_SYMBOL(gpio_direction_output); diff --git a/trunk/arch/blackfin/kernel/bfin_ksyms.c b/trunk/arch/blackfin/kernel/bfin_ksyms.c new file mode 100644 index 000000000000..f64ecb638fab --- /dev/null +++ b/trunk/arch/blackfin/kernel/bfin_ksyms.c @@ -0,0 +1,119 @@ +/* + * File: arch/blackfin/kernel/bfin_ksyms.c + * Based on: none - original work + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +/* platform dependent support */ + +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(dump_thread); + +EXPORT_SYMBOL(ip_fast_csum); + +EXPORT_SYMBOL(kernel_thread); + +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_trylock); +EXPORT_SYMBOL(__down_interruptible); + +EXPORT_SYMBOL(is_in_rom); + +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy); + +/* The following are special because they're not called + * explicitly (the C compiler generates them). Fortunately, + * their interface isn't gonna change any time soon now, so + * it's OK to leave it out of version control. + */ +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(memchr); +EXPORT_SYMBOL(get_wchan); + +/* + * libgcc functions - functions that are used internally by the + * compiler... (prototypes are not correct though, but that + * doesn't really matter since they're not versioned). + */ +extern void __ashldi3(void); +extern void __ashrdi3(void); +extern void __smulsi3_highpart(void); +extern void __umulsi3_highpart(void); +extern void __divsi3(void); +extern void __lshrdi3(void); +extern void __modsi3(void); +extern void __muldi3(void); +extern void __udivsi3(void); +extern void __umodsi3(void); + +/* gcc lib functions */ +EXPORT_SYMBOL(__ashldi3); +EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__umulsi3_highpart); +EXPORT_SYMBOL(__smulsi3_highpart); +EXPORT_SYMBOL(__divsi3); +EXPORT_SYMBOL(__lshrdi3); +EXPORT_SYMBOL(__modsi3); +EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__udivsi3); +EXPORT_SYMBOL(__umodsi3); + +EXPORT_SYMBOL(outsb); +EXPORT_SYMBOL(insb); +EXPORT_SYMBOL(outsw); +EXPORT_SYMBOL(insw); +EXPORT_SYMBOL(outsl); +EXPORT_SYMBOL(insl); +EXPORT_SYMBOL(irq_flags); +EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(blackfin_dcache_invalidate_range); +EXPORT_SYMBOL(blackfin_icache_dcache_flush_range); +EXPORT_SYMBOL(blackfin_icache_flush_range); +EXPORT_SYMBOL(blackfin_dcache_flush_range); +EXPORT_SYMBOL(blackfin_dflush_page); + +EXPORT_SYMBOL(csum_partial); +EXPORT_SYMBOL(__init_begin); +EXPORT_SYMBOL(__init_end); +EXPORT_SYMBOL(_ebss_l1); +EXPORT_SYMBOL(_stext_l1); +EXPORT_SYMBOL(_etext_l1); +EXPORT_SYMBOL(_sdata_l1); +EXPORT_SYMBOL(_ebss_b_l1); +EXPORT_SYMBOL(_sdata_b_l1); diff --git a/trunk/arch/blackfin/kernel/dma-mapping.c b/trunk/arch/blackfin/kernel/dma-mapping.c new file mode 100644 index 000000000000..539eb24e062f --- /dev/null +++ b/trunk/arch/blackfin/kernel/dma-mapping.c @@ -0,0 +1,183 @@ +/* + * File: arch/blackfin/kernel/dma-mapping.c + * Based on: + * Author: + * + * Created: + * Description: Dynamic DMA mapping support. + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static spinlock_t dma_page_lock; +static unsigned int *dma_page; +static unsigned int dma_pages; +static unsigned long dma_base; +static unsigned long dma_size; +static unsigned int dma_initialized; + +void dma_alloc_init(unsigned long start, unsigned long end) +{ + spin_lock_init(&dma_page_lock); + dma_initialized = 0; + + dma_page = (unsigned int *)__get_free_page(GFP_KERNEL); + memset(dma_page, 0, PAGE_SIZE); + dma_base = PAGE_ALIGN(start); + dma_size = PAGE_ALIGN(end) - PAGE_ALIGN(start); + dma_pages = dma_size >> PAGE_SHIFT; + memset((void *)dma_base, 0, DMA_UNCACHED_REGION); + dma_initialized = 1; + + printk(KERN_INFO "%s: dma_page @ 0x%p - %d pages at 0x%08lx\n", __FUNCTION__, + dma_page, dma_pages, dma_base); +} + +static inline unsigned int get_pages(size_t size) +{ + return ((size - 1) >> PAGE_SHIFT) + 1; +} + +static unsigned long __alloc_dma_pages(unsigned int pages) +{ + unsigned long ret = 0, flags; + int i, count = 0; + + if (dma_initialized == 0) + dma_alloc_init(_ramend - DMA_UNCACHED_REGION, _ramend); + + spin_lock_irqsave(&dma_page_lock, flags); + + for (i = 0; i < dma_pages;) { + if (dma_page[i++] == 0) { + if (++count == pages) { + while (count--) + dma_page[--i] = 1; + ret = dma_base + (i << PAGE_SHIFT); + break; + } + } else + count = 0; + } + spin_unlock_irqrestore(&dma_page_lock, flags); + return ret; +} + +static void __free_dma_pages(unsigned long addr, unsigned int pages) +{ + unsigned long page = (addr - dma_base) >> PAGE_SHIFT; + unsigned long flags; + int i; + + if ((page + pages) > dma_pages) { + printk(KERN_ERR "%s: freeing outside range.\n", __FUNCTION__); + BUG(); + } + + spin_lock_irqsave(&dma_page_lock, flags); + for (i = page; i < page + pages; i++) { + dma_page[i] = 0; + } + spin_unlock_irqrestore(&dma_page_lock, flags); +} + +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t * dma_handle, gfp_t gfp) +{ + void *ret; + + ret = (void *)__alloc_dma_pages(get_pages(size)); + + if (ret) { + memset(ret, 0, size); + *dma_handle = virt_to_phys(ret); + } + + return ret; +} +EXPORT_SYMBOL(dma_alloc_coherent); + +void +dma_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + __free_dma_pages((unsigned long)vaddr, get_pages(size)); +} +EXPORT_SYMBOL(dma_free_coherent); + +/* + * Dummy functions defined for some existing drivers + */ + +dma_addr_t +dma_map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); + + invalidate_dcache_range((unsigned long)ptr, + (unsigned long)ptr + size); + + return (dma_addr_t) ptr; +} +EXPORT_SYMBOL(dma_map_single); + +int +dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + int i; + + BUG_ON(direction == DMA_NONE); + + for (i = 0; i < nents; i++) + invalidate_dcache_range(sg_dma_address(&sg[i]), + sg_dma_address(&sg[i]) + + sg_dma_len(&sg[i])); + + return nents; +} +EXPORT_SYMBOL(dma_map_sg); + +void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); +} +EXPORT_SYMBOL(dma_unmap_single); + +void dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nhwentries, enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); +} +EXPORT_SYMBOL(dma_unmap_sg); diff --git a/trunk/arch/blackfin/kernel/dualcore_test.c b/trunk/arch/blackfin/kernel/dualcore_test.c new file mode 100644 index 000000000000..8b89c99f9dfa --- /dev/null +++ b/trunk/arch/blackfin/kernel/dualcore_test.c @@ -0,0 +1,49 @@ +/* + * File: arch/blackfin/kernel/dualcore_test.c + * Based on: + * Author: + * + * Created: + * Description: Small test code for CoreB on a BF561 + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +static int *testarg = (int*)0xfeb00000; + +static int test_init(void) +{ + *testarg = 1; + printk("Dual core test module inserted: set testarg = [%d]\n @ [%p]\n", + *testarg, testarg); + return 0; +} + +static void test_exit(void) +{ + printk("Dual core test module removed: testarg = [%d]\n", *testarg); +} + +module_init(test_init); +module_exit(test_exit); diff --git a/trunk/arch/blackfin/kernel/entry.S b/trunk/arch/blackfin/kernel/entry.S new file mode 100644 index 000000000000..5880b270bd50 --- /dev/null +++ b/trunk/arch/blackfin/kernel/entry.S @@ -0,0 +1,94 @@ +/* + * File: arch/blackfin/kernel/entry.S + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include + +#ifdef CONFIG_EXCPT_IRQ_SYSC_L1 +.section .l1.text +#else +.text +#endif + +ENTRY(_ret_from_fork) + SP += -12; + call _schedule_tail; + SP += 12; + r0 = [sp + PT_IPEND]; + cc = bittst(r0,1); + if cc jump .Lin_kernel; + RESTORE_CONTEXT + rti; +.Lin_kernel: + bitclr(r0,1); + [sp + PT_IPEND] = r0; + /* do a 'fake' RTI by jumping to [RETI] + * to avoid clearing supervisor mode in child + */ + RESTORE_ALL_SYS + p0 = reti; + jump (p0); + +ENTRY(_sys_fork) + r0 = -EINVAL; + rts; + +ENTRY(_sys_vfork) + r0 = sp; + r0 += 24; + [--sp] = rets; + SP += -12; + call _bfin_vfork; + SP += 12; + rets = [sp++]; + rts; + +ENTRY(_sys_clone) + r0 = sp; + r0 += 24; + [--sp] = rets; + SP += -12; + call _bfin_clone; + SP += 12; + rets = [sp++]; + rts; + +ENTRY(_sys_rt_sigreturn) + r0 = sp; + r0 += 24; + [--sp] = rets; + SP += -12; + call _do_rt_sigreturn; + SP += 12; + rets = [sp++]; + rts; diff --git a/trunk/arch/blackfin/kernel/flat.c b/trunk/arch/blackfin/kernel/flat.c new file mode 100644 index 000000000000..a92587b628b5 --- /dev/null +++ b/trunk/arch/blackfin/kernel/flat.c @@ -0,0 +1,101 @@ +/* + * arch/blackfin/kernel/flat.c + * + * Copyright (C) 2007 Analog Devices, 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 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 +#include +#include + +#define FLAT_BFIN_RELOC_TYPE_16_BIT 0 +#define FLAT_BFIN_RELOC_TYPE_16H_BIT 1 +#define FLAT_BFIN_RELOC_TYPE_32_BIT 2 + +unsigned long bfin_get_addr_from_rp(unsigned long *ptr, + unsigned long relval, + unsigned long flags, + unsigned long *persistent) +{ + unsigned short *usptr = (unsigned short *)ptr; + int type = (relval >> 26) & 7; + unsigned long val; + + switch (type) { + case FLAT_BFIN_RELOC_TYPE_16_BIT: + case FLAT_BFIN_RELOC_TYPE_16H_BIT: + usptr = (unsigned short *)ptr; + pr_debug("*usptr = %x", get_unaligned(usptr)); + val = get_unaligned(usptr); + val += *persistent; + break; + + case FLAT_BFIN_RELOC_TYPE_32_BIT: + pr_debug("*ptr = %lx", get_unaligned(ptr)); + val = get_unaligned(ptr); + break; + + default: + pr_debug("BINFMT_FLAT: Unknown relocation type %x\n", + type); + + return 0; + } + + /* + * Stack-relative relocs contain the offset into the stack, we + * have to add the stack's start address here and return 1 from + * flat_addr_absolute to prevent the normal address calculations + */ + if (relval & (1 << 29)) + return val + current->mm->context.end_brk; + + if ((flags & FLAT_FLAG_GOTPIC) == 0) + val = htonl(val); + return val; +} +EXPORT_SYMBOL(bfin_get_addr_from_rp); + +/* + * Insert the address ADDR into the symbol reference at RP; + * RELVAL is the raw relocation-table entry from which RP is derived + */ +void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr, + unsigned long relval) +{ + unsigned short *usptr = (unsigned short *)ptr; + int type = (relval >> 26) & 7; + + switch (type) { + case FLAT_BFIN_RELOC_TYPE_16_BIT: + put_unaligned(addr, usptr); + pr_debug("new value %x at %p", get_unaligned(usptr), + usptr); + break; + + case FLAT_BFIN_RELOC_TYPE_16H_BIT: + put_unaligned(addr >> 16, usptr); + pr_debug("new value %x", get_unaligned(usptr)); + break; + + case FLAT_BFIN_RELOC_TYPE_32_BIT: + put_unaligned(addr, ptr); + pr_debug("new ptr =%lx", get_unaligned(ptr)); + break; + } +} +EXPORT_SYMBOL(bfin_put_addr_at_rp); diff --git a/trunk/arch/blackfin/kernel/init_task.c b/trunk/arch/blackfin/kernel/init_task.c new file mode 100644 index 000000000000..b45188f8512e --- /dev/null +++ b/trunk/arch/blackfin/kernel/init_task.c @@ -0,0 +1,60 @@ +/* + * File: arch/blackfin/kernel/init_task.c + * Based on: + * Author: + * + * Created: + * Description: This file contains the simple DMA Implementation for Blackfin + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); + +struct mm_struct init_mm = INIT_MM(init_mm); +EXPORT_SYMBOL(init_mm); + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); +EXPORT_SYMBOL(init_task); + +/* + * Initial thread structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry. + */ +union thread_union init_thread_union + __attribute__ ((__section__(".data.init_task"))) = { +INIT_THREAD_INFO(init_task)}; diff --git a/trunk/arch/blackfin/kernel/irqchip.c b/trunk/arch/blackfin/kernel/irqchip.c new file mode 100644 index 000000000000..df5bf022cf79 --- /dev/null +++ b/trunk/arch/blackfin/kernel/irqchip.c @@ -0,0 +1,147 @@ +/* + * File: arch/blackfin/kernel/irqchip.c + * Based on: + * Author: + * + * Created: + * Description: This file contains the simple DMA Implementation for Blackfin + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +static unsigned long irq_err_count; +static spinlock_t irq_controller_lock; + +/* + * Dummy mask/unmask handler + */ +void dummy_mask_unmask_irq(unsigned int irq) +{ +} + +void ack_bad_irq(unsigned int irq) +{ + irq_err_count += 1; + printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); +} +EXPORT_SYMBOL(ack_bad_irq); + +static struct irq_chip bad_chip = { + .ack = dummy_mask_unmask_irq, + .mask = dummy_mask_unmask_irq, + .unmask = dummy_mask_unmask_irq, +}; + +static struct irq_desc bad_irq_desc = { + .chip = &bad_chip, + .handle_irq = handle_bad_irq, + .depth = 1, +}; + +int show_interrupts(struct seq_file *p, void *v) +{ + int i = *(loff_t *) v; + struct irqaction *action; + unsigned long flags; + + if (i < NR_IRQS) { + spin_lock_irqsave(&irq_desc[i].lock, flags); + action = irq_desc[i].action; + if (!action) + goto unlock; + + seq_printf(p, "%3d: %10u ", i, kstat_irqs(i)); + seq_printf(p, " %s", action->name); + for (action = action->next; action; action = action->next) + seq_printf(p, ", %s", action->name); + + seq_putc(p, '\n'); + unlock: + spin_unlock_irqrestore(&irq_desc[i].lock, flags); + } else if (i == NR_IRQS) { + seq_printf(p, "Err: %10lu\n", irq_err_count); + } + return 0; +} + +/* + * do_IRQ handles all hardware IRQ's. Decoded IRQs should not + * come via this function. Instead, they should provide their + * own 'handler' + */ + +#ifdef CONFIG_DO_IRQ_L1 +asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)__attribute__((l1_text)); +#endif + +asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) +{ + struct pt_regs *old_regs; + struct irq_desc *desc = irq_desc + irq; + unsigned short pending, other_ints; + + old_regs = set_irq_regs(regs); + + /* + * Some hardware gives randomly wrong interrupts. Rather + * than crashing, do something sensible. + */ + if (irq >= NR_IRQS) + desc = &bad_irq_desc; + + irq_enter(); + + generic_handle_irq(irq); + + /* If we're the only interrupt running (ignoring IRQ15 which is for + syscalls), lower our priority to IRQ14 so that softirqs run at + that level. If there's another, lower-level interrupt, irq_exit + will defer softirqs to that. */ + CSYNC(); + pending = bfin_read_IPEND() & ~0x8000; + other_ints = pending & (pending - 1); + if (other_ints == 0) + lower_to_irq14(); + irq_exit(); + + set_irq_regs(old_regs); +} + +void __init init_IRQ(void) +{ + struct irq_desc *desc; + int irq; + + spin_lock_init(&irq_controller_lock); + for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) { + *desc = bad_irq_desc; + } + + init_arch_irq(); +} diff --git a/trunk/arch/blackfin/kernel/module.c b/trunk/arch/blackfin/kernel/module.c new file mode 100644 index 000000000000..372f756f1ad9 --- /dev/null +++ b/trunk/arch/blackfin/kernel/module.c @@ -0,0 +1,429 @@ +/* + * File: arch/blackfin/kernel/module.c + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * handle arithmetic relocations. + * See binutils/bfd/elf32-bfin.c for more details + */ +#define RELOC_STACK_SIZE 100 +static uint32_t reloc_stack[RELOC_STACK_SIZE]; +static unsigned int reloc_stack_tos; + +#define is_reloc_stack_empty() ((reloc_stack_tos > 0)?0:1) + +static void reloc_stack_push(uint32_t value) +{ + reloc_stack[reloc_stack_tos++] = value; +} + +static uint32_t reloc_stack_pop(void) +{ + return reloc_stack[--reloc_stack_tos]; +} + +static uint32_t reloc_stack_operate(unsigned int oper, struct module *mod) +{ + uint32_t value; + + switch (oper) { + case R_add: + value = reloc_stack[reloc_stack_tos - 2] + + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_sub: + value = reloc_stack[reloc_stack_tos - 2] - + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_mult: + value = reloc_stack[reloc_stack_tos - 2] * + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_div: + value = reloc_stack[reloc_stack_tos - 2] / + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_mod: + value = reloc_stack[reloc_stack_tos - 2] % + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_lshift: + value = reloc_stack[reloc_stack_tos - 2] << + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_rshift: + value = reloc_stack[reloc_stack_tos - 2] >> + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_and: + value = reloc_stack[reloc_stack_tos - 2] & + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_or: + value = reloc_stack[reloc_stack_tos - 2] | + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_xor: + value = reloc_stack[reloc_stack_tos - 2] ^ + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_land: + value = reloc_stack[reloc_stack_tos - 2] && + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_lor: + value = reloc_stack[reloc_stack_tos - 2] || + reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 2; + break; + case R_neg: + value = -reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos--; + break; + case R_comp: + value = ~reloc_stack[reloc_stack_tos - 1]; + reloc_stack_tos -= 1; + break; + default: + printk(KERN_WARNING "module %s: unhandled reloction\n", + mod->name); + return 0; + } + + /* now push the new value back on stack */ + reloc_stack_push(value); + + return value; +} + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); +} + +/* Transfer the section to the L1 memory */ +int +module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs, + char *secstrings, struct module *mod) +{ + Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum; + void *dest = NULL; + + for (s = sechdrs; s < sechdrs_end; ++s) { + if ((strcmp(".l1.text", secstrings + s->sh_name) == 0) || + ((strcmp(".text", secstrings + s->sh_name)==0) && + (hdr->e_flags & FLG_CODE_IN_L1) && (s->sh_size > 0))) { + mod->arch.text_l1 = s; + dest = l1_inst_sram_alloc(s->sh_size); + if (dest == NULL) { + printk(KERN_ERR + "module %s: L1 instruction memory allocation failed\n", + mod->name); + return -1; + } + dma_memcpy(dest, (void *)s->sh_addr, s->sh_size); + s->sh_flags &= ~SHF_ALLOC; + s->sh_addr = (unsigned long)dest; + } + if ((strcmp(".l1.data", secstrings + s->sh_name) == 0)|| + ((strcmp(".data", secstrings + s->sh_name)==0) && + (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) { + mod->arch.data_a_l1 = s; + dest = l1_data_sram_alloc(s->sh_size); + if (dest == NULL) { + printk(KERN_ERR + "module %s: L1 data memory allocation failed\n", + mod->name); + return -1; + } + memcpy(dest, (void *)s->sh_addr, s->sh_size); + s->sh_flags &= ~SHF_ALLOC; + s->sh_addr = (unsigned long)dest; + } + if (strcmp(".l1.bss", secstrings + s->sh_name) == 0 || + ((strcmp(".bss", secstrings + s->sh_name)==0) && + (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) { + mod->arch.bss_a_l1 = s; + dest = l1_data_sram_alloc(s->sh_size); + if (dest == NULL) { + printk(KERN_ERR + "module %s: L1 data memory allocation failed\n", + mod->name); + return -1; + } + memset(dest, 0, s->sh_size); + s->sh_flags &= ~SHF_ALLOC; + s->sh_addr = (unsigned long)dest; + } + if (strcmp(".l1.data.B", secstrings + s->sh_name) == 0) { + mod->arch.data_b_l1 = s; + dest = l1_data_B_sram_alloc(s->sh_size); + if (dest == NULL) { + printk(KERN_ERR + "module %s: L1 data memory allocation failed\n", + mod->name); + return -1; + } + memcpy(dest, (void *)s->sh_addr, s->sh_size); + s->sh_flags &= ~SHF_ALLOC; + s->sh_addr = (unsigned long)dest; + } + if (strcmp(".l1.bss.B", secstrings + s->sh_name) == 0) { + mod->arch.bss_b_l1 = s; + dest = l1_data_B_sram_alloc(s->sh_size); + if (dest == NULL) { + printk(KERN_ERR + "module %s: L1 data memory allocation failed\n", + mod->name); + return -1; + } + memset(dest, 0, s->sh_size); + s->sh_flags &= ~SHF_ALLOC; + s->sh_addr = (unsigned long)dest; + } + } + return 0; +} + +int +apply_relocate(Elf_Shdr * sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, struct module *me) +{ + printk(KERN_ERR "module %s: .rel unsupported\n", me->name); + return -ENOEXEC; +} + +/*************************************************************************/ +/* FUNCTION : apply_relocate_add */ +/* ABSTRACT : Blackfin specific relocation handling for the loadable */ +/* modules. Modules are expected to be .o files. */ +/* Arithmetic relocations are handled. */ +/* We do not expect LSETUP to be split and hence is not */ +/* handled. */ +/* R_byte and R_byte2 are also not handled as the gas */ +/* does not generate it. */ +/*************************************************************************/ +int +apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, + struct module *mod) +{ + unsigned int i; + unsigned short tmp; + Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + uint32_t *location32; + uint16_t *location16; + uint32_t value; + + pr_debug("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location16 = + (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[i].r_offset); + location32 = (uint32_t *) location16; + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + sym = (Elf32_Sym *) sechdrs[symindex].sh_addr + + ELF32_R_SYM(rel[i].r_info); + if (is_reloc_stack_empty()) { + value = sym->st_value; + } else { + value = reloc_stack_pop(); + } + value += rel[i].r_addend; + pr_debug("location is %x, value is %x type is %d \n", + (unsigned int) location32, value, + ELF32_R_TYPE(rel[i].r_info)); + + switch (ELF32_R_TYPE(rel[i].r_info)) { + + case R_pcrel24: + case R_pcrel24_jump_l: + /* Add the value, subtract its postition */ + location16 = + (uint16_t *) (sechdrs[sechdrs[relsec].sh_info]. + sh_addr + rel[i].r_offset - 2); + location32 = (uint32_t *) location16; + value -= (uint32_t) location32; + value >>= 1; + pr_debug("value is %x, before %x-%x after %x-%x\n", value, + *location16, *(location16 + 1), + (*location16 & 0xff00) | (value >> 16 & 0x00ff), + value & 0xffff); + *location16 = + (*location16 & 0xff00) | (value >> 16 & 0x00ff); + *(location16 + 1) = value & 0xffff; + break; + case R_pcrel12_jump: + case R_pcrel12_jump_s: + value -= (uint32_t) location32; + value >>= 1; + *location16 = (value & 0xfff); + break; + case R_pcrel10: + value -= (uint32_t) location32; + value >>= 1; + *location16 = (value & 0x3ff); + break; + case R_luimm16: + pr_debug("before %x after %x\n", *location16, + (value & 0xffff)); + tmp = (value & 0xffff); + if((unsigned long)location16 >= L1_CODE_START) { + dma_memcpy(location16, &tmp, 2); + } else + *location16 = tmp; + break; + case R_huimm16: + pr_debug("before %x after %x\n", *location16, + ((value >> 16) & 0xffff)); + tmp = ((value >> 16) & 0xffff); + if((unsigned long)location16 >= L1_CODE_START) { + dma_memcpy(location16, &tmp, 2); + } else + *location16 = tmp; + break; + case R_rimm16: + *location16 = (value & 0xffff); + break; + case R_byte4_data: + pr_debug("before %x after %x\n", *location32, value); + *location32 = value; + break; + case R_push: + reloc_stack_push(value); + break; + case R_const: + reloc_stack_push(rel[i].r_addend); + break; + case R_add: + case R_sub: + case R_mult: + case R_div: + case R_mod: + case R_lshift: + case R_rshift: + case R_and: + case R_or: + case R_xor: + case R_land: + case R_lor: + case R_neg: + case R_comp: + reloc_stack_operate(ELF32_R_TYPE(rel[i].r_info), mod); + break; + default: + printk(KERN_ERR "module %s: Unknown relocation: %u\n", + mod->name, ELF32_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + } + return 0; +} + +int +module_finalize(const Elf_Ehdr * hdr, + const Elf_Shdr * sechdrs, struct module *mod) +{ + unsigned int i, strindex = 0, symindex = 0; + char *secstrings; + + secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + + for (i = 1; i < hdr->e_shnum; i++) { + /* Internal symbols and strings. */ + if (sechdrs[i].sh_type == SHT_SYMTAB) { + symindex = i; + strindex = sechdrs[i].sh_link; + } + } + + for (i = 1; i < hdr->e_shnum; i++) { + const char *strtab = (char *)sechdrs[strindex].sh_addr; + unsigned int info = sechdrs[i].sh_info; + + /* Not a valid relocation section? */ + if (info >= hdr->e_shnum) + continue; + + if ((sechdrs[i].sh_type == SHT_RELA) && + ((strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0)|| + ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) && + (hdr->e_flags & FLG_CODE_IN_L1)))) { + apply_relocate_add((Elf_Shdr *) sechdrs, strtab, + symindex, i, mod); + } + } + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ + if ((mod->arch.text_l1) && (mod->arch.text_l1->sh_addr)) + l1_inst_sram_free((void*)mod->arch.text_l1->sh_addr); + if ((mod->arch.data_a_l1) && (mod->arch.data_a_l1->sh_addr)) + l1_data_sram_free((void*)mod->arch.data_a_l1->sh_addr); + if ((mod->arch.bss_a_l1) && (mod->arch.bss_a_l1->sh_addr)) + l1_data_sram_free((void*)mod->arch.bss_a_l1->sh_addr); + if ((mod->arch.data_b_l1) && (mod->arch.data_b_l1->sh_addr)) + l1_data_B_sram_free((void*)mod->arch.data_b_l1->sh_addr); + if ((mod->arch.bss_b_l1) && (mod->arch.bss_b_l1->sh_addr)) + l1_data_B_sram_free((void*)mod->arch.bss_b_l1->sh_addr); +} diff --git a/trunk/arch/blackfin/kernel/process.c b/trunk/arch/blackfin/kernel/process.c new file mode 100644 index 000000000000..3eff7439d8d3 --- /dev/null +++ b/trunk/arch/blackfin/kernel/process.c @@ -0,0 +1,394 @@ +/* + * File: arch/blackfin/kernel/process.c + * Based on: + * Author: + * + * Created: + * Description: Blackfin architecture-dependent process handling. + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define LED_ON 0 +#define LED_OFF 1 + +asmlinkage void ret_from_fork(void); + +/* Points to the SDRAM backup memory for the stack that is currently in + * L1 scratchpad memory. + */ +void *current_l1_stack_save; + +/* The number of tasks currently using a L1 stack area. The SRAM is + * allocated/deallocated whenever this changes from/to zero. + */ +int nr_l1stack_tasks; + +/* Start and length of the area in L1 scratchpad memory which we've allocated + * for process stacks. + */ +void *l1_stack_base; +unsigned long l1_stack_len; + +/* + * Powermanagement idle function, if any.. + */ +void (*pm_idle)(void) = NULL; +EXPORT_SYMBOL(pm_idle); + +void (*pm_power_off)(void) = NULL; +EXPORT_SYMBOL(pm_power_off); + +/* + * We are using a different LED from the one used to indicate timer interrupt. + */ +#if defined(CONFIG_BFIN_IDLE_LED) +static inline void leds_switch(int flag) +{ + unsigned short tmp = 0; + + tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT(); + SSYNC(); + + if (flag == LED_ON) + tmp &= ~CONFIG_BFIN_IDLE_LED_PIN; /* light on */ + else + tmp |= CONFIG_BFIN_IDLE_LED_PIN; /* light off */ + + bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp); + SSYNC(); + +} +#else +static inline void leds_switch(int flag) +{ +} +#endif + +/* + * The idle loop on BFIN + */ +#ifdef CONFIG_IDLE_L1 +void default_idle(void)__attribute__((l1_text)); +void cpu_idle(void)__attribute__((l1_text)); +#endif + +void default_idle(void) +{ + while (!need_resched()) { + leds_switch(LED_OFF); + local_irq_disable(); + if (likely(!need_resched())) + idle_with_irq_disabled(); + local_irq_enable(); + leds_switch(LED_ON); + } +} + +void (*idle)(void) = default_idle; + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + while (1) { + idle(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } +} + +void machine_restart(char *__unused) +{ +#if defined(CONFIG_BLKFIN_CACHE) + bfin_write_IMEM_CONTROL(0x01); + SSYNC(); +#endif + bfin_reset(); + /* Dont do anything till the reset occurs */ + while (1) { + SSYNC(); + } +} + +void machine_halt(void) +{ + for (;;) + asm volatile ("idle"); +} + +void machine_power_off(void) +{ + for (;;) + asm volatile ("idle"); +} + +void show_regs(struct pt_regs *regs) +{ + printk(KERN_NOTICE "\n"); + printk(KERN_NOTICE + "PC: %08lu Status: %04lu SysStatus: %04lu RETS: %08lu\n", + regs->pc, regs->astat, regs->seqstat, regs->rets); + printk(KERN_NOTICE + "A0.x: %08lx A0.w: %08lx A1.x: %08lx A1.w: %08lx\n", + regs->a0x, regs->a0w, regs->a1x, regs->a1w); + printk(KERN_NOTICE "P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n", + regs->p0, regs->p1, regs->p2, regs->p3); + printk(KERN_NOTICE "P4: %08lx P5: %08lx\n", regs->p4, regs->p5); + printk(KERN_NOTICE "R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n", + regs->r0, regs->r1, regs->r2, regs->r3); + printk(KERN_NOTICE "R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n", + regs->r4, regs->r5, regs->r6, regs->r7); + + if (!(regs->ipend)) + printk("USP: %08lx\n", rdusp()); +} + +/* Fill in the fpu structure for a core dump. */ + +int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs) +{ + return 1; +} + +/* + * This gets run with P1 containing the + * function to call, and R1 containing + * the "args". Note P0 is clobbered on the way here. + */ +void kernel_thread_helper(void); +__asm__(".section .text\n" + ".align 4\n" + "_kernel_thread_helper:\n\t" + "\tsp += -12;\n\t" + "\tr0 = r1;\n\t" "\tcall (p1);\n\t" "\tcall _do_exit;\n" ".previous"); + +/* + * Create a kernel thread. + */ +pid_t kernel_thread(int (*fn) (void *), void *arg, unsigned long flags) +{ + struct pt_regs regs; + + memset(®s, 0, sizeof(regs)); + + regs.r1 = (unsigned long)arg; + regs.p1 = (unsigned long)fn; + regs.pc = (unsigned long)kernel_thread_helper; + regs.orig_p0 = -1; + /* Set bit 2 to tell ret_from_fork we should be returning to kernel + mode. */ + regs.ipend = 0x8002; + __asm__ __volatile__("%0 = syscfg;":"=da"(regs.syscfg):); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, + NULL); +} + +void flush_thread(void) +{ +} + +asmlinkage int bfin_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, + NULL); +} + +asmlinkage int bfin_clone(struct pt_regs *regs) +{ + unsigned long clone_flags; + unsigned long newsp; + + /* syscall2 puts clone_flags in r0 and usp in r1 */ + clone_flags = regs->r0; + newsp = regs->r1; + if (!newsp) + newsp = rdusp(); + else + newsp -= 12; + return do_fork(clone_flags, newsp, regs, 0, NULL, NULL); +} + +int +copy_thread(int nr, unsigned long clone_flags, + unsigned long usp, unsigned long topstk, + struct task_struct *p, struct pt_regs *regs) +{ + struct pt_regs *childregs; + + childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; + *childregs = *regs; + childregs->r0 = 0; + + p->thread.usp = usp; + p->thread.ksp = (unsigned long)childregs; + p->thread.pc = (unsigned long)ret_from_fork; + + return 0; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs *regs, struct user *dump) +{ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = rdusp() & ~(PAGE_SIZE - 1); + dump->u_tsize = ((unsigned long)current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long)(current->mm->brk + + (PAGE_SIZE - 1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + + if (dump->start_stack < TASK_SIZE) + dump->u_ssize = + ((unsigned long)(TASK_SIZE - + dump->start_stack)) >> PAGE_SHIFT; + + dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump); + + dump->regs.r0 = regs->r0; + dump->regs.r1 = regs->r1; + dump->regs.r2 = regs->r2; + dump->regs.r3 = regs->r3; + dump->regs.r4 = regs->r4; + dump->regs.r5 = regs->r5; + dump->regs.r6 = regs->r6; + dump->regs.r7 = regs->r7; + dump->regs.p0 = regs->p0; + dump->regs.p1 = regs->p1; + dump->regs.p2 = regs->p2; + dump->regs.p3 = regs->p3; + dump->regs.p4 = regs->p4; + dump->regs.p5 = regs->p5; + dump->regs.orig_p0 = regs->orig_p0; + dump->regs.a0w = regs->a0w; + dump->regs.a1w = regs->a1w; + dump->regs.a0x = regs->a0x; + dump->regs.a1x = regs->a1x; + dump->regs.rets = regs->rets; + dump->regs.astat = regs->astat; + dump->regs.pc = regs->pc; +} + +/* + * sys_execve() executes a new program. + */ + +asmlinkage int sys_execve(char *name, char **argv, char **envp) +{ + int error; + char *filename; + struct pt_regs *regs = (struct pt_regs *)((&name) + 6); + + lock_kernel(); + filename = getname(name); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, argv, envp, regs); + putname(filename); + out: + unlock_kernel(); + return error; +} + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long fp, pc; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + stack_page = (unsigned long)p; + fp = p->thread.usp; + do { + if (fp < stack_page + sizeof(struct thread_info) || + fp >= 8184 + stack_page) + return 0; + pc = ((unsigned long *)fp)[1]; + if (!in_sched_functions(pc)) + return pc; + fp = *(unsigned long *)fp; + } + while (count++ < 16); + return 0; +} + +#if defined(CONFIG_ACCESS_CHECK) +int _access_ok(unsigned long addr, unsigned long size) +{ + + if (addr > (addr + size)) + return 0; + if (segment_eq(get_fs(),KERNEL_DS)) + return 1; +#ifdef CONFIG_MTD_UCLINUX + if (addr >= memory_start && (addr + size) <= memory_end) + return 1; + if (addr >= memory_mtd_end && (addr + size) <= physical_mem_end) + return 1; +#else + if (addr >= memory_start && (addr + size) <= physical_mem_end) + return 1; +#endif + if (addr >= (unsigned long)__init_begin && + addr + size <= (unsigned long)__init_end) + return 1; + if (addr >= L1_SCRATCH_START + && addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH) + return 1; +#if L1_CODE_LENGTH != 0 + if (addr >= L1_CODE_START + (_etext_l1 - _stext_l1) + && addr + size <= L1_CODE_START + L1_CODE_LENGTH) + return 1; +#endif +#if L1_DATA_A_LENGTH != 0 + if (addr >= L1_DATA_A_START + (_ebss_l1 - _sdata_l1) + && addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH) + return 1; +#endif +#if L1_DATA_B_LENGTH != 0 + if (addr >= L1_DATA_B_START + && addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH) + return 1; +#endif + return 0; +} +EXPORT_SYMBOL(_access_ok); +#endif /* CONFIG_ACCESS_CHECK */ diff --git a/trunk/arch/blackfin/kernel/ptrace.c b/trunk/arch/blackfin/kernel/ptrace.c new file mode 100644 index 000000000000..d7c8e514cb92 --- /dev/null +++ b/trunk/arch/blackfin/kernel/ptrace.c @@ -0,0 +1,430 @@ +/* + * File: arch/blackfin/kernel/ptrace.c + * Based on: Taken from linux/kernel/ptrace.c + * Author: linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * Created: 1/23/92 + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_SHARED_LIBS 3 +#define TEXT_OFFSET 0 +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which bits in the SYSCFG reg the user has access to. */ +/* 1 = access 0 = no access */ +#define SYSCFG_MASK 0x0007 /* SYSCFG reg */ +/* sets the trace bits. */ +#define TRACE_BITS 0x0001 + +/* Find the stack offset for a register, relative to thread.esp0. */ +#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) + +/* + * Get the address of the live pt_regs for the specified task. + * These are saved onto the top kernel stack when the process + * is not running. + * + * Note: if a user thread is execve'd from kernel space, the + * kernel stack will not be empty on entry to the kernel, so + * ptracing these tasks will fail. + */ +static inline struct pt_regs *get_user_regs(struct task_struct *task) +{ + return (struct pt_regs *) + ((unsigned long)task->thread_info + + (THREAD_SIZE - sizeof(struct pt_regs))); +} + +/* + * Get all user integer registers. + */ +static inline int ptrace_getregs(struct task_struct *tsk, void __user * uregs) +{ + struct pt_regs *regs = get_user_regs(tsk); + return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; +} + +/* Mapping from PT_xxx to the stack offset at which the register is + * saved. Notice that usp has no stack-slot and needs to be treated + * specially (see get_reg/put_reg below). + */ + +/* + * Get contents of register REGNO in task TASK. + */ +static inline long get_reg(struct task_struct *task, int regno) +{ + unsigned char *reg_ptr; + + struct pt_regs *regs = + (struct pt_regs *)((unsigned long)task->thread_info + + (THREAD_SIZE - sizeof(struct pt_regs))); + reg_ptr = (char *)regs; + + switch (regno) { + case PT_USP: + return task->thread.usp; + default: + if (regno <= 216) + return *(long *)(reg_ptr + regno); + } + /* slight mystery ... never seems to come here but kernel misbehaves without this code! */ + + printk(KERN_WARNING "Request to get for unknown register %d\n", regno); + return 0; +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int +put_reg(struct task_struct *task, int regno, unsigned long data) +{ + char * reg_ptr; + + struct pt_regs *regs = + (struct pt_regs *)((unsigned long)task->thread_info + + (THREAD_SIZE - sizeof(struct pt_regs))); + reg_ptr = (char *)regs; + + switch (regno) { + case PT_PC: + /*********************************************************************/ + /* At this point the kernel is most likely in exception. */ + /* The RETX register will be used to populate the pc of the process. */ + /*********************************************************************/ + regs->retx = data; + regs->pc = data; + break; + case PT_RETX: + break; /* regs->retx = data; break; */ + case PT_USP: + regs->usp = data; + task->thread.usp = data; + break; + default: + if (regno <= 216) + *(long *)(reg_ptr + regno) = data; + } + return 0; +} + +/* + * check that an address falls within the bounds of the target process's memory mappings + */ +static inline int is_user_addr_valid(struct task_struct *child, + unsigned long start, unsigned long len) +{ + struct vm_list_struct *vml; + struct sram_list_struct *sraml; + + for (vml = child->mm->context.vmlist; vml; vml = vml->next) + if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end) + return 0; + + for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next) + if (start >= (unsigned long)sraml->addr + && start + len <= (unsigned long)sraml->addr + sraml->length) + return 0; + + return -EIO; +} + +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure the single step bit is not set. + */ +void ptrace_disable(struct task_struct *child) +{ + unsigned long tmp; + /* make sure the single step bit is not set. */ + tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); + put_reg(child, PT_SR, tmp); +} + +long arch_ptrace(struct task_struct *child, long request, long addr, long data) +{ + int ret; + int add = 0; + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKDATA: + pr_debug("ptrace: PEEKDATA\n"); + add = MAX_SHARED_LIBS * 4; /* space between text and data */ + /* fall through */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + { + unsigned long tmp = 0; + int copied; + + ret = -EIO; + pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add, + sizeof(data)); + if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0) + break; + pr_debug("ptrace: user address is valid\n"); + +#if L1_CODE_LENGTH != 0 + if (addr + add >= L1_CODE_START + && addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) { + safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp)); + copied = sizeof(tmp); + } else +#endif + copied = + access_process_vm(child, addr + add, &tmp, + sizeof(tmp), 0); + pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp); + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp, (unsigned long *)data); + break; + } + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: + { + unsigned long tmp; + ret = -EIO; + tmp = 0; + if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) { + printk(KERN_WARNING "ptrace error : PEEKUSR : temporarily returning " + "0 - %x sizeof(pt_regs) is %lx\n", + (int)addr, sizeof(struct pt_regs)); + break; + } + if (addr == sizeof(struct pt_regs)) { + /* PT_TEXT_ADDR */ + tmp = child->mm->start_code + TEXT_OFFSET; + } else if (addr == (sizeof(struct pt_regs) + 4)) { + /* PT_TEXT_END_ADDR */ + tmp = child->mm->end_code; + } else if (addr == (sizeof(struct pt_regs) + 8)) { + /* PT_DATA_ADDR */ + tmp = child->mm->start_data; +#ifdef CONFIG_BINFMT_ELF_FDPIC + } else if (addr == (sizeof(struct pt_regs) + 12)) { + tmp = child->mm->context.exec_fdpic_loadmap; + } else if (addr == (sizeof(struct pt_regs) + 16)) { + tmp = child->mm->context.interp_fdpic_loadmap; +#endif + } else { + tmp = get_reg(child, addr); + } + ret = put_user(tmp, (unsigned long *)data); + break; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKEDATA: + printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n"); + /* fall through */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + { + int copied; + + ret = -EIO; + pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n", + addr, add, sizeof(data), data); + if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0) + break; + pr_debug("ptrace: user address is valid\n"); + +#if L1_CODE_LENGTH != 0 + if (addr + add >= L1_CODE_START + && addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) { + safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data)); + copied = sizeof(data); + } else +#endif + copied = + access_process_vm(child, addr + add, &data, + sizeof(data), 1); + pr_debug("ptrace: copied size %d\n", copied); + if (copied != sizeof(data)) + break; + ret = 0; + break; + } + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; + if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) { + printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n"); + break; + } + + if (addr >= (sizeof(struct pt_regs))) { + ret = 0; + break; + } + if (addr == PT_SYSCFG) { + data &= SYSCFG_MASK; + data |= get_reg(child, PT_SYSCFG); + } + ret = put_reg(child, addr, data); + break; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: + { /* restart after signal. */ + long tmp; + + pr_debug("ptrace_cont\n"); + + ret = -EIO; + if (!valid_signal(data)) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + + child->exit_code = data; + /* make sure the single step bit is not set. */ + tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS); + put_reg(child, PT_SYSCFG, tmp); + pr_debug("before wake_up_process\n"); + wake_up_process(child); + ret = 0; + break; + } + + /* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: + { + long tmp; + ret = 0; + if (child->exit_state == EXIT_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS); + put_reg(child, PT_SYSCFG, tmp); + wake_up_process(child); + break; + } + + case PTRACE_SINGLESTEP: + { /* set the trap flag. */ + long tmp; + + pr_debug("single step\n"); + ret = -EIO; + if (!valid_signal(data)) + break; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + + tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS); + put_reg(child, PT_SYSCFG, tmp); + + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_DETACH: + { /* detach a process that was attached. */ + ret = ptrace_detach(child, data); + break; + } + + case PTRACE_GETREGS: + { + + /* Get all gp regs from the child. */ + ret = ptrace_getregs(child, (void __user *)data); + break; + } + + case PTRACE_SETREGS: + { + printk(KERN_NOTICE + "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n"); + /* Set all gp regs in the child. */ + ret = 0; + break; + } + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + return ret; +} + +asmlinkage void syscall_trace(void) +{ + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + + if (!(current->ptrace & PT_PTRACED)) + return; + + /* the 0x80 provides a way for the tracing parent to distinguish + * between a syscall stop and SIGTRAP delivery + */ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} diff --git a/trunk/arch/blackfin/kernel/setup.c b/trunk/arch/blackfin/kernel/setup.c new file mode 100644 index 000000000000..342bb8dd56ac --- /dev/null +++ b/trunk/arch/blackfin/kernel/setup.c @@ -0,0 +1,902 @@ +/* + * File: arch/blackfin/kernel/setup.c + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +unsigned long memory_start, memory_end, physical_mem_end; +unsigned long reserved_mem_dcache_on; +unsigned long reserved_mem_icache_on; +EXPORT_SYMBOL(memory_start); +EXPORT_SYMBOL(memory_end); +EXPORT_SYMBOL(physical_mem_end); +EXPORT_SYMBOL(_ramend); + +#ifdef CONFIG_MTD_UCLINUX +unsigned long memory_mtd_end, memory_mtd_start, mtd_size; +unsigned long _ebss; +EXPORT_SYMBOL(memory_mtd_end); +EXPORT_SYMBOL(memory_mtd_start); +EXPORT_SYMBOL(mtd_size); +#endif + +char command_line[COMMAND_LINE_SIZE]; + +#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE) +static void generate_cpl_tables(void); +#endif + +void __init bf53x_cache_init(void) +{ +#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE) + generate_cpl_tables(); +#endif + +#ifdef CONFIG_BLKFIN_CACHE + bfin_icache_init(); + printk(KERN_INFO "Instruction Cache Enabled\n"); +#endif + +#ifdef CONFIG_BLKFIN_DCACHE + bfin_dcache_init(); + printk(KERN_INFO "Data Cache Enabled" +# if defined CONFIG_BLKFIN_WB + " (write-back)" +# elif defined CONFIG_BLKFIN_WT + " (write-through)" +# endif + "\n"); +#endif +} + +void bf53x_relocate_l1_mem(void) +{ + unsigned long l1_code_length; + unsigned long l1_data_a_length; + unsigned long l1_data_b_length; + + l1_code_length = _etext_l1 - _stext_l1; + if (l1_code_length > L1_CODE_LENGTH) + l1_code_length = L1_CODE_LENGTH; + /* cannot complain as printk is not available as yet. + * But we can continue booting and complain later! + */ + + /* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */ + dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length); + + l1_data_a_length = _ebss_l1 - _sdata_l1; + if (l1_data_a_length > L1_DATA_A_LENGTH) + l1_data_a_length = L1_DATA_A_LENGTH; + + /* Copy _sdata_l1 to _ebss_l1 to L1 data bank A SRAM */ + dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length); + + l1_data_b_length = _ebss_b_l1 - _sdata_b_l1; + if (l1_data_b_length > L1_DATA_B_LENGTH) + l1_data_b_length = L1_DATA_B_LENGTH; + + /* Copy _sdata_b_l1 to _ebss_b_l1 to L1 data bank B SRAM */ + dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length + + l1_data_a_length, l1_data_b_length); + +} + +/* + * Initial parsing of the command line. Currently, we support: + * - Controlling the linux memory size: mem=xxx[KMG] + * - Controlling the physical memory size: max_mem=xxx[KMG][$][#] + * $ -> reserved memory is dcacheable + * # -> reserved memory is icacheable + */ +static __init void parse_cmdline_early(char *cmdline_p) +{ + char c = ' ', *to = cmdline_p; + unsigned int memsize; + for (;;) { + if (c == ' ') { + + if (!memcmp(to, "mem=", 4)) { + to += 4; + memsize = memparse(to, &to); + if (memsize) + _ramend = memsize; + + } else if (!memcmp(to, "max_mem=", 8)) { + to += 8; + memsize = memparse(to, &to); + if (memsize) { + physical_mem_end = memsize; + if (*to != ' ') { + if (*to == '$' + || *(to + 1) == '$') + reserved_mem_dcache_on = + 1; + if (*to == '#' + || *(to + 1) == '#') + reserved_mem_icache_on = + 1; + } + } + } + + } + c = *(to++); + if (!c) + break; + } +} + +void __init setup_arch(char **cmdline_p) +{ + int bootmap_size; + unsigned long l1_length, sclk, cclk; +#ifdef CONFIG_MTD_UCLINUX + unsigned long mtd_phys = 0; +#endif + + cclk = get_cclk(); + sclk = get_sclk(); + +#if !defined(CONFIG_BFIN_KERNEL_CLOCK) && defined(ANOMALY_05000273) + if (cclk == sclk) + panic("ANOMALY 05000273, SCLK can not be same as CCLK"); +#endif + +#if defined(ANOMALY_05000266) + bfin_read_IMDMA_D0_IRQ_STATUS(); + bfin_read_IMDMA_D1_IRQ_STATUS(); +#endif + +#ifdef DEBUG_SERIAL_EARLY_INIT + bfin_console_init(); /* early console registration */ + /* this give a chance to get printk() working before crash. */ +#endif + +#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH) + /* we need to initialize the Flashrom device here since we might + * do things with flash early on in the boot + */ + flash_probe(); +#endif + +#if defined(CONFIG_CMDLINE_BOOL) + memset(command_line, 0, sizeof(command_line)); + strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line)); + command_line[sizeof(command_line) - 1] = 0; +#endif + + /* Keep a copy of command line */ + *cmdline_p = &command_line[0]; + memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE - 1] = 0; + + /* setup memory defaults from the user config */ + physical_mem_end = 0; + _ramend = CONFIG_MEM_SIZE * 1024 * 1024; + + parse_cmdline_early(&command_line[0]); + + if (physical_mem_end == 0) + physical_mem_end = _ramend; + + /* by now the stack is part of the init task */ + memory_end = _ramend - DMA_UNCACHED_REGION; + + _ramstart = (unsigned long)__bss_stop; + memory_start = PAGE_ALIGN(_ramstart); + +#if defined(CONFIG_MTD_UCLINUX) + /* generic memory mapped MTD driver */ + memory_mtd_end = memory_end; + + mtd_phys = _ramstart; + mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 8))); + +# if defined(CONFIG_EXT2_FS) || defined(CONFIG_EXT3_FS) + if (*((unsigned short *)(mtd_phys + 0x438)) == EXT2_SUPER_MAGIC) + mtd_size = + PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x404)) << 10); +# endif + +# if defined(CONFIG_CRAMFS) + if (*((unsigned long *)(mtd_phys)) == CRAMFS_MAGIC) + mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x4))); +# endif + +# if defined(CONFIG_ROMFS_FS) + if (((unsigned long *)mtd_phys)[0] == ROMSB_WORD0 + && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1) + mtd_size = + PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2])); +# if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) + /* Due to a Hardware Anomaly we need to limit the size of usable + * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on + * 05000263 - Hardware loop corrupted when taking an ICPLB exception + */ +# if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO)) + if (memory_end >= 56 * 1024 * 1024) + memory_end = 56 * 1024 * 1024; +# else + if (memory_end >= 60 * 1024 * 1024) + memory_end = 60 * 1024 * 1024; +# endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */ +# endif /* ANOMALY_05000263 */ +# endif /* CONFIG_ROMFS_FS */ + + memory_end -= mtd_size; + + if (mtd_size == 0) { + console_init(); + panic("Don't boot kernel without rootfs attached.\n"); + } + + /* Relocate MTD image to the top of memory after the uncached memory area */ + dma_memcpy((char *)memory_end, __bss_stop, mtd_size); + + memory_mtd_start = memory_end; + _ebss = memory_mtd_start; /* define _ebss for compatible */ +#endif /* CONFIG_MTD_UCLINUX */ + +#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) + /* Due to a Hardware Anomaly we need to limit the size of usable + * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on + * 05000263 - Hardware loop corrupted when taking an ICPLB exception + */ +#if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO)) + if (memory_end >= 56 * 1024 * 1024) + memory_end = 56 * 1024 * 1024; +#else + if (memory_end >= 60 * 1024 * 1024) + memory_end = 60 * 1024 * 1024; +#endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */ + printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20); +#endif /* ANOMALY_05000263 */ + +#if !defined(CONFIG_MTD_UCLINUX) + memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/ +#endif + init_mm.start_code = (unsigned long)_stext; + init_mm.end_code = (unsigned long)_etext; + init_mm.end_data = (unsigned long)_edata; + init_mm.brk = (unsigned long)0; + + init_leds(); + + printk(KERN_INFO "Blackfin support (C) 2004-2007 Analog Devices, Inc.\n"); + printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid()); + if (bfin_revid() != bfin_compiled_revid()) + printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n", + bfin_compiled_revid(), bfin_revid()); + if (bfin_revid() < SUPPORTED_REVID) + printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n", + CPU, bfin_revid()); + printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n"); + + printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System Clock\n", + cclk / 1000000, sclk / 1000000); + +#if defined(ANOMALY_05000273) + if ((cclk >> 1) <= sclk) + printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n"); +#endif + + printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20); + printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20); + + printk(KERN_INFO "Memory map:\n" + KERN_INFO " text = 0x%p-0x%p\n" + KERN_INFO " init = 0x%p-0x%p\n" + KERN_INFO " data = 0x%p-0x%p\n" + KERN_INFO " stack = 0x%p-0x%p\n" + KERN_INFO " bss = 0x%p-0x%p\n" + KERN_INFO " available = 0x%p-0x%p\n" +#ifdef CONFIG_MTD_UCLINUX + KERN_INFO " rootfs = 0x%p-0x%p\n" +#endif +#if DMA_UNCACHED_REGION > 0 + KERN_INFO " DMA Zone = 0x%p-0x%p\n" +#endif + , _stext, _etext, + __init_begin, __init_end, + _sdata, _edata, + (void*)&init_thread_union, (void*)((int)(&init_thread_union) + 0x2000), + __bss_start, __bss_stop, + (void*)_ramstart, (void*)memory_end +#ifdef CONFIG_MTD_UCLINUX + , (void*)memory_mtd_start, (void*)(memory_mtd_start + mtd_size) +#endif +#if DMA_UNCACHED_REGION > 0 + , (void*)(_ramend - DMA_UNCACHED_REGION), (void*)(_ramend) +#endif + ); + + /* + * give all the memory to the bootmap allocator, tell it to put the + * boot mem_map at the start of memory + */ + bootmap_size = init_bootmem_node(NODE_DATA(0), memory_start >> PAGE_SHIFT, /* map goes here */ + PAGE_OFFSET >> PAGE_SHIFT, + memory_end >> PAGE_SHIFT); + /* + * free the usable memory, we have to make sure we do not free + * the bootmem bitmap so we then reserve it after freeing it :-) + */ + free_bootmem(memory_start, memory_end - memory_start); + + reserve_bootmem(memory_start, bootmap_size); + /* + * get kmalloc into gear + */ + paging_init(); + + /* check the size of the l1 area */ + l1_length = _etext_l1 - _stext_l1; + if (l1_length > L1_CODE_LENGTH) + panic("L1 memory overflow\n"); + + l1_length = _ebss_l1 - _sdata_l1; + if (l1_length > L1_DATA_A_LENGTH) + panic("L1 memory overflow\n"); + + bf53x_cache_init(); + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) +# if defined(CONFIG_BFIN_SHARED_FLASH_ENET) && defined(CONFIG_BFIN533_STAMP) + /* setup BF533_STAMP CPLD to route AMS3 to Ethernet MAC */ + bfin_write_FIO_DIR(bfin_read_FIO_DIR() | (1 << CONFIG_ENET_FLASH_PIN)); + bfin_write_FIO_FLAG_S(1 << CONFIG_ENET_FLASH_PIN); + SSYNC(); +# endif +# if defined (CONFIG_BFIN561_EZKIT) + bfin_write_FIO0_DIR(bfin_read_FIO0_DIR() | (1 << 12)); + SSYNC(); +# endif /* defined (CONFIG_BFIN561_EZKIT) */ +#endif + + printk(KERN_INFO "Hardware Trace Enabled\n"); + bfin_write_TBUFCTL(0x03); +} + +#if defined(CONFIG_BF561) +static struct cpu cpu[2]; +#else +static struct cpu cpu[1]; +#endif +static int __init topology_init(void) +{ +#if defined (CONFIG_BF561) + register_cpu(&cpu[0], 0); + register_cpu(&cpu[1], 1); + return 0; +#else + return register_cpu(cpu, 0); +#endif +} + +subsys_initcall(topology_init); + +#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE) +u16 lock_kernel_check(u32 start, u32 end) +{ + if ((start <= (u32) _stext && end >= (u32) _end) + || (start >= (u32) _stext && end <= (u32) _end)) + return IN_KERNEL; + return 0; +} + +static unsigned short __init +fill_cplbtab(struct cplb_tab *table, + unsigned long start, unsigned long end, + unsigned long block_size, unsigned long cplb_data) +{ + int i; + + switch (block_size) { + case SIZE_4M: + i = 3; + break; + case SIZE_1M: + i = 2; + break; + case SIZE_4K: + i = 1; + break; + case SIZE_1K: + default: + i = 0; + break; + } + + cplb_data = (cplb_data & ~(3 << 16)) | (i << 16); + + while ((start < end) && (table->pos < table->size)) { + + table->tab[table->pos++] = start; + + if (lock_kernel_check(start, start + block_size) == IN_KERNEL) + table->tab[table->pos++] = + cplb_data | CPLB_LOCK | CPLB_DIRTY; + else + table->tab[table->pos++] = cplb_data; + + start += block_size; + } + return 0; +} + +static unsigned short __init +close_cplbtab(struct cplb_tab *table) +{ + + while (table->pos < table->size) { + + table->tab[table->pos++] = 0; + table->tab[table->pos++] = 0; /* !CPLB_VALID */ + } + return 0; +} + +static void __init generate_cpl_tables(void) +{ + + u16 i, j, process; + u32 a_start, a_end, as, ae, as_1m; + + struct cplb_tab *t_i = NULL; + struct cplb_tab *t_d = NULL; + struct s_cplb cplb; + + cplb.init_i.size = MAX_CPLBS; + cplb.init_d.size = MAX_CPLBS; + cplb.switch_i.size = MAX_SWITCH_I_CPLBS; + cplb.switch_d.size = MAX_SWITCH_D_CPLBS; + + cplb.init_i.pos = 0; + cplb.init_d.pos = 0; + cplb.switch_i.pos = 0; + cplb.switch_d.pos = 0; + + cplb.init_i.tab = icplb_table; + cplb.init_d.tab = dcplb_table; + cplb.switch_i.tab = ipdt_table; + cplb.switch_d.tab = dpdt_table; + + cplb_data[SDRAM_KERN].end = memory_end; + +#ifdef CONFIG_MTD_UCLINUX + cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start; + cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size; + cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0; +# if defined(CONFIG_ROMFS_FS) + cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB; + + /* + * The ROMFS_FS size is often not multiple of 1MB. + * This can cause multiple CPLB sets covering the same memory area. + * This will then cause multiple CPLB hit exceptions. + * Workaround: We ensure a contiguous memory area by extending the kernel + * memory section over the mtd section. + * For ROMFS_FS memory must be covered with ICPLBs anyways. + * So there is no difference between kernel and mtd memory setup. + */ + + cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;; + cplb_data[SDRAM_RAM_MTD].valid = 0; + +# endif +#else + cplb_data[SDRAM_RAM_MTD].valid = 0; +#endif + + cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION; + cplb_data[SDRAM_DMAZ].end = _ramend; + + cplb_data[RES_MEM].start = _ramend; + cplb_data[RES_MEM].end = physical_mem_end; + + if (reserved_mem_dcache_on) + cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC; + else + cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL; + + if (reserved_mem_icache_on) + cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC; + else + cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL; + + for (i = ZERO_P; i <= L2_MEM; i++) { + + if (cplb_data[i].valid) { + + as_1m = cplb_data[i].start % SIZE_1M; + + /* We need to make sure all sections are properly 1M aligned + * However between Kernel Memory and the Kernel mtd section, depending on the + * rootfs size, there can be overlapping memory areas. + */ + + if (as_1m && i!=L1I_MEM && i!=L1D_MEM) { +#ifdef CONFIG_MTD_UCLINUX + if (i == SDRAM_RAM_MTD) { + if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start) + cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M; + else + cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)); + } else +#endif + printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n", + cplb_data[i].name, cplb_data[i].start); + } + + as = cplb_data[i].start % SIZE_4M; + ae = cplb_data[i].end % SIZE_4M; + + if (as) + a_start = cplb_data[i].start + (SIZE_4M - (as)); + else + a_start = cplb_data[i].start; + + a_end = cplb_data[i].end - ae; + + for (j = INITIAL_T; j <= SWITCH_T; j++) { + + switch (j) { + case INITIAL_T: + if (cplb_data[i].attr & INITIAL_T) { + t_i = &cplb.init_i; + t_d = &cplb.init_d; + process = 1; + } else + process = 0; + break; + case SWITCH_T: + if (cplb_data[i].attr & SWITCH_T) { + t_i = &cplb.switch_i; + t_d = &cplb.switch_d; + process = 1; + } else + process = 0; + break; + default: + process = 0; + break; + } + + if (process) { + if (cplb_data[i].attr & I_CPLB) { + + if (cplb_data[i].psize) { + fill_cplbtab(t_i, + cplb_data[i].start, + cplb_data[i].end, + cplb_data[i].psize, + cplb_data[i].i_conf); + } else { + /*icplb_table */ +#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) + if (i == SDRAM_KERN) { + fill_cplbtab(t_i, + cplb_data[i].start, + cplb_data[i].end, + SIZE_4M, + cplb_data[i].i_conf); + } else +#endif + { + fill_cplbtab(t_i, + cplb_data[i].start, + a_start, + SIZE_1M, + cplb_data[i].i_conf); + fill_cplbtab(t_i, + a_start, + a_end, + SIZE_4M, + cplb_data[i].i_conf); + fill_cplbtab(t_i, a_end, + cplb_data[i].end, + SIZE_1M, + cplb_data[i].i_conf); + } + } + + } + if (cplb_data[i].attr & D_CPLB) { + + if (cplb_data[i].psize) { + fill_cplbtab(t_d, + cplb_data[i].start, + cplb_data[i].end, + cplb_data[i].psize, + cplb_data[i].d_conf); + } else { +/*dcplb_table*/ + fill_cplbtab(t_d, + cplb_data[i].start, + a_start, SIZE_1M, + cplb_data[i].d_conf); + fill_cplbtab(t_d, a_start, + a_end, SIZE_4M, + cplb_data[i].d_conf); + fill_cplbtab(t_d, a_end, + cplb_data[i].end, + SIZE_1M, + cplb_data[i].d_conf); + + } + + } + } + } + + } + } + +/* close tables */ + + close_cplbtab(&cplb.init_i); + close_cplbtab(&cplb.init_d); + + cplb.init_i.tab[cplb.init_i.pos] = -1; + cplb.init_d.tab[cplb.init_d.pos] = -1; + cplb.switch_i.tab[cplb.switch_i.pos] = -1; + cplb.switch_d.tab[cplb.switch_d.pos] = -1; + +} + +#endif + +static inline u_long get_vco(void) +{ + u_long msel; + u_long vco; + + msel = (bfin_read_PLL_CTL() >> 9) & 0x3F; + if (0 == msel) + msel = 64; + + vco = CONFIG_CLKIN_HZ; + vco >>= (1 & bfin_read_PLL_CTL()); /* DF bit */ + vco = msel * vco; + return vco; +} + +/*Get the Core clock*/ +u_long get_cclk(void) +{ + u_long csel, ssel; + if (bfin_read_PLL_STAT() & 0x1) + return CONFIG_CLKIN_HZ; + + ssel = bfin_read_PLL_DIV(); + csel = ((ssel >> 4) & 0x03); + ssel &= 0xf; + if (ssel && ssel < (1 << csel)) /* SCLK > CCLK */ + return get_vco() / ssel; + return get_vco() >> csel; +} + +EXPORT_SYMBOL(get_cclk); + +/* Get the System clock */ +u_long get_sclk(void) +{ + u_long ssel; + + if (bfin_read_PLL_STAT() & 0x1) + return CONFIG_CLKIN_HZ; + + ssel = (bfin_read_PLL_DIV() & 0xf); + if (0 == ssel) { + printk(KERN_WARNING "Invalid System Clock\n"); + ssel = 1; + } + + return get_vco() / ssel; +} + +EXPORT_SYMBOL(get_sclk); + +/* + * Get CPU information for use by the procfs. + */ +static int show_cpuinfo(struct seq_file *m, void *v) +{ + char *cpu, *mmu, *fpu, *name; + uint32_t revid; + + u_long cclk = 0, sclk = 0; + u_int dcache_size = 0, dsup_banks = 0; + + cpu = CPU; + mmu = "none"; + fpu = "none"; + revid = bfin_revid(); + name = bfin_board_name; + + cclk = get_cclk(); + sclk = get_sclk(); + + seq_printf(m, "CPU:\t\tADSP-%s Rev. 0.%d\n" + "MMU:\t\t%s\n" + "FPU:\t\t%s\n" + "Core Clock:\t%9lu Hz\n" + "System Clock:\t%9lu Hz\n" + "BogoMips:\t%lu.%02lu\n" + "Calibration:\t%lu loops\n", + cpu, revid, mmu, fpu, + cclk, + sclk, + (loops_per_jiffy * HZ) / 500000, + ((loops_per_jiffy * HZ) / 5000) % 100, + (loops_per_jiffy * HZ)); + seq_printf(m, "Board Name:\t%s\n", name); + seq_printf(m, "Board Memory:\t%ld MB\n", physical_mem_end >> 20); + seq_printf(m, "Kernel Memory:\t%ld MB\n", (unsigned long)_ramend >> 20); + if (bfin_read_IMEM_CONTROL() & (ENICPLB | IMC)) + seq_printf(m, "I-CACHE:\tON\n"); + else + seq_printf(m, "I-CACHE:\tOFF\n"); + if ((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE)) + seq_printf(m, "D-CACHE:\tON" +#if defined CONFIG_BLKFIN_WB + " (write-back)" +#elif defined CONFIG_BLKFIN_WT + " (write-through)" +#endif + "\n"); + else + seq_printf(m, "D-CACHE:\tOFF\n"); + + + switch(bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) { + case ACACHE_BSRAM: + seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tSRAM\n"); + dcache_size = 16; + dsup_banks = 1; + break; + case ACACHE_BCACHE: + seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tCACHE\n"); + dcache_size = 32; + dsup_banks = 2; + break; + case ASRAM_BSRAM: + seq_printf(m, "DBANK-A:\tSRAM\n" "DBANK-B:\tSRAM\n"); + dcache_size = 0; + dsup_banks = 0; + break; + default: + break; + } + + + seq_printf(m, "I-CACHE Size:\t%dKB\n", BLKFIN_ICACHESIZE / 1024); + seq_printf(m, "D-CACHE Size:\t%dKB\n", dcache_size); + seq_printf(m, "I-CACHE Setup:\t%d Sub-banks/%d Ways, %d Lines/Way\n", + BLKFIN_ISUBBANKS, BLKFIN_IWAYS, BLKFIN_ILINES); + seq_printf(m, + "D-CACHE Setup:\t%d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n", + dsup_banks, BLKFIN_DSUBBANKS, BLKFIN_DWAYS, + BLKFIN_DLINES); +#ifdef CONFIG_BLKFIN_CACHE_LOCK + switch (read_iloc()) { + case WAY0_L: + seq_printf(m, "Way0 Locked-Down\n"); + break; + case WAY1_L: + seq_printf(m, "Way1 Locked-Down\n"); + break; + case WAY01_L: + seq_printf(m, "Way0,Way1 Locked-Down\n"); + break; + case WAY2_L: + seq_printf(m, "Way2 Locked-Down\n"); + break; + case WAY02_L: + seq_printf(m, "Way0,Way2 Locked-Down\n"); + break; + case WAY12_L: + seq_printf(m, "Way1,Way2 Locked-Down\n"); + break; + case WAY012_L: + seq_printf(m, "Way0,Way1 & Way2 Locked-Down\n"); + break; + case WAY3_L: + seq_printf(m, "Way3 Locked-Down\n"); + break; + case WAY03_L: + seq_printf(m, "Way0,Way3 Locked-Down\n"); + break; + case WAY13_L: + seq_printf(m, "Way1,Way3 Locked-Down\n"); + break; + case WAY013_L: + seq_printf(m, "Way 0,Way1,Way3 Locked-Down\n"); + break; + case WAY32_L: + seq_printf(m, "Way3,Way2 Locked-Down\n"); + break; + case WAY320_L: + seq_printf(m, "Way3,Way2,Way0 Locked-Down\n"); + break; + case WAY321_L: + seq_printf(m, "Way3,Way2,Way1 Locked-Down\n"); + break; + case WAYALL_L: + seq_printf(m, "All Ways are locked\n"); + break; + default: + seq_printf(m, "No Ways are locked\n"); + } +#endif + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < NR_CPUS ? ((void *)0x12345678) : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; + +void cmdline_init(unsigned long r0) +{ + if (r0) + strncpy(command_line, (char *)r0, COMMAND_LINE_SIZE); +} diff --git a/trunk/arch/blackfin/kernel/signal.c b/trunk/arch/blackfin/kernel/signal.c new file mode 100644 index 000000000000..316e65c3439d --- /dev/null +++ b/trunk/arch/blackfin/kernel/signal.c @@ -0,0 +1,356 @@ +/* + * File: arch/blackfin/kernel/signal.c + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +struct fdpic_func_descriptor { + unsigned long text; + unsigned long GOT; +}; + +struct rt_sigframe { + int sig; + struct siginfo *pinfo; + void *puc; + char retcode[8]; + struct siginfo info; + struct ucontext uc; +}; + +asmlinkage int sys_sigaltstack(const stack_t * uss, stack_t * uoss) +{ + return do_sigaltstack(uss, uoss, rdusp()); +} + +static inline int +rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *pr0) +{ + unsigned long usp = 0; + int err = 0; + +#define RESTORE(x) err |= __get_user(regs->x, &sc->sc_##x) + + /* restore passed registers */ + RESTORE(r0); RESTORE(r1); RESTORE(r2); RESTORE(r3); + RESTORE(r4); RESTORE(r5); RESTORE(r6); RESTORE(r7); + RESTORE(p0); RESTORE(p1); RESTORE(p2); RESTORE(p3); + RESTORE(p4); RESTORE(p5); + err |= __get_user(usp, &sc->sc_usp); + wrusp(usp); + RESTORE(a0w); RESTORE(a1w); + RESTORE(a0x); RESTORE(a1x); + RESTORE(astat); + RESTORE(rets); + RESTORE(pc); + RESTORE(retx); + RESTORE(fp); + RESTORE(i0); RESTORE(i1); RESTORE(i2); RESTORE(i3); + RESTORE(m0); RESTORE(m1); RESTORE(m2); RESTORE(m3); + RESTORE(l0); RESTORE(l1); RESTORE(l2); RESTORE(l3); + RESTORE(b0); RESTORE(b1); RESTORE(b2); RESTORE(b3); + RESTORE(lc0); RESTORE(lc1); + RESTORE(lt0); RESTORE(lt1); + RESTORE(lb0); RESTORE(lb1); + RESTORE(seqstat); + + regs->orig_p0 = -1; /* disable syscall checks */ + + *pr0 = regs->r0; + return err; +} + +asmlinkage int do_rt_sigreturn(unsigned long __unused) +{ + struct pt_regs *regs = (struct pt_regs *)__unused; + unsigned long usp = rdusp(); + struct rt_sigframe *frame = (struct rt_sigframe *)(usp); + sigset_t set; + int r0; + + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) + goto badframe; + + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->usp) == -EFAULT) + goto badframe; + + return r0; + + badframe: + force_sig(SIGSEGV, current); + return 0; +} + +static inline int rt_setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs) +{ + int err = 0; + +#define SETUP(x) err |= __put_user(regs->x, &sc->sc_##x) + + SETUP(r0); SETUP(r1); SETUP(r2); SETUP(r3); + SETUP(r4); SETUP(r5); SETUP(r6); SETUP(r7); + SETUP(p0); SETUP(p1); SETUP(p2); SETUP(p3); + SETUP(p4); SETUP(p5); + err |= __put_user(rdusp(), &sc->sc_usp); + SETUP(a0w); SETUP(a1w); + SETUP(a0x); SETUP(a1x); + SETUP(astat); + SETUP(rets); + SETUP(pc); + SETUP(retx); + SETUP(fp); + SETUP(i0); SETUP(i1); SETUP(i2); SETUP(i3); + SETUP(m0); SETUP(m1); SETUP(m2); SETUP(m3); + SETUP(l0); SETUP(l1); SETUP(l2); SETUP(l3); + SETUP(b0); SETUP(b1); SETUP(b2); SETUP(b3); + SETUP(lc0); SETUP(lc1); + SETUP(lt0); SETUP(lt1); + SETUP(lb0); SETUP(lb1); + SETUP(seqstat); + + return err; +} + +static inline void push_cache(unsigned long vaddr, unsigned int len) +{ + flush_icache_range(vaddr, vaddr + len); +} + +static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, + size_t frame_size) +{ + unsigned long usp; + + /* Default to using normal stack. */ + usp = rdusp(); + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (!on_sig_stack(usp)) + usp = current->sas_ss_sp + current->sas_ss_size; + } + return (void *)((usp - frame_size) & -8UL); +} + +static int +setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info, + sigset_t * set, struct pt_regs *regs) +{ + struct rt_sigframe *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + err |= __put_user((current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain-> + signal_invmap[sig] : sig), &frame->sig); + + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= + __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(rdusp()), &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= rt_setup_sigcontext(&frame->uc.uc_mcontext, regs); + err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace. */ + err |= __put_user(0x28, &(frame->retcode[0])); + err |= __put_user(0xe1, &(frame->retcode[1])); + err |= __put_user(0xad, &(frame->retcode[2])); + err |= __put_user(0x00, &(frame->retcode[3])); + err |= __put_user(0xa0, &(frame->retcode[4])); + err |= __put_user(0x00, &(frame->retcode[5])); + + if (err) + goto give_sigsegv; + + push_cache((unsigned long)&frame->retcode, sizeof(frame->retcode)); + + /* Set up registers for signal handler */ + wrusp((unsigned long)frame); + if (get_personality & FDPIC_FUNCPTRS) { + struct fdpic_func_descriptor __user *funcptr = + (struct fdpic_func_descriptor *) ka->sa.sa_handler; + __get_user(regs->pc, &funcptr->text); + __get_user(regs->p3, &funcptr->GOT); + } else + regs->pc = (unsigned long)ka->sa.sa_handler; + regs->rets = (unsigned long)(frame->retcode); + + regs->r0 = frame->sig; + regs->r1 = (unsigned long)(&frame->info); + regs->r2 = (unsigned long)(&frame->uc); + + return 0; + + give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); + return -EFAULT; +} + +static inline void +handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) +{ + switch (regs->r0) { + case -ERESTARTNOHAND: + if (!has_handler) + goto do_restart; + regs->r0 = -EINTR; + break; + + case -ERESTARTSYS: + if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { + regs->r0 = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + do_restart: + regs->p0 = regs->orig_p0; + regs->r0 = regs->orig_r0; + regs->pc -= 2; + break; + } +} + +/* + * OK, we're invoking a handler + */ +static int +handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, + sigset_t *oldset, struct pt_regs *regs) +{ + int ret; + + /* are we from a system call? to see pt_regs->orig_p0 */ + if (regs->orig_p0 >= 0) + /* If so, check system call restarting.. */ + handle_restart(regs, ka, 1); + + /* set up the stack frame */ + ret = setup_rt_frame(sig, ka, info, oldset, regs); + + if (ret == 0) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, + &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } + return ret; +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + * + * Note that we go through the signals twice: once to check the signals + * that the kernel can handle, and then we build all the user-level signal + * handling stack-frames in one go after that. + */ +asmlinkage void do_signal(struct pt_regs *regs) +{ + siginfo_t info; + int signr; + struct k_sigaction ka; + sigset_t *oldset; + + current->thread.esp0 = (unsigned long)regs; + + if (try_to_freeze()) + goto no_signal; + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + if (signr > 0) { + /* Whee! Actually deliver the signal. */ + if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } + + return; + } + +no_signal: + /* Did we come from a system call? */ + if (regs->orig_p0 >= 0) + /* Restart the system call - no handlers present */ + handle_restart(regs, NULL, 0); + + /* if there's no signal to deliver, we just put the saved sigmask + * back */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } +} diff --git a/trunk/arch/blackfin/kernel/sys_bfin.c b/trunk/arch/blackfin/kernel/sys_bfin.c new file mode 100644 index 000000000000..f436e6743f5a --- /dev/null +++ b/trunk/arch/blackfin/kernel/sys_bfin.c @@ -0,0 +1,115 @@ +/* + * File: arch/blackfin/kernel/sys_bfin.c + * Based on: + * Author: + * + * Created: + * Description: This file contains various random system calls that + * have a non-standard calling sequence on the Linux/bfin + * platform. + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. + */ +asmlinkage int sys_pipe(unsigned long *fildes) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(fildes, fd, 2 * sizeof(int))) + error = -EFAULT; + } + return error; +} + +/* common code for old and new mmaps */ +static inline long +do_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + int error = -EBADF; + struct file *file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); + out: + return error; +} + +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} + +asmlinkage int sys_getpagesize(void) +{ + return PAGE_SIZE; +} + +asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags) +{ + return sram_alloc_with_lsl(size, flags); +} + +asmlinkage int sys_sram_free(const void *addr) +{ + return sram_free_with_lsl(addr); +} + +asmlinkage void *sys_dma_memcpy(void *dest, const void *src, size_t len) +{ + return safe_dma_memcpy(dest, src, len); +} diff --git a/trunk/arch/blackfin/kernel/time.c b/trunk/arch/blackfin/kernel/time.c new file mode 100644 index 000000000000..f578176b6d92 --- /dev/null +++ b/trunk/arch/blackfin/kernel/time.c @@ -0,0 +1,326 @@ +/* + * File: arch/blackfin/kernel/time.c + * Based on: none - original work + * Author: + * + * Created: + * Description: This file contains the bfin-specific time handling details. + * Most of the stuff is located in the machine specific files. + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include + +/* This is an NTP setting */ +#define TICK_SIZE (tick_nsec / 1000) + +static void time_sched_init(irqreturn_t(*timer_routine) + (int, void *)); +static unsigned long gettimeoffset(void); +static inline void do_leds(void); + +#if (defined(CONFIG_BFIN_ALIVE_LED) || defined(CONFIG_BFIN_IDLE_LED)) +void __init init_leds(void) +{ + unsigned int tmp = 0; + +#if defined(CONFIG_BFIN_ALIVE_LED) + /* config pins as output. */ + tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_DPORT(); + SSYNC(); + bfin_write_CONFIG_BFIN_ALIVE_LED_DPORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN); + SSYNC(); + + /* First set led be off */ + tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT(); + SSYNC(); + bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN); /* light off */ + SSYNC(); +#endif + +#if defined(CONFIG_BFIN_IDLE_LED) + /* config pins as output. */ + tmp = bfin_read_CONFIG_BFIN_IDLE_LED_DPORT(); + SSYNC(); + bfin_write_CONFIG_BFIN_IDLE_LED_DPORT(tmp | CONFIG_BFIN_IDLE_LED_PIN); + SSYNC(); + + /* First set led be off */ + tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT(); + SSYNC(); + bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp | CONFIG_BFIN_IDLE_LED_PIN); /* light off */ + SSYNC(); +#endif +} +#else +void __init init_leds(void) +{ +} +#endif + +#if defined(CONFIG_BFIN_ALIVE_LED) +static inline void do_leds(void) +{ + static unsigned int count = 50; + static int flag = 0; + unsigned short tmp = 0; + + if (--count == 0) { + count = 50; + flag = ~flag; + } + tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT(); + SSYNC(); + + if (flag) + tmp &= ~CONFIG_BFIN_ALIVE_LED_PIN; /* light on */ + else + tmp |= CONFIG_BFIN_ALIVE_LED_PIN; /* light off */ + + bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp); + SSYNC(); + +} +#else +static inline void do_leds(void) +{ +} +#endif + +static struct irqaction bfin_timer_irq = { + .name = "BFIN Timer Tick", + .flags = IRQF_DISABLED +}; + +/* + * The way that the Blackfin core timer works is: + * - CCLK is divided by a programmable 8-bit pre-scaler (TSCALE) + * - Every time TSCALE ticks, a 32bit is counted down (TCOUNT) + * + * If you take the fastest clock (1ns, or 1GHz to make the math work easier) + * 10ms is 10,000,000 clock ticks, which fits easy into a 32-bit counter + * (32 bit counter is 4,294,967,296ns or 4.2 seconds) so, we don't need + * to use TSCALE, and program it to zero (which is pass CCLK through). + * If you feel like using it, try to keep HZ * TIMESCALE to some + * value that divides easy (like power of 2). + */ + +#define TIME_SCALE 1 + +static void +time_sched_init(irqreturn_t(*timer_routine) (int, void *)) +{ + u32 tcount; + + /* power up the timer, but don't enable it just yet */ + bfin_write_TCNTL(1); + CSYNC(); + + /* + * the TSCALE prescaler counter. + */ + bfin_write_TSCALE((TIME_SCALE - 1)); + + tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1); + bfin_write_TPERIOD(tcount); + bfin_write_TCOUNT(tcount); + + /* now enable the timer */ + CSYNC(); + + bfin_write_TCNTL(7); + + bfin_timer_irq.handler = (irq_handler_t)timer_routine; + /* call setup_irq instead of request_irq because request_irq calls + * kmalloc which has not been initialized yet + */ + setup_irq(IRQ_CORETMR, &bfin_timer_irq); +} + +/* + * Should return useconds since last timer tick + */ +static unsigned long gettimeoffset(void) +{ + unsigned long offset; + unsigned long clocks_per_jiffy; + + clocks_per_jiffy = bfin_read_TPERIOD(); + offset = + (clocks_per_jiffy - + bfin_read_TCOUNT()) / (((clocks_per_jiffy + 1) * HZ) / + USEC_PER_SEC); + + /* Check if we just wrapped the counters and maybe missed a tick */ + if ((bfin_read_ILAT() & (1 << IRQ_CORETMR)) + && (offset < (100000 / HZ / 2))) + offset += (USEC_PER_SEC / HZ); + + return offset; +} + +static inline int set_rtc_mmss(unsigned long nowtime) +{ + return 0; +} + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +#ifdef CONFIG_CORE_TIMER_IRQ_L1 +irqreturn_t timer_interrupt(int irq, void *dummy)__attribute__((l1_text)); +#endif + +irqreturn_t timer_interrupt(int irq, void *dummy) +{ + /* last time the cmos clock got updated */ + static long last_rtc_update = 0; + + write_seqlock(&xtime_lock); + + do_timer(1); + do_leds(); + +#ifndef CONFIG_SMP + update_process_times(user_mode(get_irq_regs())); +#endif + profile_tick(CPU_PROFILING); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + + if (ntp_synced() && + xtime.tv_sec > last_rtc_update + 660 && + (xtime.tv_nsec / NSEC_PER_USEC) >= + 500000 - ((unsigned)TICK_SIZE) / 2 + && (xtime.tv_nsec / NSEC_PER_USEC) <= + 500000 + ((unsigned)TICK_SIZE) / 2) { + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + /* Do it again in 60s. */ + last_rtc_update = xtime.tv_sec - 600; + } + write_sequnlock(&xtime_lock); + return IRQ_HANDLED; +} + +void __init time_init(void) +{ + time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60; /* 1 Jan 2007 */ + +#ifdef CONFIG_RTC_DRV_BFIN + /* [#2663] hack to filter junk RTC values that would cause + * userspace to have to deal with time values greater than + * 2^31 seconds (which uClibc cannot cope with yet) + */ + if ((bfin_read_RTC_STAT() & 0xC0000000) == 0xC0000000) { + printk(KERN_NOTICE "bfin-rtc: invalid date; resetting\n"); + bfin_write_RTC_STAT(0); + } +#endif + + /* Initialize xtime. From now on, xtime is updated with timer interrupts */ + xtime.tv_sec = secs_since_1970; + xtime.tv_nsec = 0; + + wall_to_monotonic.tv_sec = -xtime.tv_sec; + + time_sched_init(timer_interrupt); +} + +#ifndef CONFIG_GENERIC_TIME +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + unsigned long seq; + unsigned long usec, sec; + + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + usec = gettimeoffset(); + sec = xtime.tv_sec; + usec += (xtime.tv_nsec / NSEC_PER_USEC); + } + while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); + + while (usec >= USEC_PER_SEC) { + usec -= USEC_PER_SEC; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} +EXPORT_SYMBOL(do_gettimeofday); + +int do_settimeofday(struct timespec *tv) +{ + time_t wtm_sec, sec = tv->tv_sec; + long wtm_nsec, nsec = tv->tv_nsec; + + if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + return -EINVAL; + + write_seqlock_irq(&xtime_lock); + /* + * This is revolting. We need to set the xtime.tv_usec + * correctly. However, the value in this location is + * is value at the last tick. + * Discover what correction gettimeofday + * would have done, and then undo it! + */ + nsec -= (gettimeoffset() * NSEC_PER_USEC); + + wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); + wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); + + set_normalized_timespec(&xtime, sec, nsec); + set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); + + ntp_clear(); + + write_sequnlock_irq(&xtime_lock); + clock_was_set(); + + return 0; +} +EXPORT_SYMBOL(do_settimeofday); +#endif /* !CONFIG_GENERIC_TIME */ + +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) +{ + return (unsigned long long)jiffies *(NSEC_PER_SEC / HZ); +} diff --git a/trunk/arch/blackfin/kernel/traps.c b/trunk/arch/blackfin/kernel/traps.c new file mode 100644 index 000000000000..9556b73de808 --- /dev/null +++ b/trunk/arch/blackfin/kernel/traps.c @@ -0,0 +1,649 @@ +/* + * File: arch/blackfin/kernel/traps.c + * Based on: + * Author: Hamish Macdonald + * + * Created: + * Description: uses S/W interrupt 15 for the system calls + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_KGDB +# include +# include +#endif + +/* Initiate the event table handler */ +void __init trap_init(void) +{ + CSYNC(); + bfin_write_EVT3(trap); + CSYNC(); +} + +asmlinkage void trap_c(struct pt_regs *fp); + +int kstack_depth_to_print = 48; + +static int printk_address(unsigned long address) +{ + struct vm_list_struct *vml; + struct task_struct *p; + struct mm_struct *mm; + +#ifdef CONFIG_KALLSYMS + unsigned long offset = 0, symsize; + const char *symname; + char *modname; + char *delim = ":"; + char namebuf[128]; + + /* look up the address and see if we are in kernel space */ + symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf); + + if (symname) { + /* yeah! kernel space! */ + if (!modname) + modname = delim = ""; + return printk("<0x%p> { %s%s%s%s + 0x%lx }", + (void*)address, delim, modname, delim, symname, + (unsigned long)offset); + + } +#endif + + /* looks like we're off in user-land, so let's walk all the + * mappings of all our processes and see if we can't be a whee + * bit more specific + */ + write_lock_irq(&tasklist_lock); + for_each_process(p) { + mm = get_task_mm(p); + if (!mm) + continue; + + vml = mm->context.vmlist; + while (vml) { + struct vm_area_struct *vma = vml->vma; + + if (address >= vma->vm_start && address < vma->vm_end) { + char *name = p->comm; + struct file *file = vma->vm_file; + if (file) { + char _tmpbuf[256]; + name = d_path(file->f_dentry, + file->f_vfsmnt, + _tmpbuf, + sizeof(_tmpbuf)); + } + + write_unlock_irq(&tasklist_lock); + return printk("<0x%p> [ %s + 0x%lx ]", + (void*)address, name, + (unsigned long) + ((address - vma->vm_start) + + (vma->vm_pgoff << PAGE_SHIFT))); + } + + vml = vml->next; + } + } + write_unlock_irq(&tasklist_lock); + + /* we were unable to find this address anywhere */ + return printk("[<0x%p>]", (void*)address); +} + +#define trace_buffer_save(x) \ + do { \ + (x) = bfin_read_TBUFCTL(); \ + bfin_write_TBUFCTL((x) & ~TBUFEN); \ + } while (0) +#define trace_buffer_restore(x) \ + do { \ + bfin_write_TBUFCTL((x)); \ + } while (0) + +asmlinkage void trap_c(struct pt_regs *fp) +{ + int j, sig = 0; + siginfo_t info; + unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; + +#ifdef CONFIG_KGDB +# define CHK_DEBUGGER_TRAP() do { CHK_DEBUGGER(trapnr, sig, info.si_code, fp,); } while (0) +# define CHK_DEBUGGER_TRAP_MAYBE() do { if (kgdb_connected) CHK_DEBUGGER_TRAP(); } while (0) +#else +# define CHK_DEBUGGER_TRAP() do { } while (0) +# define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0) +#endif + + trace_buffer_save(j); + + /* trap_c() will be called for exceptions. During exceptions + * processing, the pc value should be set with retx value. + * With this change we can cleanup some code in signal.c- TODO + */ + fp->orig_pc = fp->retx; + /* printk("exception: 0x%x, ipend=%x, reti=%x, retx=%x\n", + trapnr, fp->ipend, fp->pc, fp->retx); */ + + /* send the appropriate signal to the user program */ + switch (trapnr) { + + /* This table works in conjuction with the one in ./mach-common/entry.S + * Some exceptions are handled there (in assembly, in exception space) + * Some are handled here, (in C, in interrupt space) + * Some, like CPLB, are handled in both, where the normal path is + * handled in assembly/exception space, and the error path is handled + * here + */ + + /* 0x00 - Linux Syscall, getting here is an error */ + /* 0x01 - userspace gdb breakpoint, handled here */ + case VEC_EXCPT01: + info.si_code = TRAP_ILLTRAP; + sig = SIGTRAP; + CHK_DEBUGGER_TRAP_MAYBE(); + /* Check if this is a breakpoint in kernel space */ + if (fp->ipend & 0xffc0) + return; + else + break; +#ifdef CONFIG_KGDB + case VEC_EXCPT02 : /* gdb connection */ + info.si_code = TRAP_ILLTRAP; + sig = SIGTRAP; + CHK_DEBUGGER_TRAP(); + return; +#else + /* 0x02 - User Defined, Caught by default */ +#endif + /* 0x03 - Atomic test and set */ + case VEC_EXCPT03: + info.si_code = SEGV_STACKFLOW; + sig = SIGSEGV; + printk(KERN_EMERG EXC_0x03); + CHK_DEBUGGER_TRAP(); + break; + /* 0x04 - spinlock - handled by _ex_spinlock, + getting here is an error */ + /* 0x05 - User Defined, Caught by default */ + /* 0x06 - User Defined, Caught by default */ + /* 0x07 - User Defined, Caught by default */ + /* 0x08 - User Defined, Caught by default */ + /* 0x09 - User Defined, Caught by default */ + /* 0x0A - User Defined, Caught by default */ + /* 0x0B - User Defined, Caught by default */ + /* 0x0C - User Defined, Caught by default */ + /* 0x0D - User Defined, Caught by default */ + /* 0x0E - User Defined, Caught by default */ + /* 0x0F - User Defined, Caught by default */ + /* 0x10 HW Single step, handled here */ + case VEC_STEP: + info.si_code = TRAP_STEP; + sig = SIGTRAP; + CHK_DEBUGGER_TRAP_MAYBE(); + /* Check if this is a single step in kernel space */ + if (fp->ipend & 0xffc0) + return; + else + break; + /* 0x11 - Trace Buffer Full, handled here */ + case VEC_OVFLOW: + info.si_code = TRAP_TRACEFLOW; + sig = SIGTRAP; + printk(KERN_EMERG EXC_0x11); + CHK_DEBUGGER_TRAP(); + break; + /* 0x12 - Reserved, Caught by default */ + /* 0x13 - Reserved, Caught by default */ + /* 0x14 - Reserved, Caught by default */ + /* 0x15 - Reserved, Caught by default */ + /* 0x16 - Reserved, Caught by default */ + /* 0x17 - Reserved, Caught by default */ + /* 0x18 - Reserved, Caught by default */ + /* 0x19 - Reserved, Caught by default */ + /* 0x1A - Reserved, Caught by default */ + /* 0x1B - Reserved, Caught by default */ + /* 0x1C - Reserved, Caught by default */ + /* 0x1D - Reserved, Caught by default */ + /* 0x1E - Reserved, Caught by default */ + /* 0x1F - Reserved, Caught by default */ + /* 0x20 - Reserved, Caught by default */ + /* 0x21 - Undefined Instruction, handled here */ + case VEC_UNDEF_I: + info.si_code = ILL_ILLOPC; + sig = SIGILL; + printk(KERN_EMERG EXC_0x21); + CHK_DEBUGGER_TRAP(); + break; + /* 0x22 - Illegal Instruction Combination, handled here */ + case VEC_ILGAL_I: + info.si_code = ILL_ILLPARAOP; + sig = SIGILL; + printk(KERN_EMERG EXC_0x22); + CHK_DEBUGGER_TRAP(); + break; + /* 0x23 - Data CPLB Protection Violation, + normal case is handled in _cplb_hdr */ + case VEC_CPLB_VL: + info.si_code = ILL_CPLB_VI; + sig = SIGILL; + printk(KERN_EMERG EXC_0x23); + CHK_DEBUGGER_TRAP(); + break; + /* 0x24 - Data access misaligned, handled here */ + case VEC_MISALI_D: + info.si_code = BUS_ADRALN; + sig = SIGBUS; + printk(KERN_EMERG EXC_0x24); + CHK_DEBUGGER_TRAP(); + break; + /* 0x25 - Unrecoverable Event, handled here */ + case VEC_UNCOV: + info.si_code = ILL_ILLEXCPT; + sig = SIGILL; + printk(KERN_EMERG EXC_0x25); + CHK_DEBUGGER_TRAP(); + break; + /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr, + error case is handled here */ + case VEC_CPLB_M: + info.si_code = BUS_ADRALN; + sig = SIGBUS; + printk(KERN_EMERG EXC_0x26); + CHK_DEBUGGER_TRAP(); + break; + /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */ + case VEC_CPLB_MHIT: + info.si_code = ILL_CPLB_MULHIT; +#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO + sig = SIGSEGV; + printk(KERN_EMERG "\n\nNULL pointer access (probably)\n"); +#else + sig = SIGILL; + printk(KERN_EMERG EXC_0x27); +#endif + CHK_DEBUGGER_TRAP(); + break; + /* 0x28 - Emulation Watchpoint, handled here */ + case VEC_WATCH: + info.si_code = TRAP_WATCHPT; + sig = SIGTRAP; + pr_debug(EXC_0x28); + CHK_DEBUGGER_TRAP_MAYBE(); + /* Check if this is a watchpoint in kernel space */ + if (fp->ipend & 0xffc0) + return; + else + break; +#ifdef CONFIG_BF535 + /* 0x29 - Instruction fetch access error (535 only) */ + case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */ + info.si_code = BUS_OPFETCH; + sig = SIGBUS; + printk(KERN_EMERG "BF535: VEC_ISTRU_VL\n"); + CHK_DEBUGGER_TRAP(); + break; +#else + /* 0x29 - Reserved, Caught by default */ +#endif + /* 0x2A - Instruction fetch misaligned, handled here */ + case VEC_MISALI_I: + info.si_code = BUS_ADRALN; + sig = SIGBUS; + printk(KERN_EMERG EXC_0x2A); + CHK_DEBUGGER_TRAP(); + break; + /* 0x2B - Instruction CPLB protection Violation, + handled in _cplb_hdr */ + case VEC_CPLB_I_VL: + info.si_code = ILL_CPLB_VI; + sig = SIGILL; + printk(KERN_EMERG EXC_0x2B); + CHK_DEBUGGER_TRAP(); + break; + /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */ + case VEC_CPLB_I_M: + info.si_code = ILL_CPLB_MISS; + sig = SIGBUS; + printk(KERN_EMERG EXC_0x2C); + CHK_DEBUGGER_TRAP(); + break; + /* 0x2D - Instruction CPLB Multiple Hits, handled here */ + case VEC_CPLB_I_MHIT: + info.si_code = ILL_CPLB_MULHIT; +#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO + sig = SIGSEGV; + printk(KERN_EMERG "\n\nJump to address 0 - 0x0fff\n"); +#else + sig = SIGILL; + printk(KERN_EMERG EXC_0x2D); +#endif + CHK_DEBUGGER_TRAP(); + break; + /* 0x2E - Illegal use of Supervisor Resource, handled here */ + case VEC_ILL_RES: + info.si_code = ILL_PRVOPC; + sig = SIGILL; + printk(KERN_EMERG EXC_0x2E); + CHK_DEBUGGER_TRAP(); + break; + /* 0x2F - Reserved, Caught by default */ + /* 0x30 - Reserved, Caught by default */ + /* 0x31 - Reserved, Caught by default */ + /* 0x32 - Reserved, Caught by default */ + /* 0x33 - Reserved, Caught by default */ + /* 0x34 - Reserved, Caught by default */ + /* 0x35 - Reserved, Caught by default */ + /* 0x36 - Reserved, Caught by default */ + /* 0x37 - Reserved, Caught by default */ + /* 0x38 - Reserved, Caught by default */ + /* 0x39 - Reserved, Caught by default */ + /* 0x3A - Reserved, Caught by default */ + /* 0x3B - Reserved, Caught by default */ + /* 0x3C - Reserved, Caught by default */ + /* 0x3D - Reserved, Caught by default */ + /* 0x3E - Reserved, Caught by default */ + /* 0x3F - Reserved, Caught by default */ + default: + info.si_code = TRAP_ILLTRAP; + sig = SIGTRAP; + printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n", + (fp->seqstat & SEQSTAT_EXCAUSE)); + CHK_DEBUGGER_TRAP(); + break; + } + + info.si_signo = sig; + info.si_errno = 0; + info.si_addr = (void *)fp->pc; + force_sig_info(sig, &info, current); + if (sig != 0 && sig != SIGTRAP) { + unsigned long stack; + dump_bfin_regs(fp, (void *)fp->retx); + dump_bfin_trace_buffer(); + show_stack(current, &stack); + if (current->mm == NULL) + panic("Kernel exception"); + } + + /* if the address that we are about to return to is not valid, set it + * to a valid address, if we have a current application or panic + */ + if (!(fp->pc <= physical_mem_end +#if L1_CODE_LENGTH != 0 + || (fp->pc >= L1_CODE_START && + fp->pc <= (L1_CODE_START + L1_CODE_LENGTH)) +#endif + )) { + if (current->mm) { + fp->pc = current->mm->start_code; + } else { + printk(KERN_EMERG "I can't return to memory that doesn't exist - bad things happen\n"); + panic("Help - I've fallen and can't get up\n"); + } + } + + trace_buffer_restore(j); + return; +} + +/* Typical exception handling routines */ + +void dump_bfin_trace_buffer(void) +{ + int tflags; + trace_buffer_save(tflags); + + if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) { + int i; + printk(KERN_EMERG "Hardware Trace:\n"); + for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) { + printk(KERN_EMERG "%2i Target : ", i); + printk_address((unsigned long)bfin_read_TBUF()); + printk("\n" KERN_EMERG " Source : "); + printk_address((unsigned long)bfin_read_TBUF()); + printk("\n"); + } + } + + trace_buffer_restore(tflags); +} +EXPORT_SYMBOL(dump_bfin_trace_buffer); + +static void show_trace(struct task_struct *tsk, unsigned long *sp) +{ + unsigned long addr; + + printk("\nCall Trace:"); +#ifdef CONFIG_KALLSYMS + printk("\n"); +#endif + + while (!kstack_end(sp)) { + addr = *sp++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (kernel_text_address(addr)) + print_ip_sym(addr); + } + + printk("\n"); +} + +void show_stack(struct task_struct *task, unsigned long *stack) +{ + unsigned long *endstack, addr; + int i; + + /* Cannot call dump_bfin_trace_buffer() here as show_stack() is + * called externally in some places in the kernel. + */ + + if (!stack) { + if (task) + stack = (unsigned long *)task->thread.ksp; + else + stack = (unsigned long *)&stack; + } + + addr = (unsigned long)stack; + endstack = (unsigned long *)PAGE_ALIGN(addr); + + printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack); + for (i = 0; i < kstack_depth_to_print; i++) { + if (stack + 1 > endstack) + break; + if (i % 8 == 0) + printk("\n" KERN_EMERG " "); + printk(" %08lx", *stack++); + } + + show_trace(task, stack); +} + +void dump_stack(void) +{ + unsigned long stack; + int tflags; + trace_buffer_save(tflags); + dump_bfin_trace_buffer(); + show_stack(current, &stack); + trace_buffer_restore(tflags); +} + +EXPORT_SYMBOL(dump_stack); + +void dump_bfin_regs(struct pt_regs *fp, void *retaddr) +{ + if (current->pid) { + printk("\nCURRENT PROCESS:\n\n"); + printk("COMM=%s PID=%d\n", current->comm, current->pid); + } else { + printk + ("\nNo Valid pid - Either things are really messed up, or you are in the kernel\n"); + } + + if (current->mm) { + printk("TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" + "BSS = 0x%p-0x%p USER-STACK = 0x%p\n\n", + (void*)current->mm->start_code, + (void*)current->mm->end_code, + (void*)current->mm->start_data, + (void*)current->mm->end_data, + (void*)current->mm->end_data, + (void*)current->mm->brk, + (void*)current->mm->start_stack); + } + + printk("return address: 0x%p; contents of [PC-16...PC+8]:\n", retaddr); + if (retaddr != 0 && retaddr <= (void*)physical_mem_end +#if L1_CODE_LENGTH != 0 + /* FIXME: Copy the code out of L1 Instruction SRAM through dma + memcpy. */ + && !(retaddr >= (void*)L1_CODE_START + && retaddr < (void*)(L1_CODE_START + L1_CODE_LENGTH)) +#endif + ) { + int i = 0; + unsigned short x = 0; + for (i = -16; i < 8; i++) { + if (get_user(x, (unsigned short *)retaddr + i)) + break; +#ifndef CONFIG_DEBUG_HWERR + /* If one of the last few instructions was a STI + * it is likily that the error occured awhile ago + * and we just noticed + */ + if (x >= 0x0040 && x <= 0x0047 && i <= 0) + panic("\n\nWARNING : You should reconfigure the kernel to turn on\n" + " 'Hardware error interrupt debugging'\n" + " The rest of this error is meanless\n"); +#endif + + if (i == -8) + printk("\n"); + if (i == 0) + printk("X\n"); + printk("%04x ", x); + } + } else + printk("Cannot look at the [PC] for it is in unreadable L1 SRAM - sorry\n"); + + printk("\n\n"); + + printk("RETE: %08lx RETN: %08lx RETX: %08lx RETS: %08lx\n", + fp->rete, fp->retn, fp->retx, fp->rets); + printk("IPEND: %04lx SYSCFG: %04lx\n", fp->ipend, fp->syscfg); + printk("SEQSTAT: %08lx SP: %08lx\n", (long)fp->seqstat, (long)fp); + printk("R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n", + fp->r0, fp->r1, fp->r2, fp->r3); + printk("R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n", + fp->r4, fp->r5, fp->r6, fp->r7); + printk("P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n", + fp->p0, fp->p1, fp->p2, fp->p3); + printk("P4: %08lx P5: %08lx FP: %08lx\n", fp->p4, fp->p5, fp->fp); + printk("A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n", + fp->a0w, fp->a0x, fp->a1w, fp->a1x); + + printk("LB0: %08lx LT0: %08lx LC0: %08lx\n", fp->lb0, fp->lt0, + fp->lc0); + printk("LB1: %08lx LT1: %08lx LC1: %08lx\n", fp->lb1, fp->lt1, + fp->lc1); + printk("B0: %08lx L0: %08lx M0: %08lx I0: %08lx\n", fp->b0, fp->l0, + fp->m0, fp->i0); + printk("B1: %08lx L1: %08lx M1: %08lx I1: %08lx\n", fp->b1, fp->l1, + fp->m1, fp->i1); + printk("B2: %08lx L2: %08lx M2: %08lx I2: %08lx\n", fp->b2, fp->l2, + fp->m2, fp->i2); + printk("B3: %08lx L3: %08lx M3: %08lx I3: %08lx\n", fp->b3, fp->l3, + fp->m3, fp->i3); + + printk("\nUSP: %08lx ASTAT: %08lx\n", rdusp(), fp->astat); + if ((long)fp->seqstat & SEQSTAT_EXCAUSE) { + printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR()); + printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR()); + } + + printk("\n\n"); +} + +#ifdef CONFIG_SYS_BFIN_SPINLOCK_L1 +asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text)); +#endif + +asmlinkage int sys_bfin_spinlock(int *spinlock) +{ + int ret = 0; + int tmp = 0; + + local_irq_disable(); + ret = get_user(tmp, spinlock); + if (ret == 0) { + if (tmp) + ret = 1; + tmp = 1; + put_user(tmp, spinlock); + } + local_irq_enable(); + return ret; +} + +void panic_cplb_error(int cplb_panic, struct pt_regs *fp) +{ + switch (cplb_panic) { + case CPLB_NO_UNLOCKED: + printk(KERN_EMERG "All CPLBs are locked\n"); + break; + case CPLB_PROT_VIOL: + return; + case CPLB_NO_ADDR_MATCH: + return; + case CPLB_UNKNOWN_ERR: + printk(KERN_EMERG "Unknown CPLB Exception\n"); + break; + } + + printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR()); + printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR()); + dump_bfin_regs(fp, (void *)fp->retx); + dump_stack(); + panic("Unrecoverable event\n"); +} diff --git a/trunk/arch/blackfin/kernel/vmlinux.lds.S b/trunk/arch/blackfin/kernel/vmlinux.lds.S new file mode 100644 index 000000000000..6ae9ebbd8e58 --- /dev/null +++ b/trunk/arch/blackfin/kernel/vmlinux.lds.S @@ -0,0 +1,228 @@ +/* + * File: arch/blackfin/kernel/vmlinux.lds.S + * Based on: none - original work + * Author: + * + * Created: Tue Sep 21 2004 + * Description: Master linker script for blackfin architecture + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define VMLINUX_SYMBOL(_sym_) _##_sym_ + +#include +#include + + +OUTPUT_FORMAT("elf32-bfin") +ENTRY(__start) +_jiffies = _jiffies_64; + +MEMORY +{ + ram : ORIGIN = CONFIG_BOOT_LOAD, LENGTH = (CONFIG_MEM_SIZE * 1024 * 1024) - (CONFIG_BOOT_LOAD) + l1_data_a : ORIGIN = L1_DATA_A_START, LENGTH = L1_DATA_A_LENGTH + l1_data_b : ORIGIN = L1_DATA_B_START, LENGTH = L1_DATA_B_LENGTH + l1_code : ORIGIN = L1_CODE_START, LENGTH = L1_CODE_LENGTH + l1_scratch : ORIGIN = L1_SCRATCH_START, LENGTH = L1_SCRATCH_LENGTH +} + +SECTIONS +{ + . = CONFIG_BOOT_LOAD; + + .text : + { + _text = .; + __stext = .; + *(.text) + SCHED_TEXT + *(.text.lock) + . = ALIGN(16); + ___start___ex_table = .; + *(__ex_table) + ___stop___ex_table = .; + + *($code) + *(.rodata) + *(.rodata.*) + *(__vermagic) /* Kernel version magic */ + *(.rodata1) + *(.fixup) + *(.spinlock.text) + + /* Kernel symbol table: Normal symbols */ + . = ALIGN(4); + ___start___ksymtab = .; + *(__ksymtab) + ___stop___ksymtab = .; + + /* Kernel symbol table: GPL-only symbols */ + ___start___ksymtab_gpl = .; + *(__ksymtab_gpl) + ___stop___ksymtab_gpl = .; + + /* Kernel symbol table: Normal unused symbols */ \ + ___start___ksymtab_unused = .; + *(__ksymtab_unused) + ___stop___ksymtab_unused = .; + + /* Kernel symbol table: GPL-only unused symbols */ + ___start___ksymtab_unused_gpl = .; + *(__ksymtab_unused_gpl) + ___stop___ksymtab_unused_gpl = .; + + + /* Kernel symbol table: GPL-future symbols */ + ___start___ksymtab_gpl_future = .; + *(__ksymtab_gpl_future) + ___stop___ksymtab_gpl_future = .; + + /* Kernel symbol table: Normal symbols */ + ___start___kcrctab = .; + *(__kcrctab) + ___stop___kcrctab = .; + + /* Kernel symbol table: GPL-only symbols */ + ___start___kcrctab_gpl = .; + *(__kcrctab_gpl) + ___stop___kcrctab_gpl = .; + + /* Kernel symbol table: GPL-future symbols */ + ___start___kcrctab_gpl_future = .; + *(__kcrctab_gpl_future) + ___stop___kcrctab_gpl_future = .; + + /* Kernel symbol table: strings */ + *(__ksymtab_strings) + + . = ALIGN(4); + __etext = .; + } > ram + + .init : + { + . = ALIGN(4096); + ___init_begin = .; + __sinittext = .; + *(.init.text) + __einittext = .; + *(.init.data) + . = ALIGN(16); + ___setup_start = .; + *(.init.setup) + ___setup_end = .; + ___start___param = .; + *(__param) + ___stop___param = .; + ___initcall_start = .; + INITCALLS + ___initcall_end = .; + ___con_initcall_start = .; + *(.con_initcall.init) + ___con_initcall_end = .; + ___security_initcall_start = .; + *(.security_initcall.init) + ___security_initcall_end = .; + . = ALIGN(4); + ___initramfs_start = .; + *(.init.ramfs) + ___initramfs_end = .; + . = ALIGN(4); + ___init_end = .; + } > ram + + __l1_lma_start = .; + + .text_l1 : + { + . = ALIGN(4); + __stext_l1 = .; + *(.l1.text) + + . = ALIGN(4); + __etext_l1 = .; + } > l1_code AT > ram + + .data_l1 : + { + . = ALIGN(4); + __sdata_l1 = .; + *(.l1.data) + __edata_l1 = .; + + . = ALIGN(4); + __sbss_l1 = .; + *(.l1.bss) + + . = ALIGN(32); + *(.data_l1.cacheline_aligned) + + . = ALIGN(4); + __ebss_l1 = .; + } > l1_data_a AT > ram + .data_b_l1 : + { + . = ALIGN(4); + __sdata_b_l1 = .; + *(.l1.data.B) + __edata_b_l1 = .; + + . = ALIGN(4); + __sbss_b_l1 = .; + *(.l1.bss.B) + + . = ALIGN(4); + __ebss_b_l1 = .; + } > l1_data_b AT > ram + + .data : + { + __sdata = .; + . = ALIGN(0x2000); + *(.data.init_task) + *(.data) + + . = ALIGN(32); + *(.data.cacheline_aligned) + + . = ALIGN(0x2000); + __edata = .; + } > ram + + /DISCARD/ : { /* Exit code and data*/ + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + } > ram + + .bss : + { + . = ALIGN(4); + ___bss_start = .; + *(.bss) + *(COMMON) + . = ALIGN(4); + ___bss_stop = .; + __end = . ; + } > ram +} diff --git a/trunk/arch/blackfin/lib/Makefile b/trunk/arch/blackfin/lib/Makefile new file mode 100644 index 000000000000..635288fc5f54 --- /dev/null +++ b/trunk/arch/blackfin/lib/Makefile @@ -0,0 +1,11 @@ +# +# arch/blackfin/lib/Makefile +# + +lib-y := \ + ashldi3.o ashrdi3.o lshrdi3.o \ + muldi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \ + checksum.o memcpy.o memset.o memcmp.o memchr.o memmove.o \ + strcmp.o strcpy.o strncmp.o strncpy.o \ + umulsi3_highpart.o smulsi3_highpart.o \ + ins.o outs.o diff --git a/trunk/arch/blackfin/lib/ashldi3.c b/trunk/arch/blackfin/lib/ashldi3.c new file mode 100644 index 000000000000..a8c279e9b192 --- /dev/null +++ b/trunk/arch/blackfin/lib/ashldi3.c @@ -0,0 +1,58 @@ +/* + * File: arch/blackfin/lib/ashldi3.c + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "gcclib.h" + +#ifdef CONFIG_ARITHMETIC_OPS_L1 +DItype __ashldi3(DItype u, word_type b)__attribute__((l1_text)); +#endif + +DItype __ashldi3(DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof(SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) { + w.s.low = 0; + w.s.high = (USItype) uu.s.low << -bm; + } else { + USItype carries = (USItype) uu.s.low >> bm; + w.s.low = (USItype) uu.s.low << b; + w.s.high = ((USItype) uu.s.high << b) | carries; + } + + return w.ll; +} diff --git a/trunk/arch/blackfin/lib/ashrdi3.c b/trunk/arch/blackfin/lib/ashrdi3.c new file mode 100644 index 000000000000..a0d3419329ca --- /dev/null +++ b/trunk/arch/blackfin/lib/ashrdi3.c @@ -0,0 +1,59 @@ +/* + * File: arch/blackfin/lib/ashrdi3.c + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "gcclib.h" + +#ifdef CONFIG_ARITHMETIC_OPS_L1 +DItype __ashrdi3(DItype u, word_type b)__attribute__((l1_text)); +#endif + +DItype __ashrdi3(DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof(SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) { + /* w.s.high = 1..1 or 0..0 */ + w.s.high = uu.s.high >> (sizeof(SItype) * BITS_PER_UNIT - 1); + w.s.low = uu.s.high >> -bm; + } else { + USItype carries = (USItype) uu.s.high << bm; + w.s.high = uu.s.high >> b; + w.s.low = ((USItype) uu.s.low >> b) | carries; + } + + return w.ll; +} diff --git a/trunk/arch/blackfin/lib/checksum.c b/trunk/arch/blackfin/lib/checksum.c new file mode 100644 index 000000000000..42768e0c80ca --- /dev/null +++ b/trunk/arch/blackfin/lib/checksum.c @@ -0,0 +1,140 @@ +/* + * File: arch/blackfin/lib/checksum.c + * Based on: none - original work + * Author: + * + * Created: + * Description: An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#ifdef CONFIG_IP_CHECKSUM_L1 +static unsigned short do_csum(const unsigned char *buff, int len)__attribute__((l1_text)); +#endif + +static unsigned short do_csum(const unsigned char *buff, int len) +{ + register unsigned long sum = 0; + int swappem = 0; + + if (1 & (unsigned long)buff) { + sum = *buff << 8; + buff++; + len--; + ++swappem; + } + + while (len > 1) { + sum += *(unsigned short *)buff; + buff += 2; + len -= 2; + } + + if (len > 0) + sum += *buff; + + /* Fold 32-bit sum to 16 bits */ + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + if (swappem) + sum = ((sum & 0xff00) >> 8) + ((sum & 0x00ff) << 8); + + return sum; + +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) +{ + return ~do_csum(iph, ihl * 4); +} + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum) +{ + /* + * Just in case we get nasty checksum data... + * Like 0xffff6ec3 in the case of our IPv6 multicast header. + * We fold to begin with, as well as at the end. + */ + sum = (sum & 0xffff) + (sum >> 16); + + sum += do_csum(buff, len); + + sum = (sum & 0xffff) + (sum >> 16); + + return sum; +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +unsigned short ip_compute_csum(const unsigned char *buff, int len) +{ + return ~do_csum(buff, len); +} + +/* + * copy from fs while checksumming, otherwise like csum_partial + */ + +unsigned int +csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst, + int len, int sum, int *csum_err) +{ + if (csum_err) + *csum_err = 0; + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} + +/* + * copy from ds while checksumming, otherwise like csum_partial + */ + +unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst, + int len, int sum) +{ + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} diff --git a/trunk/arch/blackfin/lib/divsi3.S b/trunk/arch/blackfin/lib/divsi3.S new file mode 100644 index 000000000000..3e29861852b2 --- /dev/null +++ b/trunk/arch/blackfin/lib/divsi3.S @@ -0,0 +1,216 @@ +/* + * File: arch/blackfin/lib/divsi3.S + * Based on: + * Author: + * + * Created: + * Description: 16 / 32 bit signed division. + * Special cases : + * 1) If(numerator == 0) + * return 0 + * 2) If(denominator ==0) + * return positive max = 0x7fffffff + * 3) If(numerator == denominator) + * return 1 + * 4) If(denominator ==1) + * return numerator + * 5) If(denominator == -1) + * return -numerator + * + * Operand : R0 - Numerator (i) + * R1 - Denominator (i) + * R0 - Quotient (o) + * Registers Used : R2-R7,P0-P2 + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +.global ___divsi3; + +#ifdef CONFIG_ARITHMETIC_OPS_L1 +.section .l1.text +#else +.text +#endif + +.align 2; +___divsi3 : + + + R3 = R0 ^ R1; + R0 = ABS R0; + + CC = V; + + r3 = rot r3 by -1; + r1 = abs r1; /* now both positive, r3.30 means "negate result", + ** r3.31 means overflow, add one to result + */ + cc = r0 < r1; + if cc jump .Lret_zero; + r2 = r1 >> 15; + cc = r2; + if cc jump .Lidents; + r2 = r1 << 16; + cc = r2 <= r0; + if cc jump .Lidents; + + DIVS(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + DIVQ(R0, R1); + + R0 = R0.L (Z); + r1 = r3 >> 31; /* add overflow issue back in */ + r0 = r0 + r1; + r1 = -r0; + cc = bittst(r3, 30); + if cc r0 = r1; + RTS; + +/* Can't use the primitives. Test common identities. +** If the identity is true, return the value in R2. +*/ + +.Lidents: + CC = R1 == 0; /* check for divide by zero */ + IF CC JUMP .Lident_return; + + CC = R0 == 0; /* check for division of zero */ + IF CC JUMP .Lzero_return; + + CC = R0 == R1; /* check for identical operands */ + IF CC JUMP .Lident_return; + + CC = R1 == 1; /* check for divide by 1 */ + IF CC JUMP .Lident_return; + + R2.L = ONES R1; + R2 = R2.L (Z); + CC = R2 == 1; + IF CC JUMP .Lpower_of_two; + + /* Identities haven't helped either. + ** Perform the full division process. + */ + + P1 = 31; /* Set loop counter */ + + [--SP] = (R7:5); /* Push registers R5-R7 */ + R2 = -R1; + [--SP] = R2; + R2 = R0 << 1; /* R2 lsw of dividend */ + R6 = R0 ^ R1; /* Get sign */ + R5 = R6 >> 31; /* Shift sign to LSB */ + + R0 = 0 ; /* Clear msw partial remainder */ + R2 = R2 | R5; /* Shift quotient bit */ + R6 = R0 ^ R1; /* Get new quotient bit */ + + LSETUP(.Llst,.Llend) LC0 = P1; /* Setup loop */ +.Llst: R7 = R2 >> 31; /* record copy of carry from R2 */ + R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */ + R0 = R0 << 1 || R5 = [SP]; + R0 = R0 | R7; /* and add carry */ + CC = R6 < 0; /* Check quotient(AQ) */ + /* we might be subtracting divisor (AQ==0) */ + IF CC R5 = R1; /* or we might be adding divisor (AQ==1)*/ + R0 = R0 + R5; /* do add or subtract, as indicated by AQ */ + R6 = R0 ^ R1; /* Generate next quotient bit */ + R5 = R6 >> 31; + /* Assume AQ==1, shift in zero */ + BITTGL(R5,0); /* tweak AQ to be what we want to shift in */ +.Llend: R2 = R2 + R5; /* and then set shifted-in value to + ** tweaked AQ. + */ + r1 = r3 >> 31; + r2 = r2 + r1; + cc = bittst(r3,30); + r0 = -r2; + if !cc r0 = r2; + SP += 4; + (R7:5)= [SP++]; /* Pop registers R6-R7 */ + RTS; + +.Lident_return: + CC = R1 == 0; /* check for divide by zero => 0x7fffffff */ + R2 = -1 (X); + R2 >>= 1; + IF CC JUMP .Ltrue_ident_return; + + CC = R0 == R1; /* check for identical operands => 1 */ + R2 = 1 (Z); + IF CC JUMP .Ltrue_ident_return; + + R2 = R0; /* assume divide by 1 => numerator */ + /*FALLTHRU*/ + +.Ltrue_ident_return: + R0 = R2; /* Return an identity value */ + R2 = -R2; + CC = bittst(R3,30); + IF CC R0 = R2; +.Lzero_return: + RTS; /* ...including zero */ + +.Lpower_of_two: + /* Y has a single bit set, which means it's a power of two. + ** That means we can perform the division just by shifting + ** X to the right the appropriate number of bits + */ + + /* signbits returns the number of sign bits, minus one. + ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need + ** to shift right n-signbits spaces. It also means 0x80000000 + ** is a special case, because that *also* gives a signbits of 0 + */ + + R2 = R0 >> 31; + CC = R1 < 0; + IF CC JUMP .Ltrue_ident_return; + + R1.l = SIGNBITS R1; + R1 = R1.L (Z); + R1 += -30; + R0 = LSHIFT R0 by R1.L; + r1 = r3 >> 31; + r0 = r0 + r1; + R2 = -R0; // negate result if necessary + CC = bittst(R3,30); + IF CC R0 = R2; + RTS; + +.Lret_zero: + R0 = 0; + RTS; diff --git a/trunk/arch/blackfin/lib/gcclib.h b/trunk/arch/blackfin/lib/gcclib.h new file mode 100644 index 000000000000..9ccd39a135ee --- /dev/null +++ b/trunk/arch/blackfin/lib/gcclib.h @@ -0,0 +1,47 @@ +/* + * File: arch/blackfin/lib/gcclib.h + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define BITS_PER_UNIT 8 +#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT) + +typedef unsigned int UQItype __attribute__ ((mode(QI))); +typedef int SItype __attribute__ ((mode(SI))); +typedef unsigned int USItype __attribute__ ((mode(SI))); +typedef int DItype __attribute__ ((mode(DI))); +typedef int word_type __attribute__ ((mode(__word__))); +typedef unsigned int UDItype __attribute__ ((mode(DI))); + +struct DIstruct { + SItype low, high; +}; + +typedef union { + struct DIstruct s; + DItype ll; +} DIunion; diff --git a/trunk/arch/blackfin/lib/ins.S b/trunk/arch/blackfin/lib/ins.S new file mode 100644 index 000000000000..730d2b427538 --- /dev/null +++ b/trunk/arch/blackfin/lib/ins.S @@ -0,0 +1,69 @@ +/* + * File: arch/blackfin/lib/ins.S + * Based on: + * Author: Bas Vermeulen + * + * Created: Tue Mar 22 15:27:24 CEST 2005 + * Description: Implementation of ins{bwl} for BlackFin processors using zero overhead loops. + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * Copyright (C) 2005 Bas Vermeulen, BuyWays BV + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +.align 2 + +ENTRY(_insl) + P0 = R0; /* P0 = port */ + cli R3; + P1 = R1; /* P1 = address */ + P2 = R2; /* P2 = count */ + SSYNC; + LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2; +.Llong_loop_s: R0 = [P0]; +.Llong_loop_e: [P1++] = R0; + sti R3; + RTS; + +ENTRY(_insw) + P0 = R0; /* P0 = port */ + cli R3; + P1 = R1; /* P1 = address */ + P2 = R2; /* P2 = count */ + SSYNC; + LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2; +.Lword_loop_s: R0 = W[P0]; +.Lword_loop_e: W[P1++] = R0; + sti R3; + RTS; + +ENTRY(_insb) + P0 = R0; /* P0 = port */ + cli R3; + P1 = R1; /* P1 = address */ + P2 = R2; /* P2 = count */ + SSYNC; + LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2; +.Lbyte_loop_s: R0 = B[P0]; +.Lbyte_loop_e: B[P1++] = R0; + sti R3; + RTS; diff --git a/trunk/arch/blackfin/lib/lshrdi3.c b/trunk/arch/blackfin/lib/lshrdi3.c new file mode 100644 index 000000000000..84b9c5592220 --- /dev/null +++ b/trunk/arch/blackfin/lib/lshrdi3.c @@ -0,0 +1,72 @@ +/* + * File: arch/blackfin/lib/lshrdi3.c + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define BITS_PER_UNIT 8 + +typedef int SItype __attribute__ ((mode(SI))); +typedef unsigned int USItype __attribute__ ((mode(SI))); +typedef int DItype __attribute__ ((mode(DI))); +typedef int word_type __attribute__ ((mode(__word__))); + +struct DIstruct { + SItype high, low; +}; + +typedef union { + struct DIstruct s; + DItype ll; +} DIunion; + +#ifdef CONFIG_ARITHMETIC_OPS_L1 +DItype __lshrdi3(DItype u, word_type b)__attribute__((l1_text)); +#endif + +DItype __lshrdi3(DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof(SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) { + w.s.high = 0; + w.s.low = (USItype) uu.s.high >> -bm; + } else { + USItype carries = (USItype) uu.s.high << bm; + w.s.high = (USItype) uu.s.high >> b; + w.s.low = ((USItype) uu.s.low >> b) | carries; + } + + return w.ll; +} diff --git a/trunk/arch/blackfin/lib/memchr.S b/trunk/arch/blackfin/lib/memchr.S new file mode 100644 index 000000000000..498122250d07 --- /dev/null +++ b/trunk/arch/blackfin/lib/memchr.S @@ -0,0 +1,70 @@ +/* + * File: arch/blackfin/lib/memchr.S + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +/* void *memchr(const void *s, int c, size_t n); + * R0 = address (s) + * R1 = sought byte (c) + * R2 = count (n) + * + * Returns pointer to located character. + */ + +.text + +.align 2 + +ENTRY(_memchr) + P0 = R0; /* P0 = address */ + P2 = R2; /* P2 = count */ + R1 = R1.B(Z); + CC = R2 == 0; + IF CC JUMP .Lfailed; + +.Lbytes: + LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2; + +.Lbyte_loop_s: + R3 = B[P0++](Z); + CC = R3 == R1; + IF CC JUMP .Lfound; +.Lbyte_loop_e: + NOP; + +.Lfailed: + R0=0; + RTS; + +.Lfound: + R0 = P0; + R0 += -1; + RTS; + +.size _memchr,.-_memchr diff --git a/trunk/arch/blackfin/lib/memcmp.S b/trunk/arch/blackfin/lib/memcmp.S new file mode 100644 index 000000000000..5b9502368fc6 --- /dev/null +++ b/trunk/arch/blackfin/lib/memcmp.S @@ -0,0 +1,110 @@ +/* + * File: arch/blackfin/lib/memcmp.S + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +/* int memcmp(const void *s1, const void *s2, size_t n); + * R0 = First Address (s1) + * R1 = Second Address (s2) + * R2 = count (n) + * + * Favours word aligned data. + */ + +.text + +.align 2 + +ENTRY(_memcmp) + I1 = P3; + P0 = R0; /* P0 = s1 address */ + P3 = R1; /* P3 = s2 Address */ + P2 = R2 ; /* P2 = count */ + CC = R2 <= 7(IU); + IF CC JUMP .Ltoo_small; + I0 = R1; /* s2 */ + R1 = R1 | R0; /* OR addresses together */ + R1 <<= 30; /* check bottom two bits */ + CC = AZ; /* AZ set if zero. */ + IF !CC JUMP .Lbytes ; /* Jump if addrs not aligned. */ + + P1 = P2 >> 2; /* count = n/4 */ + R3 = 3; + R2 = R2 & R3; /* remainder */ + P2 = R2; /* set remainder */ + + LSETUP (.Lquad_loop_s, .Lquad_loop_e) LC0=P1; +.Lquad_loop_s: + MNOP || R0 = [P0++] || R1 = [I0++]; + CC = R0 == R1; + IF !CC JUMP .Lquad_different; +.Lquad_loop_e: + NOP; + + P3 = I0; /* s2 */ +.Ltoo_small: + CC = P2 == 0; /* Check zero count*/ + IF CC JUMP .Lfinished; /* very unlikely*/ + +.Lbytes: + LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2; +.Lbyte_loop_s: + R1 = B[P3++](Z); /* *s2 */ + R0 = B[P0++](Z); /* *s1 */ + CC = R0 == R1; + IF !CC JUMP .Ldifferent; +.Lbyte_loop_e: + NOP; + +.Ldifferent: + R0 = R0 - R1; + P3 = I1; + RTS; + +.Lquad_different: + /* We've read two quads which don't match. + * Can't just compare them, because we're + * a little-endian machine, so the MSBs of + * the regs occur at later addresses in the + * string. + * Arrange to re-read those two quads again, + * byte-by-byte. + */ + P0 += -4; /* back up to the start of the */ + P3 = I0; /* quads, and increase the*/ + P2 += 4; /* remainder count*/ + P3 += -4; + JUMP .Lbytes; + +.Lfinished: + R0 = 0; + P3 = I1; + RTS; + +.size _memcmp,.-_memcmp diff --git a/trunk/arch/blackfin/lib/memcpy.S b/trunk/arch/blackfin/lib/memcpy.S new file mode 100644 index 000000000000..c1e00eff541c --- /dev/null +++ b/trunk/arch/blackfin/lib/memcpy.S @@ -0,0 +1,142 @@ +/* + * File: arch/blackfin/lib/memcpy.S + * Based on: + * Author: + * + * Created: + * Description: internal version of memcpy(), issued by the compiler + * to copy blocks of data around. + * This is really memmove() - it has to be able to deal with + * possible overlaps, because that ambiguity is when the compiler + * gives up and calls a function. We have our own, internal version + * so that we get something we trust, even if the user has redefined + * the normal symbol. + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +/* void *memcpy(void *dest, const void *src, size_t n); + * R0 = To Address (dest) (leave unchanged to form result) + * R1 = From Address (src) + * R2 = count + * + * Note: Favours word alignment + */ + +#ifdef CONFIG_MEMCPY_L1 +.section .l1.text +#else +.text +#endif + +.align 2 + +ENTRY(_memcpy) + CC = R2 <= 0; /* length not positive? */ + IF CC JUMP .L_P1L2147483647; /* Nothing to do */ + + P0 = R0 ; /* dst*/ + P1 = R1 ; /* src*/ + P2 = R2 ; /* length */ + + /* check for overlapping data */ + CC = R1 < R0; /* src < dst */ + IF !CC JUMP .Lno_overlap; + R3 = R1 + R2; + CC = R0 < R3; /* and dst < src+len */ + IF CC JUMP .Lhas_overlap; + +.Lno_overlap: + /* Check for aligned data.*/ + + R3 = R1 | R0; + R0 = 0x3; + R3 = R3 & R0; + CC = R3; /* low bits set on either address? */ + IF CC JUMP .Lnot_aligned; + + /* Both addresses are word-aligned, so we can copy + at least part of the data using word copies.*/ + P2 = P2 >> 2; + CC = P2 <= 2; + IF !CC JUMP .Lmore_than_seven; + /* less than eight bytes... */ + P2 = R2; + LSETUP(.Lthree_start, .Lthree_end) LC0=P2; + R0 = R1; /* setup src address for return */ +.Lthree_start: + R3 = B[P1++] (X); +.Lthree_end: + B[P0++] = R3; + + RTS; + +.Lmore_than_seven: + /* There's at least eight bytes to copy. */ + P2 += -1; /* because we unroll one iteration */ + LSETUP(.Lword_loop, .Lword_loop) LC0=P2; + R0 = R1; + I1 = P1; + R3 = [I1++]; +.Lword_loop: + MNOP || [P0++] = R3 || R3 = [I1++]; + + [P0++] = R3; + /* Any remaining bytes to copy? */ + R3 = 0x3; + R3 = R2 & R3; + CC = R3 == 0; + P1 = I1; /* in case there's something left, */ + IF !CC JUMP .Lbytes_left; + RTS; +.Lbytes_left: P2 = R3; +.Lnot_aligned: + /* From here, we're copying byte-by-byte. */ + LSETUP (.Lbyte_start, .Lbyte_end) LC0=P2; + R0 = R1; /* Save src address for return */ +.Lbyte_start: + R1 = B[P1++] (X); +.Lbyte_end: + B[P0++] = R1; + +.L_P1L2147483647: + RTS; + +.Lhas_overlap: + /* Need to reverse the copying, because the + * dst would clobber the src. + * Don't bother to work out alignment for + * the reverse case. + */ + R0 = R1; /* save src for later. */ + P0 = P0 + P2; + P0 += -1; + P1 = P1 + P2; + P1 += -1; + LSETUP(.Lover_start, .Lover_end) LC0=P2; +.Lover_start: + R1 = B[P1--] (X); +.Lover_end: + B[P0--] = R1; + + RTS; diff --git a/trunk/arch/blackfin/lib/memmove.S b/trunk/arch/blackfin/lib/memmove.S new file mode 100644 index 000000000000..2e5fb7f8df13 --- /dev/null +++ b/trunk/arch/blackfin/lib/memmove.S @@ -0,0 +1,103 @@ +/* + * File: arch/blackfin/lib/memmove.S + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +.align 2 + +/* + * C Library function MEMMOVE + * R0 = To Address (leave unchanged to form result) + * R1 = From Address + * R2 = count + * Data may overlap + */ + +ENTRY(_memmove) + I1 = P3; + P0 = R0; /* P0 = To address */ + P3 = R1; /* P3 = From Address */ + P2 = R2; /* P2 = count */ + CC = P2 == 0; /* Check zero count*/ + IF CC JUMP .Lfinished; /* very unlikely */ + + CC = R1 < R0 (IU); /* From < To */ + IF !CC JUMP .Lno_overlap; + R3 = R1 + R2; + CC = R0 <= R3 (IU); /* (From+len) >= To */ + IF CC JUMP .Loverlap; +.Lno_overlap: + R3 = 11; + CC = R2 <= R3; + IF CC JUMP .Lbytes; + R3 = R1 | R0; /* OR addresses together */ + R3 <<= 30; /* check bottom two bits */ + CC = AZ; /* AZ set if zero.*/ + IF !CC JUMP .Lbytes; /* Jump if addrs not aligned.*/ + + I0 = P3; + P1 = P2 >> 2; /* count = n/4 */ + P1 += -1; + R3 = 3; + R2 = R2 & R3; /* remainder */ + P2 = R2; /* set remainder */ + R1 = [I0++]; + + LSETUP (.Lquad_loop, .Lquad_loop) LC0=P1; +.Lquad_loop: MNOP || [P0++] = R1 || R1 = [I0++]; + [P0++] = R1; + + CC = P2 == 0; /* any remaining bytes? */ + P3 = I0; /* Ammend P3 to updated ptr. */ + IF !CC JUMP .Lbytes; + P3 = I1; + RTS; + +.Lbytes: LSETUP (.Lbyte2_s, .Lbyte2_e) LC0=P2; +.Lbyte2_s: R1 = B[P3++](Z); +.Lbyte2_e: B[P0++] = R1; + +.Lfinished: P3 = I1; + RTS; + +.Loverlap: + P2 += -1; + P0 = P0 + P2; + P3 = P3 + P2; + R1 = B[P3--] (Z); + CC = P2 == 0; + IF CC JUMP .Lno_loop; + LSETUP (.Lol_s, .Lol_e) LC0 = P2; +.Lol_s: B[P0--] = R1; +.Lol_e: R1 = B[P3--] (Z); +.Lno_loop: B[P0] = R1; + P3 = I1; + RTS; + +.size _memmove,.-_memmove diff --git a/trunk/arch/blackfin/lib/memset.S b/trunk/arch/blackfin/lib/memset.S new file mode 100644 index 000000000000..ba6d047568dd --- /dev/null +++ b/trunk/arch/blackfin/lib/memset.S @@ -0,0 +1,109 @@ +/* + * File: arch/blackfin/lib/memset.S + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +.align 2 + +#ifdef CONFIG_MEMSET_L1 +.section .l1.text +#else +.text +#endif + +/* + * C Library function MEMSET + * R0 = address (leave unchanged to form result) + * R1 = filler byte + * R2 = count + * Favours word aligned data. + */ + +ENTRY(_memset) + P0 = R0 ; /* P0 = address */ + P2 = R2 ; /* P2 = count */ + R3 = R0 + R2; /* end */ + CC = R2 <= 7(IU); + IF CC JUMP .Ltoo_small; + R1 = R1.B (Z); /* R1 = fill char */ + R2 = 3; + R2 = R0 & R2; /* addr bottom two bits */ + CC = R2 == 0; /* AZ set if zero. */ + IF !CC JUMP .Lforce_align ; /* Jump if addr not aligned. */ + +.Laligned: + P1 = P2 >> 2; /* count = n/4 */ + R2 = R1 << 8; /* create quad filler */ + R2.L = R2.L + R1.L(NS); + R2.H = R2.L + R1.H(NS); + P2 = R3; + + LSETUP (.Lquad_loop , .Lquad_loop) LC0=P1; +.Lquad_loop: + [P0++] = R2; + + CC = P0 == P2; + IF !CC JUMP .Lbytes_left; + RTS; + +.Lbytes_left: + R2 = R3; /* end point */ + R3 = P0; /* current position */ + R2 = R2 - R3; /* bytes left */ + P2 = R2; + +.Ltoo_small: + CC = P2 == 0; /* Check zero count */ + IF CC JUMP .Lfinished; /* Unusual */ + +.Lbytes: + LSETUP (.Lbyte_loop , .Lbyte_loop) LC0=P2; +.Lbyte_loop: + B[P0++] = R1; + +.Lfinished: + RTS; + +.Lforce_align: + CC = BITTST (R0, 0); /* odd byte */ + R0 = 4; + R0 = R0 - R2; + P1 = R0; + R0 = P0; /* Recover return address */ + IF !CC JUMP .Lskip1; + B[P0++] = R1; +.Lskip1: + CC = R2 <= 2; /* 2 bytes */ + P2 -= P1; /* reduce count */ + IF !CC JUMP .Laligned; + B[P0++] = R1; + B[P0++] = R1; + JUMP .Laligned; + +.size _memset,.-_memset diff --git a/trunk/arch/blackfin/lib/modsi3.S b/trunk/arch/blackfin/lib/modsi3.S new file mode 100644 index 000000000000..528b8b1ccb34 --- /dev/null +++ b/trunk/arch/blackfin/lib/modsi3.S @@ -0,0 +1,79 @@ +/* + * File: arch/blackfin/lib/modsi3.S + * Based on: + * Author: + * + * Created: + * Description: This program computes 32 bit signed remainder. It calls div32 function + * for quotient estimation. + * + * Registers used : + * Numerator/ Denominator in R0, R1 + * R0 - returns remainder. + * R2-R7 + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +.global ___modsi3; +.type ___modsi3, STT_FUNC; +.extern ___divsi3; +.type ___divsi3, STT_FUNC; + +#ifdef CONFIG_ARITHMETIC_OPS_L1 +.section .l1.text +#else +.text +#endif + +___modsi3: + + CC=R0==0; + IF CC JUMP .LRETURN_R0; /* Return 0, if numerator == 0 */ + CC=R1==0; + IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == 0 */ + CC=R0==R1; + IF CC JUMP .LRETURN_ZERO; /* Return 0, if numerator == denominator */ + CC = R1 == 1; + IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == 1 */ + CC = R1 == -1; + IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == -1 */ + + /* Valid input. Use __divsi3() to compute the quotient, and then + * derive the remainder from that. */ + + [--SP] = (R7:6); /* Push R7 and R6 */ + [--SP] = RETS; /* and return address */ + R7 = R0; /* Copy of R0 */ + R6 = R1; /* Save for later */ + SP += -12; /* Should always provide this space */ + CALL ___divsi3; /* Compute signed quotient using ___divsi3()*/ + SP += 12; + R0 *= R6; /* Quotient * divisor */ + R0 = R7 - R0; /* Dividend - (quotient * divisor) */ + RETS = [SP++]; /* Get back return address */ + (R7:6) = [SP++]; /* Pop registers R7 and R4 */ + RTS; /* Store remainder */ + +.LRETURN_ZERO: + R0 = 0; +.LRETURN_R0: + RTS; diff --git a/trunk/arch/blackfin/lib/muldi3.c b/trunk/arch/blackfin/lib/muldi3.c new file mode 100644 index 000000000000..303d0c6a6dba --- /dev/null +++ b/trunk/arch/blackfin/lib/muldi3.c @@ -0,0 +1,99 @@ +/* + * File: arch/blackfin/lib/muldi3.c + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SI_TYPE_SIZE +#define SI_TYPE_SIZE 32 +#endif +#define __ll_b (1L << (SI_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((usitype) (t) % __ll_b) +#define __ll_highpart(t) ((usitype) (t) / __ll_b) +#define BITS_PER_UNIT 8 + +#if !defined(umul_ppmm) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + usitype __x0, __x1, __x2, __x3; \ + usitype __ul, __vl, __uh, __vh; \ + \ + __ul = __ll_lowpart (u); \ + __uh = __ll_highpart (u); \ + __vl = __ll_lowpart (v); \ + __vh = __ll_highpart (v); \ + \ + __x0 = (usitype) __ul * __vl; \ + __x1 = (usitype) __ul * __vh; \ + __x2 = (usitype) __uh * __vl; \ + __x3 = (usitype) __uh * __vh; \ + \ + __x1 += __ll_highpart (__x0);/* this can't give carry */ \ + __x1 += __x2; /* but this indeed can */ \ + if (__x1 < __x2) /* did we get it? */ \ + __x3 += __ll_b; /* yes, add it in the proper pos. */ \ + \ + (w1) = __x3 + __ll_highpart (__x1); \ + (w0) = __ll_lowpart (__x1) * __ll_b + __ll_lowpart (__x0); \ + } while (0) +#endif + +#if !defined(__umulsidi3) +#define __umulsidi3(u, v) \ + ({diunion __w; \ + umul_ppmm (__w.s.high, __w.s.low, u, v); \ + __w.ll; }) +#endif + +typedef unsigned int usitype __attribute__ ((mode(SI))); +typedef int sitype __attribute__ ((mode(SI))); +typedef int ditype __attribute__ ((mode(DI))); +typedef int word_type __attribute__ ((mode(__word__))); + +struct distruct { + sitype low, high; +}; +typedef union { + struct distruct s; + ditype ll; +} diunion; + +#ifdef CONFIG_ARITHMETIC_OPS_L1 +ditype __muldi3(ditype u, ditype v)__attribute__((l1_text)); +#endif + +ditype __muldi3(ditype u, ditype v) +{ + diunion w; + diunion uu, vv; + + uu.ll = u, vv.ll = v; + w.ll = __umulsidi3(uu.s.low, vv.s.low); + w.s.high += ((usitype) uu.s.low * (usitype) vv.s.high + + (usitype) uu.s.high * (usitype) vv.s.low); + + return w.ll; +} diff --git a/trunk/arch/blackfin/lib/outs.S b/trunk/arch/blackfin/lib/outs.S new file mode 100644 index 000000000000..f8c876fe8930 --- /dev/null +++ b/trunk/arch/blackfin/lib/outs.S @@ -0,0 +1,62 @@ +/* + * File: arch/blackfin/lib/outs.S + * Based on: + * Author: Bas Vermeulen + * + * Created: Tue Mar 22 15:27:24 CEST 2005 + * Description: Implementation of outs{bwl} for BlackFin processors using zero overhead loops. + * + * Modified: Copyright (C) 2005 Bas Vermeulen, BuyWays BV + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +.align 2 + +ENTRY(_outsl) + P0 = R0; /* P0 = port */ + P1 = R1; /* P1 = address */ + P2 = R2; /* P2 = count */ + + LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2; +.Llong_loop_s: R0 = [P1++]; +.Llong_loop_e: [P0] = R0; + RTS; + +ENTRY(_outsw) + P0 = R0; /* P0 = port */ + P1 = R1; /* P1 = address */ + P2 = R2; /* P2 = count */ + + LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2; +.Lword_loop_s: R0 = W[P1++]; +.Lword_loop_e: W[P0] = R0; + RTS; + +ENTRY(_outsb) + P0 = R0; /* P0 = port */ + P1 = R1; /* P1 = address */ + P2 = R2; /* P2 = count */ + + LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2; +.Lbyte_loop_s: R0 = B[P1++]; +.Lbyte_loop_e: B[P0] = R0; + RTS; diff --git a/trunk/arch/blackfin/lib/smulsi3_highpart.S b/trunk/arch/blackfin/lib/smulsi3_highpart.S new file mode 100644 index 000000000000..10b8f8da576f --- /dev/null +++ b/trunk/arch/blackfin/lib/smulsi3_highpart.S @@ -0,0 +1,30 @@ +.align 2 +.global ___smulsi3_highpart; +.type ___smulsi3_highpart, STT_FUNC; + +#ifdef CONFIG_ARITHMETIC_OPS_L1 +.section .l1.text +#else +.text +#endif + +___smulsi3_highpart: + R2 = R1.L * R0.L (FU); + R3 = R1.H * R0.L (IS,M); + R0 = R0.H * R1.H, R1 = R0.H * R1.L (IS,M); + + R1.L = R2.H + R1.L; + cc = ac0; + R2 = cc; + + R1.L = R1.L + R3.L; + cc = ac0; + R1 >>>= 16; + R3 >>>= 16; + R1 = R1 + R3; + R1 = R1 + R2; + R2 = cc; + R1 = R1 + R2; + + R0 = R0 + R1; + RTS; diff --git a/trunk/arch/blackfin/lib/strcmp.c b/trunk/arch/blackfin/lib/strcmp.c new file mode 100644 index 000000000000..2ad47c4254ba --- /dev/null +++ b/trunk/arch/blackfin/lib/strcmp.c @@ -0,0 +1,11 @@ +#include + +#define strcmp __inline_strcmp +#include +#undef strcmp + +int strcmp(const char *dest, const char *src) +{ + return __inline_strcmp(dest, src); +} + diff --git a/trunk/arch/blackfin/lib/strcpy.c b/trunk/arch/blackfin/lib/strcpy.c new file mode 100644 index 000000000000..4dc835a8a19b --- /dev/null +++ b/trunk/arch/blackfin/lib/strcpy.c @@ -0,0 +1,11 @@ +#include + +#define strcpy __inline_strcpy +#include +#undef strcpy + +char *strcpy(char *dest, const char *src) +{ + return __inline_strcpy(dest, src); +} + diff --git a/trunk/arch/blackfin/lib/strncmp.c b/trunk/arch/blackfin/lib/strncmp.c new file mode 100644 index 000000000000..947bcfe3f3bb --- /dev/null +++ b/trunk/arch/blackfin/lib/strncmp.c @@ -0,0 +1,11 @@ +#include + +#define strncmp __inline_strncmp +#include +#undef strncmp + +int strncmp(const char *cs, const char *ct, size_t count) +{ + return __inline_strncmp(cs, ct, count); +} + diff --git a/trunk/arch/blackfin/lib/strncpy.c b/trunk/arch/blackfin/lib/strncpy.c new file mode 100644 index 000000000000..77a9b2e95097 --- /dev/null +++ b/trunk/arch/blackfin/lib/strncpy.c @@ -0,0 +1,11 @@ +#include + +#define strncpy __inline_strncpy +#include +#undef strncpy + +char *strncpy(char *dest, const char *src, size_t n) +{ + return __inline_strncpy(dest, src, n); +} + diff --git a/trunk/arch/blackfin/lib/udivsi3.S b/trunk/arch/blackfin/lib/udivsi3.S new file mode 100644 index 000000000000..d39a12916259 --- /dev/null +++ b/trunk/arch/blackfin/lib/udivsi3.S @@ -0,0 +1,298 @@ +/* + * File: arch/blackfin/lib/udivsi3.S + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#define CARRY AC0 + +#ifdef CONFIG_ARITHMETIC_OPS_L1 +.section .l1.text +#else +.text +#endif + + +ENTRY(___udivsi3) + + CC = R0 < R1 (IU); /* If X < Y, always return 0 */ + IF CC JUMP .Lreturn_ident; + + R2 = R1 << 16; + CC = R2 <= R0 (IU); + IF CC JUMP .Lidents; + + R2 = R0 >> 31; /* if X is a 31-bit number */ + R3 = R1 >> 15; /* and Y is a 15-bit number */ + R2 = R2 | R3; /* then it's okay to use the DIVQ builtins (fallthrough to fast)*/ + CC = R2; + IF CC JUMP .Ly_16bit; + +/* METHOD 1: FAST DIVQ + We know we have a 31-bit dividend, and 15-bit divisor so we can use the + simple divq approach (first setting AQ to 0 - implying unsigned division, + then 16 DIVQ's). +*/ + + AQ = CC; /* Clear AQ (CC==0) */ + +/* ISR States: When dividing two integers (32.0/16.0) using divide primitives, + we need to shift the dividend one bit to the left. + We have already checked that we have a 31-bit number so we are safe to do + that. +*/ + R0 <<= 1; + DIVQ(R0, R1); // 1 + DIVQ(R0, R1); // 2 + DIVQ(R0, R1); // 3 + DIVQ(R0, R1); // 4 + DIVQ(R0, R1); // 5 + DIVQ(R0, R1); // 6 + DIVQ(R0, R1); // 7 + DIVQ(R0, R1); // 8 + DIVQ(R0, R1); // 9 + DIVQ(R0, R1); // 10 + DIVQ(R0, R1); // 11 + DIVQ(R0, R1); // 12 + DIVQ(R0, R1); // 13 + DIVQ(R0, R1); // 14 + DIVQ(R0, R1); // 15 + DIVQ(R0, R1); // 16 + R0 = R0.L (Z); + RTS; + +.Ly_16bit: + /* We know that the upper 17 bits of Y might have bits set, + ** or that the sign bit of X might have a bit. If Y is a + ** 16-bit number, but not bigger, then we can use the builtins + ** with a post-divide correction. + ** R3 currently holds Y>>15, which means R3's LSB is the + ** bit we're interested in. + */ + + /* According to the ISR, to use the Divide primitives for + ** unsigned integer divide, the useable range is 31 bits + */ + CC = ! BITTST(R0, 31); + + /* IF condition is true we can scale our inputs and use the divide primitives, + ** with some post-adjustment + */ + R3 += -1; /* if so, Y is 0x00008nnn */ + CC &= AZ; + + /* If condition is true we can scale our inputs and use the divide primitives, + ** with some post-adjustment + */ + R3 = R1 >> 1; /* Pre-scaled divisor for primitive case */ + R2 = R0 >> 16; + + R2 = R3 - R2; /* shifted divisor < upper 16 bits of dividend */ + CC &= CARRY; + IF CC JUMP .Lshift_and_correct; + + /* Fall through to the identities */ + +/* METHOD 2: identities and manual calculation + We are not able to use the divide primites, but may still catch some special + cases. +*/ +.Lidents: + /* Test for common identities. Value to be returned is placed in R2. */ + CC = R0 == 0; /* 0/Y => 0 */ + IF CC JUMP .Lreturn_r0; + CC = R0 == R1; /* X==Y => 1 */ + IF CC JUMP .Lreturn_ident; + CC = R1 == 1; /* X/1 => X */ + IF CC JUMP .Lreturn_ident; + + R2.L = ONES R1; + R2 = R2.L (Z); + CC = R2 == 1; + IF CC JUMP .Lpower_of_two; + + [--SP] = (R7:5); /* Push registers R5-R7 */ + + /* Idents don't match. Go for the full operation. */ + + + R6 = 2; /* assume we'll shift two */ + R3 = 1; + + P2 = R1; + /* If either R0 or R1 have sign set, */ + /* divide them by two, and note it's */ + /* been done. */ + CC = R1 < 0; + R2 = R1 >> 1; + IF CC R1 = R2; /* Possibly-shifted R1 */ + IF !CC R6 = R3; /* R1 doesn't, so at most 1 shifted */ + + P0 = 0; + R3 = -R1; + [--SP] = R3; + R2 = R0 >> 1; + R2 = R0 >> 1; + CC = R0 < 0; + IF CC P0 = R6; /* Number of values divided */ + IF !CC R2 = R0; /* Shifted R0 */ + + /* P0 is 0, 1 (NR/=2) or 2 (NR/=2, DR/=2) */ + + /* r2 holds Copy dividend */ + R3 = 0; /* Clear partial remainder */ + R7 = 0; /* Initialise quotient bit */ + + P1 = 32; /* Set loop counter */ + LSETUP(.Lulst, .Lulend) LC0 = P1; /* Set loop counter */ +.Lulst: R6 = R2 >> 31; /* R6 = sign bit of R2, for carry */ + R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */ + R3 = R3 << 1 || R5 = [SP]; + R3 = R3 | R6; /* Include any carry */ + CC = R7 < 0; /* Check quotient(AQ) */ + /* If AQ==0, we'll sub divisor */ + IF CC R5 = R1; /* and if AQ==1, we'll add it. */ + R3 = R3 + R5; /* Add/sub divsor to partial remainder */ + R7 = R3 ^ R1; /* Generate next quotient bit */ + + R5 = R7 >> 31; /* Get AQ */ + BITTGL(R5, 0); /* Invert it, to get what we'll shift */ +.Lulend: R2 = R2 + R5; /* and "shift" it in. */ + + CC = P0 == 0; /* Check how many inputs we shifted */ + IF CC JUMP .Lno_mult; /* if none... */ + R6 = R2 << 1; + CC = P0 == 1; + IF CC R2 = R6; /* if 1, Q = Q*2 */ + IF !CC R1 = P2; /* if 2, restore stored divisor */ + + R3 = R2; /* Copy of R2 */ + R3 *= R1; /* Q * divisor */ + R5 = R0 - R3; /* Z = (dividend - Q * divisor) */ + CC = R1 <= R5 (IU); /* Check if divisor <= Z? */ + R6 = CC; /* if yes, R6 = 1 */ + R2 = R2 + R6; /* if yes, add one to quotient(Q) */ +.Lno_mult: + SP += 4; + (R7:5) = [SP++]; /* Pop registers R5-R7 */ + R0 = R2; /* Store quotient */ + RTS; + +.Lreturn_ident: + CC = R0 < R1 (IU); /* If X < Y, always return 0 */ + R2 = 0; + IF CC JUMP .Ltrue_return_ident; + R2 = -1 (X); /* X/0 => 0xFFFFFFFF */ + CC = R1 == 0; + IF CC JUMP .Ltrue_return_ident; + R2 = -R2; /* R2 now 1 */ + CC = R0 == R1; /* X==Y => 1 */ + IF CC JUMP .Ltrue_return_ident; + R2 = R0; /* X/1 => X */ + /*FALLTHRU*/ + +.Ltrue_return_ident: + R0 = R2; +.Lreturn_r0: + RTS; + +.Lpower_of_two: + /* Y has a single bit set, which means it's a power of two. + ** That means we can perform the division just by shifting + ** X to the right the appropriate number of bits + */ + + /* signbits returns the number of sign bits, minus one. + ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need + ** to shift right n-signbits spaces. It also means 0x80000000 + ** is a special case, because that *also* gives a signbits of 0 + */ + + R2 = R0 >> 31; + CC = R1 < 0; + IF CC JUMP .Ltrue_return_ident; + + R1.l = SIGNBITS R1; + R1 = R1.L (Z); + R1 += -30; + R0 = LSHIFT R0 by R1.L; + RTS; + +/* METHOD 3: PRESCALE AND USE THE DIVIDE PRIMITIVES WITH SOME POST-CORRECTION + Two scaling operations are required to use the divide primitives with a + divisor > 0x7FFFF. + Firstly (as in method 1) we need to shift the dividend 1 to the left for + integer division. + Secondly we need to shift both the divisor and dividend 1 to the right so + both are in range for the primitives. + The left/right shift of the dividend does nothing so we can skip it. +*/ +.Lshift_and_correct: + R2 = R0; + // R3 is already R1 >> 1 + CC=!CC; + AQ = CC; /* Clear AQ, got here with CC = 0 */ + DIVQ(R2, R3); // 1 + DIVQ(R2, R3); // 2 + DIVQ(R2, R3); // 3 + DIVQ(R2, R3); // 4 + DIVQ(R2, R3); // 5 + DIVQ(R2, R3); // 6 + DIVQ(R2, R3); // 7 + DIVQ(R2, R3); // 8 + DIVQ(R2, R3); // 9 + DIVQ(R2, R3); // 10 + DIVQ(R2, R3); // 11 + DIVQ(R2, R3); // 12 + DIVQ(R2, R3); // 13 + DIVQ(R2, R3); // 14 + DIVQ(R2, R3); // 15 + DIVQ(R2, R3); // 16 + + /* According to the Instruction Set Reference: + To divide by a divisor > 0x7FFF, + 1. prescale and perform divide to obtain quotient (Q) (done above), + 2. multiply quotient by unscaled divisor (result M) + 3. subtract the product from the divident to get an error (E = X - M) + 4. if E < divisor (Y) subtract 1, if E > divisor (Y) add 1, else return quotient (Q) + */ + R3 = R2.L (Z); /* Q = X' / Y' */ + R2 = R3; /* Preserve Q */ + R2 *= R1; /* M = Q * Y */ + R2 = R0 - R2; /* E = X - M */ + R0 = R3; /* Copy Q into result reg */ + +/* Correction: If result of the multiply is negative, we overflowed + and need to correct the result by subtracting 1 from the result.*/ + R3 = 0xFFFF (Z); + R2 = R2 >> 16; /* E >> 16 */ + CC = R2 == R3; + R3 = 1 ; + R1 = R0 - R3; + IF CC R0 = R1; + RTS; diff --git a/trunk/arch/blackfin/lib/umodsi3.S b/trunk/arch/blackfin/lib/umodsi3.S new file mode 100644 index 000000000000..b55ce96ab89f --- /dev/null +++ b/trunk/arch/blackfin/lib/umodsi3.S @@ -0,0 +1,66 @@ +/* + * File: arch/blackfin/lib/umodsi3.S + * Based on: + * Author: + * + * Created: + * Description: libgcc1 routines for Blackfin 5xx + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef CONFIG_ARITHMETIC_OPS_L1 +.section .l1.text +#else +.text +#endif + +.extern ___udivsi3; +.globl ___umodsi3 +___umodsi3: + + CC=R0==0; + IF CC JUMP .LRETURN_R0; /* Return 0, if NR == 0 */ + CC= R1==0; + IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if DR == 0 */ + CC=R0==R1; + IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if NR == DR */ + CC = R1 == 1; + IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if DR == 1 */ + CC = R0>= 16; + /* Unsigned multiplication has the nice property that we can + ignore carry on this first addition. */ + R0 = R0 + R3; + R0 = R0 + R1; + cc = ac0; + R1 = cc; + R1 = PACK(R1.l,R0.h); + R0 = R1 + R2; + RTS; diff --git a/trunk/arch/blackfin/mach-bf533/Kconfig b/trunk/arch/blackfin/mach-bf533/Kconfig new file mode 100644 index 000000000000..14297b3ed5c3 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf533/Kconfig @@ -0,0 +1,92 @@ +if (BF533 || BF532 || BF531) + +menu "BF533/2/1 Specific Configuration" + +comment "Interrupt Priority Assignment" +menu "Priority" + +config UART_ERROR + int "UART ERROR" + default 7 +config SPORT0_ERROR + int "SPORT0 ERROR" + default 7 +config SPI_ERROR + int "SPI ERROR" + default 7 +config SPORT1_ERROR + int "SPORT1 ERROR" + default 7 +config PPI_ERROR + int "PPI ERROR" + default 7 +config DMA_ERROR + int "DMA ERROR" + default 7 +config PLLWAKE_ERROR + int "PLL WAKEUP ERROR" + default 7 + +config RTC_ERROR + int "RTC ERROR" + default 8 +config DMA0_PPI + int "DMA0 PPI" + default 8 + +config DMA1_SPORT0RX + int "DMA1 (SPORT0 RX)" + default 9 +config DMA2_SPORT0TX + int "DMA2 (SPORT0 TX)" + default 9 +config DMA3_SPORT1RX + int "DMA3 (SPORT1 RX)" + default 9 +config DMA4_SPORT1TX + int "DMA4 (SPORT1 TX)" + default 9 +config DMA5_SPI + int "DMA5 (SPI)" + default 10 +config DMA6_UARTRX + int "DMA6 (UART0 RX)" + default 10 +config DMA7_UARTTX + int "DMA7 (UART0 TX)" + default 10 +config TIMER0 + int "TIMER0" + default 11 +config TIMER1 + int "TIMER1" + default 11 +config TIMER2 + int "TIMER2" + default 11 +config PFA + int "PF Interrupt A" + default 12 +config PFB + int "PF Interrupt B" + default 12 +config MEMDMA0 + int "MEMORY DMA0" + default 13 +config MEMDMA1 + int "MEMORY DMA1" + default 13 +config WDTIMER + int "WATCH DOG TIMER" + default 13 + + help + Enter the priority numbers between 7-13 ONLY. Others are Reserved. + This applies to all the above. It is not recommended to assign the + highest priority number 7 to UART or any other device. + +endmenu + +endmenu + +endif diff --git a/trunk/arch/blackfin/mach-bf533/Makefile b/trunk/arch/blackfin/mach-bf533/Makefile new file mode 100644 index 000000000000..76d2c2b8579a --- /dev/null +++ b/trunk/arch/blackfin/mach-bf533/Makefile @@ -0,0 +1,9 @@ +# +# arch/blackfin/mach-bf533/Makefile +# + +extra-y := head.o + +obj-y := ints-priority.o + +obj-$(CONFIG_CPU_FREQ_BF533) += cpu.o diff --git a/trunk/arch/blackfin/mach-bf533/boards/Makefile b/trunk/arch/blackfin/mach-bf533/boards/Makefile new file mode 100644 index 000000000000..12a631ab389d --- /dev/null +++ b/trunk/arch/blackfin/mach-bf533/boards/Makefile @@ -0,0 +1,8 @@ +# +# arch/blackfin/mach-bf533/boards/Makefile +# + +obj-$(CONFIG_GENERIC_BOARD) += generic_board.o +obj-$(CONFIG_BFIN533_STAMP) += stamp.o +obj-$(CONFIG_BFIN533_EZKIT) += ezkit.o +obj-$(CONFIG_BFIN533_BLUETECHNIX_CM) += cm_bf533.o diff --git a/trunk/arch/blackfin/mach-bf533/boards/cm_bf533.c b/trunk/arch/blackfin/mach-bf533/boards/cm_bf533.c new file mode 100644 index 000000000000..23a7f607df3f --- /dev/null +++ b/trunk/arch/blackfin/mach-bf533/boards/cm_bf533.c @@ -0,0 +1,267 @@ +/* + * File: arch/blackfin/mach-bf533/boards/cm_bf533.c + * Based on: arch/blackfin/mach-bf533/boards/ezkit.c + * Author: Aidan Williams Copright 2005 + * + * Created: 2005 + * Description: Board description file + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Name the Board for the /proc/cpuinfo + */ +char *bfin_board_name = "Bluetechnix CM BF533"; + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) +/* all SPI peripherals info goes here */ + +static struct mtd_partition bfin_spi_flash_partitions[] = { + { + .name = "bootloader", + .size = 0x00020000, + .offset = 0, + .mask_flags = MTD_CAP_ROM + },{ + .name = "kernel", + .size = 0xe0000, + .offset = 0x20000 + },{ + .name = "file system", + .size = 0x700000, + .offset = 0x00100000, + } +}; + +static struct flash_platform_data bfin_spi_flash_data = { + .name = "m25p80", + .parts = bfin_spi_flash_partitions, + .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), + .type = "m25p64", +}; + +/* SPI flash chip (m25p64) */ +static struct bfin5xx_spi_chip spi_flash_chip_info = { + .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; + +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; + +#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +static struct spi_board_info bfin_spi_board_info[] __initdata = { + { + /* the modalias must be the same as spi device driver name */ + .modalias = "m25p80", /* Name of spi_driver for this device */ + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/ + .platform_data = &bfin_spi_flash_data, + .controller_data = &spi_flash_chip_info, + .mode = SPI_MODE_3, + },{ + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 2, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) + { + .modalias = "ad1836-spi", + .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, + .controller_data = &ad1836_spi_chip_info, + }, +#endif +}; + +/* SPI controller data */ +static struct bfin5xx_spi_master spi_bfin_master_info = { + .num_chipselect = 8, + .enable_dma = 1, /* master has the ability to do dma transfer */ +}; + +static struct platform_device spi_bfin_master_device = { + .name = "bfin-spi-master", + .id = 1, /* Bus number */ + .dev = { + .platform_data = &spi_bfin_master_info, /* Passed to driver */ + }, +}; +#endif /* spi master and devices */ + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) +static struct platform_device rtc_device = { + .name = "rtc-bfin", + .id = -1, +}; +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) +static struct resource smc91x_resources[] = { + { + .start = 0x20200300, + .end = 0x20200300 + 16, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF0, + .end = IRQ_PF0, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) +static struct resource bfin_uart_resources[] = { + { + .start = 0xFFC00400, + .end = 0xFFC004FF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device bfin_uart_device = { + .name = "bfin-uart", + .id = 1, + .num_resources = ARRAY_SIZE(bfin_uart_resources), + .resource = bfin_uart_resources, +}; +#endif + +#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE) +static struct platform_device bfin_sport0_uart_device = { + .name = "bfin-sport-uart", + .id = 0, +}; + +static struct platform_device bfin_sport1_uart_device = { + .name = "bfin-sport-uart", + .id = 1, +}; +#endif + +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) +static struct resource isp1362_hcd_resources[] = { + { + .start = 0x20308000, + .end = 0x20308000, + .flags = IORESOURCE_MEM, + },{ + .start = 0x20308004, + .end = 0x20308004, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF4, + .end = IRQ_PF4, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct isp1362_platform_data isp1362_priv = { + .sel15Kres = 1, + .clknotstop = 0, + .oc_enable = 0, + .int_act_high = 0, + .int_edge_triggered = 0, + .remote_wakeup_connected = 0, + .no_power_switching = 1, + .power_switching_mode = 0, +}; + +static struct platform_device isp1362_hcd_device = { + .name = "isp1362-hcd", + .id = 0, + .dev = { + .platform_data = &isp1362_priv, + }, + .num_resources = ARRAY_SIZE(isp1362_hcd_resources), + .resource = isp1362_hcd_resources, +}; +#endif + +static struct platform_device *cm_bf533_devices[] __initdata = { +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) + &bfin_uart_device, +#endif + +#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE) + &bfin_sport0_uart_device, + &bfin_sport1_uart_device, +#endif + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) + &rtc_device, +#endif + +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) + &isp1362_hcd_device, +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + &smc91x_device, +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + &spi_bfin_master_device, +#endif +}; + +static int __init cm_bf533_init(void) +{ + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + platform_add_devices(cm_bf533_devices, ARRAY_SIZE(cm_bf533_devices)); +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); +#endif + return 0; +} + +arch_initcall(cm_bf533_init); diff --git a/trunk/arch/blackfin/mach-bf533/boards/ezkit.c b/trunk/arch/blackfin/mach-bf533/boards/ezkit.c new file mode 100644 index 000000000000..747298ea907b --- /dev/null +++ b/trunk/arch/blackfin/mach-bf533/boards/ezkit.c @@ -0,0 +1,224 @@ +/* + * File: arch/blackfin/mach-bf533/ezkit.c + * Based on: Orginal Work + * Author: Aidan Williams + * + * Created: 2005 + * Description: + * + * Modified: Robin Getz - Named the boards + * Copyright 2005 National ICT Australia (NICTA) + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Name the Board for the /proc/cpuinfo + */ +char *bfin_board_name = "ADDS-BF533-EZKIT"; + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) +static struct platform_device rtc_device = { + .name = "rtc-bfin", + .id = -1, +}; +#endif + +/* + * USB-LAN EzExtender board + * Driver needs to know address, irq and flag pin. + */ +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) +static struct resource smc91x_resources[] = { + { + .name = "smc91x-regs", + .start = 0x20310300, + .end = 0x20310300 + 16, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF9, + .end = IRQ_PF9, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) +/* all SPI peripherals info goes here */ + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition bfin_spi_flash_partitions[] = { + { + .name = "bootloader", + .size = 0x00020000, + .offset = 0, + .mask_flags = MTD_CAP_ROM + },{ + .name = "kernel", + .size = 0xe0000, + .offset = 0x20000 + },{ + .name = "file system", + .size = 0x700000, + .offset = 0x00100000, + } +}; + +static struct flash_platform_data bfin_spi_flash_data = { + .name = "m25p80", + .parts = bfin_spi_flash_partitions, + .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), + .type = "m25p64", +}; + +/* SPI flash chip (m25p64) */ +static struct bfin5xx_spi_chip spi_flash_chip_info = { + .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +static struct spi_board_info bfin_spi_board_info[] __initdata = { +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) + { + /* the modalias must be the same as spi device driver name */ + .modalias = "m25p80", /* Name of spi_driver for this device */ + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL2*/ + .platform_data = &bfin_spi_flash_data, + .controller_data = &spi_flash_chip_info, + .mode = SPI_MODE_3, + }, +#endif + +#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) + { + .modalias = "ad1836-spi", + .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, + .controller_data = &ad1836_spi_chip_info, + }, +#endif +}; + +/* SPI controller data */ +static struct bfin5xx_spi_master spi_bfin_master_info = { + .num_chipselect = 8, + .enable_dma = 1, /* master has the ability to do dma transfer */ +}; + +static struct platform_device spi_bfin_master_device = { + .name = "bfin-spi-master", + .id = 1, /* Bus number */ + .dev = { + .platform_data = &spi_bfin_master_info, /* Passed to driver */ + }, +}; +#endif /* spi master and devices */ + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) +static struct resource bfin_uart_resources[] = { + { + .start = 0xFFC00400, + .end = 0xFFC004FF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device bfin_uart_device = { + .name = "bfin-uart", + .id = 1, + .num_resources = ARRAY_SIZE(bfin_uart_resources), + .resource = bfin_uart_resources, +}; +#endif + +static struct platform_device *ezkit_devices[] __initdata = { +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + &smc91x_device, +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + &spi_bfin_master_device, +#endif + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) + &rtc_device, +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) + &bfin_uart_device, +#endif +}; + +static int __init ezkit_init(void) +{ + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices)); +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); +#endif + return 0; +} + +arch_initcall(ezkit_init); diff --git a/trunk/arch/blackfin/mach-bf533/boards/generic_board.c b/trunk/arch/blackfin/mach-bf533/boards/generic_board.c new file mode 100644 index 000000000000..c0f43ccfbfb5 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf533/boards/generic_board.c @@ -0,0 +1,95 @@ +/* + * File: arch/blackfin/mach-bf533/generic_board.c + * Based on: arch/blackfin/mach-bf533/ezkit.c + * Author: Aidan Williams + * + * Created: 2005 + * Description: + * + * Modified: + * Copyright 2005 National ICT Australia (NICTA) + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +/* + * Name the Board for the /proc/cpuinfo + */ +char *bfin_board_name = "UNKNOWN BOARD"; + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) +static struct platform_device rtc_device = { + .name = "rtc-bfin", + .id = -1, +}; +#endif + +/* + * Driver needs to know address, irq and flag pin. + */ +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) +static struct resource smc91x_resources[] = { + { + .start = 0x20300300, + .end = 0x20300300 + 16, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PROG_INTB, + .end = IRQ_PROG_INTB, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + },{ + /* + * denotes the flag pin and is used directly if + * CONFIG_IRQCHIP_DEMUX_GPIO is defined. + */ + .start = IRQ_PF7, + .end = IRQ_PF7, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +#endif + +static struct platform_device *generic_board_devices[] __initdata = { +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) + &rtc_device, +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + &smc91x_device, +#endif +}; + +static int __init generic_board_init(void) +{ + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + return platform_add_devices(generic_board_devices, ARRAY_SIZE(generic_board_devices)); +} + +arch_initcall(generic_board_init); diff --git a/trunk/arch/blackfin/mach-bf533/boards/stamp.c b/trunk/arch/blackfin/mach-bf533/boards/stamp.c new file mode 100644 index 000000000000..d7b3a5d74e8c --- /dev/null +++ b/trunk/arch/blackfin/mach-bf533/boards/stamp.c @@ -0,0 +1,321 @@ +/* + * File: arch/blackfin/mach-bf533/stamp.c + * Based on: arch/blackfin/mach-bf533/ezkit.c + * Author: Aidan Williams + * + * Created: 2005 + * Description: Board Info File for the BF533-STAMP + * + * Modified: + * Copyright 2005 National ICT Australia (NICTA) + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) +#include +#endif +#include +#include + +/* + * Name the Board for the /proc/cpuinfo + */ +char *bfin_board_name = "ADDS-BF533-STAMP"; + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) +static struct platform_device rtc_device = { + .name = "rtc-bfin", + .id = -1, +}; +#endif + +/* + * Driver needs to know address, irq and flag pin. + */ +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) +static struct resource smc91x_resources[] = { + { + .name = "smc91x-regs", + .start = 0x20300300, + .end = 0x20300300 + 16, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF7, + .end = IRQ_PF7, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +#endif + +#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) +static struct resource net2272_bfin_resources[] = { + { + .start = 0x20300000, + .end = 0x20300000 + 0x100, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF10, + .end = IRQ_PF10, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct platform_device net2272_bfin_device = { + .name = "net2272", + .id = -1, + .num_resources = ARRAY_SIZE(net2272_bfin_resources), + .resource = net2272_bfin_resources, +}; +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) +/* all SPI peripherals info goes here */ + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition bfin_spi_flash_partitions[] = { + { + .name = "bootloader", + .size = 0x00020000, + .offset = 0, + .mask_flags = MTD_CAP_ROM + },{ + .name = "kernel", + .size = 0xe0000, + .offset = 0x20000 + },{ + .name = "file system", + .size = 0x700000, + .offset = 0x00100000, + } +}; + +static struct flash_platform_data bfin_spi_flash_data = { + .name = "m25p80", + .parts = bfin_spi_flash_partitions, + .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), + .type = "m25p64", +}; + +/* SPI flash chip (m25p64) */ +static struct bfin5xx_spi_chip spi_flash_chip_info = { + .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_PBX) +static struct bfin5xx_spi_chip spi_si3xxx_chip_info = { + .ctl_reg = 0x4, /* send zero */ + .enable_dma = 0, + .bits_per_word = 8, + .cs_change_per_word = 1, +}; +#endif + +#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE) +static struct bfin5xx_spi_chip ad5304_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +static struct spi_board_info bfin_spi_board_info[] __initdata = { +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) + { + /* the modalias must be the same as spi device driver name */ + .modalias = "m25p80", /* Name of spi_driver for this device */ + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL2*/ + .platform_data = &bfin_spi_flash_data, + .controller_data = &spi_flash_chip_info, + .mode = SPI_MODE_3, + }, +#endif + +#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) + { + .modalias = "ad1836-spi", + .max_speed_hz = 31250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, + .controller_data = &ad1836_spi_chip_info, + }, +#endif + +#if defined(CONFIG_PBX) + { + .modalias = "fxs-spi", + .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 3, + .controller_data= &spi_si3xxx_chip_info, + .mode = SPI_MODE_3, + }, + { + .modalias = "fxo-spi", + .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 2, + .controller_data= &spi_si3xxx_chip_info, + .mode = SPI_MODE_3, + }, +#endif + +#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE) + { + .modalias = "ad5304_spi", + .max_speed_hz = 1000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 2, + .platform_data = NULL, + .controller_data = &ad5304_chip_info, + .mode = SPI_MODE_2, + }, +#endif +}; + +/* SPI controller data */ +static struct bfin5xx_spi_master spi_bfin_master_info = { + .num_chipselect = 8, + .enable_dma = 1, /* master has the ability to do dma transfer */ +}; + +static struct platform_device spi_bfin_master_device = { + .name = "bfin-spi-master", + .id = 1, /* Bus number */ + .dev = { + .platform_data = &spi_bfin_master_info, /* Passed to driver */ + }, +}; +#endif /* spi master and devices */ + +#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE) +static struct platform_device bfin_fb_device = { + .name = "bf537-fb", +}; +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) +static struct resource bfin_uart_resources[] = { + { + .start = 0xFFC00400, + .end = 0xFFC004FF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device bfin_uart_device = { + .name = "bfin-uart", + .id = 1, + .num_resources = ARRAY_SIZE(bfin_uart_resources), + .resource = bfin_uart_resources, +}; +#endif + +#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE) +static struct platform_device bfin_sport0_uart_device = { + .name = "bfin-sport-uart", + .id = 0, +}; + +static struct platform_device bfin_sport1_uart_device = { + .name = "bfin-sport-uart", + .id = 1, +}; +#endif + +static struct platform_device *stamp_devices[] __initdata = { +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) + &rtc_device, +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + &smc91x_device, +#endif + +#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) + &net2272_bfin_device, +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + &spi_bfin_master_device, +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) + &bfin_uart_device, +#endif + +#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE) + &bfin_sport0_uart_device, + &bfin_sport1_uart_device, +#endif +}; + +static int __init stamp_init(void) +{ + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices)); +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); +#endif + return 0; +} + +arch_initcall(stamp_init); diff --git a/trunk/arch/blackfin/mach-bf533/cpu.c b/trunk/arch/blackfin/mach-bf533/cpu.c new file mode 100644 index 000000000000..99547c4c290e --- /dev/null +++ b/trunk/arch/blackfin/mach-bf533/cpu.c @@ -0,0 +1,161 @@ +/* + * File: arch/blackfin/mach-bf533/cpu.c + * Based on: + * Author: michael.kang@analog.com + * + * Created: + * Description: clock scaling for the bf533 + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +/* CONFIG_CLKIN_HZ=11059200 */ +#define VCO5 (CONFIG_CLKIN_HZ*45) /*497664000 */ +#define VCO4 (CONFIG_CLKIN_HZ*36) /*398131200 */ +#define VCO3 (CONFIG_CLKIN_HZ*27) /*298598400 */ +#define VCO2 (CONFIG_CLKIN_HZ*18) /*199065600 */ +#define VCO1 (CONFIG_CLKIN_HZ*9) /*99532800 */ +#define VCO(x) VCO##x + +#define FREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)} +/* frequency */ +static struct cpufreq_frequency_table bf533_freq_table[] = { + FREQ(1), + FREQ(3), + {VCO4, VCO4 / 2}, {VCO4, VCO4}, + FREQ(5), + {0, CPUFREQ_TABLE_END}, +}; + +/* + * dpmc_fops->ioctl() + * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) + */ +static int bf533_getfreq(unsigned int cpu) +{ + unsigned long cclk_mhz, vco_mhz; + + /* The driver only support single cpu */ + if (cpu == 0) + dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz); + else + cclk_mhz = -1; + return cclk_mhz; +} + +static int bf533_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + unsigned long cclk_mhz; + unsigned long vco_mhz; + unsigned long flags; + unsigned int index, vco_index; + int i; + + struct cpufreq_freqs freqs; + if (cpufreq_frequency_table_target + (policy, bf533_freq_table, target_freq, relation, &index)) + return -EINVAL; + cclk_mhz = bf533_freq_table[index].frequency; + vco_mhz = bf533_freq_table[index].index; + + dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz); + freqs.old = bf533_getfreq(0); + freqs.new = cclk_mhz; + freqs.cpu = 0; + + pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n", + cclk_mhz, vco_mhz, index, target_freq, freqs.old); + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + local_irq_save(flags); + dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz); + local_irq_restore(flags); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + vco_mhz = get_vco(); + cclk_mhz = get_cclk(); + return 0; +} + +/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on + * this platform, anyway. + */ +static int bf533_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &bf533_freq_table); +} + +static int __init __bf533_cpu_init(struct cpufreq_policy *policy) +{ + int result; + + if (policy->cpu != 0) + return -EINVAL; + + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + /*Now ,only support one cpu */ + policy->cur = bf533_getfreq(0); + cpufreq_frequency_table_get_attr(bf533_freq_table, policy->cpu); + return cpufreq_frequency_table_cpuinfo(policy, bf533_freq_table); +} + +static struct freq_attr *bf533_freq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver bf533_driver = { + .verify = bf533_verify_speed, + .target = bf533_target, + .get = bf533_getfreq, + .init = __bf533_cpu_init, + .name = "bf533", + .owner = THIS_MODULE, + .attr = bf533_freq_attr, +}; + +static int __init bf533_cpu_init(void) +{ + return cpufreq_register_driver(&bf533_driver); +} + +static void __exit bf533_cpu_exit(void) +{ + cpufreq_unregister_driver(&bf533_driver); +} + +MODULE_AUTHOR("Mickael Kang"); +MODULE_DESCRIPTION("cpufreq driver for BF533 CPU"); +MODULE_LICENSE("GPL"); + +module_init(bf533_cpu_init); +module_exit(bf533_cpu_exit); diff --git a/trunk/arch/blackfin/mach-bf533/head.S b/trunk/arch/blackfin/mach-bf533/head.S new file mode 100644 index 000000000000..4808edb0680f --- /dev/null +++ b/trunk/arch/blackfin/mach-bf533/head.S @@ -0,0 +1,774 @@ +/* + * File: arch/blackfin/mach-bf533/head.S + * Based on: + * Author: Jeff Dionne COPYRIGHT 1998 D. Jeff Dionne + * + * Created: 1998 + * Description: bf533 startup file + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#if CONFIG_BFIN_KERNEL_CLOCK +#include +#endif +#if CONFIG_DEBUG_KERNEL_START +#include +#endif + +.global __rambase +.global __ramstart +.global __ramend +.extern ___bss_stop +.extern ___bss_start +.extern _bf53x_relocate_l1_mem + +#define INITIAL_STACK 0xFFB01000 + +.text + +ENTRY(__start) +ENTRY(__stext) + /* R0: argument of command line string, passed from uboot, save it */ + R7 = R0; + /* Set the SYSCFG register */ + R0 = 0x36; + /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/ + SYSCFG = R0; + R0 = 0; + + /*Clear Out All the data and pointer Registers*/ + R1 = R0; + R2 = R0; + R3 = R0; + R4 = R0; + R5 = R0; + R6 = R0; + + P0 = R0; + P1 = R0; + P2 = R0; + P3 = R0; + P4 = R0; + P5 = R0; + + LC0 = r0; + LC1 = r0; + L0 = r0; + L1 = r0; + L2 = r0; + L3 = r0; + + /* Clear Out All the DAG Registers*/ + B0 = r0; + B1 = r0; + B2 = r0; + B3 = r0; + + I0 = r0; + I1 = r0; + I2 = r0; + I3 = r0; + + M0 = r0; + M1 = r0; + M2 = r0; + M3 = r0; + +#if CONFIG_DEBUG_KERNEL_START + +/* + * Set up a temporary Event Vector Table, so if something bad happens before + * the kernel is fully started, it doesn't vector off into the bootloaders + * table + */ + P0.l = lo(EVT2); + P0.h = hi(EVT2); + P1.l = lo(EVT15); + P1.h = hi(EVT15); + P2.l = debug_kernel_start_trap; + P2.h = debug_kernel_start_trap; + + RTS = P2; + RTI = P2; + RTX = P2; + RTN = P2; + RTE = P2; + +.Lfill_temp_vector_table: + [P0++] = P2; /* Core Event Vector Table */ + CC = P0 == P1; + if !CC JUMP .Lfill_temp_vector_table + P0 = r0; + P1 = r0; + P2 = r0; + +#endif + + p0.h = hi(FIO_MASKA_C); + p0.l = lo(FIO_MASKA_C); + r0 = 0xFFFF(Z); + w[p0] = r0.L; /* Disable all interrupts */ + ssync; + + p0.h = hi(FIO_MASKB_C); + p0.l = lo(FIO_MASKB_C); + r0 = 0xFFFF(Z); + w[p0] = r0.L; /* Disable all interrupts */ + ssync; + + /* Turn off the icache */ + p0.l = (IMEM_CONTROL & 0xFFFF); + p0.h = (IMEM_CONTROL >> 16); + R1 = [p0]; + R0 = ~ENICPLB; + R0 = R0 & R1; + + /* Anomaly 05000125 */ +#ifdef ANOMALY_05000125 + CLI R2; + SSYNC; +#endif + [p0] = R0; + SSYNC; +#ifdef ANOMALY_05000125 + STI R2; +#endif + + /* Turn off the dcache */ + p0.l = (DMEM_CONTROL & 0xFFFF); + p0.h = (DMEM_CONTROL >> 16); + R1 = [p0]; + R0 = ~ENDCPLB; + R0 = R0 & R1; + + /* Anomaly 05000125 */ +#ifdef ANOMALY_05000125 + CLI R2; + SSYNC; +#endif + [p0] = R0; + SSYNC; +#ifdef ANOMALY_05000125 + STI R2; +#endif + + /* Initialise UART */ + p0.h = hi(UART_LCR); + p0.l = lo(UART_LCR); + r0 = 0x0(Z); + w[p0] = r0.L; /* To enable DLL writes */ + ssync; + + p0.h = hi(UART_DLL); + p0.l = lo(UART_DLL); + r0 = 0x0(Z); + w[p0] = r0.L; + ssync; + + p0.h = hi(UART_DLH); + p0.l = lo(UART_DLH); + r0 = 0x00(Z); + w[p0] = r0.L; + ssync; + + p0.h = hi(UART_GCTL); + p0.l = lo(UART_GCTL); + r0 = 0x0(Z); + w[p0] = r0.L; /* To enable UART clock */ + ssync; + + /* Initialize stack pointer */ + sp.l = lo(INITIAL_STACK); + sp.h = hi(INITIAL_STACK); + fp = sp; + usp = sp; + + /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */ + call _bf53x_relocate_l1_mem; +#if CONFIG_BFIN_KERNEL_CLOCK + call _start_dma_code; +#endif + + /* Code for initializing Async memory banks */ + + p2.h = hi(EBIU_AMBCTL1); + p2.l = lo(EBIU_AMBCTL1); + r0.h = hi(AMBCTL1VAL); + r0.l = lo(AMBCTL1VAL); + [p2] = r0; + ssync; + + p2.h = hi(EBIU_AMBCTL0); + p2.l = lo(EBIU_AMBCTL0); + r0.h = hi(AMBCTL0VAL); + r0.l = lo(AMBCTL0VAL); + [p2] = r0; + ssync; + + p2.h = hi(EBIU_AMGCTL); + p2.l = lo(EBIU_AMGCTL); + r0 = AMGCTLVAL; + w[p2] = r0; + ssync; + + /* This section keeps the processor in supervisor mode + * during kernel boot. Switches to user mode at end of boot. + * See page 3-9 of Hardware Reference manual for documentation. + */ + + /* EVT15 = _real_start */ + + p0.l = lo(EVT15); + p0.h = hi(EVT15); + p1.l = _real_start; + p1.h = _real_start; + [p0] = p1; + csync; + + p0.l = lo(IMASK); + p0.h = hi(IMASK); + p1.l = IMASK_IVG15; + p1.h = 0x0; + [p0] = p1; + csync; + + raise 15; + p0.l = .LWAIT_HERE; + p0.h = .LWAIT_HERE; + reti = p0; +#if defined(ANOMALY_05000281) + nop; nop; nop; +#endif + rti; + +.LWAIT_HERE: + jump .LWAIT_HERE; + +ENTRY(_real_start) + [ -- sp ] = reti; + p0.l = lo(WDOG_CTL); + p0.h = hi(WDOG_CTL); + r0 = 0xAD6(z); + w[p0] = r0; /* watchdog off for now */ + ssync; + + /* Code update for BSS size == 0 + * Zero out the bss region. + */ + + p1.l = ___bss_start; + p1.h = ___bss_start; + p2.l = ___bss_stop; + p2.h = ___bss_stop; + r0 = 0; + p2 -= p1; + lsetup (.L_clear_bss, .L_clear_bss) lc0 = p2; +.L_clear_bss: + B[p1++] = r0; + + /* In case there is a NULL pointer reference + * Zero out region before stext + */ + + p1.l = 0x0; + p1.h = 0x0; + r0.l = __stext; + r0.h = __stext; + r0 = r0 >> 1; + p2 = r0; + r0 = 0; + lsetup (.L_clear_zero, .L_clear_zero) lc0 = p2; +.L_clear_zero: + W[p1++] = r0; + +/* pass the uboot arguments to the global value command line */ + R0 = R7; + call _cmdline_init; + + p1.l = __rambase; + p1.h = __rambase; + r0.l = __sdata; + r0.h = __sdata; + [p1] = r0; + + p1.l = __ramstart; + p1.h = __ramstart; + p3.l = ___bss_stop; + p3.h = ___bss_stop; + + r1 = p3; + [p1] = r1; + + /* + * load the current thread pointer and stack + */ + r1.l = _init_thread_union; + r1.h = _init_thread_union; + + r2.l = 0x2000; + r2.h = 0x0000; + r1 = r1 + r2; + sp = r1; + usp = sp; + fp = sp; + call _start_kernel; +.L_exit: + jump.s .L_exit; + +.section .l1.text +#if CONFIG_BFIN_KERNEL_CLOCK +ENTRY(_start_dma_code) + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; + r0.h = 0x0; + [p0] = r0; + SSYNC; + + /* + * Set PLL_CTL + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over, */ + r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +.Lcheck_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump .Lcheck_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; + + p0.l = lo(EBIU_SDRRC); + p0.h = hi(EBIU_SDRRC); + r0 = mem_SDRRC; + w[p0] = r0.l; + ssync; + + p0.l = (EBIU_SDBCTL & 0xFFFF); + p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */ + r0 = mem_SDBCTL; + w[p0] = r0.l; + ssync; + + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITCLR (R0, 24); + p0.h = hi(EBIU_SDSTAT); + p0.l = lo(EBIU_SDSTAT); + r2.l = w[p0]; + cc = bittst(r2,3); + if !cc jump .Lskip; + NOP; + BITSET (R0, 23); +.Lskip: + [P2] = R0; + SSYNC; + + R0.L = lo(mem_SDGCTL); + R0.H = hi(mem_SDGCTL); + R1 = [p2]; + R1 = R1 | R0; + [P2] = R1; + SSYNC; + + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = lo(IWR_ENABLE_ALL) + r0.h = hi(IWR_ENABLE_ALL) + [p0] = r0; + SSYNC; + + RTS; +#endif /* CONFIG_BFIN_KERNEL_CLOCK */ + +ENTRY(_bfin_reset) + /* No more interrupts to be handled*/ + CLI R6; + SSYNC; + +#if defined(CONFIG_BFIN_SHARED_FLASH_ENET) + p0.h = hi(FIO_INEN); + p0.l = lo(FIO_INEN); + r0.l = ~(1 << CONFIG_ENET_FLASH_PIN); + w[p0] = r0.l; + + p0.h = hi(FIO_DIR); + p0.l = lo(FIO_DIR); + r0.l = (1 << CONFIG_ENET_FLASH_PIN); + w[p0] = r0.l; + + p0.h = hi(FIO_FLAG_C); + p0.l = lo(FIO_FLAG_C); + r0.l = (1 << CONFIG_ENET_FLASH_PIN); + w[p0] = r0.l; +#endif + + /* Clear the bits 13-15 in SWRST if they werent cleared */ + p0.h = hi(SWRST); + p0.l = lo(SWRST); + csync; + r0.l = w[p0]; + + /* Clear the IMASK register */ + p0.h = hi(IMASK); + p0.l = lo(IMASK); + r0 = 0x0; + [p0] = r0; + + /* Clear the ILAT register */ + p0.h = hi(ILAT); + p0.l = lo(ILAT); + r0 = [p0]; + [p0] = r0; + SSYNC; + + /* Disable the WDOG TIMER */ + p0.h = hi(WDOG_CTL); + p0.l = lo(WDOG_CTL); + r0.l = 0xAD6; + w[p0] = r0.l; + SSYNC; + + /* Clear the sticky bit incase it is already set */ + p0.h = hi(WDOG_CTL); + p0.l = lo(WDOG_CTL); + r0.l = 0x8AD6; + w[p0] = r0.l; + SSYNC; + + /* Program the count value */ + R0.l = 0x100; + R0.h = 0x0; + P0.h = hi(WDOG_CNT); + P0.l = lo(WDOG_CNT); + [P0] = R0; + SSYNC; + + /* Program WDOG_STAT if necessary */ + P0.h = hi(WDOG_CTL); + P0.l = lo(WDOG_CTL); + R0 = W[P0](Z); + CC = BITTST(R0,1); + if !CC JUMP .LWRITESTAT; + CC = BITTST(R0,2); + if !CC JUMP .LWRITESTAT; + JUMP .LSKIP_WRITE; + +.LWRITESTAT: + /* When watch dog timer is enabled, a write to STAT will load the contents of CNT to STAT */ + R0 = 0x0000(z); + P0.h = hi(WDOG_STAT); + P0.l = lo(WDOG_STAT) + [P0] = R0; + SSYNC; + +.LSKIP_WRITE: + /* Enable the reset event */ + P0.h = hi(WDOG_CTL); + P0.l = lo(WDOG_CTL); + R0 = W[P0](Z); + BITCLR(R0,1); + BITCLR(R0,2); + W[P0] = R0.L; + SSYNC; + NOP; + + /* Enable the wdog counter */ + R0 = W[P0](Z); + BITCLR(R0,4); + W[P0] = R0.L; + SSYNC; + + IDLE; + + RTS; + +#if CONFIG_DEBUG_KERNEL_START +debug_kernel_start_trap: + /* Set up a temp stack in L1 - SDRAM might not be working */ + P0.L = lo(L1_DATA_A_START + 0x100); + P0.H = hi(L1_DATA_A_START + 0x100); + SP = P0; + + /* Make sure the Clocks are the way I think they should be */ + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over, */ + r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +.Lcheck_again1: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump .Lcheck_again1; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; + + /* Make sure UART is enabled - you can never be sure */ + +/* + * Setup for console. Argument comes from the menuconfig + */ + +#ifdef CONFIG_BAUD_9600 +#define CONSOLE_BAUD_RATE 9600 +#elif CONFIG_BAUD_19200 +#define CONSOLE_BAUD_RATE 19200 +#elif CONFIG_BAUD_38400 +#define CONSOLE_BAUD_RATE 38400 +#elif CONFIG_BAUD_57600 +#define CONSOLE_BAUD_RATE 57600 +#elif CONFIG_BAUD_115200 +#define CONSOLE_BAUD_RATE 115200 +#endif + + p0.h = hi(UART_GCTL); + p0.l = lo(UART_GCTL); + r0 = 0x00(Z); + w[p0] = r0.L; /* To Turn off UART clocks */ + ssync; + + p0.h = hi(UART_LCR); + p0.l = lo(UART_LCR); + r0 = 0x83(Z); + w[p0] = r0.L; /* To enable DLL writes */ + ssync; + + R1 = (((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) / CONFIG_SCLK_DIV) / (CONSOLE_BAUD_RATE * 16)); + + p0.h = hi(UART_DLL); + p0.l = lo(UART_DLL); + r0 = 0xFF(Z); + r0 = R1 & R0; + w[p0] = r0.L; + ssync; + + p0.h = hi(UART_DLH); + p0.l = lo(UART_DLH); + r1 >>= 8 ; + w[p0] = r1.L; + ssync; + + p0.h = hi(UART_GCTL); + p0.l = lo(UART_GCTL); + r0 = 0x0(Z); + w[p0] = r0.L; /* To enable UART clock */ + ssync; + + p0.h = hi(UART_LCR); + p0.l = lo(UART_LCR); + r0 = 0x03(Z); + w[p0] = r0.L; /* To Turn on UART */ + ssync; + + p0.h = hi(UART_GCTL); + p0.l = lo(UART_GCTL); + r0 = 0x01(Z); + w[p0] = r0.L; /* To Turn on UART Clocks */ + ssync; + + P0.h = hi(UART_THR); + P0.l = lo(UART_THR); + P1.h = hi(UART_LSR); + P1.l = lo(UART_LSR); + + R0.L = 'K'; + call .Lwait_char; + R0.L='e'; + call .Lwait_char; + R0.L='r'; + call .Lwait_char; + R0.L='n' + call .Lwait_char; + R0.L='e' + call .Lwait_char; + R0.L='l'; + call .Lwait_char; + R0.L=' '; + call .Lwait_char; + R0.L='c'; + call .Lwait_char; + R0.L='r'; + call .Lwait_char; + R0.L='a'; + call .Lwait_char; + R0.L='s'; + call .Lwait_char; + R0.L='h'; + call .Lwait_char; + R0.L='\r'; + call .Lwait_char; + R0.L='\n'; + call .Lwait_char; + + R0.L='S'; + call .Lwait_char; + R0.L='E'; + call .Lwait_char; + R0.L='Q' + call .Lwait_char; + R0.L='S' + call .Lwait_char; + R0.L='T'; + call .Lwait_char; + R0.L='A'; + call .Lwait_char; + R0.L='T'; + call .Lwait_char; + R0.L='='; + call .Lwait_char; + R2 = SEQSTAT; + call .Ldump_reg; + + R0.L=' '; + call .Lwait_char; + R0.L='R'; + call .Lwait_char; + R0.L='E' + call .Lwait_char; + R0.L='T' + call .Lwait_char; + R0.L='X'; + call .Lwait_char; + R0.L='='; + call .Lwait_char; + R2 = RETX; + call .Ldump_reg; + + R0.L='\r'; + call .Lwait_char; + R0.L='\n'; + call .Lwait_char; + +.Ldebug_kernel_start_trap_done: + JUMP .Ldebug_kernel_start_trap_done; +.Ldump_reg: + R3 = 32; + R4 = 0x0F; + R5 = ':'; /* one past 9 */ + +.Ldump_reg2: + R0 = R2; + R3 += -4; + R0 >>>= R3; + R0 = R0 & R4; + R0 += 0x30; + CC = R0 <= R5; + if CC JUMP .Ldump_reg1; + R0 += 7; + +.Ldump_reg1: + R1.l = W[P1]; + CC = BITTST(R1, 5); + if !CC JUMP .Ldump_reg1; + W[P0] = r0; + + CC = R3 == 0; + if !CC JUMP .Ldump_reg2 + RTS; + +.Lwait_char: + R1.l = W[P1]; + CC = BITTST(R1, 5); + if !CC JUMP .Lwait_char; + W[P0] = r0; + RTS; + +#endif /* CONFIG_DEBUG_KERNEL_START */ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ + +.align 4 +__rambase: +.long 0 +__ramstart: +.long 0 +__ramend: +.long 0 diff --git a/trunk/arch/blackfin/mach-bf533/ints-priority.c b/trunk/arch/blackfin/mach-bf533/ints-priority.c new file mode 100644 index 000000000000..36a693345204 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf533/ints-priority.c @@ -0,0 +1,65 @@ +/* + * File: arch/blackfin/mach-bf533/ints-priority.c + * Based on: + * Author: Michael Hennerich + * + * Created: ? + * Description: Set up the interupt priorities + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +void program_IAR(void) +{ + /* Program the IAR0 Register with the configured priority */ + bfin_write_SIC_IAR0(((CONFIG_PLLWAKE_ERROR - 7) << PLLWAKE_ERROR_POS) | + ((CONFIG_DMA_ERROR - 7) << DMA_ERROR_POS) | + ((CONFIG_PPI_ERROR - 7) << PPI_ERROR_POS) | + ((CONFIG_SPORT0_ERROR - 7) << SPORT0_ERROR_POS) | + ((CONFIG_SPI_ERROR - 7) << SPI_ERROR_POS) | + ((CONFIG_SPORT1_ERROR - 7) << SPORT1_ERROR_POS) | + ((CONFIG_UART_ERROR - 7) << UART_ERROR_POS) | + ((CONFIG_RTC_ERROR - 7) << RTC_ERROR_POS)); + + bfin_write_SIC_IAR1(((CONFIG_DMA0_PPI - 7) << DMA0_PPI_POS) | + ((CONFIG_DMA1_SPORT0RX - 7) << DMA1_SPORT0RX_POS) | + ((CONFIG_DMA2_SPORT0TX - 7) << DMA2_SPORT0TX_POS) | + ((CONFIG_DMA3_SPORT1RX - 7) << DMA3_SPORT1RX_POS) | + ((CONFIG_DMA4_SPORT1TX - 7) << DMA4_SPORT1TX_POS) | + ((CONFIG_DMA5_SPI - 7) << DMA5_SPI_POS) | + ((CONFIG_DMA6_UARTRX - 7) << DMA6_UARTRX_POS) | + ((CONFIG_DMA7_UARTTX - 7) << DMA7_UARTTX_POS)); + + bfin_write_SIC_IAR2(((CONFIG_TIMER0 - 7) << TIMER0_POS) | + ((CONFIG_TIMER1 - 7) << TIMER1_POS) | + ((CONFIG_TIMER2 - 7) << TIMER2_POS) | + ((CONFIG_PFA - 7) << PFA_POS) | + ((CONFIG_PFB - 7) << PFB_POS) | + ((CONFIG_MEMDMA0 - 7) << MEMDMA0_POS) | + ((CONFIG_MEMDMA1 - 7) << MEMDMA1_POS) | + ((CONFIG_WDTIMER - 7) << WDTIMER_POS)); + + SSYNC(); +} diff --git a/trunk/arch/blackfin/mach-bf537/Kconfig b/trunk/arch/blackfin/mach-bf537/Kconfig new file mode 100644 index 000000000000..cc9ae38a4dda --- /dev/null +++ b/trunk/arch/blackfin/mach-bf537/Kconfig @@ -0,0 +1,141 @@ +if (BF537 || BF534 || BF536) + +menu "BF537 Specific Configuration" + +comment "PORT F/G Selection" +choice + prompt "Select BF537/6/4 default GPIO PFx PORTx" + help + Quick Hack for BF537/6/4 default GPIO PFx PORTF. + +config BF537_PORT_F + bool "Select BF537/6/4 default GPIO PFx PORTF" + depends on (BF537 || BF536 || BF534) + help + Quick Hack for BF537/6/4 default GPIO PFx PORTF. + +config BF537_PORT_G + bool "Select BF537/6/4 default GPIO PFx PORTG" + depends on (BF537 || BF536 || BF534) + help + Quick Hack for BF537/6/4 default GPIO PFx PORTG. + +config BF537_PORT_H + bool "Select BF537/6/4 default GPIO PFx PORTH" + depends on (BF537 || BF536 || BF534) + help + Quick Hack for BF537/6/4 default GPIO PFx PORTH + Use only when Blackfin EMAC support is not required. + +endchoice + +comment "Interrupt Priority Assignment" +menu "Priority" + +config IRQ_PLL_WAKEUP + int "IRQ_PLL_WAKEUP" + default 7 +config IRQ_DMA_ERROR + int "IRQ_DMA_ERROR Generic" + default 7 +config IRQ_ERROR + int "IRQ_ERROR: CAN MAC SPORT0 SPORT1 SPI UART0 UART1" + default 7 +config IRQ_RTC + int "IRQ_RTC" + default 8 +config IRQ_PPI + int "IRQ_PPI" + default 8 +config IRQ_SPORT0_RX + int "IRQ_SPORT0_RX" + default 9 +config IRQ_SPORT0_TX + int "IRQ_SPORT0_TX" + default 9 +config IRQ_SPORT1_RX + int "IRQ_SPORT1_RX" + default 9 +config IRQ_SPORT1_TX + int "IRQ_SPORT1_TX" + default 9 +config IRQ_TWI + int "IRQ_TWI" + default 10 +config IRQ_SPI + int "IRQ_SPI" + default 10 +config IRQ_UART0_RX + int "IRQ_UART0_RX" + default 10 +config IRQ_UART0_TX + int "IRQ_UART0_TX" + default 10 +config IRQ_UART1_RX + int "IRQ_UART1_RX" + default 10 +config IRQ_UART1_TX + int "IRQ_UART1_TX" + default 10 +config IRQ_CAN_RX + int "IRQ_CAN_RX" + default 11 +config IRQ_CAN_TX + int "IRQ_CAN_TX" + default 11 +config IRQ_MAC_RX + int "IRQ_MAC_RX" + default 11 +config IRQ_MAC_TX + int "IRQ_MAC_TX" + default 11 +config IRQ_TMR0 + int "IRQ_TMR0" + default 12 +config IRQ_TMR1 + int "IRQ_TMR1" + default 12 +config IRQ_TMR2 + int "IRQ_TMR2" + default 12 +config IRQ_TMR3 + int "IRQ_TMR3" + default 12 +config IRQ_TMR4 + int "IRQ_TMR4" + default 12 +config IRQ_TMR5 + int "IRQ_TMR5" + default 12 +config IRQ_TMR6 + int "IRQ_TMR6" + default 12 +config IRQ_TMR7 + int "IRQ_TMR7" + default 12 +config IRQ_PROG_INTA + int "IRQ_PROG_INTA" + default 12 +config IRQ_PORTG_INTB + int "IRQ_PORTG_INTB" + default 12 +config IRQ_MEM_DMA0 + int "IRQ_MEM_DMA0" + default 13 +config IRQ_MEM_DMA1 + int "IRQ_MEM_DMA1" + default 13 +config IRQ_WATCH + int "IRQ_WATCH" + default 13 + + help + Enter the priority numbers between 7-13 ONLY. Others are Reserved. + This applies to all the above. It is not recommended to assign the + highest priority number 7 to UART or any other device. + +endmenu + +endmenu + +endif diff --git a/trunk/arch/blackfin/mach-bf537/Makefile b/trunk/arch/blackfin/mach-bf537/Makefile new file mode 100644 index 000000000000..f32d44215bb7 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf537/Makefile @@ -0,0 +1,9 @@ +# +# arch/blackfin/mach-bf537/Makefile +# + +extra-y := head.o + +obj-y := ints-priority.o + +obj-$(CONFIG_CPU_FREQ) += cpu.o diff --git a/trunk/arch/blackfin/mach-bf537/boards/Makefile b/trunk/arch/blackfin/mach-bf537/boards/Makefile new file mode 100644 index 000000000000..23323cacc3aa --- /dev/null +++ b/trunk/arch/blackfin/mach-bf537/boards/Makefile @@ -0,0 +1,9 @@ +# +# arch/blackfin/mach-bf537/boards/Makefile +# + +obj-y += eth_mac.o +obj-$(CONFIG_GENERIC_BOARD) += generic_board.o +obj-$(CONFIG_BFIN537_STAMP) += stamp.o led.o +obj-$(CONFIG_BFIN537_BLUETECHNIX_CM) += cm_bf537.o +obj-$(CONFIG_PNAV10) += pnav10.o diff --git a/trunk/arch/blackfin/mach-bf537/boards/cm_bf537.c b/trunk/arch/blackfin/mach-bf537/boards/cm_bf537.c new file mode 100644 index 000000000000..6a60618a78ec --- /dev/null +++ b/trunk/arch/blackfin/mach-bf537/boards/cm_bf537.c @@ -0,0 +1,364 @@ +/* + * File: arch/blackfin/mach-bf537/boards/cm_bf537.c + * Based on: arch/blackfin/mach-bf533/boards/ezkit.c + * Author: Aidan Williams + * + * Created: 2005 + * Description: Board description file + * + * Modified: + * Copyright 2005 National ICT Australia (NICTA) + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Name the Board for the /proc/cpuinfo + */ +char *bfin_board_name = "Bluetechnix CM BF537"; + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) +/* all SPI peripherals info goes here */ + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition bfin_spi_flash_partitions[] = { + { + .name = "bootloader", + .size = 0x00020000, + .offset = 0, + .mask_flags = MTD_CAP_ROM + },{ + .name = "kernel", + .size = 0xe0000, + .offset = 0x20000 + },{ + .name = "file system", + .size = 0x700000, + .offset = 0x00100000, + } +}; + +static struct flash_platform_data bfin_spi_flash_data = { + .name = "m25p80", + .parts = bfin_spi_flash_partitions, + .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), + .type = "m25p64", +}; + +/* SPI flash chip (m25p64) */ +static struct bfin5xx_spi_chip spi_flash_chip_info = { + .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE) +static struct bfin5xx_spi_chip ad9960_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE) +static struct bfin5xx_spi_chip spi_mmc_chip_info = { + .enable_dma = 1, + .bits_per_word = 8, +}; +#endif + +static struct spi_board_info bfin_spi_board_info[] __initdata = { +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) + { + /* the modalias must be the same as spi device driver name */ + .modalias = "m25p80", /* Name of spi_driver for this device */ + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/ + .platform_data = &bfin_spi_flash_data, + .controller_data = &spi_flash_chip_info, + .mode = SPI_MODE_3, + }, +#endif + +#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) + { + .modalias = "ad1836-spi", + .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, + .controller_data = &ad1836_spi_chip_info, + }, +#endif + +#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE) + { + .modalias = "ad9960-spi", + .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 1, + .controller_data = &ad9960_spi_chip_info, + }, +#endif + +#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE) + { + .modalias = "spi_mmc_dummy", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 7, + .platform_data = NULL, + .controller_data = &spi_mmc_chip_info, + .mode = SPI_MODE_3, + }, + { + .modalias = "spi_mmc", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SPI_MMC_CS_CHAN, + .platform_data = NULL, + .controller_data = &spi_mmc_chip_info, + .mode = SPI_MODE_3, + }, +#endif +}; + +/* SPI controller data */ +static struct bfin5xx_spi_master spi_bfin_master_info = { + .num_chipselect = 8, + .enable_dma = 1, /* master has the ability to do dma transfer */ +}; + +static struct platform_device spi_bfin_master_device = { + .name = "bfin-spi-master", + .id = 1, /* Bus number */ + .dev = { + .platform_data = &spi_bfin_master_info, /* Passed to driver */ + }, +}; +#endif /* spi master and devices */ + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) +static struct platform_device rtc_device = { + .name = "rtc-bfin", + .id = -1, +}; +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) +static struct resource smc91x_resources[] = { + { + .start = 0x20200300, + .end = 0x20200300 + 16, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF14, + .end = IRQ_PF14, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +#endif + +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) +static struct resource isp1362_hcd_resources[] = { + { + .start = 0x20308000, + .end = 0x20308000, + .flags = IORESOURCE_MEM, + },{ + .start = 0x20308004, + .end = 0x20308004, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PG15, + .end = IRQ_PG15, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct isp1362_platform_data isp1362_priv = { + .sel15Kres = 1, + .clknotstop = 0, + .oc_enable = 0, + .int_act_high = 0, + .int_edge_triggered = 0, + .remote_wakeup_connected = 0, + .no_power_switching = 1, + .power_switching_mode = 0, +}; + +static struct platform_device isp1362_hcd_device = { + .name = "isp1362-hcd", + .id = 0, + .dev = { + .platform_data = &isp1362_priv, + }, + .num_resources = ARRAY_SIZE(isp1362_hcd_resources), + .resource = isp1362_hcd_resources, +}; +#endif + +#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) +static struct resource net2272_bfin_resources[] = { + { + .start = 0x20200000, + .end = 0x20200000 + 0x100, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF7, + .end = IRQ_PF7, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct platform_device net2272_bfin_device = { + .name = "net2272", + .id = -1, + .num_resources = ARRAY_SIZE(net2272_bfin_resources), + .resource = net2272_bfin_resources, +}; +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) +static struct resource bfin_uart_resources[] = { + { + .start = 0xFFC00400, + .end = 0xFFC004FF, + .flags = IORESOURCE_MEM, + },{ + .start = 0xFFC02000, + .end = 0xFFC020FF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device bfin_uart_device = { + .name = "bfin-uart", + .id = 1, + .num_resources = ARRAY_SIZE(bfin_uart_resources), + .resource = bfin_uart_resources, +}; +#endif + +#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE) +static struct platform_device bfin_sport0_uart_device = { + .name = "bfin-sport-uart", + .id = 0, +}; + +static struct platform_device bfin_sport1_uart_device = { + .name = "bfin-sport-uart", + .id = 1, +}; +#endif + +#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) +static struct platform_device bfin_mac_device = { + .name = "bfin_mac", +}; +#endif + +static struct platform_device *cm_bf537_devices[] __initdata = { +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) + &rtc_device, +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) + &bfin_uart_device, +#endif + +#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE) + &bfin_sport0_uart_device, + &bfin_sport1_uart_device, +#endif + +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) + &isp1362_hcd_device, +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + &smc91x_device, +#endif + +#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) + &bfin_mac_device, +#endif + +#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) + &net2272_bfin_device, +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + &spi_bfin_master_device, +#endif +}; + +static int __init cm_bf537_init(void) +{ + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + platform_add_devices(cm_bf537_devices, ARRAY_SIZE(cm_bf537_devices)); +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); +#endif + return 0; +} + +arch_initcall(cm_bf537_init); diff --git a/trunk/arch/blackfin/mach-bf537/boards/eth_mac.c b/trunk/arch/blackfin/mach-bf537/boards/eth_mac.c new file mode 100644 index 000000000000..e129a08d63de --- /dev/null +++ b/trunk/arch/blackfin/mach-bf537/boards/eth_mac.c @@ -0,0 +1,51 @@ +/* + * arch/blackfin/mach-bf537/board/eth_mac.c + * + * Copyright (C) 2007 Analog Devices, 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 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 +#include + +#if defined(CONFIG_GENERIC_BOARD) \ + || defined(CONFIG_BFIN537_STAMP) + +/* + * Currently the MAC address is saved in Flash by U-Boot + */ +#define FLASH_MAC 0x203f0000 + +void get_bf537_ether_addr(char *addr) +{ + unsigned int flash_mac = (unsigned int) FLASH_MAC; + *(u32 *)(&(addr[0])) = bfin_read32(flash_mac); + flash_mac += 4; + *(u16 *)(&(addr[4])) = bfin_read16(flash_mac); +} + +#else + +/* + * Provide MAC address function for other specific board setting + */ +void get_bf537_ether_addr(char *addr) +{ + printk(KERN_WARNING "%s: No valid Ethernet MAC address found\n",__FILE__); +} + +#endif + +EXPORT_SYMBOL(get_bf537_ether_addr); diff --git a/trunk/arch/blackfin/mach-bf537/boards/generic_board.c b/trunk/arch/blackfin/mach-bf537/boards/generic_board.c new file mode 100644 index 000000000000..9019c0edbe7c --- /dev/null +++ b/trunk/arch/blackfin/mach-bf537/boards/generic_board.c @@ -0,0 +1,445 @@ +/* + * File: arch/blackfin/mach-bf537/boards/generic_board.c + * Based on: arch/blackfin/mach-bf533/boards/ezkit.c + * Author: Aidan Williams + * + * Created: + * Description: + * + * Modified: + * Copyright 2005 National ICT Australia (NICTA) + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Name the Board for the /proc/cpuinfo + */ +char *bfin_board_name = "UNKNOWN BOARD"; + +/* + * Driver needs to know address, irq and flag pin. + */ + +#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE) +static struct resource bfin_pcmcia_cf_resources[] = { + { + .start = 0x20310000, /* IO PORT */ + .end = 0x20312000, + .flags = IORESOURCE_MEM, + },{ + .start = 0x20311000, /* Attribute Memeory */ + .end = 0x20311FFF, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PROG_INTA, + .end = IRQ_PROG_INTA, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + },{ + .start = IRQ_PF4, + .end = IRQ_PF4, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + },{ + .start = 6, /* Card Detect PF6 */ + .end = 6, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_pcmcia_cf_device = { + .name = "bfin_cf_pcmcia", + .id = -1, + .num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources), + .resource = bfin_pcmcia_cf_resources, +}; +#endif + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) +static struct platform_device rtc_device = { + .name = "rtc-bfin", + .id = -1, +}; +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) +static struct resource smc91x_resources[] = { + { + .name = "smc91x-regs", + .start = 0x20300300, + .end = 0x20300300 + 16, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PROG_INTB, + .end = IRQ_PROG_INTB, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + },{ + /* + * denotes the flag pin and is used directly if + * CONFIG_IRQCHIP_DEMUX_GPIO is defined. + */ + .start = IRQ_PF7, + .end = IRQ_PF7, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +#endif + +#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE) +static struct resource sl811_hcd_resources[] = { + { + .start = 0x20340000, + .end = 0x20340000, + .flags = IORESOURCE_MEM, + },{ + .start = 0x20340004, + .end = 0x20340004, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PROG_INTA, + .end = IRQ_PROG_INTA, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + },{ + .start = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO, + .end = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS) +void sl811_port_power(struct device *dev, int is_on) +{ + unsigned short mask = (1< +#include + +/* All functions in this file save the registers they uses. + So there is no need to save any registers before calling them. */ + + .text; + +/* Initialize LEDs. */ + +ENTRY(_led_init) + LINK 12; + [--SP] = P0; + [--SP] = R0; + [--SP] = R1; + [--SP] = R2; + R1 = PF6|PF7|PF8|PF9|PF10|PF11 (Z); + R2 = ~R1; + + P0.H = hi(PORTF_FER); + P0.L = lo(PORTF_FER); + R0 = W[P0](Z); + SSYNC; + R0 = R0 & R2; + W[P0] = R0.L; + SSYNC; + + P0.H = hi(PORTFIO_DIR); + P0.L = lo(PORTFIO_DIR); + R0 = W[P0](Z); + SSYNC; + R0 = R0 | R1; + W[P0] = R0.L; + SSYNC; + + P0.H = hi(PORTFIO_INEN); + P0.L = lo(PORTFIO_INEN); + R0 = W[P0](Z); + SSYNC; + R0 = R0 & R2; + W[P0] = R0.L; + SSYNC; + + R2 = [SP++]; + R1 = [SP++]; + R0 = [SP++]; + P0 = [SP++]; + UNLINK; + RTS; + .size _led_init, .-_led_init + +/* Set one LED on. Leave other LEDs unchanged. + It expects the LED number passed through R0. */ + +ENTRY(_led_on) + LINK 12; + [--SP] = P0; + [--SP] = R1; + CALL _led_init; + R1 = 1; + R0 += 5; + R1 <<= R0; + P0.H = hi(PORTFIO); + P0.L = lo(PORTFIO); + R0 = W[P0](Z); + SSYNC; + R0 = R0 | R1; + W[P0] = R0.L; + SSYNC; + R1 = [SP++]; + P0 = [SP++]; + UNLINK; + RTS; + .size _led_on, .-_led_on + +/* Set one LED off. Leave other LEDs unchanged. */ + +ENTRY(_led_off) + LINK 12; + [--SP] = P0; + [--SP] = R1; + CALL _led_init; + R1 = 1; + R0 += 5; + R1 <<= R0; + R1 = ~R1; + P0.H = hi(PORTFIO); + P0.L = lo(PORTFIO); + R0 = W[P0](Z); + SSYNC; + R0 = R0 & R1; + W[P0] = R0.L; + SSYNC; + R1 = [SP++]; + P0 = [SP++]; + UNLINK; + RTS; + .size _led_off, .-_led_off + +/* Toggle one LED. Leave other LEDs unchanged. */ + +ENTRY(_led_toggle) + LINK 12; + [--SP] = P0; + [--SP] = R1; + CALL _led_init; + R1 = 1; + R0 += 5; + R1 <<= R0; + P0.H = hi(PORTFIO); + P0.L = lo(PORTFIO); + R0 = W[P0](Z); + SSYNC; + R0 = R0 ^ R1; + W[P0] = R0.L; + SSYNC; + R1 = [SP++]; + P0 = [SP++]; + UNLINK; + RTS; + .size _led_toggle, .-_led_toggle + +/* Display the number using LEDs in binary format. */ + +ENTRY(_led_disp_num) + LINK 12; + [--SP] = P0; + [--SP] = R1; + [--SP] = R2; + CALL _led_init; + R1 = 0x3f(X); + R0 = R0 & R1; + R2 = 6(X); + R0 <<= R2; + R1 <<= R2; + P0.H = hi(PORTFIO); + P0.L = lo(PORTFIO); + R2 = W[P0](Z); + SSYNC; + R1 = ~R1; + R2 = R2 & R1; + R2 = R2 | R0; + W[P0] = R2.L; + SSYNC; + R2 = [SP++]; + R1 = [SP++]; + P0 = [SP++]; + UNLINK; + RTS; + .size _led_disp_num, .-_led_disp_num + +/* Toggle the number using LEDs in binary format. */ + +ENTRY(_led_toggle_num) + LINK 12; + [--SP] = P0; + [--SP] = R1; + [--SP] = R2; + CALL _led_init; + R1 = 0x3f(X); + R0 = R0 & R1; + R1 = 6(X); + R0 <<= R1; + P0.H = hi(PORTFIO); + P0.L = lo(PORTFIO); + R1 = W[P0](Z); + SSYNC; + R1 = R1 ^ R0; + W[P0] = R1.L; + SSYNC; + R2 = [SP++]; + R1 = [SP++]; + P0 = [SP++]; + UNLINK; + RTS; + .size _led_toggle_num, .-_led_toggle_num + diff --git a/trunk/arch/blackfin/mach-bf537/boards/pnav10.c b/trunk/arch/blackfin/mach-bf537/boards/pnav10.c new file mode 100644 index 000000000000..40d3a1b70ee7 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf537/boards/pnav10.c @@ -0,0 +1,523 @@ +/* + * File: arch/blackfin/mach-bf537/boards/stamp.c + * Based on: arch/blackfin/mach-bf533/boards/ezkit.c + * Author: Aidan Williams + * + * Created: + * Description: + * + * Modified: + * Copyright 2005 National ICT Australia (NICTA) + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) +#include +#endif +#include +#include +#include + +#include + +/* + * Name the Board for the /proc/cpuinfo + */ +char *bfin_board_name = "PNAV-1.0"; + +/* + * Driver needs to know address, irq and flag pin. + */ + +#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE) +static struct resource bfin_pcmcia_cf_resources[] = { + { + .start = 0x20310000, /* IO PORT */ + .end = 0x20312000, + .flags = IORESOURCE_MEM, + },{ + .start = 0x20311000, /* Attribute Memeory */ + .end = 0x20311FFF, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF4, + .end = IRQ_PF4, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + },{ + .start = 6, /* Card Detect PF6 */ + .end = 6, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_pcmcia_cf_device = { + .name = "bfin_cf_pcmcia", + .id = -1, + .num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources), + .resource = bfin_pcmcia_cf_resources, +}; +#endif + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) +static struct platform_device rtc_device = { + .name = "rtc-bfin", + .id = -1, +}; +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) +static struct resource smc91x_resources[] = { + { + .name = "smc91x-regs", + .start = 0x20300300, + .end = 0x20300300 + 16, + .flags = IORESOURCE_MEM, + },{ + + .start = IRQ_PF7, + .end = IRQ_PF7, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +#endif + +#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE) +static struct resource sl811_hcd_resources[] = { + { + .start = 0x20340000, + .end = 0x20340000, + .flags = IORESOURCE_MEM, + },{ + .start = 0x20340004, + .end = 0x20340004, + .flags = IORESOURCE_MEM, + },{ + .start = CONFIG_USB_SL811_BFIN_IRQ, + .end = CONFIG_USB_SL811_BFIN_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS) +void sl811_port_power(struct device *dev, int is_on) +{ + unsigned short mask = (1 << CONFIG_USB_SL811_BFIN_GPIO_VBUS); + + bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask); + bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask); + + if (is_on) + bfin_write_FIO_FLAG_S(mask); + else + bfin_write_FIO_FLAG_C(mask); +} +#endif + +static struct sl811_platform_data sl811_priv = { + .potpg = 10, + .power = 250, /* == 500mA */ +#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS) + .port_power = &sl811_port_power, +#endif +}; + +static struct platform_device sl811_hcd_device = { + .name = "sl811-hcd", + .id = 0, + .dev = { + .platform_data = &sl811_priv, + }, + .num_resources = ARRAY_SIZE(sl811_hcd_resources), + .resource = sl811_hcd_resources, +}; +#endif + +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) +static struct resource isp1362_hcd_resources[] = { + { + .start = 0x20360000, + .end = 0x20360000, + .flags = IORESOURCE_MEM, + },{ + .start = 0x20360004, + .end = 0x20360004, + .flags = IORESOURCE_MEM, + },{ + .start = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ, + .end = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct isp1362_platform_data isp1362_priv = { + .sel15Kres = 1, + .clknotstop = 0, + .oc_enable = 0, + .int_act_high = 0, + .int_edge_triggered = 0, + .remote_wakeup_connected = 0, + .no_power_switching = 1, + .power_switching_mode = 0, +}; + +static struct platform_device isp1362_hcd_device = { + .name = "isp1362-hcd", + .id = 0, + .dev = { + .platform_data = &isp1362_priv, + }, + .num_resources = ARRAY_SIZE(isp1362_hcd_resources), + .resource = isp1362_hcd_resources, +}; +#endif + +#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) +static struct platform_device bfin_mac_device = { + .name = "bfin_mac", +}; +#endif + +#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) +static struct resource net2272_bfin_resources[] = { + { + .start = 0x20300000, + .end = 0x20300000 + 0x100, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF7, + .end = IRQ_PF7, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct platform_device net2272_bfin_device = { + .name = "net2272", + .id = -1, + .num_resources = ARRAY_SIZE(net2272_bfin_resources), + .resource = net2272_bfin_resources, +}; +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) +/* all SPI peripherals info goes here */ + +#if defined(CONFIG_MTD_M25P80) \ + || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition bfin_spi_flash_partitions[] = { + { + .name = "bootloader", + .size = 0x00020000, + .offset = 0, + .mask_flags = MTD_CAP_ROM + },{ + .name = "kernel", + .size = 0xe0000, + .offset = 0x20000 + },{ + .name = "file system", + .size = 0x700000, + .offset = 0x00100000, + } +}; + +static struct flash_platform_data bfin_spi_flash_data = { + .name = "m25p80", + .parts = bfin_spi_flash_partitions, + .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), + .type = "m25p64", +}; + +/* SPI flash chip (m25p64) */ +static struct bfin5xx_spi_chip spi_flash_chip_info = { + .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SPI_ADC_BF533) \ + || defined(CONFIG_SPI_ADC_BF533_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) \ + || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE) +static struct bfin5xx_spi_chip ad9960_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE) +static struct bfin5xx_spi_chip spi_mmc_chip_info = { + .enable_dma = 1, + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_PBX) +static struct bfin5xx_spi_chip spi_si3xxx_chip_info = { + .ctl_reg = 0x4, /* send zero */ + .enable_dma = 0, + .bits_per_word = 8, + .cs_change_per_word = 1, +}; +#endif + + +#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { + .cs_change_per_word = 1, + .enable_dma = 0, + .bits_per_word = 16, +}; + +static const struct ad7877_platform_data bfin_ad7877_ts_info = { + .model = 7877, + .vref_delay_usecs = 50, /* internal, no capacitor */ + .x_plate_ohms = 419, + .y_plate_ohms = 486, + .pressure_max = 1000, + .pressure_min = 0, + .stopacq_polarity = 1, + .first_conversion_delay = 3, + .acquisition_time = 1, + .averaging = 1, + .pen_down_acc_interval = 1, +}; +#endif + +static struct spi_board_info bfin_spi_board_info[] __initdata = { +#if defined(CONFIG_MTD_M25P80) \ + || defined(CONFIG_MTD_M25P80_MODULE) + { + /* the modalias must be the same as spi device driver name */ + .modalias = "m25p80", /* Name of spi_driver for this device */ + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/ + .platform_data = &bfin_spi_flash_data, + .controller_data = &spi_flash_chip_info, + .mode = SPI_MODE_3, + }, +#endif + +#if defined(CONFIG_SPI_ADC_BF533) \ + || defined(CONFIG_SPI_ADC_BF533_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) \ + || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) + { + .modalias = "ad1836-spi", + .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, + .controller_data = &ad1836_spi_chip_info, + }, +#endif +#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE) + { + .modalias = "ad9960-spi", + .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 1, + .controller_data = &ad9960_spi_chip_info, + }, +#endif +#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE) + { + .modalias = "spi_mmc_dummy", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 7, + .platform_data = NULL, + .controller_data = &spi_mmc_chip_info, + .mode = SPI_MODE_3, + }, + { + .modalias = "spi_mmc", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SPI_MMC_CS_CHAN, + .platform_data = NULL, + .controller_data = &spi_mmc_chip_info, + .mode = SPI_MODE_3, + }, +#endif +#if defined(CONFIG_PBX) + { + .modalias = "fxs-spi", + .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 3, + .controller_data= &spi_si3xxx_chip_info, + .mode = SPI_MODE_3, + }, + { + .modalias = "fxo-spi", + .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 2, + .controller_data= &spi_si3xxx_chip_info, + .mode = SPI_MODE_3, + }, +#endif +#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +{ + .modalias = "ad7877", + .platform_data = &bfin_ad7877_ts_info, + .irq = IRQ_PF2, + .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 5, + .controller_data = &spi_ad7877_chip_info, +}, +#endif + +}; + +/* SPI controller data */ +static struct bfin5xx_spi_master spi_bfin_master_info = { + .num_chipselect = 8, + .enable_dma = 1, /* master has the ability to do dma transfer */ +}; + +static struct platform_device spi_bfin_master_device = { + .name = "bfin-spi-master", + .id = 1, /* Bus number */ + .dev = { + .platform_data = &spi_bfin_master_info, /* Passed to driver */ + }, +}; +#endif /* spi master and devices */ + +#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE) +static struct platform_device bfin_fb_device = { + .name = "bf537-fb", +}; +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) +static struct resource bfin_uart_resources[] = { + { + .start = 0xFFC00400, + .end = 0xFFC004FF, + .flags = IORESOURCE_MEM, + },{ + .start = 0xFFC02000, + .end = 0xFFC020FF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device bfin_uart_device = { + .name = "bfin-uart", + .id = 1, + .num_resources = ARRAY_SIZE(bfin_uart_resources), + .resource = bfin_uart_resources, +}; +#endif + + +static struct platform_device *stamp_devices[] __initdata = { +#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE) + &bfin_pcmcia_cf_device, +#endif + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) + &rtc_device, +#endif + +#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE) + &sl811_hcd_device, +#endif + +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) + &isp1362_hcd_device, +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + &smc91x_device, +#endif + +#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) + &bfin_mac_device, +#endif + +#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) + &net2272_bfin_device, +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + &spi_bfin_master_device, +#endif + +#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE) + &bfin_fb_device, +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) + &bfin_uart_device, +#endif +}; + +static int __init stamp_init(void) +{ + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices)); +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + spi_register_board_info(bfin_spi_board_info, + ARRAY_SIZE(bfin_spi_board_info)); +#endif + return 0; +} + +arch_initcall(stamp_init); diff --git a/trunk/arch/blackfin/mach-bf537/boards/stamp.c b/trunk/arch/blackfin/mach-bf537/boards/stamp.c new file mode 100644 index 000000000000..ba2f875a7f7d --- /dev/null +++ b/trunk/arch/blackfin/mach-bf537/boards/stamp.c @@ -0,0 +1,615 @@ +/* + * File: arch/blackfin/mach-bf537/boards/stamp.c + * Based on: arch/blackfin/mach-bf533/boards/ezkit.c + * Author: Aidan Williams + * + * Created: + * Description: + * + * Modified: + * Copyright 2005 National ICT Australia (NICTA) + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) +#include +#endif +#include +#include +#include +#include +#include + +#include + +/* + * Name the Board for the /proc/cpuinfo + */ +char *bfin_board_name = "ADDS-BF537-STAMP"; + +/* + * Driver needs to know address, irq and flag pin. + */ + +#define ISP1761_BASE 0x203C0000 +#define ISP1761_IRQ IRQ_PF7 + +#if defined(CONFIG_USB_ISP1760_HCD) || defined(CONFIG_USB_ISP1760_HCD_MODULE) +static struct resource bfin_isp1761_resources[] = { + [0] = { + .name = "isp1761-regs", + .start = ISP1761_BASE + 0x00000000, + .end = ISP1761_BASE + 0x000fffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ISP1761_IRQ, + .end = ISP1761_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_isp1761_device = { + .name = "isp1761", + .id = 0, + .num_resources = ARRAY_SIZE(bfin_isp1761_resources), + .resource = bfin_isp1761_resources, +}; + +static struct platform_device *bfin_isp1761_devices[] = { + &bfin_isp1761_device, +}; + +int __init bfin_isp1761_init(void) +{ + unsigned int num_devices=ARRAY_SIZE(bfin_isp1761_devices); + + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING); + + return platform_add_devices(bfin_isp1761_devices, num_devices); +} + +void __exit bfin_isp1761_exit(void) +{ + platform_device_unregister(&bfin_isp1761_device); +} + +arch_initcall(bfin_isp1761_init); +#endif + +#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE) +static struct resource bfin_pcmcia_cf_resources[] = { + { + .start = 0x20310000, /* IO PORT */ + .end = 0x20312000, + .flags = IORESOURCE_MEM, + },{ + .start = 0x20311000, /* Attribute Memeory */ + .end = 0x20311FFF, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF4, + .end = IRQ_PF4, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + },{ + .start = 6, /* Card Detect PF6 */ + .end = 6, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device bfin_pcmcia_cf_device = { + .name = "bfin_cf_pcmcia", + .id = -1, + .num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources), + .resource = bfin_pcmcia_cf_resources, +}; +#endif + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) +static struct platform_device rtc_device = { + .name = "rtc-bfin", + .id = -1, +}; +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) +static struct resource smc91x_resources[] = { + { + .name = "smc91x-regs", + .start = 0x20300300, + .end = 0x20300300 + 16, + .flags = IORESOURCE_MEM, + },{ + + .start = IRQ_PF7, + .end = IRQ_PF7, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +#endif + +#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE) +static struct resource sl811_hcd_resources[] = { + { + .start = 0x20340000, + .end = 0x20340000, + .flags = IORESOURCE_MEM, + },{ + .start = 0x20340004, + .end = 0x20340004, + .flags = IORESOURCE_MEM, + },{ + .start = CONFIG_USB_SL811_BFIN_IRQ, + .end = CONFIG_USB_SL811_BFIN_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS) +void sl811_port_power(struct device *dev, int is_on) +{ + unsigned short mask = (1 << CONFIG_USB_SL811_BFIN_GPIO_VBUS); + + bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask); + bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask); + + if (is_on) + bfin_write_FIO_FLAG_S(mask); + else + bfin_write_FIO_FLAG_C(mask); +} +#endif + +static struct sl811_platform_data sl811_priv = { + .potpg = 10, + .power = 250, /* == 500mA */ +#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS) + .port_power = &sl811_port_power, +#endif +}; + +static struct platform_device sl811_hcd_device = { + .name = "sl811-hcd", + .id = 0, + .dev = { + .platform_data = &sl811_priv, + }, + .num_resources = ARRAY_SIZE(sl811_hcd_resources), + .resource = sl811_hcd_resources, +}; +#endif + +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) +static struct resource isp1362_hcd_resources[] = { + { + .start = 0x20360000, + .end = 0x20360000, + .flags = IORESOURCE_MEM, + },{ + .start = 0x20360004, + .end = 0x20360004, + .flags = IORESOURCE_MEM, + },{ + .start = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ, + .end = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct isp1362_platform_data isp1362_priv = { + .sel15Kres = 1, + .clknotstop = 0, + .oc_enable = 0, + .int_act_high = 0, + .int_edge_triggered = 0, + .remote_wakeup_connected = 0, + .no_power_switching = 1, + .power_switching_mode = 0, +}; + +static struct platform_device isp1362_hcd_device = { + .name = "isp1362-hcd", + .id = 0, + .dev = { + .platform_data = &isp1362_priv, + }, + .num_resources = ARRAY_SIZE(isp1362_hcd_resources), + .resource = isp1362_hcd_resources, +}; +#endif + +#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) +static struct platform_device bfin_mac_device = { + .name = "bfin_mac", +}; +#endif + +#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) +static struct resource net2272_bfin_resources[] = { + { + .start = 0x20300000, + .end = 0x20300000 + 0x100, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF7, + .end = IRQ_PF7, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct platform_device net2272_bfin_device = { + .name = "net2272", + .id = -1, + .num_resources = ARRAY_SIZE(net2272_bfin_resources), + .resource = net2272_bfin_resources, +}; +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) +/* all SPI peripherals info goes here */ + +#if defined(CONFIG_MTD_M25P80) \ + || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition bfin_spi_flash_partitions[] = { + { + .name = "bootloader", + .size = 0x00020000, + .offset = 0, + .mask_flags = MTD_CAP_ROM + },{ + .name = "kernel", + .size = 0xe0000, + .offset = 0x20000 + },{ + .name = "file system", + .size = 0x700000, + .offset = 0x00100000, + } +}; + +static struct flash_platform_data bfin_spi_flash_data = { + .name = "m25p80", + .parts = bfin_spi_flash_partitions, + .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), + .type = "m25p64", +}; + +/* SPI flash chip (m25p64) */ +static struct bfin5xx_spi_chip spi_flash_chip_info = { + .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SPI_ADC_BF533) \ + || defined(CONFIG_SPI_ADC_BF533_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) \ + || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE) +static struct bfin5xx_spi_chip ad9960_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE) +static struct bfin5xx_spi_chip spi_mmc_chip_info = { + .enable_dma = 1, + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_PBX) +static struct bfin5xx_spi_chip spi_si3xxx_chip_info = { + .ctl_reg = 0x4, /* send zero */ + .enable_dma = 0, + .bits_per_word = 8, + .cs_change_per_word = 1, +}; +#endif + +#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE) +static struct bfin5xx_spi_chip ad5304_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) +static struct bfin5xx_spi_chip spi_ad7877_chip_info = { +// .cs_change_per_word = 1, + .enable_dma = 0, + .bits_per_word = 16, +}; + +static const struct ad7877_platform_data bfin_ad7877_ts_info = { + .model = 7877, + .vref_delay_usecs = 50, /* internal, no capacitor */ + .x_plate_ohms = 419, + .y_plate_ohms = 486, + .pressure_max = 1000, + .pressure_min = 0, + .stopacq_polarity = 1, + .first_conversion_delay = 3, + .acquisition_time = 1, + .averaging = 1, + .pen_down_acc_interval = 1, +}; +#endif + +static struct spi_board_info bfin_spi_board_info[] __initdata = { +#if defined(CONFIG_MTD_M25P80) \ + || defined(CONFIG_MTD_M25P80_MODULE) + { + /* the modalias must be the same as spi device driver name */ + .modalias = "m25p80", /* Name of spi_driver for this device */ + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/ + .platform_data = &bfin_spi_flash_data, + .controller_data = &spi_flash_chip_info, + .mode = SPI_MODE_3, + }, +#endif + +#if defined(CONFIG_SPI_ADC_BF533) \ + || defined(CONFIG_SPI_ADC_BF533_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) \ + || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) + { + .modalias = "ad1836-spi", + .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, + .controller_data = &ad1836_spi_chip_info, + }, +#endif +#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE) + { + .modalias = "ad9960-spi", + .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 1, + .controller_data = &ad9960_spi_chip_info, + }, +#endif +#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE) + { + .modalias = "spi_mmc_dummy", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 0, + .platform_data = NULL, + .controller_data = &spi_mmc_chip_info, + .mode = SPI_MODE_3, + }, + { + .modalias = "spi_mmc", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SPI_MMC_CS_CHAN, + .platform_data = NULL, + .controller_data = &spi_mmc_chip_info, + .mode = SPI_MODE_3, + }, +#endif +#if defined(CONFIG_PBX) + { + .modalias = "fxs-spi", + .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 3, + .controller_data= &spi_si3xxx_chip_info, + .mode = SPI_MODE_3, + }, + { + .modalias = "fxo-spi", + .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 2, + .controller_data= &spi_si3xxx_chip_info, + .mode = SPI_MODE_3, + }, +#endif +#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE) + { + .modalias = "ad5304_spi", + .max_speed_hz = 1250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 2, + .platform_data = NULL, + .controller_data = &ad5304_chip_info, + .mode = SPI_MODE_2, + }, +#endif +#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE) + { + .modalias = "ad7877", + .platform_data = &bfin_ad7877_ts_info, + .irq = IRQ_PF6, + .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 1, + .controller_data = &spi_ad7877_chip_info, + }, +#endif +}; + +/* SPI controller data */ +static struct bfin5xx_spi_master spi_bfin_master_info = { + .num_chipselect = 8, + .enable_dma = 1, /* master has the ability to do dma transfer */ +}; + +static struct platform_device spi_bfin_master_device = { + .name = "bfin-spi-master", + .id = 1, /* Bus number */ + .dev = { + .platform_data = &spi_bfin_master_info, /* Passed to driver */ + }, +}; +#endif /* spi master and devices */ + +#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE) +static struct platform_device bfin_fb_device = { + .name = "bf537-fb", +}; +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) +static struct resource bfin_uart_resources[] = { + { + .start = 0xFFC00400, + .end = 0xFFC004FF, + .flags = IORESOURCE_MEM, + },{ + .start = 0xFFC02000, + .end = 0xFFC020FF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device bfin_uart_device = { + .name = "bfin-uart", + .id = 1, + .num_resources = ARRAY_SIZE(bfin_uart_resources), + .resource = bfin_uart_resources, +}; +#endif + +#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE) +static struct platform_device i2c_bfin_twi_device = { + .name = "i2c-bfin-twi", + .id = 0, +}; +#endif + +#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE) +static struct platform_device bfin_sport0_uart_device = { + .name = "bfin-sport-uart", + .id = 0, +}; + +static struct platform_device bfin_sport1_uart_device = { + .name = "bfin-sport-uart", + .id = 1, +}; +#endif + +static struct platform_device *stamp_devices[] __initdata = { +#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE) + &bfin_pcmcia_cf_device, +#endif + +#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE) + &rtc_device, +#endif + +#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE) + &sl811_hcd_device, +#endif + +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) + &isp1362_hcd_device, +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + &smc91x_device, +#endif + +#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) + &bfin_mac_device, +#endif + +#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE) + &net2272_bfin_device, +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + &spi_bfin_master_device, +#endif + +#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE) + &bfin_fb_device, +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) + &bfin_uart_device, +#endif + +#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE) + &i2c_bfin_twi_device, +#endif + +#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE) + &bfin_sport0_uart_device, + &bfin_sport1_uart_device, +#endif +}; + +static int __init stamp_init(void) +{ + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices)); +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + spi_register_board_info(bfin_spi_board_info, + ARRAY_SIZE(bfin_spi_board_info)); +#endif + return 0; +} + +arch_initcall(stamp_init); diff --git a/trunk/arch/blackfin/mach-bf537/cpu.c b/trunk/arch/blackfin/mach-bf537/cpu.c new file mode 100644 index 000000000000..2d83b7e35469 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf537/cpu.c @@ -0,0 +1,161 @@ +/* + * File: arch/blackfin/mach-bf537/cpu.c + * Based on: + * Author: michael.kang@analog.com + * + * Created: + * Description: clock scaling for the bf537 + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +/* CONFIG_CLKIN_HZ=11059200 */ +#define VCO5 (CONFIG_CLKIN_HZ*45) /*497664000 */ +#define VCO4 (CONFIG_CLKIN_HZ*36) /*398131200 */ +#define VCO3 (CONFIG_CLKIN_HZ*27) /*298598400 */ +#define VCO2 (CONFIG_CLKIN_HZ*18) /*199065600 */ +#define VCO1 (CONFIG_CLKIN_HZ*9) /*99532800 */ +#define VCO(x) VCO##x + +#define FREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)} +/* frequency */ +static struct cpufreq_frequency_table bf537_freq_table[] = { + FREQ(1), + FREQ(3), + {VCO4, VCO4 / 2}, {VCO4, VCO4}, + FREQ(5), + {0, CPUFREQ_TABLE_END}, +}; + +/* + * dpmc_fops->ioctl() + * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) + */ +static int bf537_getfreq(unsigned int cpu) +{ + unsigned long cclk_mhz, vco_mhz; + + /* The driver only support single cpu */ + if (cpu == 0) + dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz); + else + cclk_mhz = -1; + return cclk_mhz; +} + +static int bf537_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + unsigned long cclk_mhz; + unsigned long vco_mhz; + unsigned long flags; + unsigned int index, vco_index; + int i; + + struct cpufreq_freqs freqs; + if (cpufreq_frequency_table_target + (policy, bf537_freq_table, target_freq, relation, &index)) + return -EINVAL; + cclk_mhz = bf537_freq_table[index].frequency; + vco_mhz = bf537_freq_table[index].index; + + dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz); + freqs.old = bf537_getfreq(0); + freqs.new = cclk_mhz; + freqs.cpu = 0; + + pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n", + cclk_mhz, vco_mhz, index, target_freq, freqs.old); + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + local_irq_save(flags); + dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz); + local_irq_restore(flags); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + vco_mhz = get_vco(); + cclk_mhz = get_cclk(); + return 0; +} + +/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on + * this platform, anyway. + */ +static int bf537_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &bf537_freq_table); +} + +static int __init __bf537_cpu_init(struct cpufreq_policy *policy) +{ + int result; + + if (policy->cpu != 0) + return -EINVAL; + + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + /*Now ,only support one cpu */ + policy->cur = bf537_getfreq(0); + cpufreq_frequency_table_get_attr(bf537_freq_table, policy->cpu); + return cpufreq_frequency_table_cpuinfo(policy, bf537_freq_table); +} + +static struct freq_attr *bf537_freq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver bf537_driver = { + .verify = bf537_verify_speed, + .target = bf537_target, + .get = bf537_getfreq, + .init = __bf537_cpu_init, + .name = "bf537", + .owner = THIS_MODULE, + .attr = bf537_freq_attr, +}; + +static int __init bf537_cpu_init(void) +{ + return cpufreq_register_driver(&bf537_driver); +} + +static void __exit bf537_cpu_exit(void) +{ + cpufreq_unregister_driver(&bf537_driver); +} + +MODULE_AUTHOR("Mickael Kang"); +MODULE_DESCRIPTION("cpufreq driver for BF537 CPU"); +MODULE_LICENSE("GPL"); + +module_init(bf537_cpu_init); +module_exit(bf537_cpu_exit); diff --git a/trunk/arch/blackfin/mach-bf537/head.S b/trunk/arch/blackfin/mach-bf537/head.S new file mode 100644 index 000000000000..d104e1d8e07a --- /dev/null +++ b/trunk/arch/blackfin/mach-bf537/head.S @@ -0,0 +1,602 @@ +/* + * File: arch/blackfin/mach-bf537/head.S + * Based on: arch/blackfin/mach-bf533/head.S + * Author: Jeff Dionne COPYRIGHT 1998 D. Jeff Dionne + * + * Created: 1998 + * Description: Startup code for Blackfin BF537 + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#if CONFIG_BFIN_KERNEL_CLOCK +#include +#endif + +.global __rambase +.global __ramstart +.global __ramend +.extern ___bss_stop +.extern ___bss_start +.extern _bf53x_relocate_l1_mem + +#define INITIAL_STACK 0xFFB01000 + +.text + +ENTRY(__start) +ENTRY(__stext) + /* R0: argument of command line string, passed from uboot, save it */ + R7 = R0; + /* Set the SYSCFG register */ + R0 = 0x36; + SYSCFG = R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/ + R0 = 0; + + /* Clear Out All the data and pointer Registers*/ + R1 = R0; + R2 = R0; + R3 = R0; + R4 = R0; + R5 = R0; + R6 = R0; + + P0 = R0; + P1 = R0; + P2 = R0; + P3 = R0; + P4 = R0; + P5 = R0; + + LC0 = r0; + LC1 = r0; + L0 = r0; + L1 = r0; + L2 = r0; + L3 = r0; + + /* Clear Out All the DAG Registers*/ + B0 = r0; + B1 = r0; + B2 = r0; + B3 = r0; + + I0 = r0; + I1 = r0; + I2 = r0; + I3 = r0; + + M0 = r0; + M1 = r0; + M2 = r0; + M3 = r0; + + /* Turn off the icache */ + p0.l = (IMEM_CONTROL & 0xFFFF); + p0.h = (IMEM_CONTROL >> 16); + R1 = [p0]; + R0 = ~ENICPLB; + R0 = R0 & R1; + + /* Anomaly 05000125 */ +#ifdef ANOMALY_05000125 + CLI R2; + SSYNC; +#endif + [p0] = R0; + SSYNC; +#ifdef ANOMALY_05000125 + STI R2; +#endif + + /* Turn off the dcache */ + p0.l = (DMEM_CONTROL & 0xFFFF); + p0.h = (DMEM_CONTROL >> 16); + R1 = [p0]; + R0 = ~ENDCPLB; + R0 = R0 & R1; + + /* Anomaly 05000125 */ +#ifdef ANOMALY_05000125 + CLI R2; + SSYNC; +#endif + [p0] = R0; + SSYNC; +#ifdef ANOMALY_05000125 + STI R2; +#endif + + /* Initialise General-Purpose I/O Modules on BF537 */ + /* Rev 0.0 Anomaly 05000212 - PORTx_FER, + * PORT_MUX Registers Do Not accept "writes" correctly: + */ + p0.h = hi(BFIN_PORT_MUX); + p0.l = lo(BFIN_PORT_MUX); +#ifdef ANOMALY_05000212 + R0.L = W[P0]; /* Read */ + SSYNC; +#endif + R0 = (PGDE_UART | PFTE_UART)(Z); +#ifdef ANOMALY_05000212 + W[P0] = R0.L; /* Write */ + SSYNC; +#endif + W[P0] = R0.L; /* Enable both UARTS */ + SSYNC; + + p0.h = hi(PORTF_FER); + p0.l = lo(PORTF_FER); +#ifdef ANOMALY_05000212 + R0.L = W[P0]; /* Read */ + SSYNC; +#endif + R0 = 0x000F(Z); +#ifdef ANOMALY_05000212 + W[P0] = R0.L; /* Write */ + SSYNC; +#endif + /* Enable peripheral function of PORTF for UART0 and UART1 */ + W[P0] = R0.L; + SSYNC; + +#if !defined(CONFIG_BF534) + p0.h = hi(EMAC_SYSTAT); + p0.l = lo(EMAC_SYSTAT); + R0.h = 0xFFFF; /* Clear EMAC Interrupt Status bits */ + R0.l = 0xFFFF; + [P0] = R0; + SSYNC; +#endif + +#ifdef CONFIG_BF537_PORT_H + p0.h = hi(PORTH_FER); + p0.l = lo(PORTH_FER); + R0.L = W[P0]; /* Read */ + SSYNC; + R0 = 0x0000; + W[P0] = R0.L; /* Write */ + SSYNC; + W[P0] = R0.L; /* Disable peripheral function of PORTH */ + SSYNC; +#endif + + /*Initialise UART*/ + p0.h = hi(UART_LCR); + p0.l = lo(UART_LCR); + r0 = 0x0(Z); + w[p0] = r0.L; /* To enable DLL writes */ + ssync; + + p0.h = hi(UART_DLL); + p0.l = lo(UART_DLL); + r0 = 0x00(Z); + w[p0] = r0.L; + ssync; + + p0.h = hi(UART_DLH); + p0.l = lo(UART_DLH); + r0 = 0x00(Z); + w[p0] = r0.L; + ssync; + + p0.h = hi(UART_GCTL); + p0.l = lo(UART_GCTL); + r0 = 0x0(Z); + w[p0] = r0.L; /* To enable UART clock */ + ssync; + + /* Initialize stack pointer */ + sp.l = lo(INITIAL_STACK); + sp.h = hi(INITIAL_STACK); + fp = sp; + usp = sp; + + /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */ + call _bf53x_relocate_l1_mem; +#if CONFIG_BFIN_KERNEL_CLOCK + call _start_dma_code; +#endif + /* Code for initializing Async memory banks */ + + p2.h = hi(EBIU_AMBCTL1); + p2.l = lo(EBIU_AMBCTL1); + r0.h = hi(AMBCTL1VAL); + r0.l = lo(AMBCTL1VAL); + [p2] = r0; + ssync; + + p2.h = hi(EBIU_AMBCTL0); + p2.l = lo(EBIU_AMBCTL0); + r0.h = hi(AMBCTL0VAL); + r0.l = lo(AMBCTL0VAL); + [p2] = r0; + ssync; + + p2.h = hi(EBIU_AMGCTL); + p2.l = lo(EBIU_AMGCTL); + r0 = AMGCTLVAL; + w[p2] = r0; + ssync; + + /* This section keeps the processor in supervisor mode + * during kernel boot. Switches to user mode at end of boot. + * See page 3-9 of Hardware Reference manual for documentation. + */ + + /* EVT15 = _real_start */ + + p0.l = lo(EVT15); + p0.h = hi(EVT15); + p1.l = _real_start; + p1.h = _real_start; + [p0] = p1; + csync; + + p0.l = lo(IMASK); + p0.h = hi(IMASK); + p1.l = IMASK_IVG15; + p1.h = 0x0; + [p0] = p1; + csync; + + raise 15; + p0.l = .LWAIT_HERE; + p0.h = .LWAIT_HERE; + reti = p0; +#if defined(ANOMALY_05000281) + nop; nop; nop; +#endif + rti; + +.LWAIT_HERE: + jump .LWAIT_HERE; + +ENTRY(_real_start) + [ -- sp ] = reti; + p0.l = lo(WDOG_CTL); + p0.h = hi(WDOG_CTL); + r0 = 0xAD6(z); + w[p0] = r0; /* watchdog off for now */ + ssync; + + /* Code update for BSS size == 0 + * Zero out the bss region. + */ + + p1.l = ___bss_start; + p1.h = ___bss_start; + p2.l = ___bss_stop; + p2.h = ___bss_stop; + r0 = 0; + p2 -= p1; + lsetup (.L_clear_bss, .L_clear_bss ) lc0 = p2; +.L_clear_bss: + B[p1++] = r0; + + /* In case there is a NULL pointer reference + * Zero out region before stext + */ + + p1.l = 0x0; + p1.h = 0x0; + r0.l = __stext; + r0.h = __stext; + r0 = r0 >> 1; + p2 = r0; + r0 = 0; + lsetup (.L_clear_zero, .L_clear_zero ) lc0 = p2; +.L_clear_zero: + W[p1++] = r0; + + /* pass the uboot arguments to the global value command line */ + R0 = R7; + call _cmdline_init; + + p1.l = __rambase; + p1.h = __rambase; + r0.l = __sdata; + r0.h = __sdata; + [p1] = r0; + + p1.l = __ramstart; + p1.h = __ramstart; + p3.l = ___bss_stop; + p3.h = ___bss_stop; + + r1 = p3; + [p1] = r1; + + + /* + * load the current thread pointer and stack + */ + r1.l = _init_thread_union; + r1.h = _init_thread_union; + + r2.l = 0x2000; + r2.h = 0x0000; + r1 = r1 + r2; + sp = r1; + usp = sp; + fp = sp; + call _start_kernel; +.L_exit: + jump.s .L_exit; + +.section .l1.text +#if CONFIG_BFIN_KERNEL_CLOCK +ENTRY(_start_dma_code) + + /* Enable PHY CLK buffer output */ + p0.h = hi(VR_CTL); + p0.l = lo(VR_CTL); + r0.l = w[p0]; + bitset(r0, 14); + w[p0] = r0.l; + ssync; + + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = 0x1; + r0.h = 0x0; + [p0] = r0; + SSYNC; + + /* + * Set PLL_CTL + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over, */ + r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +.Lcheck_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump .Lcheck_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; + + p0.l = lo(EBIU_SDRRC); + p0.h = hi(EBIU_SDRRC); + r0 = mem_SDRRC; + w[p0] = r0.l; + ssync; + + p0.l = (EBIU_SDBCTL & 0xFFFF); + p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */ + r0 = mem_SDBCTL; + w[p0] = r0.l; + ssync; + + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITCLR (R0, 24); + p0.h = hi(EBIU_SDSTAT); + p0.l = lo(EBIU_SDSTAT); + r2.l = w[p0]; + cc = bittst(r2,3); + if !cc jump .Lskip; + NOP; + BITSET (R0, 23); +.Lskip: + [P2] = R0; + SSYNC; + + R0.L = lo(mem_SDGCTL); + R0.H = hi(mem_SDGCTL); + R1 = [p2]; + R1 = R1 | R0; + [P2] = R1; + SSYNC; + + p0.h = hi(SIC_IWR); + p0.l = lo(SIC_IWR); + r0.l = lo(IWR_ENABLE_ALL); + r0.h = hi(IWR_ENABLE_ALL); + [p0] = r0; + SSYNC; + + RTS; +#endif /* CONFIG_BFIN_KERNEL_CLOCK */ + +ENTRY(_bfin_reset) + /* No more interrupts to be handled*/ + CLI R6; + SSYNC; + +#if defined(CONFIG_MTD_M25P80) +/* + * The following code fix the SPI flash reboot issue, + * /CS signal of the chip which is using PF10 return to GPIO mode + */ + p0.h = hi(PORTF_FER); + p0.l = lo(PORTF_FER); + r0.l = 0x0000; + w[p0] = r0.l; + SSYNC; + +/* /CS return to high */ + p0.h = hi(PORTFIO); + p0.l = lo(PORTFIO); + r0.l = 0xFFFF; + w[p0] = r0.l; + SSYNC; + +/* Delay some time, This is necessary */ + r1.h = 0; + r1.l = 0x400; + p1 = r1; + lsetup (_delay_lab1,_delay_lab1_end ) lc1 = p1; +_delay_lab1: + r0.h = 0; + r0.l = 0x8000; + p0 = r0; + lsetup (_delay_lab0,_delay_lab0_end ) lc0 = p0; +_delay_lab0: + nop; +_delay_lab0_end: + nop; +_delay_lab1_end: + nop; +#endif + + /* Clear the bits 13-15 in SWRST if they werent cleared */ + p0.h = hi(SWRST); + p0.l = lo(SWRST); + csync; + r0.l = w[p0]; + + /* Clear the IMASK register */ + p0.h = hi(IMASK); + p0.l = lo(IMASK); + r0 = 0x0; + [p0] = r0; + + /* Clear the ILAT register */ + p0.h = hi(ILAT); + p0.l = lo(ILAT); + r0 = [p0]; + [p0] = r0; + SSYNC; + + /* Disable the WDOG TIMER */ + p0.h = hi(WDOG_CTL); + p0.l = lo(WDOG_CTL); + r0.l = 0xAD6; + w[p0] = r0.l; + SSYNC; + + /* Clear the sticky bit incase it is already set */ + p0.h = hi(WDOG_CTL); + p0.l = lo(WDOG_CTL); + r0.l = 0x8AD6; + w[p0] = r0.l; + SSYNC; + + /* Program the count value */ + R0.l = 0x100; + R0.h = 0x0; + P0.h = hi(WDOG_CNT); + P0.l = lo(WDOG_CNT); + [P0] = R0; + SSYNC; + + /* Program WDOG_STAT if necessary */ + P0.h = hi(WDOG_CTL); + P0.l = lo(WDOG_CTL); + R0 = W[P0](Z); + CC = BITTST(R0,1); + if !CC JUMP .LWRITESTAT; + CC = BITTST(R0,2); + if !CC JUMP .LWRITESTAT; + JUMP .LSKIP_WRITE; + +.LWRITESTAT: + /* When watch dog timer is enabled, + * a write to STAT will load the contents of CNT to STAT + */ + R0 = 0x0000(z); + P0.h = hi(WDOG_STAT); + P0.l = lo(WDOG_STAT) + [P0] = R0; + SSYNC; + +.LSKIP_WRITE: + /* Enable the reset event */ + P0.h = hi(WDOG_CTL); + P0.l = lo(WDOG_CTL); + R0 = W[P0](Z); + BITCLR(R0,1); + BITCLR(R0,2); + W[P0] = R0.L; + SSYNC; + NOP; + + /* Enable the wdog counter */ + R0 = W[P0](Z); + BITCLR(R0,4); + W[P0] = R0.L; + SSYNC; + + IDLE; + + RTS; + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ + +.align 4 +__rambase: +.long 0 +__ramstart: +.long 0 +__ramend: +.long 0 diff --git a/trunk/arch/blackfin/mach-bf537/ints-priority.c b/trunk/arch/blackfin/mach-bf537/ints-priority.c new file mode 100644 index 000000000000..fd6308eccbe6 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf537/ints-priority.c @@ -0,0 +1,74 @@ +/* + * File: arch/blackfin/mach-bf537/ints-priority.c + * Based on: arch/blackfin/mach-bf533/ints-priority.c + * Author: Michael Hennerich + * + * Created: + * Description: Set up the interupt priorities + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +void program_IAR(void) +{ + /* Program the IAR0 Register with the configured priority */ + bfin_write_SIC_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) | + ((CONFIG_IRQ_DMA_ERROR - 7) << IRQ_DMA_ERROR_POS) | + ((CONFIG_IRQ_ERROR - 7) << IRQ_ERROR_POS) | + ((CONFIG_IRQ_RTC - 7) << IRQ_RTC_POS) | + ((CONFIG_IRQ_PPI - 7) << IRQ_PPI_POS) | + ((CONFIG_IRQ_SPORT0_RX - 7) << IRQ_SPORT0_RX_POS) | + ((CONFIG_IRQ_SPORT0_TX - 7) << IRQ_SPORT0_TX_POS) | + ((CONFIG_IRQ_SPORT1_RX - 7) << IRQ_SPORT1_RX_POS)); + + bfin_write_SIC_IAR1(((CONFIG_IRQ_SPORT1_TX - 7) << IRQ_SPORT1_TX_POS) | + ((CONFIG_IRQ_TWI - 7) << IRQ_TWI_POS) | + ((CONFIG_IRQ_SPI - 7) << IRQ_SPI_POS) | + ((CONFIG_IRQ_UART0_RX - 7) << IRQ_UART0_RX_POS) | + ((CONFIG_IRQ_UART0_TX - 7) << IRQ_UART0_TX_POS) | + ((CONFIG_IRQ_UART1_RX - 7) << IRQ_UART1_RX_POS) | + ((CONFIG_IRQ_UART1_TX - 7) << IRQ_UART1_TX_POS) | + ((CONFIG_IRQ_CAN_RX - 7) << IRQ_CAN_RX_POS)); + + bfin_write_SIC_IAR2(((CONFIG_IRQ_CAN_TX - 7) << IRQ_CAN_TX_POS) | + ((CONFIG_IRQ_MAC_RX - 7) << IRQ_MAC_RX_POS) | + ((CONFIG_IRQ_MAC_TX - 7) << IRQ_MAC_TX_POS) | + ((CONFIG_IRQ_TMR0 - 7) << IRQ_TMR0_POS) | + ((CONFIG_IRQ_TMR1 - 7) << IRQ_TMR1_POS) | + ((CONFIG_IRQ_TMR2 - 7) << IRQ_TMR2_POS) | + ((CONFIG_IRQ_TMR3 - 7) << IRQ_TMR3_POS) | + ((CONFIG_IRQ_TMR4 - 7) << IRQ_TMR4_POS)); + + bfin_write_SIC_IAR3(((CONFIG_IRQ_TMR5 - 7) << IRQ_TMR5_POS) | + ((CONFIG_IRQ_TMR6 - 7) << IRQ_TMR6_POS) | + ((CONFIG_IRQ_TMR7 - 7) << IRQ_TMR7_POS) | + ((CONFIG_IRQ_PROG_INTA - 7) << IRQ_PROG_INTA_POS) | + ((CONFIG_IRQ_PORTG_INTB - 7) << IRQ_PORTG_INTB_POS) | + ((CONFIG_IRQ_MEM_DMA0 - 7) << IRQ_MEM_DMA0_POS) | + ((CONFIG_IRQ_MEM_DMA1 - 7) << IRQ_MEM_DMA1_POS) | + ((CONFIG_IRQ_WATCH - 7) << IRQ_WATCH_POS)); + + SSYNC(); +} diff --git a/trunk/arch/blackfin/mach-bf561/Kconfig b/trunk/arch/blackfin/mach-bf561/Kconfig new file mode 100644 index 000000000000..0a17c4cf0059 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf561/Kconfig @@ -0,0 +1,222 @@ +if BF561 + +menu "BF561 Specific Configuration" + +comment "Core B Support" + +menu "Core B Support" + +config BF561_COREB + bool "Enable Core B support" + default y + +config BF561_COREB_RESET + bool "Enable Core B reset support" + default n + help + This requires code in the application that is loaded + into Core B. In order to reset, the application needs + to install an interrupt handler for Supplemental + Interrupt 0, that sets RETI to 0xff600000 and writes + bit 11 of SICB_SYSCR when bit 5 of SICA_SYSCR is 0. + This causes Core B to stall when Supplemental Interrupt + 0 is set, and will reset PC to 0xff600000 when + COREB_SRAM_INIT is cleared. + +endmenu + +comment "Interrupt Priority Assignment" + +menu "Priority" + +config IRQ_PLL_WAKEUP + int "PLL Wakeup Interrupt" + default 7 +config IRQ_DMA1_ERROR + int "DMA1 Error (generic)" + default 7 +config IRQ_DMA2_ERROR + int "DMA2 Error (generic)" + default 7 +config IRQ_IMDMA_ERROR + int "IMDMA Error (generic)" + default 7 +config IRQ_PPI0_ERROR + int "PPI0 Error Interrupt" + default 7 +config IRQ_PPI1_ERROR + int "PPI1 Error Interrupt" + default 7 +config IRQ_SPORT0_ERROR + int "SPORT0 Error Interrupt" + default 7 +config IRQ_SPORT1_ERROR + int "SPORT1 Error Interrupt" + default 7 +config IRQ_SPI_ERROR + int "SPI Error Interrupt" + default 7 +config IRQ_UART_ERROR + int "UART Error Interrupt" + default 7 +config IRQ_RESERVED_ERROR + int "Reserved Interrupt" + default 7 +config IRQ_DMA1_0 + int "DMA1 0 Interrupt(PPI1)" + default 8 +config IRQ_DMA1_1 + int "DMA1 1 Interrupt(PPI2)" + default 8 +config IRQ_DMA1_2 + int "DMA1 2 Interrupt" + default 8 +config IRQ_DMA1_3 + int "DMA1 3 Interrupt" + default 8 +config IRQ_DMA1_4 + int "DMA1 4 Interrupt" + default 8 +config IRQ_DMA1_5 + int "DMA1 5 Interrupt" + default 8 +config IRQ_DMA1_6 + int "DMA1 6 Interrupt" + default 8 +config IRQ_DMA1_7 + int "DMA1 7 Interrupt" + default 8 +config IRQ_DMA1_8 + int "DMA1 8 Interrupt" + default 8 +config IRQ_DMA1_9 + int "DMA1 9 Interrupt" + default 8 +config IRQ_DMA1_10 + int "DMA1 10 Interrupt" + default 8 +config IRQ_DMA1_11 + int "DMA1 11 Interrupt" + default 8 +config IRQ_DMA2_0 + int "DMA2 0 (SPORT0 RX)" + default 9 +config IRQ_DMA2_1 + int "DMA2 1 (SPORT0 TX)" + default 9 +config IRQ_DMA2_2 + int "DMA2 2 (SPORT1 RX)" + default 9 +config IRQ_DMA2_3 + int "DMA2 3 (SPORT2 TX)" + default 9 +config IRQ_DMA2_4 + int "DMA2 4 (SPI)" + default 9 +config IRQ_DMA2_5 + int "DMA2 5 (UART RX)" + default 9 +config IRQ_DMA2_6 + int "DMA2 6 (UART TX)" + default 9 +config IRQ_DMA2_7 + int "DMA2 7 Interrupt" + default 9 +config IRQ_DMA2_8 + int "DMA2 8 Interrupt" + default 9 +config IRQ_DMA2_9 + int "DMA2 9 Interrupt" + default 9 +config IRQ_DMA2_10 + int "DMA2 10 Interrupt" + default 9 +config IRQ_DMA2_11 + int "DMA2 11 Interrupt" + default 9 +config IRQ_TIMER0 + int "TIMER 0 Interrupt" + default 10 +config IRQ_TIMER1 + int "TIMER 1 Interrupt" + default 10 +config IRQ_TIMER2 + int "TIMER 2 Interrupt" + default 10 +config IRQ_TIMER3 + int "TIMER 3 Interrupt" + default 10 +config IRQ_TIMER4 + int "TIMER 4 Interrupt" + default 10 +config IRQ_TIMER5 + int "TIMER 5 Interrupt" + default 10 +config IRQ_TIMER6 + int "TIMER 6 Interrupt" + default 10 +config IRQ_TIMER7 + int "TIMER 7 Interrupt" + default 10 +config IRQ_TIMER8 + int "TIMER 8 Interrupt" + default 10 +config IRQ_TIMER9 + int "TIMER 9 Interrupt" + default 10 +config IRQ_TIMER10 + int "TIMER 10 Interrupt" + default 10 +config IRQ_TIMER11 + int "TIMER 11 Interrupt" + default 10 +config IRQ_PROG0_INTA + int "Programmable Flags0 A (8)" + default 11 +config IRQ_PROG0_INTB + int "Programmable Flags0 B (8)" + default 11 +config IRQ_PROG1_INTA + int "Programmable Flags1 A (8)" + default 11 +config IRQ_PROG1_INTB + int "Programmable Flags1 B (8)" + default 11 +config IRQ_PROG2_INTA + int "Programmable Flags2 A (8)" + default 11 +config IRQ_PROG2_INTB + int "Programmable Flags2 B (8)" + default 11 +config IRQ_DMA1_WRRD0 + int "MDMA1 0 write/read INT" + default 8 +config IRQ_DMA1_WRRD1 + int "MDMA1 1 write/read INT" + default 8 +config IRQ_DMA2_WRRD0 + int "MDMA2 0 write/read INT" + default 9 +config IRQ_DMA2_WRRD1 + int "MDMA2 1 write/read INT" + default 9 +config IRQ_IMDMA_WRRD0 + int "IMDMA 0 write/read INT" + default 12 +config IRQ_IMDMA_WRRD1 + int "IMDMA 1 write/read INT" + default 12 +config IRQ_WDTIMER + int "Watch Dog Timer" + default 13 + + help + Enter the priority numbers between 7-13 ONLY. Others are Reserved. + This applies to all the above. It is not recommended to assign the + highest priority number 7 to UART or any other device. + +endmenu + +endmenu + +endif diff --git a/trunk/arch/blackfin/mach-bf561/Makefile b/trunk/arch/blackfin/mach-bf561/Makefile new file mode 100644 index 000000000000..57f475a55161 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf561/Makefile @@ -0,0 +1,9 @@ +# +# arch/blackfin/mach-bf561/Makefile +# + +extra-y := head.o + +obj-y := ints-priority.o + +obj-$(CONFIG_BF561_COREB) += coreb.o diff --git a/trunk/arch/blackfin/mach-bf561/boards/Makefile b/trunk/arch/blackfin/mach-bf561/boards/Makefile new file mode 100644 index 000000000000..886edc739ab4 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf561/boards/Makefile @@ -0,0 +1,7 @@ +# +# arch/blackfin/mach-bf561/boards/Makefile +# + +obj-$(CONFIG_GENERIC_BOARD) += generic_board.o +obj-$(CONFIG_BFIN561_EZKIT) += ezkit.o +obj-$(CONFIG_BFIN561_BLUETECHNIX_CM) += cm_bf561.o diff --git a/trunk/arch/blackfin/mach-bf561/boards/cm_bf561.c b/trunk/arch/blackfin/mach-bf561/boards/cm_bf561.c new file mode 100644 index 000000000000..6824e956d153 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf561/boards/cm_bf561.c @@ -0,0 +1,289 @@ +/* + * File: arch/blackfin/mach-bf533/boards/cm_bf561.c + * Based on: arch/blackfin/mach-bf533/boards/ezkit.c + * Author: Aidan Williams Copright 2005 + * + * Created: 2006 + * Description: Board description file + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Name the Board for the /proc/cpuinfo + */ +char *bfin_board_name = "Bluetechnix CM BF561"; + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) +/* all SPI perpherals info goes here */ + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition bfin_spi_flash_partitions[] = { + { + .name = "bootloader", + .size = 0x00020000, + .offset = 0, + .mask_flags = MTD_CAP_ROM + },{ + .name = "kernel", + .size = 0xe0000, + .offset = 0x20000 + },{ + .name = "file system", + .size = 0x700000, + .offset = 0x00100000, + } +}; + +static struct flash_platform_data bfin_spi_flash_data = { + .name = "m25p80", + .parts = bfin_spi_flash_partitions, + .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), + .type = "m25p64", +}; + +/* SPI flash chip (m25p64) */ +static struct bfin5xx_spi_chip spi_flash_chip_info = { + .enable_dma = 0, /* use dma transfer with this chip*/ + .bits_per_word = 8, +}; +#endif + +#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE) +/* SPI ADC chip */ +static struct bfin5xx_spi_chip spi_adc_chip_info = { + .enable_dma = 1, /* use dma transfer with this chip*/ + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE) +static struct bfin5xx_spi_chip ad9960_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif + +#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE) +static struct bfin5xx_spi_chip spi_mmc_chip_info = { + .enable_dma = 1, + .bits_per_word = 8, +}; +#endif + +static struct spi_board_info bfin_spi_board_info[] __initdata = { +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) + { + /* the modalias must be the same as spi device driver name */ + .modalias = "m25p80", /* Name of spi_driver for this device */ + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/ + .platform_data = &bfin_spi_flash_data, + .controller_data = &spi_flash_chip_info, + .mode = SPI_MODE_3, + }, +#endif + +#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE) + { + .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */ + .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, /* Framework bus number */ + .chip_select = 1, /* Framework chip select. */ + .platform_data = NULL, /* No spi_driver specific config */ + .controller_data = &spi_adc_chip_info, + }, +#endif + +#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) + { + .modalias = "ad1836-spi", + .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, + .controller_data = &ad1836_spi_chip_info, + }, +#endif +#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE) + { + .modalias = "ad9960-spi", + .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 1, + .controller_data = &ad9960_spi_chip_info, + }, +#endif +#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE) + { + .modalias = "spi_mmc", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SPI_MMC_CS_CHAN, + .platform_data = NULL, + .controller_data = &spi_mmc_chip_info, + .mode = SPI_MODE_3, + }, +#endif +}; + +/* SPI controller data */ +static struct bfin5xx_spi_master spi_bfin_master_info = { + .num_chipselect = 8, + .enable_dma = 1, /* master has the ability to do dma transfer */ +}; + +static struct platform_device spi_bfin_master_device = { + .name = "bfin-spi-master", + .id = 1, /* Bus number */ + .dev = { + .platform_data = &spi_bfin_master_info, /* Passed to driver */ + }, +}; +#endif /* spi master and devices */ + + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + +static struct resource smc91x_resources[] = { + { + .name = "smc91x-regs", + .start = 0x28000300, + .end = 0x28000300 + 16, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF0, + .end = IRQ_PF0, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +#endif + +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) +static struct resource isp1362_hcd_resources[] = { + { + .start = 0x24008000, + .end = 0x24008000, + .flags = IORESOURCE_MEM, + },{ + .start = 0x24008004, + .end = 0x24008004, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PF47, + .end = IRQ_PF47, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct isp1362_platform_data isp1362_priv = { + .sel15Kres = 1, + .clknotstop = 0, + .oc_enable = 0, + .int_act_high = 0, + .int_edge_triggered = 0, + .remote_wakeup_connected = 0, + .no_power_switching = 1, + .power_switching_mode = 0, +}; + +static struct platform_device isp1362_hcd_device = { + .name = "isp1362-hcd", + .id = 0, + .dev = { + .platform_data = &isp1362_priv, + }, + .num_resources = ARRAY_SIZE(isp1362_hcd_resources), + .resource = isp1362_hcd_resources, +}; +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) +static struct resource bfin_uart_resources[] = { + { + .start = 0xFFC00400, + .end = 0xFFC004FF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device bfin_uart_device = { + .name = "bfin-uart", + .id = 1, + .num_resources = ARRAY_SIZE(bfin_uart_resources), + .resource = bfin_uart_resources, +}; +#endif + +static struct platform_device *cm_bf561_devices[] __initdata = { + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) + &bfin_uart_device, +#endif + +#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE) + &isp1362_hcd_device, +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + &smc91x_device, +#endif + +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + &spi_bfin_master_device, +#endif + +}; + +static int __init cm_bf561_init(void) +{ + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + platform_add_devices(cm_bf561_devices, ARRAY_SIZE(cm_bf561_devices)); +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info)); +#endif + return 0; +} + +arch_initcall(cm_bf561_init); diff --git a/trunk/arch/blackfin/mach-bf561/boards/ezkit.c b/trunk/arch/blackfin/mach-bf561/boards/ezkit.c new file mode 100644 index 000000000000..14eb4f9a68ea --- /dev/null +++ b/trunk/arch/blackfin/mach-bf561/boards/ezkit.c @@ -0,0 +1,147 @@ +/* + * File: arch/blackfin/mach-bf561/ezkit.c + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +/* + * Name the Board for the /proc/cpuinfo + */ +char *bfin_board_name = "ADDS-BF561-EZKIT"; + +/* + * USB-LAN EzExtender board + * Driver needs to know address, irq and flag pin. + */ +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) +static struct resource smc91x_resources[] = { + { + .name = "smc91x-regs", + .start = 0x2C010300, + .end = 0x2C010300 + 16, + .flags = IORESOURCE_MEM, + },{ + + .start = IRQ_PF9, + .end = IRQ_PF9, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +#endif + +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) +static struct resource bfin_uart_resources[] = { + { + .start = 0xFFC00400, + .end = 0xFFC004FF, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device bfin_uart_device = { + .name = "bfin-uart", + .id = 1, + .num_resources = ARRAY_SIZE(bfin_uart_resources), + .resource = bfin_uart_resources, +}; +#endif + +#ifdef CONFIG_SPI_BFIN +#if defined(CONFIG_SND_BLACKFIN_AD1836) \ + || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) +static struct bfin5xx_spi_chip ad1836_spi_chip_info = { + .enable_dma = 0, + .bits_per_word = 16, +}; +#endif +#endif + +/* SPI controller data */ +static struct bfin5xx_spi_master spi_bfin_master_info = { + .num_chipselect = 8, + .enable_dma = 1, /* master has the ability to do dma transfer */ +}; + +static struct platform_device spi_bfin_master_device = { + .name = "bfin-spi-master", + .id = 1, /* Bus number */ + .dev = { + .platform_data = &spi_bfin_master_info, /* Passed to driver */ + }, +}; + +static struct spi_board_info bfin_spi_board_info[] __initdata = { +#if defined(CONFIG_SND_BLACKFIN_AD1836) \ + || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE) + { + .modalias = "ad1836-spi", + .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT, + .controller_data = &ad1836_spi_chip_info, + }, +#endif +}; + +static struct platform_device *ezkit_devices[] __initdata = { +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + &smc91x_device, +#endif +#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE) + &spi_bfin_master_device, +#endif +#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE) + &bfin_uart_device, +#endif +}; + +static int __init ezkit_init(void) +{ + int ret; + + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + ret = platform_add_devices(ezkit_devices, + ARRAY_SIZE(ezkit_devices)); + if (ret < 0) + return ret; + return spi_register_board_info(bfin_spi_board_info, + ARRAY_SIZE(bfin_spi_board_info)); +} + +arch_initcall(ezkit_init); diff --git a/trunk/arch/blackfin/mach-bf561/boards/generic_board.c b/trunk/arch/blackfin/mach-bf561/boards/generic_board.c new file mode 100644 index 000000000000..585ecdd2f6a5 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf561/boards/generic_board.c @@ -0,0 +1,82 @@ +/* + * File: arch/blackfin/mach-bf561/generic_board.c + * Based on: arch/blackfin/mach-bf533/ezkit.c + * Author: Aidan Williams + * + * Created: + * Description: + * + * Modified: + * Copyright 2005 National ICT Australia (NICTA) + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +char *bfin_board_name = "UNKNOWN BOARD"; + +/* + * Driver needs to know address, irq and flag pin. + */ +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) +static struct resource smc91x_resources[] = { + { + .start = 0x2C010300, + .end = 0x2C010300 + 16, + .flags = IORESOURCE_MEM, + },{ + .start = IRQ_PROG_INTB, + .end = IRQ_PROG_INTB, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + },{ + /* + * denotes the flag pin and is used directly if + * CONFIG_IRQCHIP_DEMUX_GPIO is defined. + */ + .start = IRQ_PF9, + .end = IRQ_PF9, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +#endif + +static struct platform_device *generic_board_devices[] __initdata = { +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + &smc91x_device, +#endif +}; + +static int __init generic_board_init(void) +{ + printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__); + return platform_add_devices(generic_board_devices, + ARRAY_SIZE(generic_board_devices)); +} + +arch_initcall(generic_board_init); diff --git a/trunk/arch/blackfin/mach-bf561/coreb.c b/trunk/arch/blackfin/mach-bf561/coreb.c new file mode 100644 index 000000000000..b28582fe083c --- /dev/null +++ b/trunk/arch/blackfin/mach-bf561/coreb.c @@ -0,0 +1,402 @@ +/* + * File: arch/blackfin/mach-bf561/coreb.c + * Based on: + * Author: + * + * Created: + * Description: Handle CoreB on a BF561 + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_VER "v0.1" + +static spinlock_t coreb_lock; +static wait_queue_head_t coreb_dma_wait; + +#define COREB_IS_OPEN 0x00000001 +#define COREB_IS_RUNNING 0x00000010 + +#define CMD_COREB_INDEX 1 +#define CMD_COREB_START 2 +#define CMD_COREB_STOP 3 +#define CMD_COREB_RESET 4 + +#define COREB_MINOR 229 + +static unsigned long coreb_status = 0; +static unsigned long coreb_base = 0xff600000; +static unsigned long coreb_size = 0x4000; +int coreb_dma_done; + +static loff_t coreb_lseek(struct file *file, loff_t offset, int origin); +static ssize_t coreb_read(struct file *file, char *buf, size_t count, + loff_t * ppos); +static ssize_t coreb_write(struct file *file, const char *buf, size_t count, + loff_t * ppos); +static int coreb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg); +static int coreb_open(struct inode *inode, struct file *file); +static int coreb_release(struct inode *inode, struct file *file); + +static irqreturn_t coreb_dma_interrupt(int irq, void *dev_id) +{ + clear_dma_irqstat(CH_MEM_STREAM2_DEST); + coreb_dma_done = 1; + wake_up_interruptible(&coreb_dma_wait); + return IRQ_HANDLED; +} + +static ssize_t coreb_write(struct file *file, const char *buf, size_t count, + loff_t * ppos) +{ + unsigned long p = *ppos; + ssize_t wrote = 0; + + if (p + count > coreb_size) + return -EFAULT; + + while (count > 0) { + int len = count; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + + coreb_dma_done = 0; + + /* Source Channel */ + set_dma_start_addr(CH_MEM_STREAM2_SRC, (unsigned long)buf); + set_dma_x_count(CH_MEM_STREAM2_SRC, len); + set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char)); + set_dma_config(CH_MEM_STREAM2_SRC, RESTART); + /* Destination Channel */ + set_dma_start_addr(CH_MEM_STREAM2_DEST, coreb_base + p); + set_dma_x_count(CH_MEM_STREAM2_DEST, len); + set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char)); + set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN); + + enable_dma(CH_MEM_STREAM2_SRC); + enable_dma(CH_MEM_STREAM2_DEST); + + wait_event_interruptible(coreb_dma_wait, coreb_dma_done); + + disable_dma(CH_MEM_STREAM2_SRC); + disable_dma(CH_MEM_STREAM2_DEST); + + count -= len; + wrote += len; + buf += len; + p += len; + } + *ppos = p; + return wrote; +} + +static ssize_t coreb_read(struct file *file, char *buf, size_t count, + loff_t * ppos) +{ + unsigned long p = *ppos; + ssize_t read = 0; + + if ((p + count) > coreb_size) + return -EFAULT; + + while (count > 0) { + int len = count; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + + coreb_dma_done = 0; + + /* Source Channel */ + set_dma_start_addr(CH_MEM_STREAM2_SRC, coreb_base + p); + set_dma_x_count(CH_MEM_STREAM2_SRC, len); + set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char)); + set_dma_config(CH_MEM_STREAM2_SRC, RESTART); + /* Destination Channel */ + set_dma_start_addr(CH_MEM_STREAM2_DEST, (unsigned long)buf); + set_dma_x_count(CH_MEM_STREAM2_DEST, len); + set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char)); + set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN); + + enable_dma(CH_MEM_STREAM2_SRC); + enable_dma(CH_MEM_STREAM2_DEST); + + wait_event_interruptible(coreb_dma_wait, coreb_dma_done); + + disable_dma(CH_MEM_STREAM2_SRC); + disable_dma(CH_MEM_STREAM2_DEST); + + count -= len; + read += len; + buf += len; + p += len; + } + + return read; +} + +static loff_t coreb_lseek(struct file *file, loff_t offset, int origin) +{ + loff_t ret; + + mutex_lock(&file->f_dentry->d_inode->i_mutex); + + switch (origin) { + case 0 /* SEEK_SET */ : + if (offset < coreb_size) { + file->f_pos = offset; + ret = file->f_pos; + } else + ret = -EINVAL; + break; + case 1 /* SEEK_CUR */ : + if ((offset + file->f_pos) < coreb_size) { + file->f_pos += offset; + ret = file->f_pos; + } else + ret = -EINVAL; + default: + ret = -EINVAL; + } + mutex_unlock(&file->f_dentry->d_inode->i_mutex); + return ret; +} + +static int coreb_open(struct inode *inode, struct file *file) +{ + spin_lock_irq(&coreb_lock); + + if (coreb_status & COREB_IS_OPEN) + goto out_busy; + + coreb_status |= COREB_IS_OPEN; + + spin_unlock_irq(&coreb_lock); + return 0; + + out_busy: + spin_unlock_irq(&coreb_lock); + return -EBUSY; +} + +static int coreb_release(struct inode *inode, struct file *file) +{ + spin_lock_irq(&coreb_lock); + coreb_status &= ~COREB_IS_OPEN; + spin_unlock_irq(&coreb_lock); + return 0; +} + +static int coreb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + int coreb_index = 0; + + switch (cmd) { + case CMD_COREB_INDEX: + if (copy_from_user(&coreb_index, (int *)arg, sizeof(int))) { + retval = -EFAULT; + break; + } + + spin_lock_irq(&coreb_lock); + switch (coreb_index) { + case 0: + coreb_base = 0xff600000; + coreb_size = 0x4000; + break; + case 1: + coreb_base = 0xff610000; + coreb_size = 0x4000; + break; + case 2: + coreb_base = 0xff500000; + coreb_size = 0x8000; + break; + case 3: + coreb_base = 0xff400000; + coreb_size = 0x8000; + break; + default: + retval = -EINVAL; + break; + } + spin_unlock_irq(&coreb_lock); + + mutex_lock(&file->f_dentry->d_inode->i_mutex); + file->f_pos = 0; + mutex_unlock(&file->f_dentry->d_inode->i_mutex); + break; + case CMD_COREB_START: + spin_lock_irq(&coreb_lock); + if (coreb_status & COREB_IS_RUNNING) { + retval = -EBUSY; + break; + } + printk(KERN_INFO "Starting Core B\n"); + coreb_status |= COREB_IS_RUNNING; + bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020); + SSYNC(); + spin_lock_irq(&coreb_lock); + break; +#if defined(CONFIG_BF561_COREB_RESET) + case CMD_COREB_STOP: + spin_lock_irq(&coreb_lock); + printk(KERN_INFO "Stopping Core B\n"); + bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020); + bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080); + coreb_status &= ~COREB_IS_RUNNING; + spin_lock_irq(&coreb_lock); + break; + case CMD_COREB_RESET: + printk(KERN_INFO "Resetting Core B\n"); + bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080); + break; +#endif + } + + return retval; +} + +static struct file_operations coreb_fops = { + .owner = THIS_MODULE, + .llseek = coreb_lseek, + .read = coreb_read, + .write = coreb_write, + .ioctl = coreb_ioctl, + .open = coreb_open, + .release = coreb_release +}; + +static struct miscdevice coreb_dev = { + COREB_MINOR, + "coreb", + &coreb_fops +}; + +static ssize_t coreb_show_status(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, + "Base Address:\t0x%08lx\n" + "Core B is %s\n" + "SICA_SYSCR:\t%04x\n" + "SICB_SYSCR:\t%04x\n" + "\n" + "IRQ Status:\tCore A\t\tCore B\n" + "ISR0:\t\t%08x\t\t%08x\n" + "ISR1:\t\t%08x\t\t%08x\n" + "IMASK0:\t\t%08x\t\t%08x\n" + "IMASK1:\t\t%08x\t\t%08x\n", + coreb_base, + coreb_status & COREB_IS_RUNNING ? "running" : "stalled", + bfin_read_SICA_SYSCR(), bfin_read_SICB_SYSCR(), + bfin_read_SICA_ISR0(), bfin_read_SICB_ISR0(), + bfin_read_SICA_ISR1(), bfin_read_SICB_ISR0(), + bfin_read_SICA_IMASK0(), bfin_read_SICB_IMASK0(), + bfin_read_SICA_IMASK1(), bfin_read_SICB_IMASK1()); +} + +static DEVICE_ATTR(coreb_status, S_IRUGO, coreb_show_status, NULL); + +int __init bf561_coreb_init(void) +{ + init_waitqueue_head(&coreb_dma_wait); + + spin_lock_init(&coreb_lock); + /* Request the core memory regions for Core B */ + if (request_mem_region(0xff600000, 0x4000, + "Core B - Instruction SRAM") == NULL) + goto exit; + + if (request_mem_region(0xFF610000, 0x4000, + "Core B - Instruction SRAM") == NULL) + goto release_instruction_a_sram; + + if (request_mem_region(0xFF500000, 0x8000, + "Core B - Data Bank B SRAM") == NULL) + goto release_instruction_b_sram; + + if (request_mem_region(0xff400000, 0x8000, + "Core B - Data Bank A SRAM") == NULL) + goto release_data_b_sram; + + if (request_dma(CH_MEM_STREAM2_DEST, "Core B - DMA Destination") < 0) + goto release_data_a_sram; + + if (request_dma(CH_MEM_STREAM2_SRC, "Core B - DMA Source") < 0) + goto release_dma_dest; + + set_dma_callback(CH_MEM_STREAM2_DEST, coreb_dma_interrupt, NULL); + + misc_register(&coreb_dev); + + if (device_create_file(coreb_dev.this_device, &dev_attr_coreb_status)) + goto release_dma_src; + + printk(KERN_INFO "BF561 Core B driver %s initialized.\n", MODULE_VER); + return 0; + + release_dma_src: + free_dma(CH_MEM_STREAM2_SRC); + release_dma_dest: + free_dma(CH_MEM_STREAM2_DEST); + release_data_a_sram: + release_mem_region(0xff400000, 0x8000); + release_data_b_sram: + release_mem_region(0xff500000, 0x8000); + release_instruction_b_sram: + release_mem_region(0xff610000, 0x4000); + release_instruction_a_sram: + release_mem_region(0xff600000, 0x4000); + exit: + return -ENOMEM; +} + +void __exit bf561_coreb_exit(void) +{ + device_remove_file(coreb_dev.this_device, &dev_attr_coreb_status); + misc_deregister(&coreb_dev); + + release_mem_region(0xff610000, 0x4000); + release_mem_region(0xff600000, 0x4000); + release_mem_region(0xff500000, 0x8000); + release_mem_region(0xff400000, 0x8000); + + free_dma(CH_MEM_STREAM2_DEST); + free_dma(CH_MEM_STREAM2_SRC); +} + +module_init(bf561_coreb_init); +module_exit(bf561_coreb_exit); + +MODULE_AUTHOR("Bas Vermeulen "); +MODULE_DESCRIPTION("BF561 Core B Support"); diff --git a/trunk/arch/blackfin/mach-bf561/head.S b/trunk/arch/blackfin/mach-bf561/head.S new file mode 100644 index 000000000000..7bca478526b9 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf561/head.S @@ -0,0 +1,512 @@ +/* + * File: arch/blackfin/mach-bf561/head.S + * Based on: arch/blackfin/mach-bf533/head.S + * Author: + * + * Created: + * Description: BF561 startup file + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#if CONFIG_BFIN_KERNEL_CLOCK +#include +#endif + +.global __rambase +.global __ramstart +.global __ramend +.extern ___bss_stop +.extern ___bss_start +.extern _bf53x_relocate_l1_mem + +#define INITIAL_STACK 0xFFB01000 + +.text + +ENTRY(__start) +ENTRY(__stext) + /* R0: argument of command line string, passed from uboot, save it */ + R7 = R0; + /* Set the SYSCFG register */ + R0 = 0x36; + SYSCFG = R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/ + R0 = 0; + + /*Clear Out All the data and pointer Registers*/ + R1 = R0; + R2 = R0; + R3 = R0; + R4 = R0; + R5 = R0; + R6 = R0; + + P0 = R0; + P1 = R0; + P2 = R0; + P3 = R0; + P4 = R0; + P5 = R0; + + LC0 = r0; + LC1 = r0; + L0 = r0; + L1 = r0; + L2 = r0; + L3 = r0; + + /* Clear Out All the DAG Registers*/ + B0 = r0; + B1 = r0; + B2 = r0; + B3 = r0; + + I0 = r0; + I1 = r0; + I2 = r0; + I3 = r0; + + M0 = r0; + M1 = r0; + M2 = r0; + M3 = r0; + + /* Turn off the icache */ + p0.l = (IMEM_CONTROL & 0xFFFF); + p0.h = (IMEM_CONTROL >> 16); + R1 = [p0]; + R0 = ~ENICPLB; + R0 = R0 & R1; + + /* Anomaly 05000125 */ +#ifdef ANOMALY_05000125 + CLI R2; + SSYNC; +#endif + [p0] = R0; + SSYNC; +#ifdef ANOMALY_05000125 + STI R2; +#endif + + /* Turn off the dcache */ + p0.l = (DMEM_CONTROL & 0xFFFF); + p0.h = (DMEM_CONTROL >> 16); + R1 = [p0]; + R0 = ~ENDCPLB; + R0 = R0 & R1; + + /* Anomaly 05000125 */ +#ifdef ANOMALY_05000125 + CLI R2; + SSYNC; +#endif + [p0] = R0; + SSYNC; +#ifdef ANOMALY_05000125 + STI R2; +#endif + + /* Initialise UART*/ + p0.h = hi(UART_LCR); + p0.l = lo(UART_LCR); + r0 = 0x0(Z); + w[p0] = r0.L; /* To enable DLL writes */ + ssync; + + p0.h = hi(UART_DLL); + p0.l = lo(UART_DLL); + r0 = 0x0(Z); + w[p0] = r0.L; + ssync; + + p0.h = hi(UART_DLH); + p0.l = lo(UART_DLH); + r0 = 0x00(Z); + w[p0] = r0.L; + ssync; + + p0.h = hi(UART_GCTL); + p0.l = lo(UART_GCTL); + r0 = 0x0(Z); + w[p0] = r0.L; /* To enable UART clock */ + ssync; + + /* Initialize stack pointer */ + sp.l = lo(INITIAL_STACK); + sp.h = hi(INITIAL_STACK); + fp = sp; + usp = sp; + + /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */ + call _bf53x_relocate_l1_mem; +#if CONFIG_BFIN_KERNEL_CLOCK + call _start_dma_code; +#endif + + /* Code for initializing Async memory banks */ + + p2.h = hi(EBIU_AMBCTL1); + p2.l = lo(EBIU_AMBCTL1); + r0.h = hi(AMBCTL1VAL); + r0.l = lo(AMBCTL1VAL); + [p2] = r0; + ssync; + + p2.h = hi(EBIU_AMBCTL0); + p2.l = lo(EBIU_AMBCTL0); + r0.h = hi(AMBCTL0VAL); + r0.l = lo(AMBCTL0VAL); + [p2] = r0; + ssync; + + p2.h = hi(EBIU_AMGCTL); + p2.l = lo(EBIU_AMGCTL); + r0 = AMGCTLVAL; + w[p2] = r0; + ssync; + + /* This section keeps the processor in supervisor mode + * during kernel boot. Switches to user mode at end of boot. + * See page 3-9 of Hardware Reference manual for documentation. + */ + + /* EVT15 = _real_start */ + + p0.l = lo(EVT15); + p0.h = hi(EVT15); + p1.l = _real_start; + p1.h = _real_start; + [p0] = p1; + csync; + + p0.l = lo(IMASK); + p0.h = hi(IMASK); + p1.l = IMASK_IVG15; + p1.h = 0x0; + [p0] = p1; + csync; + + raise 15; + p0.l = .LWAIT_HERE; + p0.h = .LWAIT_HERE; + reti = p0; +#if defined(ANOMALY_05000281) + nop; nop; nop; +#endif + rti; + +.LWAIT_HERE: + jump .LWAIT_HERE; + +ENTRY(_real_start) + [ -- sp ] = reti; + p0.l = lo(WDOGA_CTL); + p0.h = hi(WDOGA_CTL); + r0 = 0xAD6(z); + w[p0] = r0; /* watchdog off for now */ + ssync; + + /* Code update for BSS size == 0 + * Zero out the bss region. + */ + + p1.l = ___bss_start; + p1.h = ___bss_start; + p2.l = ___bss_stop; + p2.h = ___bss_stop; + r0 = 0; + p2 -= p1; + lsetup (.L_clear_bss, .L_clear_bss ) lc0 = p2; +.L_clear_bss: + B[p1++] = r0; + + /* In case there is a NULL pointer reference + * Zero out region before stext + */ + + p1.l = 0x0; + p1.h = 0x0; + r0.l = __stext; + r0.h = __stext; + r0 = r0 >> 1; + p2 = r0; + r0 = 0; + lsetup (.L_clear_zero, .L_clear_zero ) lc0 = p2; +.L_clear_zero: + W[p1++] = r0; + +/* pass the uboot arguments to the global value command line */ + R0 = R7; + call _cmdline_init; + + p1.l = __rambase; + p1.h = __rambase; + r0.l = __sdata; + r0.h = __sdata; + [p1] = r0; + + p1.l = __ramstart; + p1.h = __ramstart; + p3.l = ___bss_stop; + p3.h = ___bss_stop; + + r1 = p3; + [p1] = r1; + + /* + * load the current thread pointer and stack + */ + r1.l = _init_thread_union; + r1.h = _init_thread_union; + + r2.l = 0x2000; + r2.h = 0x0000; + r1 = r1 + r2; + sp = r1; + usp = sp; + fp = sp; + call _start_kernel; +.L_exit: + jump.s .L_exit; + +.section .l1.text +#if CONFIG_BFIN_KERNEL_CLOCK +ENTRY(_start_dma_code) + p0.h = hi(SICA_IWR0); + p0.l = lo(SICA_IWR0); + r0.l = 0x1; + [p0] = r0; + SSYNC; + + /* + * Set PLL_CTL + * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors + * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK + * - [7] = output delay (add 200ps of delay to mem signals) + * - [6] = input delay (add 200ps of input delay to mem signals) + * - [5] = PDWN : 1=All Clocks off + * - [3] = STOPCK : 1=Core Clock off + * - [1] = PLL_OFF : 1=Disable Power to PLL + * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL + * all other bits set to zero + */ + + p0.h = hi(PLL_LOCKCNT); + p0.l = lo(PLL_LOCKCNT); + r0 = 0x300(Z); + w[p0] = r0.l; + ssync; + + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITSET (R0, 24); + [P2] = R0; + SSYNC; + + r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */ + r0 = r0 << 9; /* Shift it over, */ + r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/ + r0 = r1 | r0; + r1 = PLL_BYPASS; /* Bypass the PLL? */ + r1 = r1 << 8; /* Shift it over */ + r0 = r1 | r0; /* add them all together */ + + p0.h = hi(PLL_CTL); + p0.l = lo(PLL_CTL); /* Load the address */ + cli r2; /* Disable interrupts */ + ssync; + w[p0] = r0.l; /* Set the value */ + idle; /* Wait for the PLL to stablize */ + sti r2; /* Enable interrupts */ + +.Lcheck_again: + p0.h = hi(PLL_STAT); + p0.l = lo(PLL_STAT); + R0 = W[P0](Z); + CC = BITTST(R0,5); + if ! CC jump .Lcheck_again; + + /* Configure SCLK & CCLK Dividers */ + r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV); + p0.h = hi(PLL_DIV); + p0.l = lo(PLL_DIV); + w[p0] = r0.l; + ssync; + + p0.l = lo(EBIU_SDRRC); + p0.h = hi(EBIU_SDRRC); + r0 = mem_SDRRC; + w[p0] = r0.l; + ssync; + + p0.l = (EBIU_SDBCTL & 0xFFFF); + p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */ + r0 = mem_SDBCTL; + w[p0] = r0.l; + ssync; + + P2.H = hi(EBIU_SDGCTL); + P2.L = lo(EBIU_SDGCTL); + R0 = [P2]; + BITCLR (R0, 24); + p0.h = hi(EBIU_SDSTAT); + p0.l = lo(EBIU_SDSTAT); + r2.l = w[p0]; + cc = bittst(r2,3); + if !cc jump .Lskip; + NOP; + BITSET (R0, 23); +.Lskip: + [P2] = R0; + SSYNC; + + R0.L = lo(mem_SDGCTL); + R0.H = hi(mem_SDGCTL); + R1 = [p2]; + R1 = R1 | R0; + [P2] = R1; + SSYNC; + + RTS; +#endif /* CONFIG_BFIN_KERNEL_CLOCK */ + +ENTRY(_bfin_reset) + /* No more interrupts to be handled*/ + CLI R6; + SSYNC; + +#if defined(CONFIG_BFIN_SHARED_FLASH_ENET) + p0.h = hi(FIO_INEN); + p0.l = lo(FIO_INEN); + r0.l = ~(PF1 | PF0); + w[p0] = r0.l; + + p0.h = hi(FIO_DIR); + p0.l = lo(FIO_DIR); + r0.l = (PF1 | PF0); + w[p0] = r0.l; + + p0.h = hi(FIO_FLAG_C); + p0.l = lo(FIO_FLAG_C); + r0.l = (PF1 | PF0); + w[p0] = r0.l; +#endif + + /* Clear the bits 13-15 in SWRST if they werent cleared */ + p0.h = hi(SICA_SWRST); + p0.l = lo(SICA_SWRST); + csync; + r0.l = w[p0]; + + /* Clear the IMASK register */ + p0.h = hi(IMASK); + p0.l = lo(IMASK); + r0 = 0x0; + [p0] = r0; + + /* Clear the ILAT register */ + p0.h = hi(ILAT); + p0.l = lo(ILAT); + r0 = [p0]; + [p0] = r0; + SSYNC; + + /* Disable the WDOG TIMER */ + p0.h = hi(WDOGA_CTL); + p0.l = lo(WDOGA_CTL); + r0.l = 0xAD6; + w[p0] = r0.l; + SSYNC; + + /* Clear the sticky bit incase it is already set */ + p0.h = hi(WDOGA_CTL); + p0.l = lo(WDOGA_CTL); + r0.l = 0x8AD6; + w[p0] = r0.l; + SSYNC; + + /* Program the count value */ + R0.l = 0x100; + R0.h = 0x0; + P0.h = hi(WDOGA_CNT); + P0.l = lo(WDOGA_CNT); + [P0] = R0; + SSYNC; + + /* Program WDOG_STAT if necessary */ + P0.h = hi(WDOGA_CTL); + P0.l = lo(WDOGA_CTL); + R0 = W[P0](Z); + CC = BITTST(R0,1); + if !CC JUMP .LWRITESTAT; + CC = BITTST(R0,2); + if !CC JUMP .LWRITESTAT; + JUMP .LSKIP_WRITE; + +.LWRITESTAT: + /* When watch dog timer is enabled, + * a write to STAT will load the contents of CNT to STAT + */ + R0 = 0x0000(z); + P0.h = hi(WDOGA_STAT); + P0.l = lo(WDOGA_STAT) + [P0] = R0; + SSYNC; + +.LSKIP_WRITE: + /* Enable the reset event */ + P0.h = hi(WDOGA_CTL); + P0.l = lo(WDOGA_CTL); + R0 = W[P0](Z); + BITCLR(R0,1); + BITCLR(R0,2); + W[P0] = R0.L; + SSYNC; + NOP; + + /* Enable the wdog counter */ + R0 = W[P0](Z); + BITCLR(R0,4); + W[P0] = R0.L; + SSYNC; + + IDLE; + + RTS; + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ + +.align 4 +__rambase: +.long 0 +__ramstart: +.long 0 +__ramend: +.long 0 diff --git a/trunk/arch/blackfin/mach-bf561/ints-priority.c b/trunk/arch/blackfin/mach-bf561/ints-priority.c new file mode 100644 index 000000000000..89c52ff95b27 --- /dev/null +++ b/trunk/arch/blackfin/mach-bf561/ints-priority.c @@ -0,0 +1,108 @@ +/* + * File: arch/blackfin/mach-bf561/ints-priority.c + * Based on: arch/blackfin/mach-bf537/ints-priority.c + * Author: Michael Hennerich + * + * Created: + * Description: Set up the interupt priorities + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +void program_IAR(void) +{ + /* Program the IAR0 Register with the configured priority */ + bfin_write_SICA_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) | + ((CONFIG_IRQ_DMA1_ERROR - 7) << IRQ_DMA1_ERROR_POS) | + ((CONFIG_IRQ_DMA2_ERROR - 7) << IRQ_DMA2_ERROR_POS) | + ((CONFIG_IRQ_IMDMA_ERROR - 7) << IRQ_IMDMA_ERROR_POS) | + ((CONFIG_IRQ_PPI0_ERROR - 7) << IRQ_PPI0_ERROR_POS) | + ((CONFIG_IRQ_PPI1_ERROR - 7) << IRQ_PPI1_ERROR_POS) | + ((CONFIG_IRQ_SPORT0_ERROR - 7) << IRQ_SPORT0_ERROR_POS) | + ((CONFIG_IRQ_SPORT1_ERROR - 7) << IRQ_SPORT1_ERROR_POS)); + + bfin_write_SICA_IAR1(((CONFIG_IRQ_SPI_ERROR - 7) << IRQ_SPI_ERROR_POS) | + ((CONFIG_IRQ_UART_ERROR - 7) << IRQ_UART_ERROR_POS) | + ((CONFIG_IRQ_RESERVED_ERROR - 7) << IRQ_RESERVED_ERROR_POS) | + ((CONFIG_IRQ_DMA1_0 - 7) << IRQ_DMA1_0_POS) | + ((CONFIG_IRQ_DMA1_1 - 7) << IRQ_DMA1_1_POS) | + ((CONFIG_IRQ_DMA1_2 - 7) << IRQ_DMA1_2_POS) | + ((CONFIG_IRQ_DMA1_3 - 7) << IRQ_DMA1_3_POS) | + ((CONFIG_IRQ_DMA1_4 - 7) << IRQ_DMA1_4_POS)); + + bfin_write_SICA_IAR2(((CONFIG_IRQ_DMA1_5 - 7) << IRQ_DMA1_5_POS) | + ((CONFIG_IRQ_DMA1_6 - 7) << IRQ_DMA1_6_POS) | + ((CONFIG_IRQ_DMA1_7 - 7) << IRQ_DMA1_7_POS) | + ((CONFIG_IRQ_DMA1_8 - 7) << IRQ_DMA1_8_POS) | + ((CONFIG_IRQ_DMA1_9 - 7) << IRQ_DMA1_9_POS) | + ((CONFIG_IRQ_DMA1_10 - 7) << IRQ_DMA1_10_POS) | + ((CONFIG_IRQ_DMA1_11 - 7) << IRQ_DMA1_11_POS) | + ((CONFIG_IRQ_DMA2_0 - 7) << IRQ_DMA2_0_POS)); + + bfin_write_SICA_IAR3(((CONFIG_IRQ_DMA2_1 - 7) << IRQ_DMA2_1_POS) | + ((CONFIG_IRQ_DMA2_2 - 7) << IRQ_DMA2_2_POS) | + ((CONFIG_IRQ_DMA2_3 - 7) << IRQ_DMA2_3_POS) | + ((CONFIG_IRQ_DMA2_4 - 7) << IRQ_DMA2_4_POS) | + ((CONFIG_IRQ_DMA2_5 - 7) << IRQ_DMA2_5_POS) | + ((CONFIG_IRQ_DMA2_6 - 7) << IRQ_DMA2_6_POS) | + ((CONFIG_IRQ_DMA2_7 - 7) << IRQ_DMA2_7_POS) | + ((CONFIG_IRQ_DMA2_8 - 7) << IRQ_DMA2_8_POS)); + + bfin_write_SICA_IAR4(((CONFIG_IRQ_DMA2_9 - 7) << IRQ_DMA2_9_POS) | + ((CONFIG_IRQ_DMA2_10 - 7) << IRQ_DMA2_10_POS) | + ((CONFIG_IRQ_DMA2_11 - 7) << IRQ_DMA2_11_POS) | + ((CONFIG_IRQ_TIMER0 - 7) << IRQ_TIMER0_POS) | + ((CONFIG_IRQ_TIMER1 - 7) << IRQ_TIMER1_POS) | + ((CONFIG_IRQ_TIMER2 - 7) << IRQ_TIMER2_POS) | + ((CONFIG_IRQ_TIMER3 - 7) << IRQ_TIMER3_POS) | + ((CONFIG_IRQ_TIMER4 - 7) << IRQ_TIMER4_POS)); + + bfin_write_SICA_IAR5(((CONFIG_IRQ_TIMER5 - 7) << IRQ_TIMER5_POS) | + ((CONFIG_IRQ_TIMER6 - 7) << IRQ_TIMER6_POS) | + ((CONFIG_IRQ_TIMER7 - 7) << IRQ_TIMER7_POS) | + ((CONFIG_IRQ_TIMER8 - 7) << IRQ_TIMER8_POS) | + ((CONFIG_IRQ_TIMER9 - 7) << IRQ_TIMER9_POS) | + ((CONFIG_IRQ_TIMER10 - 7) << IRQ_TIMER10_POS) | + ((CONFIG_IRQ_TIMER11 - 7) << IRQ_TIMER11_POS) | + ((CONFIG_IRQ_PROG0_INTA - 7) << IRQ_PROG0_INTA_POS)); + + bfin_write_SICA_IAR6(((CONFIG_IRQ_PROG0_INTB - 7) << IRQ_PROG0_INTB_POS) | + ((CONFIG_IRQ_PROG1_INTA - 7) << IRQ_PROG1_INTA_POS) | + ((CONFIG_IRQ_PROG1_INTB - 7) << IRQ_PROG1_INTB_POS) | + ((CONFIG_IRQ_PROG2_INTA - 7) << IRQ_PROG2_INTA_POS) | + ((CONFIG_IRQ_PROG2_INTB - 7) << IRQ_PROG2_INTB_POS) | + ((CONFIG_IRQ_DMA1_WRRD0 - 7) << IRQ_DMA1_WRRD0_POS) | + ((CONFIG_IRQ_DMA1_WRRD1 - 7) << IRQ_DMA1_WRRD1_POS) | + ((CONFIG_IRQ_DMA2_WRRD0 - 7) << IRQ_DMA2_WRRD0_POS)); + + bfin_write_SICA_IAR7(((CONFIG_IRQ_DMA2_WRRD1 - 7) << IRQ_DMA2_WRRD1_POS) | + ((CONFIG_IRQ_IMDMA_WRRD0 - 7) << IRQ_IMDMA_WRRD0_POS) | + ((CONFIG_IRQ_IMDMA_WRRD1 - 7) << IRQ_IMDMA_WRRD1_POS) | + ((CONFIG_IRQ_WDTIMER - 7) << IRQ_WDTIMER_POS) | + (0 << IRQ_RESERVED_1_POS) | (0 << IRQ_RESERVED_2_POS) | + (0 << IRQ_SUPPLE_0_POS) | (0 << IRQ_SUPPLE_1_POS)); + + SSYNC(); +} diff --git a/trunk/arch/blackfin/mach-common/Makefile b/trunk/arch/blackfin/mach-common/Makefile new file mode 100644 index 000000000000..d3a49073d196 --- /dev/null +++ b/trunk/arch/blackfin/mach-common/Makefile @@ -0,0 +1,12 @@ +# +# arch/blackfin/mach-common/Makefile +# + +obj-y := \ + cache.o cacheinit.o cplbhdlr.o cplbmgr.o entry.o \ + interrupt.o lock.o dpmc.o irqpanic.o + +obj-$(CONFIG_CPLB_INFO) += cplbinfo.o +obj-$(CONFIG_BFIN_SINGLE_CORE) += ints-priority-sc.o +obj-$(CONFIG_BFIN_DUAL_CORE) += ints-priority-dc.o +obj-$(CONFIG_PM) += pm.o diff --git a/trunk/arch/blackfin/mach-common/cache.S b/trunk/arch/blackfin/mach-common/cache.S new file mode 100644 index 000000000000..bb9446ef66ef --- /dev/null +++ b/trunk/arch/blackfin/mach-common/cache.S @@ -0,0 +1,253 @@ +/* + * File: arch/blackfin/mach-common/cache.S + * Based on: + * Author: LG Soft India + * + * Created: + * Description: cache control support + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +.text +.align 2 +ENTRY(_cache_invalidate) + + /* + * Icache or DcacheA or DcacheB Invalidation + * or any combination thereof + * R0 has bits + * CPLB_ENABLE_ICACHE_P,CPLB_ENABLE_DCACHE_P,CPLB_ENABLE_DCACHE2_P + * set as required + */ + [--SP] = R7; + + R7 = R0; + CC = BITTST(R7,CPLB_ENABLE_ICACHE_P); + IF !CC JUMP .Lno_icache; + [--SP] = RETS; + CALL _icache_invalidate; + RETS = [SP++]; +.Lno_icache: + CC = BITTST(R7,CPLB_ENABLE_DCACHE_P); + IF !CC JUMP .Lno_dcache_a; + R0 = 0; /* specifies bank A */ + [--SP] = RETS; + CALL _dcache_invalidate; + RETS = [SP++]; +.Lno_dcache_a: + CC = BITTST(R7,CPLB_ENABLE_DCACHE2_P); + IF !CC JUMP .Lno_dcache_b; + R0 = 0; + BITSET(R0, 23); /* specifies bank B */ + [--SP] = RETS; + CALL _dcache_invalidate; + RETS = [SP++]; +.Lno_dcache_b: + R7 = [SP++]; + RTS; + +/* Invalidate the Entire Instruction cache by + * disabling IMC bit + */ +ENTRY(_icache_invalidate) +ENTRY(_invalidate_entire_icache) + [--SP] = ( R7:5); + + P0.L = (IMEM_CONTROL & 0xFFFF); + P0.H = (IMEM_CONTROL >> 16); + R7 = [P0]; + + /* Clear the IMC bit , All valid bits in the instruction + * cache are set to the invalid state + */ + BITCLR(R7,IMC_P); + CLI R6; + SSYNC; /* SSYNC required before invalidating cache. */ + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + /* Configures the instruction cache agian */ + R6 = (IMC | ENICPLB); + R7 = R7 | R6; + + CLI R6; + SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + ( R7:5) = [SP++]; + RTS; + +/* + * blackfin_cache_flush_range(start, end) + * Invalidate all cache lines assocoiated with this + * area of memory. + * + * start: Start address + * end: End address + */ +ENTRY(_blackfin_icache_flush_range) + R2 = -L1_CACHE_BYTES; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; + IFLUSH [P0]; +1: + IFLUSH [P0++]; + CC = P0 < P1 (iu); + IF CC JUMP 1b (bp); + IFLUSH [P0]; + SSYNC; + RTS; + +/* + * blackfin_icache_dcache_flush_range(start, end) + * FLUSH all cache lines assocoiated with this + * area of memory. + * + * start: Start address + * end: End address + */ + +ENTRY(_blackfin_icache_dcache_flush_range) + R2 = -L1_CACHE_BYTES; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; + IFLUSH [P0]; +1: + FLUSH [P0]; + IFLUSH [P0++]; + CC = P0 < P1 (iu); + IF CC JUMP 1b (bp); + IFLUSH [P0]; + FLUSH [P0]; + SSYNC; + RTS; + +/* Throw away all D-cached data in specified region without any obligation to + * write them back. However, we must clean the D-cached entries around the + * boundaries of the start and/or end address is not cache aligned. + * + * Start: start address, + * end : end address. + */ + +ENTRY(_blackfin_dcache_invalidate_range) + R2 = -L1_CACHE_BYTES; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; + FLUSHINV[P0]; +1: + FLUSHINV[P0++]; + CC = P0 < P1 (iu); + IF CC JUMP 1b (bp); + + /* If the data crosses a cache line, then we'll be pointing to + * the last cache line, but won't have flushed/invalidated it yet, + * so do one more. + */ + FLUSHINV[P0]; + SSYNC; + RTS; + +/* Invalidate the Entire Data cache by + * clearing DMC[1:0] bits + */ +ENTRY(_invalidate_entire_dcache) +ENTRY(_dcache_invalidate) + [--SP] = ( R7:6); + + P0.L = (DMEM_CONTROL & 0xFFFF); + P0.H = (DMEM_CONTROL >> 16); + R7 = [P0]; + + /* Clear the DMC[1:0] bits, All valid bits in the data + * cache are set to the invalid state + */ + BITCLR(R7,DMC0_P); + BITCLR(R7,DMC1_P); + CLI R6; + SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + /* Configures the data cache again */ + + R6 = DMEM_CNTR; + R7 = R7 | R6; + + CLI R6; + SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + ( R7:6) = [SP++]; + RTS; + +ENTRY(_blackfin_dcache_flush_range) + R2 = -L1_CACHE_BYTES; + R2 = R0 & R2; + P0 = R2; + P1 = R1; + CSYNC; + FLUSH[P0]; +1: + FLUSH[P0++]; + CC = P0 < P1 (iu); + IF CC JUMP 1b (bp); + + /* If the data crosses a cache line, then we'll be pointing to + * the last cache line, but won't have flushed it yet, so do + * one more. + */ + FLUSH[P0]; + SSYNC; + RTS; + +ENTRY(_blackfin_dflush_page) + P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT); + P0 = R0; + CSYNC; + FLUSH[P0]; + LSETUP (.Lfl1, .Lfl1) LC0 = P1; +.Lfl1: FLUSH [P0++]; + SSYNC; + RTS; diff --git a/trunk/arch/blackfin/mach-common/cacheinit.S b/trunk/arch/blackfin/mach-common/cacheinit.S new file mode 100644 index 000000000000..8c17f099e5eb --- /dev/null +++ b/trunk/arch/blackfin/mach-common/cacheinit.S @@ -0,0 +1,137 @@ +/* + * File: arch/blackfin/mach-common/cacheinit.S + * Based on: + * Author: LG Soft India + * + * Created: ? + * Description: cache initialization + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This function sets up the data and instruction cache. The + * tables like icplb table, dcplb table and Page Descriptor table + * are defined in cplbtab.h. You can configure those tables for + * your suitable requirements + */ + +#include +#include + +.text + +#if defined(CONFIG_BLKFIN_CACHE) +ENTRY(_bfin_icache_init) + + /* Initialize Instruction CPLBS */ + + I0.L = (ICPLB_ADDR0 & 0xFFFF); + I0.H = (ICPLB_ADDR0 >> 16); + + I1.L = (ICPLB_DATA0 & 0xFFFF); + I1.H = (ICPLB_DATA0 >> 16); + + I2.L = _icplb_table; + I2.H = _icplb_table; + + r1 = -1; /* end point comparison */ + r3 = 15; /* max counter */ + +/* read entries from table */ + +.Lread_iaddr: + R0 = [I2++]; + CC = R0 == R1; + IF CC JUMP .Lidone; + [I0++] = R0; + +.Lread_idata: + R2 = [I2++]; + [I1++] = R2; + R3 = R3 + R1; + CC = R3 == R1; + IF !CC JUMP .Lread_iaddr; + +.Lidone: + /* Enable Instruction Cache */ + P0.l = (IMEM_CONTROL & 0xFFFF); + P0.h = (IMEM_CONTROL >> 16); + R1 = [P0]; + R0 = (IMC | ENICPLB); + R0 = R0 | R1; + + /* Anomaly 05000125 */ + CLI R2; + SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ + .align 8; + [P0] = R0; + SSYNC; + STI R2; + RTS; +#endif + +#if defined(CONFIG_BLKFIN_DCACHE) +ENTRY(_bfin_dcache_init) + + /* Initialize Data CPLBS */ + + I0.L = (DCPLB_ADDR0 & 0xFFFF); + I0.H = (DCPLB_ADDR0 >> 16); + + I1.L = (DCPLB_DATA0 & 0xFFFF); + I1.H = (DCPLB_DATA0 >> 16); + + I2.L = _dcplb_table; + I2.H = _dcplb_table; + + R1 = -1; /* end point comparison */ + R3 = 15; /* max counter */ + + /* read entries from table */ +.Lread_daddr: + R0 = [I2++]; + cc = R0 == R1; + IF CC JUMP .Lddone; + [I0++] = R0; + +.Lread_ddata: + R2 = [I2++]; + [I1++] = R2; + R3 = R3 + R1; + CC = R3 == R1; + IF !CC JUMP .Lread_daddr; +.Lddone: + P0.L = (DMEM_CONTROL & 0xFFFF); + P0.H = (DMEM_CONTROL >> 16); + R1 = [P0]; + + R0 = DMEM_CNTR; + + R0 = R0 | R1; + /* Anomaly 05000125 */ + CLI R2; + SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ + .align 8; + [P0] = R0; + SSYNC; + STI R2; + RTS; +#endif diff --git a/trunk/arch/blackfin/mach-common/cplbhdlr.S b/trunk/arch/blackfin/mach-common/cplbhdlr.S new file mode 100644 index 000000000000..b979067c49ef --- /dev/null +++ b/trunk/arch/blackfin/mach-common/cplbhdlr.S @@ -0,0 +1,130 @@ +/* + * File: arch/blackfin/mach-common/cplbhdlr.S + * Based on: + * Author: LG Soft India + * + * Created: ? + * Description: CPLB exception handler + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#ifdef CONFIG_EXCPT_IRQ_SYSC_L1 +.section .l1.text +#else +.text +#endif + +.type _cplb_mgr, STT_FUNC; +.type _panic_cplb_error, STT_FUNC; + +.align 2 + +.global __cplb_hdr; +.type __cplb_hdr, STT_FUNC; +ENTRY(__cplb_hdr) + R2 = SEQSTAT; + + /* Mask the contents of SEQSTAT and leave only EXCAUSE in R2 */ + R2 <<= 26; + R2 >>= 26; + + R1 = 0x23; /* Data access CPLB protection violation */ + CC = R2 == R1; + IF !CC JUMP .Lnot_data_write; + R0 = 2; /* is a write to data space*/ + JUMP .Lis_icplb_miss; + +.Lnot_data_write: + R1 = 0x2C; /* CPLB miss on an instruction fetch */ + CC = R2 == R1; + R0 = 0; /* is_data_miss == False*/ + IF CC JUMP .Lis_icplb_miss; + + R1 = 0x26; + CC = R2 == R1; + IF !CC JUMP .Lunknown; + + R0 = 1; /* is_data_miss == True*/ + +.Lis_icplb_miss: + +#if defined(CONFIG_BLKFIN_CACHE) || defined(CONFIG_BLKFIN_DCACHE) +# if defined(CONFIG_BLKFIN_CACHE) && !defined(CONFIG_BLKFIN_DCACHE) + R1 = CPLB_ENABLE_ICACHE; +# endif +# if !defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE) + R1 = CPLB_ENABLE_DCACHE; +# endif +# if defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE) + R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE; +# endif +#else + R1 = 0; +#endif + + [--SP] = RETS; + CALL _cplb_mgr; + RETS = [SP++]; + CC = R0 == 0; + IF !CC JUMP .Lnot_replaced; + RTS; + +/* + * Diagnostic exception handlers + */ +.Lunknown: + R0 = CPLB_UNKNOWN_ERR; + JUMP .Lcplb_error; + +.Lnot_replaced: + CC = R0 == CPLB_NO_UNLOCKED; + IF !CC JUMP .Lnext_check; + R0 = CPLB_NO_UNLOCKED; + JUMP .Lcplb_error; + +.Lnext_check: + CC = R0 == CPLB_NO_ADDR_MATCH; + IF !CC JUMP .Lnext_check2; + R0 = CPLB_NO_ADDR_MATCH; + JUMP .Lcplb_error; + +.Lnext_check2: + CC = R0 == CPLB_PROT_VIOL; + IF !CC JUMP .Lstrange_return_from_cplb_mgr; + R0 = CPLB_PROT_VIOL; + JUMP .Lcplb_error; + +.Lstrange_return_from_cplb_mgr: + IDLE; + CSYNC; + JUMP .Lstrange_return_from_cplb_mgr; + +.Lcplb_error: + R1 = sp; + SP += -12; + call _panic_cplb_error; + SP += 12; + JUMP _handle_bad_cplb; diff --git a/trunk/arch/blackfin/mach-common/cplbinfo.c b/trunk/arch/blackfin/mach-common/cplbinfo.c new file mode 100644 index 000000000000..d65fac39d1bf --- /dev/null +++ b/trunk/arch/blackfin/mach-common/cplbinfo.c @@ -0,0 +1,211 @@ +/* + * File: arch/blackfin/mach-common/cplbinfo.c + * Based on: + * Author: Sonic Zhang + * + * Created: Jan. 2005 + * Description: Display CPLB status + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define CPLB_I 1 +#define CPLB_D 2 + +#define SYNC_SYS SSYNC() +#define SYNC_CORE CSYNC() + +#define CPLB_BIT_PAGESIZE 0x30000 + +static int page_size_table[4] = { + 0x00000400, /* 1K */ + 0x00001000, /* 4K */ + 0x00100000, /* 1M */ + 0x00400000 /* 4M */ +}; + +static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" }; + +static int cplb_find_entry(unsigned long *cplb_addr, + unsigned long *cplb_data, unsigned long addr, + unsigned long data) +{ + int ii; + + for (ii = 0; ii < 16; ii++) + if (addr >= cplb_addr[ii] && addr < cplb_addr[ii] + + page_size_table[(cplb_data[ii] & CPLB_BIT_PAGESIZE) >> 16] + && (cplb_data[ii] == data)) + return ii; + + return -1; +} + +static char *cplb_print_entry(char *buf, int type) +{ + unsigned long *p_addr = dpdt_table; + unsigned long *p_data = dpdt_table + 1; + unsigned long *p_icount = dpdt_swapcount_table; + unsigned long *p_ocount = dpdt_swapcount_table + 1; + unsigned long *cplb_addr = (unsigned long *)DCPLB_ADDR0; + unsigned long *cplb_data = (unsigned long *)DCPLB_DATA0; + int entry = 0, used_cplb = 0; + + if (type == CPLB_I) { + buf += sprintf(buf, "Instrction CPLB entry:\n"); + p_addr = ipdt_table; + p_data = ipdt_table + 1; + p_icount = ipdt_swapcount_table; + p_ocount = ipdt_swapcount_table + 1; + cplb_addr = (unsigned long *)ICPLB_ADDR0; + cplb_data = (unsigned long *)ICPLB_DATA0; + } else + buf += sprintf(buf, "Data CPLB entry:\n"); + + buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\ +\tiCount\toCount\n"); + + while (*p_addr != 0xffffffff) { + entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data); + if (entry >= 0) + used_cplb |= 1 << entry; + + buf += + sprintf(buf, + "0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n", + *p_addr, *p_data, + page_size_string_table[(*p_data & 0x30000) >> 16], + (*p_data & CPLB_VALID) ? 'Y' : 'N', + (*p_data & CPLB_LOCK) ? 'Y' : 'N', entry, *p_icount, + *p_ocount); + + p_addr += 2; + p_data += 2; + p_icount += 2; + p_ocount += 2; + } + + if (used_cplb != 0xffff) { + buf += sprintf(buf, "Unused/mismatched CPLBs:\n"); + + for (entry = 0; entry < 16; entry++) + if (0 == ((1 << entry) & used_cplb)) { + int flags = cplb_data[entry]; + buf += + sprintf(buf, + "%2d: 0x%08lx\t0x%05x\t%s\t%c\t%c\n", + entry, cplb_addr[entry], flags, + page_size_string_table[(flags & + 0x30000) >> + 16], + (flags & CPLB_VALID) ? 'Y' : 'N', + (flags & CPLB_LOCK) ? 'Y' : 'N'); + } + } + + buf += sprintf(buf, "\n"); + + return buf; +} + +static int cplbinfo_proc_output(char *buf) +{ + char *p; + + p = buf; + + p += sprintf(p, + "------------------ CPLB Information ------------------\n\n"); + + if (bfin_read_IMEM_CONTROL() & ENICPLB) + p = cplb_print_entry(p, CPLB_I); + else + p += sprintf(p, "Instruction CPLB is disabled.\n\n"); + + if (bfin_read_DMEM_CONTROL() & ENDCPLB) + p = cplb_print_entry(p, CPLB_D); + else + p += sprintf(p, "Data CPLB is disabled.\n"); + + return p - buf; +} + +static int cplbinfo_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = cplbinfo_proc_output(page); + if (len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; +} + +static int cplbinfo_write_proc(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + printk(KERN_INFO "Reset the CPLB swap in/out counts.\n"); + memset(ipdt_swapcount_table, 0, MAX_SWITCH_I_CPLBS * sizeof(unsigned long)); + memset(dpdt_swapcount_table, 0, MAX_SWITCH_D_CPLBS * sizeof(unsigned long)); + + return count; +} + +static int __init cplbinfo_init(void) +{ + struct proc_dir_entry *entry; + + if ((entry = create_proc_entry("cplbinfo", 0, NULL)) == NULL) { + return -ENOMEM; + } + + entry->read_proc = cplbinfo_read_proc; + entry->write_proc = cplbinfo_write_proc; + entry->data = NULL; + + return 0; +} + +static void __exit cplbinfo_exit(void) +{ + remove_proc_entry("cplbinfo", NULL); +} + +module_init(cplbinfo_init); +module_exit(cplbinfo_exit); diff --git a/trunk/arch/blackfin/mach-common/cplbmgr.S b/trunk/arch/blackfin/mach-common/cplbmgr.S new file mode 100644 index 000000000000..f5efc4bc65e6 --- /dev/null +++ b/trunk/arch/blackfin/mach-common/cplbmgr.S @@ -0,0 +1,607 @@ +/* + * File: arch/blackfin/mach-common/cplbmgtr.S + * Based on: + * Author: LG Soft India + * + * Created: ? + * Description: CPLB replacement routine for CPLB mismatch + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Usage: int _cplb_mgr(is_data_miss,int enable_cache) + * is_data_miss==2 => Mark as Dirty, write to the clean data page + * is_data_miss==1 => Replace a data CPLB. + * is_data_miss==0 => Replace an instruction CPLB. + * + * Returns: + * CPLB_RELOADED => Successfully updated CPLB table. + * CPLB_NO_UNLOCKED => All CPLBs are locked, so cannot be evicted. + * This indicates that the CPLBs in the configuration + * tablei are badly configured, as this should never + * occur. + * CPLB_NO_ADDR_MATCH => The address being accessed, that triggered the + * exception, is not covered by any of the CPLBs in + * the configuration table. The application is + * presumably misbehaving. + * CPLB_PROT_VIOL => The address being accessed, that triggered the + * exception, was not a first-write to a clean Write + * Back Data page, and so presumably is a genuine + * violation of the page's protection attributes. + * The application is misbehaving. + */ + +#include +#include +#include + +#ifdef CONFIG_EXCPT_IRQ_SYSC_L1 +.section .l1.text +#else +.text +#endif + +.align 2; +ENTRY(_cplb_mgr) + + [--SP]=( R7:4,P5:3 ); + + CC = R0 == 2; + IF CC JUMP .Ldcplb_write; + + CC = R0 == 0; + IF !CC JUMP .Ldcplb_miss_compare; + + /* ICPLB Miss Exception. We need to choose one of the + * currently-installed CPLBs, and replace it with one + * from the configuration table. + */ + + P4.L = (ICPLB_FAULT_ADDR & 0xFFFF); + P4.H = (ICPLB_FAULT_ADDR >> 16); + + P1 = 16; + P5.L = _page_size_table; + P5.H = _page_size_table; + + P0.L = (ICPLB_DATA0 & 0xFFFF); + P0.H = (ICPLB_DATA0 >> 16); + R4 = [P4]; /* Get faulting address*/ + R6 = 64; /* Advance past the fault address, which*/ + R6 = R6 + R4; /* we'll use if we find a match*/ + R3 = ((16 << 8) | 2); /* Extract mask, bits 16 and 17.*/ + + R5 = 0; +.Lisearch: + + R1 = [P0-0x100]; /* Address for this CPLB */ + + R0 = [P0++]; /* Info for this CPLB*/ + CC = BITTST(R0,0); /* Is the CPLB valid?*/ + IF !CC JUMP .Lnomatch; /* Skip it, if not.*/ + CC = R4 < R1(IU); /* If fault address less than page start*/ + IF CC JUMP .Lnomatch; /* then skip this one.*/ + R2 = EXTRACT(R0,R3.L) (Z); /* Get page size*/ + P1 = R2; + P1 = P5 + (P1<<2); /* index into page-size table*/ + R2 = [P1]; /* Get the page size*/ + R1 = R1 + R2; /* and add to page start, to get page end*/ + CC = R4 < R1(IU); /* and see whether fault addr is in page.*/ + IF !CC R4 = R6; /* If so, advance the address and finish loop.*/ + IF !CC JUMP .Lisearch_done; +.Lnomatch: + /* Go around again*/ + R5 += 1; + CC = BITTST(R5, 4); /* i.e CC = R5 >= 16*/ + IF !CC JUMP .Lisearch; + +.Lisearch_done: + I0 = R4; /* Fault address we'll search for*/ + + /* set up pointers */ + P0.L = (ICPLB_DATA0 & 0xFFFF); + P0.H = (ICPLB_DATA0 >> 16); + + /* The replacement procedure for ICPLBs */ + + P4.L = (IMEM_CONTROL & 0xFFFF); + P4.H = (IMEM_CONTROL >> 16); + + /* disable cplbs */ + R5 = [P4]; /* Control Register*/ + BITCLR(R5,ENICPLB_P); + CLI R1; + SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ + .align 8; + [P4] = R5; + SSYNC; + STI R1; + + R1 = -1; /* end point comparison */ + R3 = 16; /* counter */ + + /* Search through CPLBs for first non-locked entry */ + /* Overwrite it by moving everyone else up by 1 */ +.Licheck_lock: + R0 = [P0++]; + R3 = R3 + R1; + CC = R3 == R1; + IF CC JUMP .Lall_locked; + CC = BITTST(R0, 0); /* an invalid entry is good */ + IF !CC JUMP .Lifound_victim; + CC = BITTST(R0,1); /* but a locked entry isn't */ + IF CC JUMP .Licheck_lock; + +.Lifound_victim: +#ifdef CONFIG_CPLB_INFO + R7 = [P0 - 0x104]; + P2.L = _ipdt_table; + P2.H = _ipdt_table; + P3.L = _ipdt_swapcount_table; + P3.H = _ipdt_swapcount_table; + P3 += -4; +.Licount: + R2 = [P2]; /* address from config table */ + P2 += 8; + P3 += 8; + CC = R2==-1; + IF CC JUMP .Licount_done; + CC = R7==R2; + IF !CC JUMP .Licount; + R7 = [P3]; + R7 += 1; + [P3] = R7; + CSYNC; +.Licount_done: +#endif + LC0=R3; + LSETUP(.Lis_move,.Lie_move) LC0; +.Lis_move: + R0 = [P0]; + [P0 - 4] = R0; + R0 = [P0 - 0x100]; + [P0-0x104] = R0; +.Lie_move:P0+=4; + + /* We've made space in the ICPLB table, so that ICPLB15 + * is now free to be overwritten. Next, we have to determine + * which CPLB we need to install, from the configuration + * table. This is a matter of getting the start-of-page + * addresses and page-lengths from the config table, and + * determining whether the fault address falls within that + * range. + */ + + P2.L = _ipdt_table; + P2.H = _ipdt_table; +#ifdef CONFIG_CPLB_INFO + P3.L = _ipdt_swapcount_table; + P3.H = _ipdt_swapcount_table; + P3 += -8; +#endif + P0.L = _page_size_table; + P0.H = _page_size_table; + + /* Retrieve our fault address (which may have been advanced + * because the faulting instruction crossed a page boundary). + */ + + R0 = I0; + + /* An extraction pattern, to get the page-size bits from + * the CPLB data entry. Bits 16-17, so two bits at posn 16. + */ + + R1 = ((16<<8)|2); +.Linext: R4 = [P2++]; /* address from config table */ + R2 = [P2++]; /* data from config table */ +#ifdef CONFIG_CPLB_INFO + P3 += 8; +#endif + + CC = R4 == -1; /* End of config table*/ + IF CC JUMP .Lno_page_in_table; + + /* See if failed address > start address */ + CC = R4 <= R0(IU); + IF !CC JUMP .Linext; + + /* extract page size (17:16)*/ + R3 = EXTRACT(R2, R1.L) (Z); + + /* add page size to addr to get range */ + + P5 = R3; + P5 = P0 + (P5 << 2); /* scaled, for int access*/ + R3 = [P5]; + R3 = R3 + R4; + + /* See if failed address < (start address + page size) */ + CC = R0 < R3(IU); + IF !CC JUMP .Linext; + + /* We've found a CPLB in the config table that covers + * the faulting address, so install this CPLB into the + * last entry of the table. + */ + + P1.L = (ICPLB_DATA15 & 0xFFFF); /* ICPLB_DATA15 */ + P1.H = (ICPLB_DATA15 >> 16); + [P1] = R2; + [P1-0x100] = R4; +#ifdef CONFIG_CPLB_INFO + R3 = [P3]; + R3 += 1; + [P3] = R3; +#endif + + /* P4 points to IMEM_CONTROL, and R5 contains its old + * value, after we disabled ICPLBS. Re-enable them. + */ + + BITSET(R5,ENICPLB_P); + CLI R2; + SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ + .align 8; + [P4] = R5; + SSYNC; + STI R2; + + ( R7:4,P5:3 ) = [SP++]; + R0 = CPLB_RELOADED; + RTS; + +/* FAILED CASES*/ +.Lno_page_in_table: + ( R7:4,P5:3 ) = [SP++]; + R0 = CPLB_NO_ADDR_MATCH; + RTS; +.Lall_locked: + ( R7:4,P5:3 ) = [SP++]; + R0 = CPLB_NO_UNLOCKED; + RTS; +.Lprot_violation: + ( R7:4,P5:3 ) = [SP++]; + R0 = CPLB_PROT_VIOL; + RTS; + +.Ldcplb_write: + + /* if a DCPLB is marked as write-back (CPLB_WT==0), and + * it is clean (CPLB_DIRTY==0), then a write to the + * CPLB's page triggers a protection violation. We have to + * mark the CPLB as dirty, to indicate that there are + * pending writes associated with the CPLB. + */ + + P4.L = (DCPLB_STATUS & 0xFFFF); + P4.H = (DCPLB_STATUS >> 16); + P3.L = (DCPLB_DATA0 & 0xFFFF); + P3.H = (DCPLB_DATA0 >> 16); + R5 = [P4]; + + /* A protection violation can be caused by more than just writes + * to a clean WB page, so we have to ensure that: + * - It's a write + * - to a clean WB page + * - and is allowed in the mode the access occurred. + */ + + CC = BITTST(R5, 16); /* ensure it was a write*/ + IF !CC JUMP .Lprot_violation; + + /* to check the rest, we have to retrieve the DCPLB.*/ + + /* The low half of DCPLB_STATUS is a bit mask*/ + + R2 = R5.L (Z); /* indicating which CPLB triggered the event.*/ + R3 = 30; /* so we can use this to determine the offset*/ + R2.L = SIGNBITS R2; + R2 = R2.L (Z); /* into the DCPLB table.*/ + R3 = R3 - R2; + P4 = R3; + P3 = P3 + (P4<<2); + R3 = [P3]; /* Retrieve the CPLB*/ + + /* Now we can check whether it's a clean WB page*/ + + CC = BITTST(R3, 14); /* 0==WB, 1==WT*/ + IF CC JUMP .Lprot_violation; + CC = BITTST(R3, 7); /* 0 == clean, 1 == dirty*/ + IF CC JUMP .Lprot_violation; + + /* Check whether the write is allowed in the mode that was active.*/ + + R2 = 1<<3; /* checking write in user mode*/ + CC = BITTST(R5, 17); /* 0==was user, 1==was super*/ + R5 = CC; + R2 <<= R5; /* if was super, check write in super mode*/ + R2 = R3 & R2; + CC = R2 == 0; + IF CC JUMP .Lprot_violation; + + /* It's a genuine write-to-clean-page.*/ + + BITSET(R3, 7); /* mark as dirty*/ + [P3] = R3; /* and write back.*/ + NOP; + CSYNC; + ( R7:4,P5:3 ) = [SP++]; + R0 = CPLB_RELOADED; + RTS; + +.Ldcplb_miss_compare: + + /* Data CPLB Miss event. We need to choose a CPLB to + * evict, and then locate a new CPLB to install from the + * config table, that covers the faulting address. + */ + + P1.L = (DCPLB_DATA15 & 0xFFFF); + P1.H = (DCPLB_DATA15 >> 16); + + P4.L = (DCPLB_FAULT_ADDR & 0xFFFF); + P4.H = (DCPLB_FAULT_ADDR >> 16); + R4 = [P4]; + I0 = R4; + + /* The replacement procedure for DCPLBs*/ + + R6 = R1; /* Save for later*/ + + /* Turn off CPLBs while we work.*/ + P4.L = (DMEM_CONTROL & 0xFFFF); + P4.H = (DMEM_CONTROL >> 16); + R5 = [P4]; + BITCLR(R5,ENDCPLB_P); + CLI R0; + SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ + .align 8; + [P4] = R5; + SSYNC; + STI R0; + + /* Start looking for a CPLB to evict. Our order of preference + * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs + * are no good. + */ + + I1.L = (DCPLB_DATA0 & 0xFFFF); + I1.H = (DCPLB_DATA0 >> 16); + P1 = 2; + P2 = 16; + I2.L = _dcplb_preference; + I2.H = _dcplb_preference; + LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1; +.Lsdsearch1: + R0 = [I2++]; /* Get the bits we're interested in*/ + P0 = I1; /* Go back to start of table*/ + LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2; +.Lsdsearch2: + R1 = [P0++]; /* Fetch each installed CPLB in turn*/ + R2 = R1 & R0; /* and test for interesting bits.*/ + CC = R2 == 0; /* If none are set, it'll do.*/ + IF !CC JUMP .Lskip_stack_check; + + R2 = [P0 - 0x104]; /* R2 - PageStart */ + P3.L = _page_size_table; /* retrieve end address */ + P3.H = _page_size_table; /* retrieve end address */ + R3 = 0x1002; /* 16th - position, 2 bits -length */ +#ifdef ANOMALY_05000209 + nop; /* Anomaly 05000209 */ +#endif + R7 = EXTRACT(R1,R3.l); + R7 = R7 << 2; /* Page size index offset */ + P5 = R7; + P3 = P3 + P5; + R7 = [P3]; /* page size in bytes */ + + R7 = R2 + R7; /* R7 - PageEnd */ + R4 = SP; /* Test SP is in range */ + + CC = R7 < R4; /* if PageEnd < SP */ + IF CC JUMP .Ldfound_victim; + R3 = 0x284; /* stack length from start of trap till + * the point. + * 20 stack locations for future modifications + */ + R4 = R4 + R3; + CC = R4 < R2; /* if SP + stacklen < PageStart */ + IF CC JUMP .Ldfound_victim; +.Lskip_stack_check: + +.Ledsearch2: NOP; +.Ledsearch1: NOP; + + /* If we got here, we didn't find a DCPLB we considered + * replacable, which means all of them were locked. + */ + + JUMP .Lall_locked; +.Ldfound_victim: + +#ifdef CONFIG_CPLB_INFO + R7 = [P0 - 0x104]; + P2.L = _dpdt_table; + P2.H = _dpdt_table; + P3.L = _dpdt_swapcount_table; + P3.H = _dpdt_swapcount_table; + P3 += -4; +.Ldicount: + R2 = [P2]; + P2 += 8; + P3 += 8; + CC = R2==-1; + IF CC JUMP .Ldicount_done; + CC = R7==R2; + IF !CC JUMP .Ldicount; + R7 = [P3]; + R7 += 1; + [P3] = R7; +.Ldicount_done: +#endif + + /* Clean down the hardware loops*/ + R2 = 0; + LC1 = R2; + LC0 = R2; + + /* There's a suitable victim in [P0-4] (because we've + * advanced already). + */ + +.LDdoverwrite: + + /* [P0-4] is a suitable victim CPLB, so we want to + * overwrite it by moving all the following CPLBs + * one space closer to the start. + */ + + R1.L = (DCPLB_DATA16 & 0xFFFF); /* DCPLB_DATA15 + 4 */ + R1.H = (DCPLB_DATA16 >> 16); + R0 = P0; + + /* If the victim happens to be in DCPLB15, + * we don't need to move anything. + */ + + CC = R1 == R0; + IF CC JUMP .Lde_moved; + R1 = R1 - R0; + R1 >>= 2; + P1 = R1; + LSETUP(.Lds_move, .Lde_move) LC0=P1; +.Lds_move: + R0 = [P0++]; /* move data */ + [P0 - 8] = R0; + R0 = [P0-0x104] /* move address */ +.Lde_move: [P0-0x108] = R0; + + /* We've now made space in DCPLB15 for the new CPLB to be + * installed. The next stage is to locate a CPLB in the + * config table that covers the faulting address. + */ + +.Lde_moved:NOP; + R0 = I0; /* Our faulting address */ + + P2.L = _dpdt_table; + P2.H = _dpdt_table; +#ifdef CONFIG_CPLB_INFO + P3.L = _dpdt_swapcount_table; + P3.H = _dpdt_swapcount_table; + P3 += -8; +#endif + + P1.L = _page_size_table; + P1.H = _page_size_table; + + /* An extraction pattern, to retrieve bits 17:16.*/ + + R1 = (16<<8)|2; +.Ldnext: R4 = [P2++]; /* address */ + R2 = [P2++]; /* data */ +#ifdef CONFIG_CPLB_INFO + P3 += 8; +#endif + + CC = R4 == -1; + IF CC JUMP .Lno_page_in_table; + + /* See if failed address > start address */ + CC = R4 <= R0(IU); + IF !CC JUMP .Ldnext; + + /* extract page size (17:16)*/ + R3 = EXTRACT(R2, R1.L) (Z); + + /* add page size to addr to get range */ + + P5 = R3; + P5 = P1 + (P5 << 2); + R3 = [P5]; + R3 = R3 + R4; + + /* See if failed address < (start address + page size) */ + CC = R0 < R3(IU); + IF !CC JUMP .Ldnext; + + /* We've found the CPLB that should be installed, so + * write it into CPLB15, masking off any caching bits + * if necessary. + */ + + P1.L = (DCPLB_DATA15 & 0xFFFF); + P1.H = (DCPLB_DATA15 >> 16); + + /* If the DCPLB has cache bits set, but caching hasn't + * been enabled, then we want to mask off the cache-in-L1 + * bit before installing. Moreover, if caching is off, we + * also want to ensure that the DCPLB has WT mode set, rather + * than WB, since WB pages still trigger first-write exceptions + * even when not caching is off, and the page isn't marked as + * cachable. Finally, we could mark the page as clean, not dirty, + * but we choose to leave that decision to the user; if the user + * chooses to have a CPLB pre-defined as dirty, then they always + * pay the cost of flushing during eviction, but don't pay the + * cost of first-write exceptions to mark the page as dirty. + */ + +#ifdef CONFIG_BLKFIN_WT + BITSET(R6, 14); /* Set WT*/ +#endif + + [P1] = R2; + [P1-0x100] = R4; +#ifdef CONFIG_CPLB_INFO + R3 = [P3]; + R3 += 1; + [P3] = R3; +#endif + + /* We've installed the CPLB, so re-enable CPLBs. P4 + * points to DMEM_CONTROL, and R5 is the value we + * last wrote to it, when we were disabling CPLBs. + */ + + BITSET(R5,ENDCPLB_P); + CLI R2; + .align 8; + [P4] = R5; + SSYNC; + STI R2; + + ( R7:4,P5:3 ) = [SP++]; + R0 = CPLB_RELOADED; + RTS; + +.data +.align 4; +_page_size_table: +.byte4 0x00000400; /* 1K */ +.byte4 0x00001000; /* 4K */ +.byte4 0x00100000; /* 1M */ +.byte4 0x00400000; /* 4M */ + +.align 4; +_dcplb_preference: +.byte4 0x00000001; /* valid bit */ +.byte4 0x00000002; /* lock bit */ diff --git a/trunk/arch/blackfin/mach-common/dpmc.S b/trunk/arch/blackfin/mach-common/dpmc.S new file mode 100644 index 000000000000..97cdcd6a00d4 --- /dev/null +++ b/trunk/arch/blackfin/mach-common/dpmc.S @@ -0,0 +1,418 @@ +/* + * File: arch/blackfin/mach-common/dpmc.S + * Based on: + * Author: LG Soft India + * + * Created: ? + * Description: Watchdog Timer APIs + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +.text + +ENTRY(_unmask_wdog_wakeup_evt) + [--SP] = ( R7:0, P5:0 ); +#if defined(CONFIG_BF561) + P0.H = hi(SICA_IWR1); + P0.L = lo(SICA_IWR1); +#else + P0.h = (SIC_IWR >> 16); + P0.l = (SIC_IWR & 0xFFFF); +#endif + R7 = [P0]; +#if defined(CONFIG_BF561) + BITSET(R7, 27); +#else + BITSET(R7,(IRQ_WATCH - IVG7)); +#endif + [P0] = R7; + SSYNC; + + ( R7:0, P5:0 ) = [SP++]; + RTS; + +.LWRITE_TO_STAT: + /* When watch dog timer is enabled, a write to STAT will load the + * contents of CNT to STAT + */ + R7 = 0x0000(z); +#if defined(CONFIG_BF561) + P0.h = (WDOGA_STAT >> 16); + P0.l = (WDOGA_STAT & 0xFFFF); +#else + P0.h = (WDOG_STAT >> 16); + P0.l = (WDOG_STAT & 0xFFFF); +#endif + [P0] = R7; + SSYNC; + JUMP .LSKIP_WRITE_TO_STAT; + +ENTRY(_program_wdog_timer) + [--SP] = ( R7:0, P5:0 ); +#if defined(CONFIG_BF561) + P0.h = (WDOGA_CNT >> 16); + P0.l = (WDOGA_CNT & 0xFFFF); +#else + P0.h = (WDOG_CNT >> 16); + P0.l = (WDOG_CNT & 0xFFFF); +#endif + [P0] = R0; + SSYNC; + +#if defined(CONFIG_BF561) + P0.h = (WDOGA_CTL >> 16); + P0.l = (WDOGA_CTL & 0xFFFF); +#else + P0.h = (WDOG_CTL >> 16); + P0.l = (WDOG_CTL & 0xFFFF); +#endif + R7 = W[P0](Z); + CC = BITTST(R7,1); + if !CC JUMP .LWRITE_TO_STAT; + CC = BITTST(R7,2); + if !CC JUMP .LWRITE_TO_STAT; + +.LSKIP_WRITE_TO_STAT: +#if defined(CONFIG_BF561) + P0.h = (WDOGA_CTL >> 16); + P0.l = (WDOGA_CTL & 0xFFFF); +#else + P0.h = (WDOG_CTL >> 16); + P0.l = (WDOG_CTL & 0xFFFF); +#endif + R7 = W[P0](Z); + BITCLR(R7,1); /* Enable GP event */ + BITSET(R7,2); + W[P0] = R7.L; + SSYNC; + NOP; + + R7 = W[P0](Z); + BITCLR(R7,4); /* Enable the wdog counter */ + W[P0] = R7.L; + SSYNC; + + ( R7:0, P5:0 ) = [SP++]; + RTS; + +ENTRY(_clear_wdog_wakeup_evt) + [--SP] = ( R7:0, P5:0 ); + +#if defined(CONFIG_BF561) + P0.h = (WDOGA_CTL >> 16); + P0.l = (WDOGA_CTL & 0xFFFF); +#else + P0.h = (WDOG_CTL >> 16); + P0.l = (WDOG_CTL & 0xFFFF); +#endif + R7 = 0x0AD6(Z); + W[P0] = R7.L; + SSYNC; + + R7 = W[P0](Z); + BITSET(R7,15); + W[P0] = R7.L; + SSYNC; + + R7 = W[P0](Z); + BITSET(R7,1); + BITSET(R7,2); + W[P0] = R7.L; + SSYNC; + + ( R7:0, P5:0 ) = [SP++]; + RTS; + +ENTRY(_disable_wdog_timer) + [--SP] = ( R7:0, P5:0 ); +#if defined(CONFIG_BF561) + P0.h = (WDOGA_CTL >> 16); + P0.l = (WDOGA_CTL & 0xFFFF); +#else + P0.h = (WDOG_CTL >> 16); + P0.l = (WDOG_CTL & 0xFFFF); +#endif + R7 = 0xAD6(Z); + W[P0] = R7.L; + SSYNC; + ( R7:0, P5:0 ) = [SP++]; + RTS; + +#if !defined(CONFIG_BF561) + +.section .l1.text + +ENTRY(_sleep_mode) + [--SP] = ( R7:0, P5:0 ); + [--SP] = RETS; + + call _set_sic_iwr; + + R0 = 0xFFFF (Z); + call _set_rtc_istat + + P0.H = hi(PLL_CTL); + P0.L = lo(PLL_CTL); + R1 = W[P0](z); + BITSET (R1, 3); + W[P0] = R1.L; + + CLI R2; + SSYNC; + IDLE; + STI R2; + + call _test_pll_locked; + + R0 = IWR_ENABLE(0); + call _set_sic_iwr; + + P0.H = hi(PLL_CTL); + P0.L = lo(PLL_CTL); + R7 = w[p0](z); + BITCLR (R7, 3); + BITCLR (R7, 5); + w[p0] = R7.L; + IDLE; + call _test_pll_locked; + + RETS = [SP++]; + ( R7:0, P5:0 ) = [SP++]; + RTS; + +ENTRY(_hibernate_mode) + [--SP] = ( R7:0, P5:0 ); + [--SP] = RETS; + + call _set_sic_iwr; + + R0 = 0xFFFF (Z); + call _set_rtc_istat + + P0.H = hi(VR_CTL); + P0.L = lo(VR_CTL); + R1 = W[P0](z); + BITSET (R1, 8); + BITCLR (R1, 0); + BITCLR (R1, 1); + W[P0] = R1.L; + SSYNC; + + CLI R2; + IDLE; + + /* Actually, adding anything may not be necessary...SDRAM contents + * are lost + */ + +ENTRY(_deep_sleep) + [--SP] = ( R7:0, P5:0 ); + [--SP] = RETS; + + CLI R4; + + call _set_sic_iwr; + + call _set_sdram_srfs; + + /* Clear all the interrupts,bits sticky */ + R0 = 0xFFFF (Z); + call _set_rtc_istat + + P0.H = hi(PLL_CTL); + P0.L = lo(PLL_CTL); + R0 = W[P0](z); + BITSET (R0, 5); + W[P0] = R0.L; + + call _test_pll_locked; + + SSYNC; + IDLE; + + call _unset_sdram_srfs; + + call _test_pll_locked; + + R0 = IWR_ENABLE(0); + call _set_sic_iwr; + + P0.H = hi(PLL_CTL); + P0.L = lo(PLL_CTL); + R0 = w[p0](z); + BITCLR (R0, 3); + BITCLR (R0, 5); + BITCLR (R0, 8); + w[p0] = R0; + IDLE; + call _test_pll_locked; + + STI R4; + + RETS = [SP++]; + ( R7:0, P5:0 ) = [SP++]; + RTS; + +ENTRY(_sleep_deeper) + [--SP] = ( R7:0, P5:0 ); + [--SP] = RETS; + + CLI R4; + + P3 = R0; + R0 = IWR_ENABLE(0); + call _set_sic_iwr; + call _set_sdram_srfs; + + /* Clear all the interrupts,bits sticky */ + R0 = 0xFFFF (Z); + call _set_rtc_istat + + P0.H = hi(PLL_DIV); + P0.L = lo(PLL_DIV); + R6 = W[P0](z); + R0.L = 0xF; + W[P0] = R0.l; + + P0.H = hi(PLL_CTL); + P0.L = lo(PLL_CTL); + R5 = W[P0](z); + R0.L = (MIN_VC/CONFIG_CLKIN_HZ) << 9; + W[P0] = R0.l; + + SSYNC; + IDLE; + + call _test_pll_locked; + + P0.H = hi(VR_CTL); + P0.L = lo(VR_CTL); + R7 = W[P0](z); + R1 = 0x6; + R1 <<= 16; + R2 = 0x0404(Z); + R1 = R1|R2; + + R2 = DEPOSIT(R7, R1); + W[P0] = R2; + + SSYNC; + IDLE; + + call _test_pll_locked; + + P0.H = hi(PLL_CTL); + P0.L = lo(PLL_CTL); + R0 = W[P0](z); + BITSET (R0, 3); + W[P0] = R0.L; + + R0 = P3; + call _set_sic_iwr; + + SSYNC; + IDLE; + + call _test_pll_locked; + + R0 = IWR_ENABLE(0); + call _set_sic_iwr; + + P0.H = hi(VR_CTL); + P0.L = lo(VR_CTL); + W[P0]= R7; + + SSYNC; + IDLE; + + call _test_pll_locked; + + P0.H = hi(PLL_DIV); + P0.L = lo(PLL_DIV); + W[P0]= R6; + + P0.H = hi(PLL_CTL); + P0.L = lo(PLL_CTL); + w[p0] = R5; + IDLE; + call _test_pll_locked; + + call _unset_sdram_srfs; + + STI R4; + + RETS = [SP++]; + ( R7:0, P5:0 ) = [SP++]; + RTS; + +ENTRY(_set_sdram_srfs) + /* set the sdram to self refresh mode */ + P0.H = hi(EBIU_SDGCTL); + P0.L = lo(EBIU_SDGCTL); + R2 = [P0]; + R3.H = hi(SRFS); + R3.L = lo(SRFS); + R2 = R2|R3; + [P0] = R2; + ssync; + RTS; + +ENTRY(_unset_sdram_srfs) + /* set the sdram out of self refresh mode */ + P0.H = hi(EBIU_SDGCTL); + P0.L = lo(EBIU_SDGCTL); + R2 = [P0]; + R3.H = hi(SRFS); + R3.L = lo(SRFS); + R3 = ~R3; + R2 = R2&R3; + [P0] = R2; + ssync; + RTS; + +ENTRY(_set_sic_iwr) + P0.H = hi(SIC_IWR); + P0.L = lo(SIC_IWR); + [P0] = R0; + SSYNC; + RTS; + +ENTRY(_set_rtc_istat) + P0.H = hi(RTC_ISTAT); + P0.L = lo(RTC_ISTAT); + w[P0] = R0.L; + SSYNC; + RTS; + +ENTRY(_test_pll_locked) + P0.H = hi(PLL_STAT); + P0.L = lo(PLL_STAT); +1: + R0 = W[P0] (Z); + CC = BITTST(R0,5); + IF !CC JUMP 1b; + RTS; +#endif diff --git a/trunk/arch/blackfin/mach-common/entry.S b/trunk/arch/blackfin/mach-common/entry.S new file mode 100644 index 000000000000..8eb0a9023482 --- /dev/null +++ b/trunk/arch/blackfin/mach-common/entry.S @@ -0,0 +1,1207 @@ +/* + * File: arch/blackfin/mach-common/entry.S + * Based on: + * Author: Linus Torvalds + * + * Created: ? + * Description: contains the system-call and fault low-level handling routines. + * This also contains the timer-interrupt handler, as well as all + * interrupts and faults that can result in a task-switch. + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * 25-Dec-2004 - LG Soft India + * 1. Fix in return_from_int, to make sure any pending + * system call in ILAT for this process to get + * executed, otherwise in case context switch happens, + * system call of first process (i.e in ILAT) will be + * carried forward to the switched process. + * 2. Removed Constant references for the following + * a. IPEND + * b. EXCAUSE mask + * c. PAGE Mask + */ + +/* + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. + */ + + +#include +#include +#include +#include +#include /* TIF_NEED_RESCHED */ +#include + +#include + +#ifdef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE + /* + * TODO: this should be proper save/restore, but for now + * we'll just cheat and use 0x1/0x13 + */ +# define DEBUG_START_HWTRACE \ + P5.l = LO(TBUFCTL); \ + P5.h = HI(TBUFCTL); \ + R7 = 0x13; \ + [P5] = R7; +# define DEBUG_STOP_HWTRACE \ + P5.l = LO(TBUFCTL); \ + P5.h = HI(TBUFCTL); \ + R7 = 0x01; \ + [P5] = R7; +#else +# define DEBUG_START_HWTRACE +# define DEBUG_STOP_HWTRACE +#endif + +#ifdef CONFIG_EXCPT_IRQ_SYSC_L1 +.section .l1.text +#else +.text +#endif + +/* Slightly simplified and streamlined entry point for CPLB misses. + * This one does not lower the level to IRQ5, and thus can be used to + * patch up CPLB misses on the kernel stack. + */ +ENTRY(_ex_dcplb) +#if defined(ANOMALY_05000261) + /* + * Work around an anomaly: if we see a new DCPLB fault, return + * without doing anything. Then, if we get the same fault again, + * handle it. + */ + p5.l = _last_cplb_fault_retx; + p5.h = _last_cplb_fault_retx; + r7 = [p5]; + r6 = retx; + [p5] = r6; + cc = r6 == r7; + if !cc jump _return_from_exception; + /* fall through */ +#endif + +ENTRY(_ex_icplb) + (R7:6,P5:4) = [sp++]; + ASTAT = [sp++]; + SAVE_ALL_SYS + call __cplb_hdr; + DEBUG_START_HWTRACE + RESTORE_ALL_SYS + SP = RETN; + rtx; + +ENTRY(_ex_spinlock) + /* Transform this into a syscall - twiddle the syscall vector. */ + p5.l = lo(EVT15); + p5.h = hi(EVT15); + r7.l = _spinlock_bh; + r7.h = _spinlock_bh; + [p5] = r7; + csync; + /* Fall through. */ + +ENTRY(_ex_syscall) + DEBUG_START_HWTRACE + (R7:6,P5:4) = [sp++]; + ASTAT = [sp++]; + raise 15; /* invoked by TRAP #0, for sys call */ + sp = retn; + rtx + +ENTRY(_spinlock_bh) + SAVE_ALL_SYS + /* To end up here, vector 15 was changed - so we have to change it + * back. + */ + p0.l = lo(EVT15); + p0.h = hi(EVT15); + p1.l = _evt_system_call; + p1.h = _evt_system_call; + [p0] = p1; + csync; + r0 = [sp + PT_R0]; + sp += -12; + call _sys_bfin_spinlock; + sp += 12; + [SP + PT_R0] = R0; + RESTORE_ALL_SYS + rti; + +ENTRY(_ex_soft_bp) + r7 = retx; + r7 += -2; + retx = r7; + jump.s _ex_trap_c; + +ENTRY(_ex_single_step) + r7 = retx; + r6 = reti; + cc = r7 == r6; + if cc jump _return_from_exception + r7 = syscfg; + bitclr (r7, 0); + syscfg = R7; + + p5.l = lo(IPEND); + p5.h = hi(IPEND); + r6 = [p5]; + cc = bittst(r6, 5); + if !cc jump _ex_trap_c; + p4.l = lo(EVT5); + p4.h = hi(EVT5); + r6.h = _exception_to_level5; + r6.l = _exception_to_level5; + r7 = [p4]; + cc = r6 == r7; + if !cc jump _ex_trap_c; + +_return_from_exception: + DEBUG_START_HWTRACE + (R7:6,P5:4) = [sp++]; + ASTAT = [sp++]; + sp = retn; + rtx; + +ENTRY(_handle_bad_cplb) + /* To get here, we just tried and failed to change a CPLB + * so, handle things in trap_c (C code), by lowering to + * IRQ5, just like we normally do. Since this is not a + * "normal" return path, we have a do alot of stuff to + * the stack to get ready so, we can fall through - we + * need to make a CPLB exception look like a normal exception + */ + + DEBUG_START_HWTRACE + RESTORE_ALL_SYS + [--sp] = ASTAT; + [--sp] = (R7:6, P5:4); + +ENTRY(_ex_trap_c) + /* Call C code (trap_c) to handle the exception, which most + * likely involves sending a signal to the current process. + * To avoid double faults, lower our priority to IRQ5 first. + */ + P5.h = _exception_to_level5; + P5.l = _exception_to_level5; + p4.l = lo(EVT5); + p4.h = hi(EVT5); + [p4] = p5; + csync; + + /* Disable all interrupts, but make sure level 5 is enabled so + * we can switch to that level. Save the old mask. */ + cli r6; + p4.l = _excpt_saved_imask; + p4.h = _excpt_saved_imask; + [p4] = r6; + r6 = 0x3f; + sti r6; + + /* Save the excause into a circular buffer, in case the instruction + * which caused this excecptions causes others. + */ + P5.l = _in_ptr_excause; + P5.h = _in_ptr_excause; + R7 = [P5]; + R7 += 4; + R6 = 0xF; + R7 = R7 & R6; + [P5] = R7; + R6.l = _excause_circ_buf; + R6.h = _excause_circ_buf; + R7 = R7 + R6; + p5 = R7; + R6 = SEQSTAT; + [P5] = R6; + + DEBUG_START_HWTRACE + (R7:6,P5:4) = [sp++]; + ASTAT = [sp++]; + SP = RETN; + raise 5; + rtx; + +ENTRY(_exception_to_level5) + SAVE_ALL_SYS + + /* Restore interrupt mask. We haven't pushed RETI, so this + * doesn't enable interrupts until we return from this handler. */ + p4.l = _excpt_saved_imask; + p4.h = _excpt_saved_imask; + r6 = [p4]; + sti r6; + + /* Restore the hardware error vector. */ + P5.h = _evt_ivhw; + P5.l = _evt_ivhw; + p4.l = lo(EVT5); + p4.h = hi(EVT5); + [p4] = p5; + csync; + + p2.l = lo(IPEND); + p2.h = hi(IPEND); + csync; + r0 = [p2]; /* Read current IPEND */ + [sp + PT_IPEND] = r0; /* Store IPEND */ + + /* Pop the excause from the circular buffer and push it on the stack + * (in the right place - if you change the location of SEQSTAT, you + * must change this offset. + */ +.L_excep_to_5_again: + P5.l = _out_ptr_excause; + P5.h = _out_ptr_excause; + R7 = [P5]; + R7 += 4; + R6 = 0xF; + R7 = R7 & R6; + [P5] = R7; + R6.l = _excause_circ_buf; + R6.h = _excause_circ_buf; + R7 = R7 + R6; + P5 = R7; + R1 = [P5]; + [SP + 8] = r1; + + r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ + SP += -12; + call _trap_c; + SP += 12; + + /* See if anything else is in the exception buffer + * if there is, process it + */ + P5.l = _out_ptr_excause; + P5.h = _out_ptr_excause; + P4.l = _in_ptr_excause; + P4.h = _in_ptr_excause; + R6 = [P5]; + R7 = [P4]; + CC = R6 == R7; + if ! CC JUMP .L_excep_to_5_again + + call _ret_from_exception; + RESTORE_ALL_SYS + rti; + +ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ + /* Since the kernel stack can be anywhere, it's not guaranteed to be + * covered by a CPLB. Switch to an exception stack; use RETN as a + * scratch register (for want of a better option). + */ + retn = sp; + sp.l = _exception_stack_top; + sp.h = _exception_stack_top; + /* Try to deal with syscalls quickly. */ + [--sp] = ASTAT; + [--sp] = (R7:6, P5:4); + DEBUG_STOP_HWTRACE + r7 = SEQSTAT; /* reason code is in bit 5:0 */ + r6.l = lo(SEQSTAT_EXCAUSE); + r6.h = hi(SEQSTAT_EXCAUSE); + r7 = r7 & r6; + p5.h = _extable; + p5.l = _extable; + p4 = r7; + p5 = p5 + (p4 << 2); + p4 = [p5]; + jump (p4); + +.Lbadsys: + r7 = -ENOSYS; /* signextending enough */ + [sp + PT_R0] = r7; /* return value from system call */ + jump .Lsyscall_really_exit; + +ENTRY(_kernel_execve) + link SIZEOF_PTREGS; + p0 = sp; + r3 = SIZEOF_PTREGS / 4; + r4 = 0(x); +0: + [p0++] = r4; + r3 += -1; + cc = r3 == 0; + if !cc jump 0b (bp); + + p0 = sp; + sp += -16; + [sp + 12] = p0; + call _do_execve; + SP += 16; + cc = r0 == 0; + if ! cc jump 1f; + /* Success. Copy our temporary pt_regs to the top of the kernel + * stack and do a normal exception return. + */ + r1 = sp; + r0 = (-KERNEL_STACK_SIZE) (x); + r1 = r1 & r0; + p2 = r1; + p3 = [p2]; + r0 = KERNEL_STACK_SIZE - 4 (z); + p1 = r0; + p1 = p1 + p2; + + p0 = fp; + r4 = [p0--]; + r3 = SIZEOF_PTREGS / 4; +0: + r4 = [p0--]; + [p1--] = r4; + r3 += -1; + cc = r3 == 0; + if ! cc jump 0b (bp); + + r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z); + p1 = r0; + p1 = p1 + p2; + sp = p1; + r0 = syscfg; + [SP + PT_SYSCFG] = r0; + [p3 + (TASK_THREAD + THREAD_KSP)] = sp; + + RESTORE_CONTEXT; + rti; +1: + unlink; + rts; + +ENTRY(_system_call) + /* Store IPEND */ + p2.l = lo(IPEND); + p2.h = hi(IPEND); + csync; + r0 = [p2]; + [sp + PT_IPEND] = r0; + + /* Store RETS for now */ + r0 = rets; + [sp + PT_RESERVED] = r0; + /* Set the stack for the current process */ + r7 = sp; + r6.l = lo(ALIGN_PAGE_MASK); + r6.h = hi(ALIGN_PAGE_MASK); + r7 = r7 & r6; /* thread_info */ + p2 = r7; + p2 = [p2]; + + [p2+(TASK_THREAD+THREAD_KSP)] = sp; + + /* Check the System Call */ + r7 = __NR_syscall; + /* System call number is passed in P0 */ + r6 = p0; + cc = r6 < r7; + if ! cc jump .Lbadsys; + + /* are we tracing syscalls?*/ + r7 = sp; + r6.l = lo(ALIGN_PAGE_MASK); + r6.h = hi(ALIGN_PAGE_MASK); + r7 = r7 & r6; + p2 = r7; + r7 = [p2+TI_FLAGS]; + CC = BITTST(r7,TIF_SYSCALL_TRACE); + if CC JUMP _sys_trace; + + /* Execute the appropriate system call */ + + p4 = p0; + p5.l = _sys_call_table; + p5.h = _sys_call_table; + p5 = p5 + (p4 << 2); + r0 = [sp + PT_R0]; + r1 = [sp + PT_R1]; + r2 = [sp + PT_R2]; + p5 = [p5]; + + [--sp] = r5; + [--sp] = r4; + [--sp] = r3; + SP += -12; + call (p5); + SP += 24; + [sp + PT_R0] = r0; + +.Lresume_userspace: + r7 = sp; + r4.l = lo(ALIGN_PAGE_MASK); + r4.h = hi(ALIGN_PAGE_MASK); + r7 = r7 & r4; /* thread_info->flags */ + p5 = r7; +.Lresume_userspace_1: + /* Disable interrupts. */ + [--sp] = reti; + reti = [sp++]; + + r7 = [p5 + TI_FLAGS]; + r4.l = lo(_TIF_WORK_MASK); + r4.h = hi(_TIF_WORK_MASK); + r7 = r7 & r4; + +.Lsyscall_resched: + cc = BITTST(r7, TIF_NEED_RESCHED); + if !cc jump .Lsyscall_sigpending; + + /* Reenable interrupts. */ + [--sp] = reti; + r0 = [sp++]; + + SP += -12; + call _schedule; + SP += 12; + + jump .Lresume_userspace_1; + +.Lsyscall_sigpending: + cc = BITTST(r7, TIF_RESTORE_SIGMASK); + if cc jump .Lsyscall_do_signals; + cc = BITTST(r7, TIF_SIGPENDING); + if !cc jump .Lsyscall_really_exit; +.Lsyscall_do_signals: + /* Reenable interrupts. */ + [--sp] = reti; + r0 = [sp++]; + + r0 = sp; + SP += -12; + call _do_signal; + SP += 12; + +.Lsyscall_really_exit: + r5 = [sp + PT_RESERVED]; + rets = r5; + rts; + +_sys_trace: + call _syscall_trace; + + /* Execute the appropriate system call */ + + p4 = [SP + PT_P0]; + p5.l = _sys_call_table; + p5.h = _sys_call_table; + p5 = p5 + (p4 << 2); + r0 = [sp + PT_R0]; + r1 = [sp + PT_R1]; + r2 = [sp + PT_R2]; + r3 = [sp + PT_R3]; + r4 = [sp + PT_R4]; + r5 = [sp + PT_R5]; + p5 = [p5]; + + [--sp] = r5; + [--sp] = r4; + [--sp] = r3; + SP += -12; + call (p5); + SP += 24; + [sp + PT_R0] = r0; + + call _syscall_trace; + jump .Lresume_userspace; + +ENTRY(_resume) + /* + * Beware - when entering resume, prev (the current task) is + * in r0, next (the new task) is in r1. + */ + p0 = r0; + p1 = r1; + [--sp] = rets; + [--sp] = fp; + [--sp] = (r7:4, p5:3); + + /* save usp */ + p2 = usp; + [p0+(TASK_THREAD+THREAD_USP)] = p2; + + /* save current kernel stack pointer */ + [p0+(TASK_THREAD+THREAD_KSP)] = sp; + + /* save program counter */ + r1.l = _new_old_task; + r1.h = _new_old_task; + [p0+(TASK_THREAD+THREAD_PC)] = r1; + + /* restore the kernel stack pointer */ + sp = [p1+(TASK_THREAD+THREAD_KSP)]; + + /* restore user stack pointer */ + p0 = [p1+(TASK_THREAD+THREAD_USP)]; + usp = p0; + + /* restore pc */ + p0 = [p1+(TASK_THREAD+THREAD_PC)]; + jump (p0); + + /* + * Following code actually lands up in a new (old) task. + */ + +_new_old_task: + (r7:4, p5:3) = [sp++]; + fp = [sp++]; + rets = [sp++]; + + /* + * When we come out of resume, r0 carries "old" task, becuase we are + * in "new" task. + */ + rts; + +ENTRY(_ret_from_exception) + p2.l = lo(IPEND); + p2.h = hi(IPEND); + + csync; + r0 = [p2]; + [sp + PT_IPEND] = r0; + +1: + r1 = 0x37(Z); + r2 = ~r1; + r2.h = 0; + r0 = r2 & r0; + cc = r0 == 0; + if !cc jump 4f; /* if not return to user mode, get out */ + + /* Make sure any pending system call or deferred exception + * return in ILAT for this process to get executed, otherwise + * in case context switch happens, system call of + * first process (i.e in ILAT) will be carried + * forward to the switched process + */ + + p2.l = lo(ILAT); + p2.h = hi(ILAT); + r0 = [p2]; + r1 = (EVT_IVG14 | EVT_IVG15) (z); + r0 = r0 & r1; + cc = r0 == 0; + if !cc jump 5f; + + /* Set the stack for the current process */ + r7 = sp; + r4.l = lo(ALIGN_PAGE_MASK); + r4.h = hi(ALIGN_PAGE_MASK); + r7 = r7 & r4; /* thread_info->flags */ + p5 = r7; + r7 = [p5 + TI_FLAGS]; + r4.l = lo(_TIF_WORK_MASK); + r4.h = hi(_TIF_WORK_MASK); + r7 = r7 & r4; + cc = r7 == 0; + if cc jump 4f; + + p0.l = lo(EVT15); + p0.h = hi(EVT15); + p1.l = _schedule_and_signal; + p1.h = _schedule_and_signal; + [p0] = p1; + csync; + raise 15; /* raise evt14 to do signal or reschedule */ +4: + r0 = syscfg; + bitclr(r0, 0); + syscfg = r0; +5: + rts; + +ENTRY(_return_from_int) + /* If someone else already raised IRQ 15, do nothing. */ + csync; + p2.l = lo(ILAT); + p2.h = hi(ILAT); + r0 = [p2]; + cc = bittst (r0, EVT_IVG15_P); + if cc jump 2f; + + /* if not return to user mode, get out */ + p2.l = lo(IPEND); + p2.h = hi(IPEND); + r0 = [p2]; + r1 = 0x17(Z); + r2 = ~r1; + r2.h = 0; + r0 = r2 & r0; + r1 = 1; + r1 = r0 - r1; + r2 = r0 & r1; + cc = r2 == 0; + if !cc jump 2f; + + /* Lower the interrupt level to 15. */ + p0.l = lo(EVT15); + p0.h = hi(EVT15); + p1.l = _schedule_and_signal_from_int; + p1.h = _schedule_and_signal_from_int; + [p0] = p1; + csync; +#if defined(ANOMALY_05000281) + r0.l = lo(CONFIG_BOOT_LOAD); + r0.h = hi(CONFIG_BOOT_LOAD); + reti = r0; +#endif + r0 = 0x801f (z); + STI r0; + raise 15; /* raise evt15 to do signal or reschedule */ + rti; +2: + rts; + +ENTRY(_lower_to_irq14) +#if defined(ANOMALY_05000281) + r0.l = lo(CONFIG_BOOT_LOAD); + r0.h = hi(CONFIG_BOOT_LOAD); + reti = r0; +#endif + r0 = 0x401f; + sti r0; + raise 14; + rti; +ENTRY(_evt14_softirq) +#ifdef CONFIG_DEBUG_HWERR + r0 = 0x3f; + sti r0; +#else + cli r0; +#endif + [--sp] = RETI; + SP += 4; + rts; + +_schedule_and_signal_from_int: + /* To end up here, vector 15 was changed - so we have to change it + * back. + */ + p0.l = lo(EVT15); + p0.h = hi(EVT15); + p1.l = _evt_system_call; + p1.h = _evt_system_call; + [p0] = p1; + csync; + p1 = rets; + [sp + PT_RESERVED] = p1; + + p0.l = _irq_flags; + p0.h = _irq_flags; + r0 = [p0]; + sti r0; + + jump.s .Lresume_userspace; + +_schedule_and_signal: + SAVE_CONTEXT_SYSCALL + /* To end up here, vector 15 was changed - so we have to change it + * back. + */ + p0.l = lo(EVT15); + p0.h = hi(EVT15); + p1.l = _evt_system_call; + p1.h = _evt_system_call; + [p0] = p1; + csync; + p0.l = 1f; + p0.h = 1f; + [sp + PT_RESERVED] = P0; + call .Lresume_userspace; +1: + RESTORE_CONTEXT + rti; + +/* Make sure when we start, that the circular buffer is initialized properly + * R0 and P0 are call clobbered, so we can use them here. + */ +ENTRY(_init_exception_buff) + r0 = 0; + p0.h = _in_ptr_excause; + p0.l = _in_ptr_excause; + [p0] = r0; + p0.h = _out_ptr_excause; + p0.l = _out_ptr_excause; + [p0] = r0; + rts; + +/* + * Put these in the kernel data section - that should always be covered by + * a CPLB. This is needed to ensure we don't get double fault conditions + */ + +#ifdef CONFIG_SYSCALL_TAB_L1 +.section .l1.data +#else +.data +#endif +ALIGN +_extable: + /* entry for each EXCAUSE[5:0] + * This table bmust be in sync with the table in ./kernel/traps.c + * EXCPT instruction can provide 4 bits of EXCAUSE, allowing 16 to be user defined + */ + .long _ex_syscall; /* 0x00 - User Defined - Linux Syscall */ + .long _ex_soft_bp /* 0x01 - User Defined - Software breakpoint */ + .long _ex_trap_c /* 0x02 - User Defined */ + .long _ex_trap_c /* 0x03 - User Defined - Atomic test and set service */ + .long _ex_spinlock /* 0x04 - User Defined */ + .long _ex_trap_c /* 0x05 - User Defined */ + .long _ex_trap_c /* 0x06 - User Defined */ + .long _ex_trap_c /* 0x07 - User Defined */ + .long _ex_trap_c /* 0x08 - User Defined */ + .long _ex_trap_c /* 0x09 - User Defined */ + .long _ex_trap_c /* 0x0A - User Defined */ + .long _ex_trap_c /* 0x0B - User Defined */ + .long _ex_trap_c /* 0x0C - User Defined */ + .long _ex_trap_c /* 0x0D - User Defined */ + .long _ex_trap_c /* 0x0E - User Defined */ + .long _ex_trap_c /* 0x0F - User Defined */ + .long _ex_single_step /* 0x10 - HW Single step */ + .long _ex_trap_c /* 0x11 - Trace Buffer Full */ + .long _ex_trap_c /* 0x12 - Reserved */ + .long _ex_trap_c /* 0x13 - Reserved */ + .long _ex_trap_c /* 0x14 - Reserved */ + .long _ex_trap_c /* 0x15 - Reserved */ + .long _ex_trap_c /* 0x16 - Reserved */ + .long _ex_trap_c /* 0x17 - Reserved */ + .long _ex_trap_c /* 0x18 - Reserved */ + .long _ex_trap_c /* 0x19 - Reserved */ + .long _ex_trap_c /* 0x1A - Reserved */ + .long _ex_trap_c /* 0x1B - Reserved */ + .long _ex_trap_c /* 0x1C - Reserved */ + .long _ex_trap_c /* 0x1D - Reserved */ + .long _ex_trap_c /* 0x1E - Reserved */ + .long _ex_trap_c /* 0x1F - Reserved */ + .long _ex_trap_c /* 0x20 - Reserved */ + .long _ex_trap_c /* 0x21 - Undefined Instruction */ + .long _ex_trap_c /* 0x22 - Illegal Instruction Combination */ + .long _ex_dcplb /* 0x23 - Data CPLB Protection Violation */ + .long _ex_trap_c /* 0x24 - Data access misaligned */ + .long _ex_trap_c /* 0x25 - Unrecoverable Event */ + .long _ex_dcplb /* 0x26 - Data CPLB Miss */ + .long _ex_trap_c /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero */ + .long _ex_trap_c /* 0x28 - Emulation Watchpoint */ + .long _ex_trap_c /* 0x29 - Instruction fetch access error (535 only) */ + .long _ex_trap_c /* 0x2A - Instruction fetch misaligned */ + .long _ex_icplb /* 0x2B - Instruction CPLB protection Violation */ + .long _ex_icplb /* 0x2C - Instruction CPLB miss */ + .long _ex_trap_c /* 0x2D - Instruction CPLB Multiple Hits */ + .long _ex_trap_c /* 0x2E - Illegal use of Supervisor Resource */ + .long _ex_trap_c /* 0x2E - Illegal use of Supervisor Resource */ + .long _ex_trap_c /* 0x2F - Reserved */ + .long _ex_trap_c /* 0x30 - Reserved */ + .long _ex_trap_c /* 0x31 - Reserved */ + .long _ex_trap_c /* 0x32 - Reserved */ + .long _ex_trap_c /* 0x33 - Reserved */ + .long _ex_trap_c /* 0x34 - Reserved */ + .long _ex_trap_c /* 0x35 - Reserved */ + .long _ex_trap_c /* 0x36 - Reserved */ + .long _ex_trap_c /* 0x37 - Reserved */ + .long _ex_trap_c /* 0x38 - Reserved */ + .long _ex_trap_c /* 0x39 - Reserved */ + .long _ex_trap_c /* 0x3A - Reserved */ + .long _ex_trap_c /* 0x3B - Reserved */ + .long _ex_trap_c /* 0x3C - Reserved */ + .long _ex_trap_c /* 0x3D - Reserved */ + .long _ex_trap_c /* 0x3E - Reserved */ + .long _ex_trap_c /* 0x3F - Reserved */ + +ALIGN +ENTRY(_sys_call_table) + .long _sys_ni_syscall /* 0 - old "setup()" system call*/ + .long _sys_exit + .long _sys_fork + .long _sys_read + .long _sys_write + .long _sys_open /* 5 */ + .long _sys_close + .long _sys_ni_syscall /* old waitpid */ + .long _sys_creat + .long _sys_link + .long _sys_unlink /* 10 */ + .long _sys_execve + .long _sys_chdir + .long _sys_time + .long _sys_mknod + .long _sys_chmod /* 15 */ + .long _sys_chown /* chown16 */ + .long _sys_ni_syscall /* old break syscall holder */ + .long _sys_ni_syscall /* old stat */ + .long _sys_lseek + .long _sys_getpid /* 20 */ + .long _sys_mount + .long _sys_ni_syscall /* old umount */ + .long _sys_setuid + .long _sys_getuid + .long _sys_stime /* 25 */ + .long _sys_ptrace + .long _sys_alarm + .long _sys_ni_syscall /* old fstat */ + .long _sys_pause + .long _sys_ni_syscall /* old utime */ /* 30 */ + .long _sys_ni_syscall /* old stty syscall holder */ + .long _sys_ni_syscall /* old gtty syscall holder */ + .long _sys_access + .long _sys_nice + .long _sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + .long _sys_sync + .long _sys_kill + .long _sys_rename + .long _sys_mkdir + .long _sys_rmdir /* 40 */ + .long _sys_dup + .long _sys_pipe + .long _sys_times + .long _sys_ni_syscall /* old prof syscall holder */ + .long _sys_brk /* 45 */ + .long _sys_setgid + .long _sys_getgid + .long _sys_ni_syscall /* old sys_signal */ + .long _sys_geteuid /* geteuid16 */ + .long _sys_getegid /* getegid16 */ /* 50 */ + .long _sys_acct + .long _sys_umount /* recycled never used phys() */ + .long _sys_ni_syscall /* old lock syscall holder */ + .long _sys_ioctl + .long _sys_fcntl /* 55 */ + .long _sys_ni_syscall /* old mpx syscall holder */ + .long _sys_setpgid + .long _sys_ni_syscall /* old ulimit syscall holder */ + .long _sys_ni_syscall /* old old uname */ + .long _sys_umask /* 60 */ + .long _sys_chroot + .long _sys_ustat + .long _sys_dup2 + .long _sys_getppid + .long _sys_getpgrp /* 65 */ + .long _sys_setsid + .long _sys_ni_syscall /* old sys_sigaction */ + .long _sys_sgetmask + .long _sys_ssetmask + .long _sys_setreuid /* setreuid16 */ /* 70 */ + .long _sys_setregid /* setregid16 */ + .long _sys_ni_syscall /* old sys_sigsuspend */ + .long _sys_ni_syscall /* old sys_sigpending */ + .long _sys_sethostname + .long _sys_setrlimit /* 75 */ + .long _sys_ni_syscall /* old getrlimit */ + .long _sys_getrusage + .long _sys_gettimeofday + .long _sys_settimeofday + .long _sys_getgroups /* getgroups16 */ /* 80 */ + .long _sys_setgroups /* setgroups16 */ + .long _sys_ni_syscall /* old_select */ + .long _sys_symlink + .long _sys_ni_syscall /* old lstat */ + .long _sys_readlink /* 85 */ + .long _sys_uselib + .long _sys_ni_syscall /* sys_swapon */ + .long _sys_reboot + .long _sys_ni_syscall /* old_readdir */ + .long _sys_ni_syscall /* sys_mmap */ /* 90 */ + .long _sys_munmap + .long _sys_truncate + .long _sys_ftruncate + .long _sys_fchmod + .long _sys_fchown /* fchown16 */ /* 95 */ + .long _sys_getpriority + .long _sys_setpriority + .long _sys_ni_syscall /* old profil syscall holder */ + .long _sys_statfs + .long _sys_fstatfs /* 100 */ + .long _sys_ni_syscall + .long _sys_ni_syscall /* old sys_socketcall */ + .long _sys_syslog + .long _sys_setitimer + .long _sys_getitimer /* 105 */ + .long _sys_newstat + .long _sys_newlstat + .long _sys_newfstat + .long _sys_ni_syscall /* old uname */ + .long _sys_ni_syscall /* iopl for i386 */ /* 110 */ + .long _sys_vhangup + .long _sys_ni_syscall /* obsolete idle() syscall */ + .long _sys_ni_syscall /* vm86old for i386 */ + .long _sys_wait4 + .long _sys_ni_syscall /* 115 */ /* sys_swapoff */ + .long _sys_sysinfo + .long _sys_ni_syscall /* old sys_ipc */ + .long _sys_fsync + .long _sys_ni_syscall /* old sys_sigreturn */ + .long _sys_clone /* 120 */ + .long _sys_setdomainname + .long _sys_newuname + .long _sys_ni_syscall /* old sys_modify_ldt */ + .long _sys_adjtimex + .long _sys_ni_syscall /* 125 */ /* sys_mprotect */ + .long _sys_ni_syscall /* old sys_sigprocmask */ + .long _sys_ni_syscall /* old "creat_module" */ + .long _sys_init_module + .long _sys_delete_module + .long _sys_ni_syscall /* 130: old "get_kernel_syms" */ + .long _sys_quotactl + .long _sys_getpgid + .long _sys_fchdir + .long _sys_bdflush + .long _sys_ni_syscall /* 135 */ /* sys_sysfs */ + .long _sys_personality + .long _sys_ni_syscall /* for afs_syscall */ + .long _sys_setfsuid /* setfsuid16 */ + .long _sys_setfsgid /* setfsgid16 */ + .long _sys_llseek /* 140 */ + .long _sys_getdents + .long _sys_ni_syscall /* sys_select */ + .long _sys_flock + .long _sys_ni_syscall /* sys_msync */ + .long _sys_readv /* 145 */ + .long _sys_writev + .long _sys_getsid + .long _sys_fdatasync + .long _sys_sysctl + .long _sys_ni_syscall /* 150 */ /* sys_mlock */ + .long _sys_ni_syscall /* sys_munlock */ + .long _sys_ni_syscall /* sys_mlockall */ + .long _sys_ni_syscall /* sys_munlockall */ + .long _sys_sched_setparam + .long _sys_sched_getparam /* 155 */ + .long _sys_sched_setscheduler + .long _sys_sched_getscheduler + .long _sys_sched_yield + .long _sys_sched_get_priority_max + .long _sys_sched_get_priority_min /* 160 */ + .long _sys_sched_rr_get_interval + .long _sys_nanosleep + .long _sys_ni_syscall /* sys_mremap */ + .long _sys_setresuid /* setresuid16 */ + .long _sys_getresuid /* getresuid16 */ /* 165 */ + .long _sys_ni_syscall /* for vm86 */ + .long _sys_ni_syscall /* old "query_module" */ + .long _sys_ni_syscall /* sys_poll */ + .long _sys_ni_syscall /* sys_nfsservctl */ + .long _sys_setresgid /* setresgid16 */ /* 170 */ + .long _sys_getresgid /* getresgid16 */ + .long _sys_prctl + .long _sys_rt_sigreturn + .long _sys_rt_sigaction + .long _sys_rt_sigprocmask /* 175 */ + .long _sys_rt_sigpending + .long _sys_rt_sigtimedwait + .long _sys_rt_sigqueueinfo + .long _sys_rt_sigsuspend + .long _sys_pread64 /* 180 */ + .long _sys_pwrite64 + .long _sys_lchown /* lchown16 */ + .long _sys_getcwd + .long _sys_capget + .long _sys_capset /* 185 */ + .long _sys_sigaltstack + .long _sys_sendfile + .long _sys_ni_syscall /* streams1 */ + .long _sys_ni_syscall /* streams2 */ + .long _sys_vfork /* 190 */ + .long _sys_getrlimit + .long _sys_mmap2 + .long _sys_truncate64 + .long _sys_ftruncate64 + .long _sys_stat64 /* 195 */ + .long _sys_lstat64 + .long _sys_fstat64 + .long _sys_chown + .long _sys_getuid + .long _sys_getgid /* 200 */ + .long _sys_geteuid + .long _sys_getegid + .long _sys_setreuid + .long _sys_setregid + .long _sys_getgroups /* 205 */ + .long _sys_setgroups + .long _sys_fchown + .long _sys_setresuid + .long _sys_getresuid + .long _sys_setresgid /* 210 */ + .long _sys_getresgid + .long _sys_lchown + .long _sys_setuid + .long _sys_setgid + .long _sys_setfsuid /* 215 */ + .long _sys_setfsgid + .long _sys_pivot_root + .long _sys_ni_syscall /* sys_mincore */ + .long _sys_ni_syscall /* sys_madvise */ + .long _sys_getdents64 /* 220 */ + .long _sys_fcntl64 + .long _sys_ni_syscall /* reserved for TUX */ + .long _sys_ni_syscall + .long _sys_gettid + .long _sys_ni_syscall /* 225 */ /* sys_readahead */ + .long _sys_setxattr + .long _sys_lsetxattr + .long _sys_fsetxattr + .long _sys_getxattr + .long _sys_lgetxattr /* 230 */ + .long _sys_fgetxattr + .long _sys_listxattr + .long _sys_llistxattr + .long _sys_flistxattr + .long _sys_removexattr /* 235 */ + .long _sys_lremovexattr + .long _sys_fremovexattr + .long _sys_tkill + .long _sys_sendfile64 + .long _sys_futex /* 240 */ + .long _sys_sched_setaffinity + .long _sys_sched_getaffinity + .long _sys_ni_syscall /* sys_set_thread_area */ + .long _sys_ni_syscall /* sys_get_thread_area */ + .long _sys_io_setup /* 245 */ + .long _sys_io_destroy + .long _sys_io_getevents + .long _sys_io_submit + .long _sys_io_cancel + .long _sys_ni_syscall /* 250 */ /* sys_alloc_hugepages */ + .long _sys_ni_syscall /* sys_freec_hugepages */ + .long _sys_exit_group + .long _sys_lookup_dcookie + .long _sys_bfin_spinlock + .long _sys_epoll_create /* 255 */ + .long _sys_epoll_ctl + .long _sys_epoll_wait + .long _sys_ni_syscall /* remap_file_pages */ + .long _sys_set_tid_address + .long _sys_timer_create /* 260 */ + .long _sys_timer_settime + .long _sys_timer_gettime + .long _sys_timer_getoverrun + .long _sys_timer_delete + .long _sys_clock_settime /* 265 */ + .long _sys_clock_gettime + .long _sys_clock_getres + .long _sys_clock_nanosleep + .long _sys_statfs64 + .long _sys_fstatfs64 /* 270 */ + .long _sys_tgkill + .long _sys_utimes + .long _sys_fadvise64_64 + .long _sys_ni_syscall /* vserver */ + .long _sys_ni_syscall /* 275, mbind */ + .long _sys_ni_syscall /* get_mempolicy */ + .long _sys_ni_syscall /* set_mempolicy */ + .long _sys_mq_open + .long _sys_mq_unlink + .long _sys_mq_timedsend /* 280 */ + .long _sys_mq_timedreceive + .long _sys_mq_notify + .long _sys_mq_getsetattr + .long _sys_ni_syscall /* kexec_load */ + .long _sys_waitid /* 285 */ + .long _sys_add_key + .long _sys_request_key + .long _sys_keyctl + .long _sys_ioprio_set + .long _sys_ioprio_get /* 290 */ + .long _sys_inotify_init + .long _sys_inotify_add_watch + .long _sys_inotify_rm_watch + .long _sys_ni_syscall /* migrate_pages */ + .long _sys_openat /* 295 */ + .long _sys_mkdirat + .long _sys_mknodat + .long _sys_fchownat + .long _sys_futimesat + .long _sys_fstatat64 /* 300 */ + .long _sys_unlinkat + .long _sys_renameat + .long _sys_linkat + .long _sys_symlinkat + .long _sys_readlinkat /* 305 */ + .long _sys_fchmodat + .long _sys_faccessat + .long _sys_pselect6 + .long _sys_ppoll + .long _sys_unshare /* 310 */ + .long _sys_sram_alloc + .long _sys_sram_free + .long _sys_dma_memcpy + .long _sys_accept + .long _sys_bind /* 315 */ + .long _sys_connect + .long _sys_getpeername + .long _sys_getsockname + .long _sys_getsockopt + .long _sys_listen /* 320 */ + .long _sys_recv + .long _sys_recvfrom + .long _sys_recvmsg + .long _sys_send + .long _sys_sendmsg /* 325 */ + .long _sys_sendto + .long _sys_setsockopt + .long _sys_shutdown + .long _sys_socket + .long _sys_socketpair /* 330 */ + .long _sys_semctl + .long _sys_semget + .long _sys_semop + .long _sys_msgctl + .long _sys_msgget /* 335 */ + .long _sys_msgrcv + .long _sys_msgsnd + .long _sys_shmat + .long _sys_shmctl + .long _sys_shmdt /* 340 */ + .long _sys_shmget + .rept NR_syscalls-(.-_sys_call_table)/4 + .long _sys_ni_syscall + .endr +_excpt_saved_imask: + .long 0; + +_exception_stack: + .rept 1024 + .long 0; + .endr +_exception_stack_top: + +#if defined(ANOMALY_05000261) +/* Used by the assembly entry point to work around an anomaly. */ +_last_cplb_fault_retx: + .long 0; +#endif +/* + * Single instructions can have multiple faults, which need to be + * handled by traps.c, in irq5. We store the exception cause to ensure + * we don't miss a double fault condition + */ +ENTRY(_in_ptr_excause) + .long 0; +ENTRY(_out_ptr_excause) + .long 0; +ALIGN +ENTRY(_excause_circ_buf) + .rept 4 + .long 0 + .endr diff --git a/trunk/arch/blackfin/mach-common/interrupt.S b/trunk/arch/blackfin/mach-common/interrupt.S new file mode 100644 index 000000000000..dd45664f0d02 --- /dev/null +++ b/trunk/arch/blackfin/mach-common/interrupt.S @@ -0,0 +1,253 @@ +/* + * File: arch/blackfin/mach-common/interrupt.S + * Based on: + * Author: D. Jeff Dionne + * Kenneth Albanowski + * + * Created: ? + * Description: Interrupt Entries + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_I_ENTRY_L1 +.section .l1.text +#else +.text +#endif + +.align 4 /* just in case */ + +/* + * initial interrupt handlers + */ + +#ifndef CONFIG_KGDB + /* interrupt routine for emulation - 0 */ + /* Currently used only if GDB stub is not in - invalid */ + /* gdb-stub set the evt itself */ + /* save registers for post-mortem only */ +ENTRY(_evt_emulation) + SAVE_ALL_SYS +#ifdef CONFIG_FRAME_POINTER + fp = 0; +#endif + r0 = IRQ_EMU; + r1 = sp; + SP += -12; + call _irq_panic; + SP += 12; + /* - GDB stub fills this in by itself (if defined) */ + rte; +#endif + +/* Common interrupt entry code. First we do CLI, then push + * RETI, to keep interrupts disabled, but to allow this state to be changed + * by local_bh_enable. + * R0 contains the interrupt number, while R1 may contain the value of IPEND, + * or garbage if IPEND won't be needed by the ISR. */ +__common_int_entry: + [--sp] = fp; + [--sp] = usp; + + [--sp] = i0; + [--sp] = i1; + [--sp] = i2; + [--sp] = i3; + + [--sp] = m0; + [--sp] = m1; + [--sp] = m2; + [--sp] = m3; + + [--sp] = l0; + [--sp] = l1; + [--sp] = l2; + [--sp] = l3; + + [--sp] = b0; + [--sp] = b1; + [--sp] = b2; + [--sp] = b3; + [--sp] = a0.x; + [--sp] = a0.w; + [--sp] = a1.x; + [--sp] = a1.w; + + [--sp] = LC0; + [--sp] = LC1; + [--sp] = LT0; + [--sp] = LT1; + [--sp] = LB0; + [--sp] = LB1; + + [--sp] = ASTAT; + + [--sp] = r0; /* Skip reserved */ + [--sp] = RETS; + r2 = RETI; + [--sp] = r2; + [--sp] = RETX; + [--sp] = RETN; + [--sp] = RETE; + [--sp] = SEQSTAT; + [--sp] = r1; /* IPEND - R1 may or may not be set up before jumping here. */ + + /* Switch to other method of keeping interrupts disabled. */ +#ifdef CONFIG_DEBUG_HWERR + r1 = 0x3f; + sti r1; +#else + cli r1; +#endif + [--sp] = RETI; /* orig_pc */ + /* Clear all L registers. */ + r1 = 0 (x); + l0 = r1; + l1 = r1; + l2 = r1; + l3 = r1; +#ifdef CONFIG_FRAME_POINTER + fp = 0; +#endif + +#ifdef ANOMALY_05000283 + cc = r7 == r7; + p5.h = 0xffc0; + p5.l = 0x0014; + if cc jump 1f; + r7.l = W[p5]; +1: +#endif + r1 = sp; + SP += -12; + call _do_irq; + SP += 12; + call _return_from_int; +.Lcommon_restore_context: + RESTORE_CONTEXT + rti; + +/* interrupt routine for ivhw - 5 */ +ENTRY(_evt_ivhw) + SAVE_CONTEXT +#ifdef CONFIG_FRAME_POINTER + fp = 0; +#endif +#ifdef ANOMALY_05000283 + cc = r7 == r7; + p5.h = 0xffc0; + p5.l = 0x0014; + if cc jump 1f; + r7.l = W[p5]; +1: +#endif + p0.l = lo(TBUFCTL); + p0.h = hi(TBUFCTL); + r0 = 1; + [p0] = r0; + r0 = IRQ_HWERR; + r1 = sp; + +#ifdef CONFIG_HARDWARE_PM + r7 = SEQSTAT; + r7 = r7 >>> 0xe; + r6 = 0x1F; + r7 = r7 & r6; + r5 = 0x12; + cc = r7 == r5; + if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */ +#endif + + SP += -12; + call _irq_panic; + SP += 12; + rti; +#ifdef CONFIG_HARDWARE_PM +.Lcall_do_ovf: + + SP += -12; + call _pm_overflow; + SP += 12; + + jump .Lcommon_restore_context; +#endif + +/* interrupt routine for evt2 - 2. This is NMI. */ +ENTRY(_evt_evt2) + SAVE_CONTEXT +#ifdef CONFIG_FRAME_POINTER + fp = 0; +#endif +#ifdef ANOMALY_05000283 + cc = r7 == r7; + p5.h = 0xffc0; + p5.l = 0x0014; + if cc jump 1f; + r7.l = W[p5]; +1: +#endif + r0 = IRQ_NMI; + r1 = sp; + SP += -12; + call _asm_do_IRQ; + SP += 12; + RESTORE_CONTEXT + rtn; + +/* interrupt routine for core timer - 6 */ +ENTRY(_evt_timer) + TIMER_INTERRUPT_ENTRY(EVT_IVTMR_P) + +/* interrupt routine for evt7 - 7 */ +ENTRY(_evt_evt7) + INTERRUPT_ENTRY(EVT_IVG7_P) +ENTRY(_evt_evt8) + INTERRUPT_ENTRY(EVT_IVG8_P) +ENTRY(_evt_evt9) + INTERRUPT_ENTRY(EVT_IVG9_P) +ENTRY(_evt_evt10) + INTERRUPT_ENTRY(EVT_IVG10_P) +ENTRY(_evt_evt11) + INTERRUPT_ENTRY(EVT_IVG11_P) +ENTRY(_evt_evt12) + INTERRUPT_ENTRY(EVT_IVG12_P) +ENTRY(_evt_evt13) + INTERRUPT_ENTRY(EVT_IVG13_P) + + + /* interrupt routine for system_call - 15 */ +ENTRY(_evt_system_call) + SAVE_CONTEXT_SYSCALL +#ifdef CONFIG_FRAME_POINTER + fp = 0; +#endif + call _system_call; + jump .Lcommon_restore_context; diff --git a/trunk/arch/blackfin/mach-common/ints-priority-dc.c b/trunk/arch/blackfin/mach-common/ints-priority-dc.c new file mode 100644 index 000000000000..f3cf07036c2a --- /dev/null +++ b/trunk/arch/blackfin/mach-common/ints-priority-dc.c @@ -0,0 +1,476 @@ +/* + * File: arch/blackfin/mach-common/ints-priority-dc.c + * Based on: + * Author: + * + * Created: ? + * Description: Set up the interupt priorities + * + * Modified: + * 1996 Roman Zippel + * 1999 D. Jeff Dionne + * 2000-2001 Lineo, Inc. D. Jefff Dionne + * 2002 Arcturus Networks Inc. MaTed + * 2003 Metrowerks/Motorola + * 2003 Bas Vermeulen + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#ifdef CONFIG_KGDB +#include +#endif +#include +#include +#include +#include + +/* + * NOTES: + * - we have separated the physical Hardware interrupt from the + * levels that the LINUX kernel sees (see the description in irq.h) + * - + */ + +unsigned long irq_flags = 0; + +/* The number of spurious interrupts */ +atomic_t num_spurious; + +struct ivgx { + /* irq number for request_irq, available in mach-bf561/irq.h */ + int irqno; + /* corresponding bit in the SICA_ISR0 register */ + int isrflag0; + /* corresponding bit in the SICA_ISR1 register */ + int isrflag1; +} ivg_table[NR_PERI_INTS]; + +struct ivg_slice { + /* position of first irq in ivg_table for given ivg */ + struct ivgx *ifirst; + struct ivgx *istop; +} ivg7_13[IVG13 - IVG7 + 1]; + +static void search_IAR(void); + +/* + * Search SIC_IAR and fill tables with the irqvalues + * and their positions in the SIC_ISR register. + */ +static void __init search_IAR(void) +{ + unsigned ivg, irq_pos = 0; + for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) { + int irqn; + + ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos]; + + for (irqn = 0; irqn < NR_PERI_INTS; irqn++) { + int iar_shift = (irqn & 7) * 4; + if (ivg == + (0xf & + bfin_read32((unsigned long *)SICA_IAR0 + + (irqn >> 3)) >> iar_shift)) { + ivg_table[irq_pos].irqno = IVG7 + irqn; + ivg_table[irq_pos].isrflag0 = + (irqn < 32 ? (1 << irqn) : 0); + ivg_table[irq_pos].isrflag1 = + (irqn < 32 ? 0 : (1 << (irqn - 32))); + ivg7_13[ivg].istop++; + irq_pos++; + } + } + } +} + +/* + * This is for BF561 internal IRQs + */ + +static void ack_noop(unsigned int irq) +{ + /* Dummy function. */ +} + +static void bf561_core_mask_irq(unsigned int irq) +{ + irq_flags &= ~(1 << irq); + if (!irqs_disabled()) + local_irq_enable(); +} + +static void bf561_core_unmask_irq(unsigned int irq) +{ + irq_flags |= 1 << irq; + /* + * If interrupts are enabled, IMASK must contain the same value + * as irq_flags. Make sure that invariant holds. If interrupts + * are currently disabled we need not do anything; one of the + * callers will take care of setting IMASK to the proper value + * when reenabling interrupts. + * local_irq_enable just does "STI irq_flags", so it's exactly + * what we need. + */ + if (!irqs_disabled()) + local_irq_enable(); + return; +} + +static void bf561_internal_mask_irq(unsigned int irq) +{ + unsigned long irq_mask; + if ((irq - (IRQ_CORETMR + 1)) < 32) { + irq_mask = (1 << (irq - (IRQ_CORETMR + 1))); + bfin_write_SICA_IMASK0(bfin_read_SICA_IMASK0() & ~irq_mask); + } else { + irq_mask = (1 << (irq - (IRQ_CORETMR + 1) - 32)); + bfin_write_SICA_IMASK1(bfin_read_SICA_IMASK1() & ~irq_mask); + } +} + +static void bf561_internal_unmask_irq(unsigned int irq) +{ + unsigned long irq_mask; + + if ((irq - (IRQ_CORETMR + 1)) < 32) { + irq_mask = (1 << (irq - (IRQ_CORETMR + 1))); + bfin_write_SICA_IMASK0(bfin_read_SICA_IMASK0() | irq_mask); + } else { + irq_mask = (1 << (irq - (IRQ_CORETMR + 1) - 32)); + bfin_write_SICA_IMASK1(bfin_read_SICA_IMASK1() | irq_mask); + } + SSYNC(); +} + +static struct irq_chip bf561_core_irqchip = { + .ack = ack_noop, + .mask = bf561_core_mask_irq, + .unmask = bf561_core_unmask_irq, +}; + +static struct irq_chip bf561_internal_irqchip = { + .ack = ack_noop, + .mask = bf561_internal_mask_irq, + .unmask = bf561_internal_unmask_irq, +}; + +#ifdef CONFIG_IRQCHIP_DEMUX_GPIO +static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)]; +static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)]; + +static void bf561_gpio_ack_irq(unsigned int irq) +{ + u16 gpionr = irq - IRQ_PF0; + + if(gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) { + set_gpio_data(gpionr, 0); + SSYNC(); + } +} + +static void bf561_gpio_mask_ack_irq(unsigned int irq) +{ + u16 gpionr = irq - IRQ_PF0; + + if(gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) { + set_gpio_data(gpionr, 0); + SSYNC(); + } + + set_gpio_maska(gpionr, 0); + SSYNC(); +} + +static void bf561_gpio_mask_irq(unsigned int irq) +{ + set_gpio_maska(irq - IRQ_PF0, 0); + SSYNC(); +} + +static void bf561_gpio_unmask_irq(unsigned int irq) +{ + set_gpio_maska(irq - IRQ_PF0, 1); + SSYNC(); +} + +static unsigned int bf561_gpio_irq_startup(unsigned int irq) +{ + unsigned int ret; + u16 gpionr = irq - IRQ_PF0; + + if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) { + + ret = gpio_request(gpionr, NULL); + if(ret) + return ret; + + } + + gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr); + bf561_gpio_unmask_irq(irq); + + return ret; + +} + +static void bf561_gpio_irq_shutdown(unsigned int irq) +{ + bf561_gpio_mask_irq(irq); + gpio_free(irq - IRQ_PF0); + gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0); +} + +static int bf561_gpio_irq_type(unsigned int irq, unsigned int type) +{ + + unsigned int ret; + u16 gpionr = irq - IRQ_PF0; + + + if (type == IRQ_TYPE_PROBE) { + /* only probe unenabled GPIO interrupt lines */ + if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)) + return 0; + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + + } + + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | + IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { + + if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) { + + ret = gpio_request(gpionr, NULL); + if(ret) + return ret; + + } + + gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr); + } else { + gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr); + return 0; + } + + + set_gpio_dir(gpionr, 0); + set_gpio_inen(gpionr, 1); + + + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { + gpio_edge_triggered[gpio_bank(gpionr)] |= gpio_bit(gpionr); + set_gpio_edge(gpionr, 1); + } else { + set_gpio_edge(gpionr, 0); + gpio_edge_triggered[gpio_bank(gpionr)] &= ~gpio_bit(gpionr); + } + + if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) + == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) + set_gpio_both(gpionr, 1); + else + set_gpio_both(gpionr, 0); + + if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW))) + set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */ + else + set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */ + + SSYNC(); + + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) + set_irq_handler(irq, handle_edge_irq); + else + set_irq_handler(irq, handle_level_irq); + + return 0; +} + +static struct irq_chip bf561_gpio_irqchip = { + .ack = bf561_gpio_ack_irq, + .mask = bf561_gpio_mask_irq, + .mask_ack = bf561_gpio_mask_ack_irq, + .unmask = bf561_gpio_unmask_irq, + .set_type = bf561_gpio_irq_type, + .startup = bf561_gpio_irq_startup, + .shutdown = bf561_gpio_irq_shutdown +}; + +static void bf561_demux_gpio_irq(unsigned int inta_irq, + struct irq_desc *intb_desc) +{ + int irq, flag_d, mask; + u16 gpio; + + switch (inta_irq) { + case IRQ_PROG0_INTA: + irq = IRQ_PF0; + break; + case IRQ_PROG1_INTA: + irq = IRQ_PF16; + break; + case IRQ_PROG2_INTA: + irq = IRQ_PF32; + break; + default: + dump_stack(); + return; + } + + gpio = irq - IRQ_PF0; + + flag_d = get_gpiop_data(gpio); + mask = flag_d & (gpio_enabled[gpio_bank(gpio)] & + get_gpiop_maska(gpio)); + + do { + if (mask & 1) { + struct irq_desc *desc = irq_desc + irq; + desc->handle_irq(irq, desc); + } + irq++; + mask >>= 1; + } while (mask); + + +} + +#endif /* CONFIG_IRQCHIP_DEMUX_GPIO */ + +/* + * This function should be called during kernel startup to initialize + * the BFin IRQ handling routines. + */ +int __init init_arch_irq(void) +{ + int irq; + unsigned long ilat = 0; + /* Disable all the peripheral intrs - page 4-29 HW Ref manual */ + bfin_write_SICA_IMASK0(SIC_UNMASK_ALL); + bfin_write_SICA_IMASK1(SIC_UNMASK_ALL); + SSYNC(); + + local_irq_disable(); + + init_exception_buff(); + +#ifndef CONFIG_KGDB + bfin_write_EVT0(evt_emulation); +#endif + bfin_write_EVT2(evt_evt2); + bfin_write_EVT3(trap); + bfin_write_EVT5(evt_ivhw); + bfin_write_EVT6(evt_timer); + bfin_write_EVT7(evt_evt7); + bfin_write_EVT8(evt_evt8); + bfin_write_EVT9(evt_evt9); + bfin_write_EVT10(evt_evt10); + bfin_write_EVT11(evt_evt11); + bfin_write_EVT12(evt_evt12); + bfin_write_EVT13(evt_evt13); + bfin_write_EVT14(evt14_softirq); + bfin_write_EVT15(evt_system_call); + CSYNC(); + + for (irq = 0; irq < SYS_IRQS; irq++) { + if (irq <= IRQ_CORETMR) + set_irq_chip(irq, &bf561_core_irqchip); + else + set_irq_chip(irq, &bf561_internal_irqchip); +#ifdef CONFIG_IRQCHIP_DEMUX_GPIO + if ((irq != IRQ_PROG0_INTA) && + (irq != IRQ_PROG1_INTA) && (irq != IRQ_PROG2_INTA)) { +#endif + set_irq_handler(irq, handle_simple_irq); +#ifdef CONFIG_IRQCHIP_DEMUX_GPIO + } else { + set_irq_chained_handler(irq, bf561_demux_gpio_irq); + } +#endif + + } + +#ifdef CONFIG_IRQCHIP_DEMUX_GPIO + for (irq = IRQ_PF0; irq <= IRQ_PF47; irq++) { + set_irq_chip(irq, &bf561_gpio_irqchip); + /* if configured as edge, then will be changed to do_edge_IRQ */ + set_irq_handler(irq, handle_level_irq); + } +#endif + bfin_write_IMASK(0); + CSYNC(); + ilat = bfin_read_ILAT(); + CSYNC(); + bfin_write_ILAT(ilat); + CSYNC(); + + printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n"); + /* IMASK=xxx is equivalent to STI xx or irq_flags=xx, + * local_irq_enable() + */ + program_IAR(); + /* Therefore it's better to setup IARs before interrupts enabled */ + search_IAR(); + + /* Enable interrupts IVG7-15 */ + irq_flags = irq_flags | IMASK_IVG15 | + IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | + IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; + + return 0; +} + +#ifdef CONFIG_DO_IRQ_L1 +void do_irq(int vec, struct pt_regs *fp)__attribute__((l1_text)); +#endif + +void do_irq(int vec, struct pt_regs *fp) +{ + if (vec == EVT_IVTMR_P) { + vec = IRQ_CORETMR; + } else { + struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst; + struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop; + unsigned long sic_status0, sic_status1; + + SSYNC(); + sic_status0 = bfin_read_SICA_IMASK0() & bfin_read_SICA_ISR0(); + sic_status1 = bfin_read_SICA_IMASK1() & bfin_read_SICA_ISR1(); + + for (;; ivg++) { + if (ivg >= ivg_stop) { + atomic_inc(&num_spurious); + return; + } else if ((sic_status0 & ivg->isrflag0) || + (sic_status1 & ivg->isrflag1)) + break; + } + vec = ivg->irqno; + } + asm_do_IRQ(vec, fp); + +#ifdef CONFIG_KGDB + kgdb_process_breakpoint(); +#endif +} diff --git a/trunk/arch/blackfin/mach-common/ints-priority-sc.c b/trunk/arch/blackfin/mach-common/ints-priority-sc.c new file mode 100644 index 000000000000..34b62288ec3c --- /dev/null +++ b/trunk/arch/blackfin/mach-common/ints-priority-sc.c @@ -0,0 +1,577 @@ +/* + * File: arch/blackfin/mach-common/ints-priority-sc.c + * Based on: + * Author: + * + * Created: ? + * Description: Set up the interupt priorities + * + * Modified: + * 1996 Roman Zippel + * 1999 D. Jeff Dionne + * 2000-2001 Lineo, Inc. D. Jefff Dionne + * 2002 Arcturus Networks Inc. MaTed + * 2003 Metrowerks/Motorola + * 2003 Bas Vermeulen + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#ifdef CONFIG_KGDB +#include +#endif +#include +#include +#include +#include + +#ifdef BF537_FAMILY +# define BF537_GENERIC_ERROR_INT_DEMUX +#else +# undef BF537_GENERIC_ERROR_INT_DEMUX +#endif + +/* + * NOTES: + * - we have separated the physical Hardware interrupt from the + * levels that the LINUX kernel sees (see the description in irq.h) + * - + */ + +unsigned long irq_flags = 0; + +/* The number of spurious interrupts */ +atomic_t num_spurious; + +struct ivgx { + /* irq number for request_irq, available in mach-bf533/irq.h */ + int irqno; + /* corresponding bit in the SIC_ISR register */ + int isrflag; +} ivg_table[NR_PERI_INTS]; + +struct ivg_slice { + /* position of first irq in ivg_table for given ivg */ + struct ivgx *ifirst; + struct ivgx *istop; +} ivg7_13[IVG13 - IVG7 + 1]; + +static void search_IAR(void); + +/* + * Search SIC_IAR and fill tables with the irqvalues + * and their positions in the SIC_ISR register. + */ +static void __init search_IAR(void) +{ + unsigned ivg, irq_pos = 0; + for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) { + int irqn; + + ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = + &ivg_table[irq_pos]; + + for (irqn = 0; irqn < NR_PERI_INTS; irqn++) { + int iar_shift = (irqn & 7) * 4; + if (ivg == + (0xf & + bfin_read32((unsigned long *) SIC_IAR0 + + (irqn >> 3)) >> iar_shift)) { + ivg_table[irq_pos].irqno = IVG7 + irqn; + ivg_table[irq_pos].isrflag = 1 << irqn; + ivg7_13[ivg].istop++; + irq_pos++; + } + } + } +} + +/* + * This is for BF533 internal IRQs + */ + +static void ack_noop(unsigned int irq) +{ + /* Dummy function. */ +} + +static void bfin_core_mask_irq(unsigned int irq) +{ + irq_flags &= ~(1 << irq); + if (!irqs_disabled()) + local_irq_enable(); +} + +static void bfin_core_unmask_irq(unsigned int irq) +{ + irq_flags |= 1 << irq; + /* + * If interrupts are enabled, IMASK must contain the same value + * as irq_flags. Make sure that invariant holds. If interrupts + * are currently disabled we need not do anything; one of the + * callers will take care of setting IMASK to the proper value + * when reenabling interrupts. + * local_irq_enable just does "STI irq_flags", so it's exactly + * what we need. + */ + if (!irqs_disabled()) + local_irq_enable(); + return; +} + +static void bfin_internal_mask_irq(unsigned int irq) +{ + bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() & + ~(1 << (irq - (IRQ_CORETMR + 1)))); + SSYNC(); +} + +static void bfin_internal_unmask_irq(unsigned int irq) +{ + bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | + (1 << (irq - (IRQ_CORETMR + 1)))); + SSYNC(); +} + +static struct irq_chip bfin_core_irqchip = { + .ack = ack_noop, + .mask = bfin_core_mask_irq, + .unmask = bfin_core_unmask_irq, +}; + +static struct irq_chip bfin_internal_irqchip = { + .ack = ack_noop, + .mask = bfin_internal_mask_irq, + .unmask = bfin_internal_unmask_irq, +}; + +#ifdef BF537_GENERIC_ERROR_INT_DEMUX +static int error_int_mask; + +static void bfin_generic_error_ack_irq(unsigned int irq) +{ + +} + +static void bfin_generic_error_mask_irq(unsigned int irq) +{ + error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR)); + + if (!error_int_mask) { + local_irq_disable(); + bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() & + ~(1 << + (IRQ_GENERIC_ERROR - + (IRQ_CORETMR + 1)))); + SSYNC(); + local_irq_enable(); + } +} + +static void bfin_generic_error_unmask_irq(unsigned int irq) +{ + local_irq_disable(); + bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | 1 << + (IRQ_GENERIC_ERROR - (IRQ_CORETMR + 1))); + SSYNC(); + local_irq_enable(); + + error_int_mask |= 1L << (irq - IRQ_PPI_ERROR); +} + +static struct irq_chip bfin_generic_error_irqchip = { + .ack = bfin_generic_error_ack_irq, + .mask = bfin_generic_error_mask_irq, + .unmask = bfin_generic_error_unmask_irq, +}; + +static void bfin_demux_error_irq(unsigned int int_err_irq, + struct irq_desc *intb_desc) +{ + int irq = 0; + + SSYNC(); + +#if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) + if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK) + irq = IRQ_MAC_ERROR; + else +#endif + if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK) + irq = IRQ_SPORT0_ERROR; + else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK) + irq = IRQ_SPORT1_ERROR; + else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK) + irq = IRQ_PPI_ERROR; + else if (bfin_read_CAN_GIF() & CAN_ERR_MASK) + irq = IRQ_CAN_ERROR; + else if (bfin_read_SPI_STAT() & SPI_ERR_MASK) + irq = IRQ_SPI_ERROR; + else if ((bfin_read_UART0_IIR() & UART_ERR_MASK_STAT1) && + (bfin_read_UART0_IIR() & UART_ERR_MASK_STAT0)) + irq = IRQ_UART0_ERROR; + else if ((bfin_read_UART1_IIR() & UART_ERR_MASK_STAT1) && + (bfin_read_UART1_IIR() & UART_ERR_MASK_STAT0)) + irq = IRQ_UART1_ERROR; + + if (irq) { + if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR))) { + struct irq_desc *desc = irq_desc + irq; + desc->handle_irq(irq, desc); + } else { + + switch (irq) { + case IRQ_PPI_ERROR: + bfin_write_PPI_STATUS(PPI_ERR_MASK); + break; +#if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) + case IRQ_MAC_ERROR: + bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK); + break; +#endif + case IRQ_SPORT0_ERROR: + bfin_write_SPORT0_STAT(SPORT_ERR_MASK); + break; + + case IRQ_SPORT1_ERROR: + bfin_write_SPORT1_STAT(SPORT_ERR_MASK); + break; + + case IRQ_CAN_ERROR: + bfin_write_CAN_GIS(CAN_ERR_MASK); + break; + + case IRQ_SPI_ERROR: + bfin_write_SPI_STAT(SPI_ERR_MASK); + break; + + default: + break; + } + + pr_debug("IRQ %d:" + " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n", + irq); + } + } else + printk(KERN_ERR + "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR" + " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n", + __FUNCTION__, __FILE__, __LINE__); + + +} +#endif /* BF537_GENERIC_ERROR_INT_DEMUX */ + +#ifdef CONFIG_IRQCHIP_DEMUX_GPIO + +static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)]; +static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)]; + +static void bfin_gpio_ack_irq(unsigned int irq) +{ + u16 gpionr = irq - IRQ_PF0; + + if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) { + set_gpio_data(gpionr, 0); + SSYNC(); + } +} + +static void bfin_gpio_mask_ack_irq(unsigned int irq) +{ + u16 gpionr = irq - IRQ_PF0; + + if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) { + set_gpio_data(gpionr, 0); + SSYNC(); + } + + set_gpio_maska(gpionr, 0); + SSYNC(); +} + +static void bfin_gpio_mask_irq(unsigned int irq) +{ + set_gpio_maska(irq - IRQ_PF0, 0); + SSYNC(); +} + +static void bfin_gpio_unmask_irq(unsigned int irq) +{ + set_gpio_maska(irq - IRQ_PF0, 1); + SSYNC(); +} + +static unsigned int bfin_gpio_irq_startup(unsigned int irq) +{ + unsigned int ret; + u16 gpionr = irq - IRQ_PF0; + + if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) { + ret = gpio_request(gpionr, NULL); + if (ret) + return ret; + } + + gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr); + bfin_gpio_unmask_irq(irq); + + return ret; +} + +static void bfin_gpio_irq_shutdown(unsigned int irq) +{ + bfin_gpio_mask_irq(irq); + gpio_free(irq - IRQ_PF0); + gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0); +} + +static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) +{ + + unsigned int ret; + u16 gpionr = irq - IRQ_PF0; + + if (type == IRQ_TYPE_PROBE) { + /* only probe unenabled GPIO interrupt lines */ + if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)) + return 0; + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + } + + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | + IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) + { + if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) { + ret = gpio_request(gpionr, NULL); + if (ret) + return ret; + } + + gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr); + } else { + gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr); + return 0; + } + + set_gpio_dir(gpionr, 0); + set_gpio_inen(gpionr, 1); + + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { + gpio_edge_triggered[gpio_bank(gpionr)] |= gpio_bit(gpionr); + set_gpio_edge(gpionr, 1); + } else { + set_gpio_edge(gpionr, 0); + gpio_edge_triggered[gpio_bank(gpionr)] &= ~gpio_bit(gpionr); + } + + if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) + == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) + set_gpio_both(gpionr, 1); + else + set_gpio_both(gpionr, 0); + + if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW))) + set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */ + else + set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */ + + SSYNC(); + + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) + set_irq_handler(irq, handle_edge_irq); + else + set_irq_handler(irq, handle_level_irq); + + return 0; +} + + +static struct irq_chip bfin_gpio_irqchip = { + .ack = bfin_gpio_ack_irq, + .mask = bfin_gpio_mask_irq, + .mask_ack = bfin_gpio_mask_ack_irq, + .unmask = bfin_gpio_unmask_irq, + .set_type = bfin_gpio_irq_type, + .startup = bfin_gpio_irq_startup, + .shutdown = bfin_gpio_irq_shutdown +}; + +static void bfin_demux_gpio_irq(unsigned int intb_irq, + struct irq_desc *intb_desc) +{ + u16 i; + + for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=16) { + int irq = IRQ_PF0 + i; + int flag_d = get_gpiop_data(i); + int mask = + flag_d & (gpio_enabled[gpio_bank(i)] & + get_gpiop_maska(i)); + + while (mask) { + if (mask & 1) { + struct irq_desc *desc = irq_desc + irq; + desc->handle_irq(irq, desc); + } + irq++; + mask >>= 1; + } + } +} + +#endif /* CONFIG_IRQCHIP_DEMUX_GPIO */ + +/* + * This function should be called during kernel startup to initialize + * the BFin IRQ handling routines. + */ +int __init init_arch_irq(void) +{ + int irq; + unsigned long ilat = 0; + /* Disable all the peripheral intrs - page 4-29 HW Ref manual */ + bfin_write_SIC_IMASK(SIC_UNMASK_ALL); + SSYNC(); + + local_irq_disable(); + +#ifndef CONFIG_KGDB + bfin_write_EVT0(evt_emulation); +#endif + bfin_write_EVT2(evt_evt2); + bfin_write_EVT3(trap); + bfin_write_EVT5(evt_ivhw); + bfin_write_EVT6(evt_timer); + bfin_write_EVT7(evt_evt7); + bfin_write_EVT8(evt_evt8); + bfin_write_EVT9(evt_evt9); + bfin_write_EVT10(evt_evt10); + bfin_write_EVT11(evt_evt11); + bfin_write_EVT12(evt_evt12); + bfin_write_EVT13(evt_evt13); + bfin_write_EVT14(evt14_softirq); + bfin_write_EVT15(evt_system_call); + CSYNC(); + + for (irq = 0; irq < SYS_IRQS; irq++) { + if (irq <= IRQ_CORETMR) + set_irq_chip(irq, &bfin_core_irqchip); + else + set_irq_chip(irq, &bfin_internal_irqchip); +#ifdef BF537_GENERIC_ERROR_INT_DEMUX + if (irq != IRQ_GENERIC_ERROR) { +#endif + +#ifdef CONFIG_IRQCHIP_DEMUX_GPIO + if ((irq != IRQ_PROG_INTA) /*PORT F & G MASK_A Interrupt*/ +# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)) + && (irq != IRQ_MAC_RX) /*PORT H MASK_A Interrupt*/ +# endif + ) { +#endif + set_irq_handler(irq, handle_simple_irq); +#ifdef CONFIG_IRQCHIP_DEMUX_GPIO + } else { + set_irq_chained_handler(irq, + bfin_demux_gpio_irq); + } +#endif + +#ifdef BF537_GENERIC_ERROR_INT_DEMUX + } else { + set_irq_handler(irq, bfin_demux_error_irq); + } +#endif + } +#ifdef BF537_GENERIC_ERROR_INT_DEMUX + for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++) { + set_irq_chip(irq, &bfin_generic_error_irqchip); + set_irq_handler(irq, handle_level_irq); + } +#endif + +#ifdef CONFIG_IRQCHIP_DEMUX_GPIO + for (irq = IRQ_PF0; irq < NR_IRQS; irq++) { + set_irq_chip(irq, &bfin_gpio_irqchip); + /* if configured as edge, then will be changed to do_edge_IRQ */ + set_irq_handler(irq, handle_level_irq); + } +#endif + bfin_write_IMASK(0); + CSYNC(); + ilat = bfin_read_ILAT(); + CSYNC(); + bfin_write_ILAT(ilat); + CSYNC(); + + printk(KERN_INFO + "Configuring Blackfin Priority Driven Interrupts\n"); + /* IMASK=xxx is equivalent to STI xx or irq_flags=xx, + * local_irq_enable() + */ + program_IAR(); + /* Therefore it's better to setup IARs before interrupts enabled */ + search_IAR(); + + /* Enable interrupts IVG7-15 */ + irq_flags = irq_flags | IMASK_IVG15 | + IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | + IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | + IMASK_IVGHW; + + return 0; +} + +#ifdef CONFIG_DO_IRQ_L1 +void do_irq(int vec, struct pt_regs *fp)__attribute__((l1_text)); +#endif + +void do_irq(int vec, struct pt_regs *fp) +{ + if (vec == EVT_IVTMR_P) { + vec = IRQ_CORETMR; + } else { + struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst; + struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop; + unsigned long sic_status; + + SSYNC(); + sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR(); + + for (;; ivg++) { + if (ivg >= ivg_stop) { + atomic_inc(&num_spurious); + return; + } else if (sic_status & ivg->isrflag) + break; + } + vec = ivg->irqno; + } + asm_do_IRQ(vec, fp); + +#ifdef CONFIG_KGDB + kgdb_process_breakpoint(); +#endif +} diff --git a/trunk/arch/blackfin/mach-common/irqpanic.c b/trunk/arch/blackfin/mach-common/irqpanic.c new file mode 100644 index 000000000000..f05e3dadaf33 --- /dev/null +++ b/trunk/arch/blackfin/mach-common/irqpanic.c @@ -0,0 +1,194 @@ +/* + * File: arch/blackfin/mach-common/irqpanic.c + * Based on: + * Author: + * + * Created: ? + * Description: panic kernel with dump information + * + * Modified: rgetz - added cache checking code 14Feb06 + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "../oprofile/op_blackfin.h" + +#ifdef CONFIG_DEBUG_ICACHE_CHECK +#define L1_ICACHE_START 0xffa10000 +#define L1_ICACHE_END 0xffa13fff +void irq_panic(int reason, struct pt_regs *regs) __attribute__ ((l1_text)); +#endif + +/* + * irq_panic - calls panic with string setup + */ +asmlinkage void irq_panic(int reason, struct pt_regs *regs) +{ + int sig = 0; + siginfo_t info; + +#ifdef CONFIG_DEBUG_ICACHE_CHECK + unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa; + unsigned short i, j, die; + unsigned int bad[10][6]; + + /* check entire cache for coherency + * Since printk is in cacheable memory, + * don't call it until you have checked everything + */ + + die = 0; + i = 0; + + /* check icache */ + + for (ca = L1_ICACHE_START; ca <= L1_ICACHE_END && i < 10; ca += 32) { + + /* Grab various address bits for the itest_cmd fields */ + cmd = (((ca & 0x3000) << 4) | /* ca[13:12] for SBNK[1:0] */ + ((ca & 0x0c00) << 16) | /* ca[11:10] for WAYSEL[1:0] */ + ((ca & 0x3f8)) | /* ca[09:03] for SET[4:0] and DW[1:0] */ + 0); /* Access Tag, Read access */ + + SSYNC(); + bfin_write_ITEST_COMMAND(cmd); + SSYNC(); + tag = bfin_read_ITEST_DATA0(); + SSYNC(); + + /* if tag is marked as valid, check it */ + if (tag & 1) { + /* The icache is arranged in 4 groups of 64-bits */ + for (j = 0; j < 32; j += 8) { + cmd = ((((ca + j) & 0x3000) << 4) | /* ca[13:12] for SBNK[1:0] */ + (((ca + j) & 0x0c00) << 16) | /* ca[11:10] for WAYSEL[1:0] */ + (((ca + j) & 0x3f8)) | /* ca[09:03] for SET[4:0] and DW[1:0] */ + 4); /* Access Data, Read access */ + + SSYNC(); + bfin_write_ITEST_COMMAND(cmd); + SSYNC(); + + cache_hi = bfin_read_ITEST_DATA1(); + cache_lo = bfin_read_ITEST_DATA0(); + + pa = ((unsigned int *)((tag & 0xffffcc00) | + ((ca + j) & ~(0xffffcc00)))); + + /* + * Debugging this, enable + * + * printk("addr: %08x %08x%08x | %08x%08x\n", + * ((unsigned int *)((tag & 0xffffcc00) | ((ca+j) & ~(0xffffcc00)))), + * cache_hi, cache_lo, *(pa+1), *pa); + */ + + if (cache_hi != *(pa + 1) || cache_lo != *pa) { + /* Since icache is not working, stay out of it, by not printing */ + die = 1; + bad[i][0] = (ca + j); + bad[i][1] = cache_hi; + bad[i][2] = cache_lo; + bad[i][3] = ((tag & 0xffffcc00) | + ((ca + j) & ~(0xffffcc00))); + bad[i][4] = *(pa + 1); + bad[i][5] = *(pa); + i++; + } + } + } + } + if (die) { + printk(KERN_EMERG "icache coherency error\n"); + for (j = 0; j <= i; j++) { + printk(KERN_EMERG + "cache address : %08x cache value : %08x%08x\n", + bad[j][0], bad[j][1], bad[j][2]); + printk(KERN_EMERG + "physical address: %08x SDRAM value : %08x%08x\n", + bad[j][3], bad[j][4], bad[j][5]); + } + panic("icache coherency error"); + } else { + printk(KERN_EMERG "icache checked, and OK\n"); + } +#endif + + printk(KERN_EMERG "\n"); + printk(KERN_EMERG "Exception: IRQ 0x%x entered\n", reason); + printk(KERN_EMERG " code=[0x%08lx], stack frame=0x%08lx, " + " bad PC=0x%08lx\n", + (unsigned long)regs->seqstat, + (unsigned long)regs, + (unsigned long)regs->pc); + if (reason == 0x5) { + printk(KERN_EMERG "----------- HARDWARE ERROR -----------\n"); + + /* There is only need to check for Hardware Errors, since other + * EXCEPTIONS are handled in TRAPS.c (MH) + */ + switch (regs->seqstat & SEQSTAT_HWERRCAUSE) { + case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR): /* System MMR Error */ + info.si_code = BUS_ADRALN; + sig = SIGBUS; + printk(KERN_EMERG HWC_x2); + break; + case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): /* External Memory Addressing Error */ + info.si_code = BUS_ADRERR; + sig = SIGBUS; + printk(KERN_EMERG HWC_x3); + break; + case (SEQSTAT_HWERRCAUSE_PERF_FLOW): /* Performance Monitor Overflow */ + printk(KERN_EMERG HWC_x12); + break; + case (SEQSTAT_HWERRCAUSE_RAISE_5): /* RAISE 5 instruction */ + printk(KERN_EMERG HWC_x18); + break; + default: /* Reserved */ + printk(KERN_EMERG HWC_default); + break; + } + } + + regs->ipend = bfin_read_IPEND(); + dump_bfin_regs(regs, (void *)regs->pc); + if (0 == (info.si_signo = sig) || 0 == user_mode(regs)) /* in kernelspace */ + panic("Unhandled IRQ or exceptions!\n"); + else { /* in userspace */ + info.si_errno = 0; + info.si_addr = (void *)regs->pc; + force_sig_info(sig, &info, current); + } +} + +#ifdef CONFIG_HARDWARE_PM +/* + * call the handler of Performance overflow + */ +asmlinkage void pm_overflow(int irq, struct pt_regs *regs) +{ + pm_overflow_handler(irq, regs); +} +#endif diff --git a/trunk/arch/blackfin/mach-common/lock.S b/trunk/arch/blackfin/mach-common/lock.S new file mode 100644 index 000000000000..2cbb15b33925 --- /dev/null +++ b/trunk/arch/blackfin/mach-common/lock.S @@ -0,0 +1,204 @@ +/* + * File: arch/blackfin/mach-common/lock.S + * Based on: + * Author: LG Soft India + * + * Created: ? + * Description: kernel locks + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +.text + +#ifdef CONFIG_BLKFIN_CACHE_LOCK + +/* When you come here, it is assumed that + * R0 - Which way to be locked + */ + +ENTRY(_cache_grab_lock) + + [--SP]=( R7:0,P5:0 ); + + P1.H = (IMEM_CONTROL >> 16); + P1.L = (IMEM_CONTROL & 0xFFFF); + P5.H = (ICPLB_ADDR0 >> 16); + P5.L = (ICPLB_ADDR0 & 0xFFFF); + P4.H = (ICPLB_DATA0 >> 16); + P4.L = (ICPLB_DATA0 & 0xFFFF); + R7 = R0; + + /* If the code of interest already resides in the cache + * invalidate the entire cache itself. + * invalidate_entire_icache; + */ + + SP += -12; + [--SP] = RETS; + CALL _invalidate_entire_icache; + RETS = [SP++]; + SP += 12; + + /* Disable the Interrupts*/ + + CLI R3; + +.LLOCK_WAY: + + /* Way0 - 0xFFA133E0 + * Way1 - 0xFFA137E0 + * Way2 - 0xFFA13BE0 Total Way Size = 4K + * Way3 - 0xFFA13FE0 + */ + + /* Procedure Ex. -Set the locks for other ways by setting ILOC[3:1] + * Only Way0 of the instruction cache can now be + * replaced by a new code + */ + + R5 = R7; + CC = BITTST(R7,0); + IF CC JUMP .LCLEAR1; + R7 = 0; + BITSET(R7,0); + JUMP .LDONE1; + +.LCLEAR1: + R7 = 0; + BITCLR(R7,0); +.LDONE1: R4 = R7 << 3; + R7 = [P1]; + R7 = R7 | R4; + SSYNC; /* SSYNC required writing to IMEM_CONTROL. */ + .align 8; + [P1] = R7; + SSYNC; + + R7 = R5; + CC = BITTST(R7,1); + IF CC JUMP .LCLEAR2; + R7 = 0; + BITSET(R7,1); + JUMP .LDONE2; + +.LCLEAR2: + R7 = 0; + BITCLR(R7,1); +.LDONE2: R4 = R7 << 3; + R7 = [P1]; + R7 = R7 | R4; + SSYNC; /* SSYNC required writing to IMEM_CONTROL. */ + .align 8; + [P1] = R7; + SSYNC; + + R7 = R5; + CC = BITTST(R7,2); + IF CC JUMP .LCLEAR3; + R7 = 0; + BITSET(R7,2); + JUMP .LDONE3; +.LCLEAR3: + R7 = 0; + BITCLR(R7,2); +.LDONE3: R4 = R7 << 3; + R7 = [P1]; + R7 = R7 | R4; + SSYNC; /* SSYNC required writing to IMEM_CONTROL. */ + .align 8; + [P1] = R7; + SSYNC; + + + R7 = R5; + CC = BITTST(R7,3); + IF CC JUMP .LCLEAR4; + R7 = 0; + BITSET(R7,3); + JUMP .LDONE4; +.LCLEAR4: + R7 = 0; + BITCLR(R7,3); +.LDONE4: R4 = R7 << 3; + R7 = [P1]; + R7 = R7 | R4; + SSYNC; /* SSYNC required writing to IMEM_CONTROL. */ + .align 8; + [P1] = R7; + SSYNC; + + STI R3; + + ( R7:0,P5:0 ) = [SP++]; + + RTS; + +/* After the execution of critical code, the code is now locked into + * the cache way. Now we need to set ILOC. + * + * R0 - Which way to be locked + */ + +ENTRY(_cache_lock) + + [--SP]=( R7:0,P5:0 ); + + P1.H = (IMEM_CONTROL >> 16); + P1.L = (IMEM_CONTROL & 0xFFFF); + + /* Disable the Interrupts*/ + CLI R3; + + R7 = [P1]; + R2 = 0xFFFFFF87 (X); + R7 = R7 & R2; + R0 = R0 << 3; + R7 = R0 | R7; + SSYNC; /* SSYNC required writing to IMEM_CONTROL. */ + .align 8; + [P1] = R7; + SSYNC; + /* Renable the Interrupts */ + STI R3; + + ( R7:0,P5:0 ) = [SP++]; + RTS; + +#endif /* BLKFIN_CACHE_LOCK */ + +/* Return the ILOC bits of IMEM_CONTROL + */ + +ENTRY(_read_iloc) + + P1.H = (IMEM_CONTROL >> 16); + P1.L = (IMEM_CONTROL & 0xFFFF); + R1 = 0xF; + R0 = [P1]; + R0 = R0 >> 3; + R0 = R0 & R1; + + RTS; diff --git a/trunk/arch/blackfin/mach-common/pm.c b/trunk/arch/blackfin/mach-common/pm.c new file mode 100644 index 000000000000..deb27272c658 --- /dev/null +++ b/trunk/arch/blackfin/mach-common/pm.c @@ -0,0 +1,181 @@ +/* + * File: arch/blackfin/mach-common/pm.c + * Based on: arm/mach-omap/pm.c + * Author: Cliff Brake Copyright (c) 2001 + * + * Created: 2001 + * Description: Power management for the bfin + * + * Modified: Nicolas Pitre - PXA250 support + * Copyright (c) 2002 Monta Vista Software, Inc. + * David Singleton - OMAP1510 + * Copyright (c) 2002 Monta Vista Software, Inc. + * Dirk Behme - OMAP1510/1610 + * Copyright 2004 + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include +#include +#include + + +#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_H +#define WAKEUP_TYPE PM_WAKE_HIGH +#endif + +#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_L +#define WAKEUP_TYPE PM_WAKE_LOW +#endif + +#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_F +#define WAKEUP_TYPE PM_WAKE_FALLING +#endif + +#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_R +#define WAKEUP_TYPE PM_WAKE_RISING +#endif + +#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_B +#define WAKEUP_TYPE PM_WAKE_BOTH_EDGES +#endif + +void bfin_pm_suspend_standby_enter(void) +{ +#ifdef CONFIG_PM_WAKEUP_BY_GPIO + gpio_pm_wakeup_request(CONFIG_PM_WAKEUP_GPIO_NUMBER, WAKEUP_TYPE); +#endif + +#if defined(CONFIG_PM_WAKEUP_BY_GPIO) || defined(CONFIG_PM_WAKEUP_GPIO_API) + { + u32 flags; + + local_irq_save(flags); + + sleep_deeper(gpio_pm_setup()); /*Goto Sleep*/ + + gpio_pm_restore(); + + bfin_write_SIC_IWR(IWR_ENABLE_ALL); + + local_irq_restore(flags); + } +#endif + +#if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR) + sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR); + bfin_write_SIC_IWR(IWR_ENABLE_ALL); +#endif /* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */ +} + + +/* + * bfin_pm_prepare - Do preliminary suspend work. + * @state: suspend state we're entering. + * + */ +static int bfin_pm_prepare(suspend_state_t state) +{ + int error = 0; + + switch (state) { + case PM_SUSPEND_STANDBY: + break; + case PM_SUSPEND_MEM: + return -ENOTSUPP; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + + default: + return -EINVAL; + } + + return error; +} + +/* + * bfin_pm_enter - Actually enter a sleep state. + * @state: State we're entering. + * + */ +static int bfin_pm_enter(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + bfin_pm_suspend_standby_enter(); + break; + case PM_SUSPEND_MEM: + return -ENOTSUPP; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * bfin_pm_finish - Finish up suspend sequence. + * @state: State we're coming out of. + * + * This is called after we wake back up (or if entering the sleep state + * failed). + */ +static int bfin_pm_finish(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + break; + + case PM_SUSPEND_MEM: + return -ENOTSUPP; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + + default: + return -EINVAL; + } + + return 0; +} + +struct pm_ops bfin_pm_ops = { + .pm_disk_mode = PM_DISK_PLATFORM, + .prepare = bfin_pm_prepare, + .enter = bfin_pm_enter, + .finish = bfin_pm_finish, +}; + +static int __init bfin_pm_init(void) +{ + pm_set_ops(&bfin_pm_ops); + return 0; +} + +__initcall(bfin_pm_init); diff --git a/trunk/arch/blackfin/mm/Makefile b/trunk/arch/blackfin/mm/Makefile new file mode 100644 index 000000000000..2a7202ce01fd --- /dev/null +++ b/trunk/arch/blackfin/mm/Makefile @@ -0,0 +1,5 @@ +# +# arch/blackfin/mm/Makefile +# + +obj-y := blackfin_sram.o init.o diff --git a/trunk/arch/blackfin/mm/blackfin_sram.c b/trunk/arch/blackfin/mm/blackfin_sram.c new file mode 100644 index 000000000000..dd0c6501c424 --- /dev/null +++ b/trunk/arch/blackfin/mm/blackfin_sram.c @@ -0,0 +1,540 @@ +/* + * File: arch/blackfin/mm/blackfin_sram.c + * Based on: + * Author: + * + * Created: + * Description: SRAM driver for Blackfin ADSP-BF5xx + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "blackfin_sram.h" + +spinlock_t l1sram_lock, l1_data_sram_lock, l1_inst_sram_lock; + +#if CONFIG_L1_MAX_PIECE < 16 +#undef CONFIG_L1_MAX_PIECE +#define CONFIG_L1_MAX_PIECE 16 +#endif + +#if CONFIG_L1_MAX_PIECE > 1024 +#undef CONFIG_L1_MAX_PIECE +#define CONFIG_L1_MAX_PIECE 1024 +#endif + +#define SRAM_SLT_NULL 0 +#define SRAM_SLT_FREE 1 +#define SRAM_SLT_ALLOCATED 2 + +/* the data structure for L1 scratchpad and DATA SRAM */ +struct l1_sram_piece { + void *paddr; + int size; + int flag; +}; + +static struct l1_sram_piece l1_ssram[CONFIG_L1_MAX_PIECE]; + +#if L1_DATA_A_LENGTH != 0 +static struct l1_sram_piece l1_data_A_sram[CONFIG_L1_MAX_PIECE]; +#endif + +#if L1_DATA_B_LENGTH != 0 +static struct l1_sram_piece l1_data_B_sram[CONFIG_L1_MAX_PIECE]; +#endif + +#if L1_CODE_LENGTH != 0 +static struct l1_sram_piece l1_inst_sram[CONFIG_L1_MAX_PIECE]; +#endif + +/* L1 Scratchpad SRAM initialization function */ +void l1sram_init(void) +{ + printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n", + L1_SCRATCH_LENGTH >> 10); + + memset(&l1_ssram, 0x00, sizeof(l1_ssram)); + l1_ssram[0].paddr = (void*)L1_SCRATCH_START; + l1_ssram[0].size = L1_SCRATCH_LENGTH; + l1_ssram[0].flag = SRAM_SLT_FREE; + + /* mutex initialize */ + spin_lock_init(&l1sram_lock); +} + +void l1_data_sram_init(void) +{ +#if L1_DATA_A_LENGTH != 0 + printk(KERN_INFO "Blackfin DATA_A SRAM: %d KB\n", + L1_DATA_A_LENGTH >> 10); + + memset(&l1_data_A_sram, 0x00, sizeof(l1_data_A_sram)); + l1_data_A_sram[0].paddr = (void*)L1_DATA_A_START + + (_ebss_l1 - _sdata_l1); + l1_data_A_sram[0].size = L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1); + l1_data_A_sram[0].flag = SRAM_SLT_FREE; +#endif +#if L1_DATA_B_LENGTH != 0 + printk(KERN_INFO "Blackfin DATA_B SRAM: %d KB\n", + L1_DATA_B_LENGTH >> 10); + + memset(&l1_data_B_sram, 0x00, sizeof(l1_data_B_sram)); + l1_data_B_sram[0].paddr = (void*)L1_DATA_B_START; + l1_data_B_sram[0].size = L1_DATA_B_LENGTH; + l1_data_B_sram[0].flag = SRAM_SLT_FREE; +#endif + + /* mutex initialize */ + spin_lock_init(&l1_data_sram_lock); +} + +void l1_inst_sram_init(void) +{ +#if L1_CODE_LENGTH != 0 + printk(KERN_INFO "Blackfin Instruction SRAM: %d KB\n", + L1_CODE_LENGTH >> 10); + + memset(&l1_inst_sram, 0x00, sizeof(l1_inst_sram)); + l1_inst_sram[0].paddr = (void*)L1_CODE_START + (_etext_l1 - _stext_l1); + l1_inst_sram[0].size = L1_CODE_LENGTH - (_etext_l1 - _stext_l1); + l1_inst_sram[0].flag = SRAM_SLT_FREE; +#endif + + /* mutex initialize */ + spin_lock_init(&l1_inst_sram_lock); +} + +/* L1 memory allocate function */ +static void *_l1_sram_alloc(size_t size, struct l1_sram_piece *pfree, int count) +{ + int i, index = 0; + void *addr = NULL; + + if (size <= 0) + return NULL; + + /* Align the size */ + size = (size + 3) & ~3; + + /* not use the good method to match the best slot !!! */ + /* search an available memeory slot */ + for (i = 0; i < count; i++) { + if ((pfree[i].flag == SRAM_SLT_FREE) + && (pfree[i].size >= size)) { + addr = pfree[i].paddr; + pfree[i].flag = SRAM_SLT_ALLOCATED; + index = i; + break; + } + } + if (i >= count) + return NULL; + + /* updated the NULL memeory slot !!! */ + if (pfree[i].size > size) { + for (i = 0; i < count; i++) { + if (pfree[i].flag == SRAM_SLT_NULL) { + pfree[i].flag = SRAM_SLT_FREE; + pfree[i].paddr = addr + size; + pfree[i].size = pfree[index].size - size; + pfree[index].size = size; + break; + } + } + } + + return addr; +} + +/* Allocate the largest available block. */ +static void *_l1_sram_alloc_max(struct l1_sram_piece *pfree, int count, + unsigned long *psize) +{ + unsigned long best = 0; + int i, index = -1; + void *addr = NULL; + + /* search an available memeory slot */ + for (i = 0; i < count; i++) { + if (pfree[i].flag == SRAM_SLT_FREE && pfree[i].size > best) { + addr = pfree[i].paddr; + index = i; + best = pfree[i].size; + } + } + if (index < 0) + return NULL; + *psize = best; + + pfree[index].flag = SRAM_SLT_ALLOCATED; + return addr; +} + +/* L1 memory free function */ +static int _l1_sram_free(const void *addr, + struct l1_sram_piece *pfree, int count) +{ + int i, index = 0; + + /* search the relevant memory slot */ + for (i = 0; i < count; i++) { + if (pfree[i].paddr == addr) { + if (pfree[i].flag != SRAM_SLT_ALLOCATED) { + /* error log */ + return -1; + } + index = i; + break; + } + } + if (i >= count) + return -1; + + pfree[index].flag = SRAM_SLT_FREE; + + /* link the next address slot */ + for (i = 0; i < count; i++) { + if (((pfree[index].paddr + pfree[index].size) == pfree[i].paddr) + && (pfree[i].flag == SRAM_SLT_FREE)) { + pfree[i].flag = SRAM_SLT_NULL; + pfree[index].size += pfree[i].size; + pfree[index].flag = SRAM_SLT_FREE; + break; + } + } + + /* link the last address slot */ + for (i = 0; i < count; i++) { + if (((pfree[i].paddr + pfree[i].size) == pfree[index].paddr) && + (pfree[i].flag == SRAM_SLT_FREE)) { + pfree[index].flag = SRAM_SLT_NULL; + pfree[i].size += pfree[index].size; + break; + } + } + + return 0; +} + +int sram_free(const void *addr) +{ + if (0) {} +#if L1_CODE_LENGTH != 0 + else if (addr >= (void *)L1_CODE_START + && addr < (void *)(L1_CODE_START + L1_CODE_LENGTH)) + return l1_inst_sram_free(addr); +#endif +#if L1_DATA_A_LENGTH != 0 + else if (addr >= (void *)L1_DATA_A_START + && addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH)) + return l1_data_A_sram_free(addr); +#endif +#if L1_DATA_B_LENGTH != 0 + else if (addr >= (void *)L1_DATA_B_START + && addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH)) + return l1_data_B_sram_free(addr); +#endif + else + return -1; +} +EXPORT_SYMBOL(sram_free); + +void *l1_data_A_sram_alloc(size_t size) +{ + unsigned flags; + void *addr = NULL; + + /* add mutex operation */ + spin_lock_irqsave(&l1_data_sram_lock, flags); + +#if L1_DATA_A_LENGTH != 0 + addr = _l1_sram_alloc(size, l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram)); +#endif + + /* add mutex operation */ + spin_unlock_irqrestore(&l1_data_sram_lock, flags); + + pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n", + (long unsigned int)addr, size); + + return addr; +} +EXPORT_SYMBOL(l1_data_A_sram_alloc); + +int l1_data_A_sram_free(const void *addr) +{ + unsigned flags; + int ret; + + /* add mutex operation */ + spin_lock_irqsave(&l1_data_sram_lock, flags); + +#if L1_DATA_A_LENGTH != 0 + ret = _l1_sram_free(addr, + l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram)); +#else + ret = -1; +#endif + + /* add mutex operation */ + spin_unlock_irqrestore(&l1_data_sram_lock, flags); + + return ret; +} +EXPORT_SYMBOL(l1_data_A_sram_free); + +void *l1_data_B_sram_alloc(size_t size) +{ +#if L1_DATA_B_LENGTH != 0 + unsigned flags; + void *addr; + + /* add mutex operation */ + spin_lock_irqsave(&l1_data_sram_lock, flags); + + addr = _l1_sram_alloc(size, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram)); + + /* add mutex operation */ + spin_unlock_irqrestore(&l1_data_sram_lock, flags); + + pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n", + (long unsigned int)addr, size); + + return addr; +#else + return NULL; +#endif +} +EXPORT_SYMBOL(l1_data_B_sram_alloc); + +int l1_data_B_sram_free(const void *addr) +{ +#if L1_DATA_B_LENGTH != 0 + unsigned flags; + int ret; + + /* add mutex operation */ + spin_lock_irqsave(&l1_data_sram_lock, flags); + + ret = _l1_sram_free(addr, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram)); + + /* add mutex operation */ + spin_unlock_irqrestore(&l1_data_sram_lock, flags); + + return ret; +#else + return -1; +#endif +} +EXPORT_SYMBOL(l1_data_B_sram_free); + +void *l1_data_sram_alloc(size_t size) +{ + void *addr = l1_data_A_sram_alloc(size); + + if (!addr) + addr = l1_data_B_sram_alloc(size); + + return addr; +} +EXPORT_SYMBOL(l1_data_sram_alloc); + +void *l1_data_sram_zalloc(size_t size) +{ + void *addr = l1_data_sram_alloc(size); + + if (addr) + memset(addr, 0x00, size); + + return addr; +} +EXPORT_SYMBOL(l1_data_sram_zalloc); + +int l1_data_sram_free(const void *addr) +{ + int ret; + ret = l1_data_A_sram_free(addr); + if (ret == -1) + ret = l1_data_B_sram_free(addr); + return ret; +} +EXPORT_SYMBOL(l1_data_sram_free); + +void *l1_inst_sram_alloc(size_t size) +{ +#if L1_DATA_A_LENGTH != 0 + unsigned flags; + void *addr; + + /* add mutex operation */ + spin_lock_irqsave(&l1_inst_sram_lock, flags); + + addr = _l1_sram_alloc(size, l1_inst_sram, ARRAY_SIZE(l1_inst_sram)); + + /* add mutex operation */ + spin_unlock_irqrestore(&l1_inst_sram_lock, flags); + + pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n", + (long unsigned int)addr, size); + + return addr; +#else + return NULL; +#endif +} +EXPORT_SYMBOL(l1_inst_sram_alloc); + +int l1_inst_sram_free(const void *addr) +{ +#if L1_CODE_LENGTH != 0 + unsigned flags; + int ret; + + /* add mutex operation */ + spin_lock_irqsave(&l1_inst_sram_lock, flags); + + ret = _l1_sram_free(addr, l1_inst_sram, ARRAY_SIZE(l1_inst_sram)); + + /* add mutex operation */ + spin_unlock_irqrestore(&l1_inst_sram_lock, flags); + + return ret; +#else + return -1; +#endif +} +EXPORT_SYMBOL(l1_inst_sram_free); + +/* L1 Scratchpad memory allocate function */ +void *l1sram_alloc(size_t size) +{ + unsigned flags; + void *addr; + + /* add mutex operation */ + spin_lock_irqsave(&l1sram_lock, flags); + + addr = _l1_sram_alloc(size, l1_ssram, ARRAY_SIZE(l1_ssram)); + + /* add mutex operation */ + spin_unlock_irqrestore(&l1sram_lock, flags); + + return addr; +} + +/* L1 Scratchpad memory allocate function */ +void *l1sram_alloc_max(size_t *psize) +{ + unsigned flags; + void *addr; + + /* add mutex operation */ + spin_lock_irqsave(&l1sram_lock, flags); + + addr = _l1_sram_alloc_max(l1_ssram, ARRAY_SIZE(l1_ssram), psize); + + /* add mutex operation */ + spin_unlock_irqrestore(&l1sram_lock, flags); + + return addr; +} + +/* L1 Scratchpad memory free function */ +int l1sram_free(const void *addr) +{ + unsigned flags; + int ret; + + /* add mutex operation */ + spin_lock_irqsave(&l1sram_lock, flags); + + ret = _l1_sram_free(addr, l1_ssram, ARRAY_SIZE(l1_ssram)); + + /* add mutex operation */ + spin_unlock_irqrestore(&l1sram_lock, flags); + + return ret; +} + +int sram_free_with_lsl(const void *addr) +{ + struct sram_list_struct *lsl, **tmp; + struct mm_struct *mm = current->mm; + + for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next) + if ((*tmp)->addr == addr) + goto found; + return -1; +found: + lsl = *tmp; + sram_free(addr); + *tmp = lsl->next; + kfree(lsl); + + return 0; +} +EXPORT_SYMBOL(sram_free_with_lsl); + +void *sram_alloc_with_lsl(size_t size, unsigned long flags) +{ + void *addr = NULL; + struct sram_list_struct *lsl = NULL; + struct mm_struct *mm = current->mm; + + lsl = kmalloc(sizeof(struct sram_list_struct), GFP_KERNEL); + if (!lsl) + return NULL; + memset(lsl, 0, sizeof(*lsl)); + + if (flags & L1_INST_SRAM) + addr = l1_inst_sram_alloc(size); + + if (addr == NULL && (flags & L1_DATA_A_SRAM)) + addr = l1_data_A_sram_alloc(size); + + if (addr == NULL && (flags & L1_DATA_B_SRAM)) + addr = l1_data_B_sram_alloc(size); + + if (addr == NULL) { + kfree(lsl); + return NULL; + } + lsl->addr = addr; + lsl->length = size; + lsl->next = mm->context.sram_list; + mm->context.sram_list = lsl; + return addr; +} +EXPORT_SYMBOL(sram_alloc_with_lsl); diff --git a/trunk/arch/blackfin/mm/blackfin_sram.h b/trunk/arch/blackfin/mm/blackfin_sram.h new file mode 100644 index 000000000000..0fb73b78dd60 --- /dev/null +++ b/trunk/arch/blackfin/mm/blackfin_sram.h @@ -0,0 +1,38 @@ +/* + * File: arch/blackfin/mm/blackfin_sram.h + * Based on: arch/blackfin/mm/blackfin_sram.c + * Author: Mike Frysinger + * + * Created: Aug 2006 + * Description: Local prototypes meant for internal use only + * + * Modified: + * Copyright 2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __BLACKFIN_SRAM_H__ +#define __BLACKFIN_SRAM_H__ + +extern void l1sram_init(void); +extern void l1_inst_sram_init(void); +extern void l1_data_sram_init(void); +extern void *l1sram_alloc(size_t); + +#endif diff --git a/trunk/arch/blackfin/mm/init.c b/trunk/arch/blackfin/mm/init.c new file mode 100644 index 000000000000..73f72abed432 --- /dev/null +++ b/trunk/arch/blackfin/mm/init.c @@ -0,0 +1,208 @@ +/* + * File: arch/blackfin/mm/init.c + * Based on: + * Author: + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include "blackfin_sram.h" + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving a inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +static unsigned long empty_bad_page_table; + +static unsigned long empty_bad_page; + +unsigned long empty_zero_page; + +void show_mem(void) +{ + unsigned long i; + int free = 0, total = 0, reserved = 0, shared = 0; + + int cached = 0; + printk(KERN_INFO "Mem-info:\n"); + show_free_areas(); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageReserved(mem_map + i)) + reserved++; + else if (PageSwapCache(mem_map + i)) + cached++; + else if (!page_count(mem_map + i)) + free++; + else + shared += page_count(mem_map + i) - 1; + } + printk(KERN_INFO "%d pages of RAM\n", total); + printk(KERN_INFO "%d free pages\n", free); + printk(KERN_INFO "%d reserved pages\n", reserved); + printk(KERN_INFO "%d pages shared\n", shared); + printk(KERN_INFO "%d pages swap cached\n", cached); +} + +/* + * paging_init() continues the virtual memory environment setup which + * was begun by the code in arch/head.S. + * The parameters are pointers to where to stick the starting and ending + * addresses of available kernel virtual memory. + */ +void paging_init(void) +{ + /* + * make sure start_mem is page aligned, otherwise bootmem and + * page_alloc get different views og the world + */ + unsigned long end_mem = memory_end & PAGE_MASK; + + pr_debug("start_mem is %#lx virtual_end is %#lx\n", PAGE_ALIGN(memory_start), end_mem); + + /* + * initialize the bad page table and bad page to point + * to a couple of allocated pages + */ + empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + /* + * Set up SFC/DFC registers (user data space) + */ + set_fs(KERNEL_DS); + + pr_debug("free_area_init -> start_mem is %#lx virtual_end is %#lx\n", + PAGE_ALIGN(memory_start), end_mem); + + { + unsigned long zones_size[MAX_NR_ZONES] = { 0, }; + + zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT; +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = 0; +#endif + free_area_init(zones_size); + } +} + +void mem_init(void) +{ + unsigned int codek = 0, datak = 0, initk = 0; + unsigned long tmp; + unsigned int len = _ramend - _rambase; + unsigned long start_mem = memory_start; + unsigned long end_mem = memory_end; + + end_mem &= PAGE_MASK; + high_memory = (void *)end_mem; + + start_mem = PAGE_ALIGN(start_mem); + max_mapnr = num_physpages = MAP_NR(high_memory); + printk(KERN_INFO "Physical pages: %lx\n", num_physpages); + + /* This will put all memory onto the freelists. */ + totalram_pages = free_all_bootmem(); + + codek = (_etext - _stext) >> 10; + datak = (__bss_stop - __bss_start) >> 10; + initk = (__init_end - __init_begin) >> 10; + + tmp = nr_free_pages() << PAGE_SHIFT; + printk(KERN_INFO + "Memory available: %luk/%uk RAM, (%uk init code, %uk kernel code, %uk data, %uk dma)\n", + tmp >> 10, len >> 10, initk, codek, datak, DMA_UNCACHED_REGION >> 10); + + /* Initialize the blackfin L1 Memory. */ + l1sram_init(); + l1_data_sram_init(); + l1_inst_sram_init(); + + /* Allocate this once; never free it. We assume this gives us a + pointer to the start of L1 scratchpad memory; panic if it + doesn't. */ + tmp = (unsigned long)l1sram_alloc(sizeof(struct l1_scratch_task_info)); + if (tmp != (unsigned long)L1_SCRATCH_TASK_INFO) { + printk(KERN_EMERG "mem_init(): Did not get the right address from l1sram_alloc: %08lx != %08lx\n", + tmp, (unsigned long)L1_SCRATCH_TASK_INFO); + panic("No L1, time to give up\n"); + } +} + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + int pages = 0; + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(virt_to_page(start)); + init_page_count(virt_to_page(start)); + free_page(start); + totalram_pages++; + pages++; + } + printk(KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages); +} +#endif + +void free_initmem(void) +{ +#ifdef CONFIG_RAMKERNEL + unsigned long addr; +/* + * the following code should be cool even if these sections + * are not page aligned. + */ + addr = PAGE_ALIGN((unsigned long)(__init_begin)); + /* next to check that the page we free is not a partial page */ + for (; addr + PAGE_SIZE < (unsigned long)(__init_end); + addr += PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + init_page_count(virt_to_page(addr)); + free_page(addr); + totalram_pages++; + } + printk(KERN_NOTICE + "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n", + (addr - PAGE_ALIGN((long)__init_begin)) >> 10, + (int)(PAGE_ALIGN((unsigned long)(__init_begin))), + (int)(addr - PAGE_SIZE)); +#endif +} diff --git a/trunk/arch/blackfin/oprofile/Kconfig b/trunk/arch/blackfin/oprofile/Kconfig new file mode 100644 index 000000000000..0a2fd999c941 --- /dev/null +++ b/trunk/arch/blackfin/oprofile/Kconfig @@ -0,0 +1,29 @@ +menu "Profiling support" +depends on EXPERIMENTAL + +config PROFILING + bool "Profiling support (EXPERIMENTAL)" + help + Say Y here to enable the extended profiling support mechanisms used + by profilers such as OProfile. + +config OPROFILE + tristate "OProfile system profiling (EXPERIMENTAL)" + depends on PROFILING + help + OProfile is a profiling system capable of profiling the + whole system, include the kernel, kernel modules, libraries, + and applications. + + If unsure, say N. + +config HARDWARE_PM + tristate "Hardware Performance Monitor Profiling" + depends on PROFILING + help + take use of hardware performance monitor to profiling the kernel + and application. + + If unsure, say N. + +endmenu diff --git a/trunk/arch/blackfin/oprofile/Makefile b/trunk/arch/blackfin/oprofile/Makefile new file mode 100644 index 000000000000..634e300d67e2 --- /dev/null +++ b/trunk/arch/blackfin/oprofile/Makefile @@ -0,0 +1,14 @@ +# +# arch/blackfin/oprofile/Makefile +# + +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + +oprofile-y := $(DRIVER_OBJS) common.o +oprofile-$(CONFIG_HARDWARE_PM) += op_model_bf533.o diff --git a/trunk/arch/blackfin/oprofile/common.c b/trunk/arch/blackfin/oprofile/common.c new file mode 100644 index 000000000000..009a1700c854 --- /dev/null +++ b/trunk/arch/blackfin/oprofile/common.c @@ -0,0 +1,168 @@ +/* + * File: arch/blackfin/oprofile/common.c + * Based on: arch/alpha/oprofile/common.c + * Author: Anton Blanchard + * + * Created: + * Description: + * + * Modified: + * Copyright (C) 2004 Anton Blanchard , IBM + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "op_blackfin.h" + +#define BFIN_533_ID 0xE5040003 +#define BFIN_537_ID 0xE5040002 + +static int pfmon_enabled; +static struct mutex pfmon_lock; + +struct op_bfin533_model *model; + +struct op_counter_config ctr[OP_MAX_COUNTER]; + +static int op_bfin_setup(void) +{ + int ret; + + /* Pre-compute the values to stuff in the hardware registers. */ + spin_lock(&oprofilefs_lock); + ret = model->reg_setup(ctr); + spin_unlock(&oprofilefs_lock); + + return ret; +} + +static void op_bfin_shutdown(void) +{ +#if 0 + /* what is the difference between shutdown and stop? */ +#endif +} + +static int op_bfin_start(void) +{ + int ret = -EBUSY; + + printk(KERN_INFO "KSDBG:in %s\n", __FUNCTION__); + mutex_lock(&pfmon_lock); + if (!pfmon_enabled) { + ret = model->start(ctr); + pfmon_enabled = !ret; + } + mutex_unlock(&pfmon_lock); + + return ret; +} + +static void op_bfin_stop(void) +{ + mutex_lock(&pfmon_lock); + if (pfmon_enabled) { + model->stop(); + pfmon_enabled = 0; + } + mutex_unlock(&pfmon_lock); +} + +static int op_bfin_create_files(struct super_block *sb, struct dentry *root) +{ + int i; + + for (i = 0; i < model->num_counters; ++i) { + struct dentry *dir; + char buf[3]; + printk(KERN_INFO "Oprofile: creating files... \n"); + + snprintf(buf, sizeof buf, "%d", i); + dir = oprofilefs_mkdir(sb, root, buf); + + oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); + oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); + oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); + /* + * We dont support per counter user/kernel selection, but + * we leave the entries because userspace expects them + */ + oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); + oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); + oprofilefs_create_ulong(sb, dir, "unit_mask", + &ctr[i].unit_mask); + } + + return 0; +} +int __init oprofile_arch_init(struct oprofile_operations *ops) +{ +#ifdef CONFIG_HARDWARE_PM + unsigned int dspid; + + mutex_init(&pfmon_lock); + + dspid = bfin_read_DSPID(); + + printk(KERN_INFO "Oprofile got the cpu id is 0x%x. \n", dspid); + + switch (dspid) { + case BFIN_533_ID: + model = &op_model_bfin533; + model->num_counters = 2; + break; + case BFIN_537_ID: + model = &op_model_bfin533; + model->num_counters = 2; + break; + default: + return -ENODEV; + } + + ops->cpu_type = model->name; + ops->create_files = op_bfin_create_files; + ops->setup = op_bfin_setup; + ops->shutdown = op_bfin_shutdown; + ops->start = op_bfin_start; + ops->stop = op_bfin_stop; + + printk(KERN_INFO "oprofile: using %s performance monitoring.\n", + ops->cpu_type); + + return 0; +#else + return -1; +#endif +} + +void oprofile_arch_exit(void) +{ +} diff --git a/trunk/arch/blackfin/oprofile/op_blackfin.h b/trunk/arch/blackfin/oprofile/op_blackfin.h new file mode 100644 index 000000000000..f88f446c814f --- /dev/null +++ b/trunk/arch/blackfin/oprofile/op_blackfin.h @@ -0,0 +1,98 @@ +/* + * File: arch/blackfin/oprofile/op_blackfin.h + * Based on: + * Author: Anton Blanchard + * + * Created: + * Description: + * + * Modified: + * Copyright (C) 2004 Anton Blanchard , IBM + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef OP_BLACKFIN_H +#define OP_BLACKFIN_H 1 + +#define OP_MAX_COUNTER 2 + +#include + +/* Per-counter configuration as set via oprofilefs. */ +struct op_counter_config { + unsigned long valid; + unsigned long enabled; + unsigned long event; + unsigned long count; + unsigned long kernel; + unsigned long user; + unsigned long unit_mask; +}; + +/* System-wide configuration as set via oprofilefs. */ +struct op_system_config { + unsigned long enable_kernel; + unsigned long enable_user; +}; + +/* Per-arch configuration */ +struct op_bfin533_model { + int (*reg_setup) (struct op_counter_config *); + int (*start) (struct op_counter_config *); + void (*stop) (void); + int num_counters; + char *name; +}; + +extern struct op_bfin533_model op_model_bfin533; + +static inline unsigned int ctr_read(void) +{ + unsigned int tmp; + + tmp = bfin_read_PFCTL(); + __builtin_bfin_csync(); + + return tmp; +} + +static inline void ctr_write(unsigned int val) +{ + bfin_write_PFCTL(val); + __builtin_bfin_csync(); +} + +static inline void count_read(unsigned int *count) +{ + count[0] = bfin_read_PFCNTR0(); + count[1] = bfin_read_PFCNTR1(); + __builtin_bfin_csync(); +} + +static inline void count_write(unsigned int *count) +{ + bfin_write_PFCNTR0(count[0]); + bfin_write_PFCNTR1(count[1]); + __builtin_bfin_csync(); +} + +extern int pm_overflow_handler(int irq, struct pt_regs *regs); + +#endif diff --git a/trunk/arch/blackfin/oprofile/op_model_bf533.c b/trunk/arch/blackfin/oprofile/op_model_bf533.c new file mode 100644 index 000000000000..b7a20a006b49 --- /dev/null +++ b/trunk/arch/blackfin/oprofile/op_model_bf533.c @@ -0,0 +1,161 @@ +/* + * File: arch/blackfin/oprofile/op_model_bf533.c + * Based on: + * Author: Anton Blanchard + * + * Created: + * Description: + * + * Modified: + * Copyright (C) 2004 Anton Blanchard , IBM + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "op_blackfin.h" + +#define PM_ENABLE 0x01; +#define PM_CTL1_ENABLE 0x18 +#define PM_CTL0_ENABLE 0xC000 +#define COUNT_EDGE_ONLY 0x3000000 + +static int oprofile_running; + +static unsigned curr_pfctl, curr_count[2]; + +static int bfin533_reg_setup(struct op_counter_config *ctr) +{ + unsigned int pfctl = ctr_read(); + unsigned int count[2]; + + /* set Blackfin perf monitor regs with ctr */ + if (ctr[0].enabled) { + pfctl |= (PM_CTL0_ENABLE | ((char)ctr[0].event << 5)); + count[0] = 0xFFFFFFFF - ctr[0].count; + curr_count[0] = count[0]; + } + if (ctr[1].enabled) { + pfctl |= (PM_CTL1_ENABLE | ((char)ctr[1].event << 16)); + count[1] = 0xFFFFFFFF - ctr[1].count; + curr_count[1] = count[1]; + } + + pr_debug("ctr[0].enabled=%d,ctr[1].enabled=%d,ctr[0].event<<5=0x%x,ctr[1].event<<16=0x%x\n", ctr[0].enabled, ctr[1].enabled, ctr[0].event << 5, ctr[1].event << 16); + pfctl |= COUNT_EDGE_ONLY; + curr_pfctl = pfctl; + + pr_debug("write 0x%x to pfctl\n", pfctl); + ctr_write(pfctl); + count_write(count); + + return 0; +} + +static int bfin533_start(struct op_counter_config *ctr) +{ + unsigned int pfctl = ctr_read(); + + pfctl |= PM_ENABLE; + curr_pfctl = pfctl; + + ctr_write(pfctl); + + oprofile_running = 1; + pr_debug("start oprofile counter \n"); + + return 0; +} + +static void bfin533_stop(void) +{ + int pfctl; + + pfctl = ctr_read(); + pfctl &= ~PM_ENABLE; + /* freeze counters */ + ctr_write(pfctl); + + oprofile_running = 0; + pr_debug("stop oprofile counter \n"); +} + +static int get_kernel(void) +{ + int ipend, is_kernel; + + ipend = bfin_read_IPEND(); + + /* test bit 15 */ + is_kernel = ((ipend & 0x8000) != 0); + + return is_kernel; +} + +int pm_overflow_handler(int irq, struct pt_regs *regs) +{ + int is_kernel; + int i, cpu; + unsigned int pc, pfctl; + unsigned int count[2]; + + pr_debug("get interrupt in %s\n", __FUNCTION__); + if (oprofile_running == 0) { + pr_debug("error: entering interrupt when oprofile is stopped.\n\r"); + return -1; + } + + is_kernel = get_kernel(); + cpu = smp_processor_id(); + pc = regs->pc; + pfctl = ctr_read(); + + /* read the two event counter regs */ + count_read(count); + + /* if the counter overflows, add sample to oprofile buffer */ + for (i = 0; i < 2; ++i) { + if (oprofile_running) { + oprofile_add_sample(regs, i); + } + } + + /* reset the perfmon counter */ + ctr_write(curr_pfctl); + count_write(curr_count); + return 0; +} + +struct op_bfin533_model op_model_bfin533 = { + .reg_setup = bfin533_reg_setup, + .start = bfin533_start, + .stop = bfin533_stop, + .num_counters = 2, + .name = "blackfin/bf533" +}; diff --git a/trunk/arch/blackfin/oprofile/timer_int.c b/trunk/arch/blackfin/oprofile/timer_int.c new file mode 100644 index 000000000000..8fba16c846c9 --- /dev/null +++ b/trunk/arch/blackfin/oprofile/timer_int.c @@ -0,0 +1,74 @@ +/* + * File: arch/blackfin/oprofile/timer_int.c + * Based on: + * Author: Michael Kang + * + * Created: + * Description: + * + * Modified: + * Copyright 2004-2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include + +static void enable_sys_timer0() +{ +} +static void disable_sys_timer0() +{ +} + +static irqreturn_t sys_timer0_int_handler(int irq, void *dev_id, + struct pt_regs *regs) +{ + oprofile_add_sample(regs, 0); + return IRQ_HANDLED; +} + +static int sys_timer0_start(void) +{ + enable_sys_timer0(); + return request_irq(IVG11, sys_timer0_int_handler, 0, "sys_timer0", NULL); +} + +static void sys_timer0_stop(void) +{ + disable_sys_timer(); +} + +int __init sys_timer0_init(struct oprofile_operations *ops) +{ + extern int nmi_active; + + if (nmi_active <= 0) + return -ENODEV; + + ops->start = timer_start; + ops->stop = timer_stop; + ops->cpu_type = "timer"; + printk(KERN_INFO "oprofile: using NMI timer interrupt.\n"); + return 0; +} diff --git a/trunk/arch/cris/arch-v10/kernel/ptrace.c b/trunk/arch/cris/arch-v10/kernel/ptrace.c index 961c0d58ded4..fd2129a04586 100644 --- a/trunk/arch/cris/arch-v10/kernel/ptrace.c +++ b/trunk/arch/cris/arch-v10/kernel/ptrace.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/cris/arch-v10/kernel/signal.c b/trunk/arch/cris/arch-v10/kernel/signal.c index 19bcad05716f..41d4a5f93284 100644 --- a/trunk/arch/cris/arch-v10/kernel/signal.c +++ b/trunk/arch/cris/arch-v10/kernel/signal.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/cris/arch-v32/drivers/pci/dma.c b/trunk/arch/cris/arch-v32/drivers/pci/dma.c index 70d3bf0c92e8..832fc63504d4 100644 --- a/trunk/arch/cris/arch-v32/drivers/pci/dma.c +++ b/trunk/arch/cris/arch-v32/drivers/pci/dma.c @@ -76,7 +76,7 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, { void __iomem *mem_base; int pages = size >> PAGE_SHIFT; - int bitmap_size = (pages + 31)/32; + int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) goto out; diff --git a/trunk/arch/cris/arch-v32/kernel/fasttimer.c b/trunk/arch/cris/arch-v32/kernel/fasttimer.c index 5daeb6f7f3b7..79e1e4c2ca1d 100644 --- a/trunk/arch/cris/arch-v32/kernel/fasttimer.c +++ b/trunk/arch/cris/arch-v32/kernel/fasttimer.c @@ -603,23 +603,8 @@ void schedule_usleep(unsigned long us) #ifdef CONFIG_PROC_FS static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - ,int *eof, void *data_unused -#else - ,int unused -#endif - ); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) + ,int *eof, void *data_unused); static struct proc_dir_entry *fasttimer_proc_entry; -#else -static struct proc_dir_entry fasttimer_proc_entry = -{ - 0, 9, "fasttimer", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, NULL /* ops -- default to array */, - &proc_fasttimer_read /* get_info */, -}; -#endif #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_PROC_FS @@ -628,12 +613,7 @@ static struct proc_dir_entry fasttimer_proc_entry = #define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300) static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - ,int *eof, void *data_unused -#else - ,int unused -#endif - ) + ,int *eof, void *data_unused) { unsigned long flags; int i = 0; @@ -808,9 +788,7 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len memcpy(buf, bigbuf + offset, len); *start = buf; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) *eof = 1; -#endif return len; } @@ -974,12 +952,8 @@ void fast_timer_init(void) printk("fast_timer_init()\n"); #ifdef CONFIG_PROC_FS -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) fasttimer_proc_entry->read_proc = proc_fasttimer_read; -#else - proc_register_dynamic(&proc_root, &fasttimer_proc_entry); -#endif #endif /* PROC_FS */ if(request_irq(TIMER_INTR_VECT, timer_trig_interrupt, IRQF_DISABLED, "fast timer int", NULL)) diff --git a/trunk/arch/cris/arch-v32/kernel/ptrace.c b/trunk/arch/cris/arch-v32/kernel/ptrace.c index 82cf2e3624a4..d4d57b741334 100644 --- a/trunk/arch/cris/arch-v32/kernel/ptrace.c +++ b/trunk/arch/cris/arch-v32/kernel/ptrace.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/cris/kernel/crisksyms.c b/trunk/arch/cris/kernel/crisksyms.c index 1f20c16ac2a4..105bb5ed48f7 100644 --- a/trunk/arch/cris/kernel/crisksyms.c +++ b/trunk/arch/cris/kernel/crisksyms.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/cris/kernel/profile.c b/trunk/arch/cris/kernel/profile.c index 4cfcae620507..aad0a9e5991a 100644 --- a/trunk/arch/cris/kernel/profile.c +++ b/trunk/arch/cris/kernel/profile.c @@ -15,39 +15,47 @@ static int prof_running = 0; void cris_profile_sample(struct pt_regs* regs) { - if (!prof_running) - return; - if (user_mode(regs)) - *(unsigned int*)sample_buffer_pos = current->pid; - else - *(unsigned int*)sample_buffer_pos = 0; - *(unsigned int*)(sample_buffer_pos + 4) = instruction_pointer(regs); - sample_buffer_pos += 8; - if (sample_buffer_pos == sample_buffer + SAMPLE_BUFFER_SIZE) - sample_buffer_pos = sample_buffer; + if (!prof_running) + return; + + if (user_mode(regs)) + *(unsigned int*)sample_buffer_pos = current->pid; + else + *(unsigned int*)sample_buffer_pos = 0; + + *(unsigned int*)(sample_buffer_pos + 4) = instruction_pointer(regs); + sample_buffer_pos += 8; + + if (sample_buffer_pos == sample_buffer + SAMPLE_BUFFER_SIZE) + sample_buffer_pos = sample_buffer; } static ssize_t -read_cris_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos) +read_cris_profile(struct file *file, char __user *buf, + size_t count, loff_t *ppos) { - unsigned long p = *ppos; - if (p > SAMPLE_BUFFER_SIZE) - return 0; - if (p + count > SAMPLE_BUFFER_SIZE) - count = SAMPLE_BUFFER_SIZE - p; - if (copy_to_user(buf, sample_buffer + p,count)) + unsigned long p = *ppos; + + if (p > SAMPLE_BUFFER_SIZE) + return 0; + + if (p + count > SAMPLE_BUFFER_SIZE) + count = SAMPLE_BUFFER_SIZE - p; + if (copy_to_user(buf, sample_buffer + p,count)) return -EFAULT; - memset(sample_buffer + p, 0, count); - *ppos += count; - return count; + + memset(sample_buffer + p, 0, count); + *ppos += count; + + return count; } static ssize_t write_cris_profile(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - sample_buffer_pos = sample_buffer; - memset(sample_buffer, 0, SAMPLE_BUFFER_SIZE); + sample_buffer_pos = sample_buffer; + memset(sample_buffer, 0, SAMPLE_BUFFER_SIZE); } static const struct file_operations cris_proc_profile_operations = { @@ -58,16 +66,23 @@ static const struct file_operations cris_proc_profile_operations = { static int __init init_cris_profile(void) { - struct proc_dir_entry *entry; - sample_buffer = kmalloc(SAMPLE_BUFFER_SIZE, GFP_KERNEL); - sample_buffer_pos = sample_buffer; - entry = create_proc_entry("system_profile", S_IWUSR | S_IRUGO, NULL); - if (entry) { - entry->proc_fops = &cris_proc_profile_operations; - entry->size = SAMPLE_BUFFER_SIZE; - } - prof_running = 1; - return 0; + struct proc_dir_entry *entry; + + sample_buffer = kmalloc(SAMPLE_BUFFER_SIZE, GFP_KERNEL); + if (!sample_buffer) { + return -ENOMEM; + } + + sample_buffer_pos = sample_buffer; + + entry = create_proc_entry("system_profile", S_IWUSR | S_IRUGO, NULL); + if (entry) { + entry->proc_fops = &cris_proc_profile_operations; + entry->size = SAMPLE_BUFFER_SIZE; + } + prof_running = 1; + + return 0; } __initcall(init_cris_profile); diff --git a/trunk/arch/cris/kernel/ptrace.c b/trunk/arch/cris/kernel/ptrace.c index 2b6363cbe985..1085d037027b 100644 --- a/trunk/arch/cris/kernel/ptrace.c +++ b/trunk/arch/cris/kernel/ptrace.c @@ -67,7 +67,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/frv/Kconfig b/trunk/arch/frv/Kconfig index cea237413aa2..eed694312a79 100644 --- a/trunk/arch/frv/Kconfig +++ b/trunk/arch/frv/Kconfig @@ -53,6 +53,10 @@ config ARCH_HAS_ILOG2_U64 bool default y +config ARCH_USES_SLAB_PAGE_STRUCT + bool + default y + mainmenu "Fujitsu FR-V Kernel Configuration" source "init/Kconfig" diff --git a/trunk/arch/frv/kernel/irq.c b/trunk/arch/frv/kernel/irq.c index 87f360a4ea27..c7e59dcadee4 100644 --- a/trunk/arch/frv/kernel/irq.c +++ b/trunk/arch/frv/kernel/irq.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/frv/kernel/ptrace.c b/trunk/arch/frv/kernel/ptrace.c index fcff819b4340..ce88fb95ee59 100644 --- a/trunk/arch/frv/kernel/ptrace.c +++ b/trunk/arch/frv/kernel/ptrace.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/frv/kernel/semaphore.c b/trunk/arch/frv/kernel/semaphore.c index f278cdf3a72f..8e182ced1a0f 100644 --- a/trunk/arch/frv/kernel/semaphore.c +++ b/trunk/arch/frv/kernel/semaphore.c @@ -19,7 +19,7 @@ struct sem_waiter { struct task_struct *task; }; -#if SEMAPHORE_DEBUG +#ifdef CONFIG_DEBUG_SEMAPHORE void semtrace(struct semaphore *sem, const char *str) { if (sem->debug) diff --git a/trunk/arch/frv/kernel/signal.c b/trunk/arch/frv/kernel/signal.c index 85baeae9666a..d64bcaff54cd 100644 --- a/trunk/arch/frv/kernel/signal.c +++ b/trunk/arch/frv/kernel/signal.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/frv/kernel/sys_frv.c b/trunk/arch/frv/kernel/sys_frv.c index c4d4348c9e8e..26b3df32b9a7 100644 --- a/trunk/arch/frv/kernel/sys_frv.c +++ b/trunk/arch/frv/kernel/sys_frv.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/frv/mm/elf-fdpic.c b/trunk/arch/frv/mm/elf-fdpic.c index 9477ccce070e..cac2c01a3a56 100644 --- a/trunk/arch/frv/mm/elf-fdpic.c +++ b/trunk/arch/frv/mm/elf-fdpic.c @@ -64,6 +64,10 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi if (len > TASK_SIZE) return -ENOMEM; + /* handle MAP_FIXED */ + if (flags & MAP_FIXED) + return addr; + /* only honour a hint if we're not going to clobber something doing so */ if (addr) { addr = PAGE_ALIGN(addr); diff --git a/trunk/arch/frv/mm/pgalloc.c b/trunk/arch/frv/mm/pgalloc.c index 19b13be114a2..598a26ab8ad8 100644 --- a/trunk/arch/frv/mm/pgalloc.c +++ b/trunk/arch/frv/mm/pgalloc.c @@ -151,9 +151,7 @@ void __init pgtable_cache_init(void) pgd_cache = kmem_cache_create("pgd", PTRS_PER_PGD * sizeof(pgd_t), PTRS_PER_PGD * sizeof(pgd_t), - 0, + SLAB_PANIC, pgd_ctor, pgd_dtor); - if (!pgd_cache) - panic("pgtable_cache_init(): Cannot create pgd cache"); } diff --git a/trunk/arch/h8300/Kconfig b/trunk/arch/h8300/Kconfig index 1734d96422c6..618dbad696f6 100644 --- a/trunk/arch/h8300/Kconfig +++ b/trunk/arch/h8300/Kconfig @@ -49,10 +49,18 @@ config GENERIC_HWEIGHT bool default y +config GENERIC_HARDIRQS + bool + default y + config GENERIC_CALIBRATE_DELAY bool default y +config GENERIC_TIME + bool + default y + config TIME_LOW_RES bool default y diff --git a/trunk/arch/h8300/Makefile b/trunk/arch/h8300/Makefile index 40b3f56f3666..b2d896a7e598 100644 --- a/trunk/arch/h8300/Makefile +++ b/trunk/arch/h8300/Makefile @@ -41,7 +41,7 @@ LDFLAGS += $(ldflags-y) CROSS_COMPILE = h8300-elf- LIBGCC := $(shell $(CROSS-COMPILE)$(CC) $(CFLAGS) -print-libgcc-file-name) -head-y := arch/$(ARCH)/platform/$(platform-y)/$(board-y)/crt0_$(model-y).o +head-y := arch/$(ARCH)/platform/$(PLATFORM)/$(BOARD)/crt0_$(MODEL).o core-y += arch/$(ARCH)/kernel/ \ arch/$(ARCH)/mm/ diff --git a/trunk/arch/h8300/boot/Makefile b/trunk/arch/h8300/boot/Makefile index 65086d925ca7..0bb62e064eea 100644 --- a/trunk/arch/h8300/boot/Makefile +++ b/trunk/arch/h8300/boot/Makefile @@ -1,12 +1,22 @@ # arch/h8300/boot/Makefile -targets := vmlinux.srec vmlinux.bin +targets := vmlinux.srec vmlinux.bin zImage +subdir- := compressed OBJCOPYFLAGS_vmlinux.srec := -Osrec OBJCOPYFLAGS_vmlinux.bin := -Obinary +OBJCOPYFLAGS_zImage := -O binary -R .note -R .comment -R .stab -R .stabstr -S $(obj)/vmlinux.srec $(obj)/vmlinux.bin: vmlinux FORCE $(call if_changed,objcopy) @echo ' Kernel: $@ is ready' +$(obj)/zImage: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + @echo 'Kernel: $@ is ready' + +$(obj)/compressed/vmlinux: FORCE + $(Q)$(MAKE) $(build)=$(obj)/compressed $@ + CLEAN_FILES += arch/$(ARCH)/vmlinux.bin arch/$(ARCH)/vmlinux.srec + diff --git a/trunk/arch/h8300/boot/compressed/Makefile b/trunk/arch/h8300/boot/compressed/Makefile new file mode 100644 index 000000000000..71aac82a8ae0 --- /dev/null +++ b/trunk/arch/h8300/boot/compressed/Makefile @@ -0,0 +1,37 @@ +# +# linux/arch/sh/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux +# + +targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o +EXTRA_AFLAGS := -traditional + +OBJECTS = $(obj)/head.o $(obj)/misc.o + +# +# IMAGE_OFFSET is the load offset of the compression loader +# Assign dummy values if these 2 variables are not defined, +# in order to suppress error message. +# +CONFIG_MEMORY_START ?= 0x00400000 +CONFIG_BOOT_LINK_OFFSET ?= 0x00400000 +IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET)]) + +LDFLAGS_vmlinux := -T $(obj)/vmlinux.lds + +$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE + $(call if_changed,ld) + @: + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +LDFLAGS_piggy.o := -r --format binary --oformat elf32-h8300 -T +OBJCOPYFLAGS := -O binary + +$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,ld) diff --git a/trunk/arch/h8300/boot/compressed/head.S b/trunk/arch/h8300/boot/compressed/head.S new file mode 100644 index 000000000000..b8e90d12d19e --- /dev/null +++ b/trunk/arch/h8300/boot/compressed/head.S @@ -0,0 +1,47 @@ +/* + * linux/arch/h8300/boot/compressed/head.S + * + * Copyright (C) 2006 Yoshinori Sato + */ + +.h8300h +#include + +#define SRAM_START 0xff4000 + + .section .text.startup + .global startup +startup: + mov.l #SRAM_START+0x8000, sp + mov.l #__sbss, er0 + mov.l #__ebss, er1 + sub.l er0, er1 + shlr er1 + shlr er1 + sub.l er2, er2 +1: + mov.l er2, @er0 + adds #4, er0 + dec.l #1, er1 + bne 1b + jsr @_decompress_kernel + jmp @0x400000 + + .align 9 +fake_headers_as_bzImage: + .word 0 + .ascii "HdrS" ; header signature + .word 0x0202 ; header version number (>= 0x0105) + ; or else old loadlin-1.5 will fail) + .word 0 ; default_switch + .word 0 ; SETUPSEG + .word 0x1000 + .word 0 ; pointing to kernel version string + .byte 0 ; = 0, old one (LILO, Loadlin, + ; 0xTV: T=0 for LILO + ; V = version + .byte 1 ; Load flags bzImage=1 + .word 0x8000 ; size to move, when setup is not + .long 0x100000 ; 0x100000 = default for big kernel + .long 0 ; address of loaded ramdisk image + .long 0 ; its size in bytes diff --git a/trunk/arch/h8300/boot/compressed/misc.c b/trunk/arch/h8300/boot/compressed/misc.c new file mode 100644 index 000000000000..845074588af0 --- /dev/null +++ b/trunk/arch/h8300/boot/compressed/misc.c @@ -0,0 +1,219 @@ +/* + * arch/h8300/boot/compressed/misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * + * Adapted for h8300 by Yoshinori Sato 2006 + */ + +#include + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#undef memset +#undef memcpy +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize = 0; /* valid bytes in inbuf */ +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +extern char input_data[]; +extern int input_len; + +static long bytes_out = 0; +static uch *output_data; +static unsigned long output_ptr = 0; + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +int puts(const char *); + +extern int _text; /* Defined in vmlinux.lds.S */ +extern int _end; +static unsigned long free_mem_ptr; +static unsigned long free_mem_end_ptr; + +#define HEAP_SIZE 0x10000 + +#include "../../../../lib/inflate.c" + +#define SCR *((volatile unsigned char *)0xffff8a) +#define TDR *((volatile unsigned char *)0xffff8b) +#define SSR *((volatile unsigned char *)0xffff8c) + +static void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error"); + if (free_mem_ptr == 0) error("Memory error"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("Out of memory"); + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +int puts(const char *s) +{ + return 0; +} + +void* memset(void* s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; +} + +static void error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +#define STACK_SIZE (4096) +long user_stack [STACK_SIZE]; +long* stack_start = &user_stack[STACK_SIZE]; + +void decompress_kernel(void) +{ + output_data = 0; + output_ptr = (unsigned long)0x400000; + free_mem_ptr = (unsigned long)&_end; + free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; + + makecrc(); + puts("Uncompressing Linux... "); + gunzip(); + puts("Ok, booting the kernel.\n"); +} diff --git a/trunk/arch/h8300/kernel/Makefile b/trunk/arch/h8300/kernel/Makefile index 4edbc2ef6ca2..ccc1a7fbf94b 100644 --- a/trunk/arch/h8300/kernel/Makefile +++ b/trunk/arch/h8300/kernel/Makefile @@ -4,10 +4,8 @@ extra-y := vmlinux.lds -obj-y := process.o traps.o ptrace.o ints.o \ +obj-y := process.o traps.o ptrace.o irq.o \ sys_h8300.o time.o semaphore.o signal.o \ - setup.o gpio.o init_task.o syscalls.o devres.o - -devres-y = ../../../kernel/irq/devres.o + setup.o gpio.o init_task.o syscalls.o obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o diff --git a/trunk/arch/h8300/kernel/irq.c b/trunk/arch/h8300/kernel/irq.c new file mode 100644 index 000000000000..43d21e93f41f --- /dev/null +++ b/trunk/arch/h8300/kernel/irq.c @@ -0,0 +1,211 @@ +/* + * linux/arch/h8300/kernel/irq.c + * + * Copyright 2007 Yoshinori Sato + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/*#define DEBUG*/ + +extern unsigned long *interrupt_redirect_table; +extern const int h8300_saved_vectors[]; +extern const unsigned long h8300_trap_table[]; +int h8300_enable_irq_pin(unsigned int irq); +void h8300_disable_irq_pin(unsigned int irq); + +#define CPU_VECTOR ((unsigned long *)0x000000) +#define ADDR_MASK (0xffffff) + +static inline int is_ext_irq(unsigned int irq) +{ + return (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS)); +} + +static void h8300_enable_irq(unsigned int irq) +{ + if (is_ext_irq(irq)) + IER_REGS |= 1 << (irq - EXT_IRQ0); +} + +static void h8300_disable_irq(unsigned int irq) +{ + if (is_ext_irq(irq)) + IER_REGS &= ~(1 << (irq - EXT_IRQ0)); +} + +static void h8300_end_irq(unsigned int irq) +{ +} + +static unsigned int h8300_startup_irq(unsigned int irq) +{ + if (is_ext_irq(irq)) + return h8300_enable_irq_pin(irq); + else + return 0; +} + +static void h8300_shutdown_irq(unsigned int irq) +{ + if (is_ext_irq(irq)) + h8300_disable_irq_pin(irq); +} + +/* + * h8300 interrupt controler implementation + */ +struct irq_chip h8300irq_chip = { + .name = "H8300-INTC", + .startup = h8300_startup_irq, + .shutdown = h8300_shutdown_irq, + .enable = h8300_enable_irq, + .disable = h8300_disable_irq, + .ack = NULL, + .end = h8300_end_irq, +}; + +void ack_bad_irq(unsigned int irq) +{ + printk("unexpected IRQ trap at vector %02x\n", irq); +} + +#if defined(CONFIG_RAMKERNEL) +static unsigned long __init *get_vector_address(void) +{ + unsigned long *rom_vector = CPU_VECTOR; + unsigned long base,tmp; + int vec_no; + + base = rom_vector[EXT_IRQ0] & ADDR_MASK; + + /* check romvector format */ + for (vec_no = EXT_IRQ1; vec_no <= EXT_IRQ0+EXT_IRQS; vec_no++) { + if ((base+(vec_no - EXT_IRQ0)*4) != (rom_vector[vec_no] & ADDR_MASK)) + return NULL; + } + + /* ramvector base address */ + base -= EXT_IRQ0*4; + + /* writerble check */ + tmp = ~(*(volatile unsigned long *)base); + (*(volatile unsigned long *)base) = tmp; + if ((*(volatile unsigned long *)base) != tmp) + return NULL; + return (unsigned long *)base; +} + +static void __init setup_vector(void) +{ + int i; + unsigned long *ramvec,*ramvec_p; + const unsigned long *trap_entry; + const int *saved_vector; + + ramvec = get_vector_address(); + if (ramvec == NULL) + panic("interrupt vector serup failed."); + else + printk(KERN_INFO "virtual vector at 0x%08lx\n",(unsigned long)ramvec); + + /* create redirect table */ + ramvec_p = ramvec; + trap_entry = h8300_trap_table; + saved_vector = h8300_saved_vectors; + for ( i = 0; i < NR_IRQS; i++) { + if (i == *saved_vector) { + ramvec_p++; + saved_vector++; + } else { + if ( i < NR_TRAPS ) { + if (*trap_entry) + *ramvec_p = VECTOR(*trap_entry); + ramvec_p++; + trap_entry++; + } else + *ramvec_p++ = REDIRECT(interrupt_entry); + } + } + interrupt_redirect_table = ramvec; +#ifdef DEBUG + ramvec_p = ramvec; + for (i = 0; i < NR_IRQS; i++) { + if ((i % 8) == 0) + printk(KERN_DEBUG "\n%p: ",ramvec_p); + printk(KERN_DEBUG "%p ",*ramvec_p); + ramvec_p++; + } + printk(KERN_DEBUG "\n"); +#endif +} +#else +#define setup_vector() do { } while(0) +#endif + +void __init init_IRQ(void) +{ + int c; + + setup_vector(); + + for (c = 0; c < NR_IRQS; c++) { + irq_desc[c].status = IRQ_DISABLED; + irq_desc[c].action = NULL; + irq_desc[c].depth = 1; + irq_desc[c].chip = &h8300irq_chip; + } +} + +asmlinkage void do_IRQ(int irq) +{ + irq_enter(); + __do_IRQ(irq); + irq_exit(); +} + +#if defined(CONFIG_PROC_FS) +int show_interrupts(struct seq_file *p, void *v) +{ + int i = *(loff_t *) v, j; + struct irqaction * action; + unsigned long flags; + + if (i == 0) + seq_puts(p, " CPU0"); + + if (i < NR_IRQS) { + spin_lock_irqsave(&irq_desc[i].lock, flags); + action = irq_desc[i].action; + if (!action) + goto unlock; + seq_printf(p, "%3d: ",i); + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); + seq_printf(p, " %14s", irq_desc[i].chip->name); + seq_printf(p, "-%-8s", irq_desc[i].name); + seq_printf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + seq_printf(p, ", %s", action->name); + seq_putc(p, '\n'); +unlock: + spin_unlock_irqrestore(&irq_desc[i].lock, flags); + } + return 0; +} +#endif diff --git a/trunk/arch/h8300/kernel/ptrace.c b/trunk/arch/h8300/kernel/ptrace.c index f6031373dc21..8f2411db7eaf 100644 --- a/trunk/arch/h8300/kernel/ptrace.c +++ b/trunk/arch/h8300/kernel/ptrace.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/h8300/kernel/setup.c b/trunk/arch/h8300/kernel/setup.c index 313cd8081044..b2e86d0255e6 100644 --- a/trunk/arch/h8300/kernel/setup.c +++ b/trunk/arch/h8300/kernel/setup.c @@ -33,10 +33,7 @@ #include #include - -#ifdef CONFIG_BLK_DEV_INITRD #include -#endif #if defined(__H8300H__) #define CPU "H8/300H" diff --git a/trunk/arch/h8300/kernel/sys_h8300.c b/trunk/arch/h8300/kernel/sys_h8300.c index 302a2dfe634a..11ba75a05220 100644 --- a/trunk/arch/h8300/kernel/sys_h8300.c +++ b/trunk/arch/h8300/kernel/sys_h8300.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/h8300/kernel/time.c b/trunk/arch/h8300/kernel/time.c index d1ef615ba895..330638220a2e 100644 --- a/trunk/arch/h8300/kernel/time.c +++ b/trunk/arch/h8300/kernel/time.c @@ -44,7 +44,7 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs) #ifndef CONFIG_SMP update_process_times(user_mode(regs)); #endif - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); } void time_init(void) @@ -66,55 +66,3 @@ void time_init(void) platform_timer_setup(timer_interrupt); } - -/* - * This version of gettimeofday has near microsecond resolution. - */ -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - unsigned long usec, sec; - - read_lock_irqsave(&xtime_lock, flags); - usec = 0; - sec = xtime.tv_sec; - usec += (xtime.tv_nsec / 1000); - read_unlock_irqrestore(&xtime_lock, flags); - - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -EXPORT_SYMBOL(do_gettimeofday); - -int do_settimeofday(struct timespec *tv) -{ - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_lock_irq(&xtime_lock); - /* This is revolting. We need to set the xtime.tv_usec - * correctly. However, the value in this location is - * is value at the last tick. - * Discover what correction gettimeofday - * would have done, and then undo it! - */ - while (tv->tv_nsec < 0) { - tv->tv_nsec += NSEC_PER_SEC; - tv->tv_sec--; - } - - xtime.tv_sec = tv->tv_sec; - xtime.tv_nsec = tv->tv_nsec; - ntp_clear(); - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); diff --git a/trunk/arch/h8300/mm/kmap.c b/trunk/arch/h8300/mm/kmap.c index 26ab17286a53..5c7af09ae8d1 100644 --- a/trunk/arch/h8300/mm/kmap.c +++ b/trunk/arch/h8300/mm/kmap.c @@ -24,12 +24,14 @@ #undef DEBUG +#define VIRT_OFFSET (0x01000000) + /* * Map some physical address range into the kernel address space. */ void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag) { - return (void *)physaddr; + return (void *)(physaddr + VIRT_OFFSET); } /* diff --git a/trunk/arch/h8300/platform/h8300h/Makefile b/trunk/arch/h8300/platform/h8300h/Makefile index 5d42c772f75a..b24ea08aa0a7 100644 --- a/trunk/arch/h8300/platform/h8300h/Makefile +++ b/trunk/arch/h8300/platform/h8300h/Makefile @@ -4,4 +4,4 @@ # Reuse any files we can from the H8/300H # -obj-y := entry.o ints_h8300h.o ptrace_h8300h.o +obj-y := entry.o irq_pin.o ptrace_h8300h.o diff --git a/trunk/arch/h8300/platform/h8300h/entry.S b/trunk/arch/h8300/platform/h8300h/entry.S index d2dea2432fb2..f86ac3b5d4de 100644 --- a/trunk/arch/h8300/platform/h8300h/entry.S +++ b/trunk/arch/h8300/platform/h8300h/entry.S @@ -30,12 +30,12 @@ mov.l er0,@-sp stc ccr,r0l /* check kernel mode */ - orc #0x10,ccr btst #4,r0l bne 5f mov.l sp,@SYMBOL_NAME(sw_usp) /* user mode */ mov.l @sp,er0 + orc #0x10,ccr mov.l @SYMBOL_NAME(sw_ksp),sp sub.l #(LRET-LORIG),sp /* allocate LORIG - LRET */ mov.l er0,@-sp @@ -165,7 +165,7 @@ SYMBOL_NAME_LABEL(interrupt_entry) dec.l #1,er0 mov.l sp,er1 subs #4,er1 /* adjust ret_pc */ - jsr @SYMBOL_NAME(process_int) + jsr @SYMBOL_NAME(do_IRQ) mov.l @SYMBOL_NAME(irq_stat)+CPUSTAT_SOFTIRQ_PENDING,er0 beq 1f jsr @SYMBOL_NAME(do_softirq) diff --git a/trunk/arch/h8300/platform/h8300h/generic/Makefile b/trunk/arch/h8300/platform/h8300h/generic/Makefile index b6ea7688a616..32b964a9010e 100644 --- a/trunk/arch/h8300/platform/h8300h/generic/Makefile +++ b/trunk/arch/h8300/platform/h8300h/generic/Makefile @@ -2,5 +2,5 @@ # Makefile for the linux kernel. # +extra-y := crt0_$(MODEL).o obj-y := timer.o -extra-y = crt0_$(MODEL).o diff --git a/trunk/arch/h8300/platform/h8300h/ints_h8300h.c b/trunk/arch/h8300/platform/h8300h/ints_h8300h.c deleted file mode 100644 index f1777119b871..000000000000 --- a/trunk/arch/h8300/platform/h8300h/ints_h8300h.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * linux/arch/h8300/platform/h8300h/ints_h8300h.c - * Interrupt handling CPU variants - * - * Yoshinori Sato - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -/* saved vector list */ -const int __initdata h8300_saved_vectors[]={ -#if defined(CONFIG_GDB_DEBUG) - TRAP3_VEC, -#endif - -1 -}; - -/* trap entry table */ -const unsigned long __initdata h8300_trap_table[NR_TRAPS]={ - 0,0,0,0,0,0,0,0, - (unsigned long)system_call, /* TRAPA #0 */ - 0,0, - (unsigned long)trace_break, /* TRAPA #3 */ -}; - -int h8300_enable_irq_pin(unsigned int irq) -{ - int bitmask; - if (irq < EXT_IRQ0 || irq > EXT_IRQ5) - return 0; - - /* initialize IRQ pin */ - bitmask = 1 << (irq - EXT_IRQ0); - switch(irq) { - case EXT_IRQ0: - case EXT_IRQ1: - case EXT_IRQ2: - case EXT_IRQ3: - if (H8300_GPIO_RESERVE(H8300_GPIO_P8, bitmask) == 0) - return -EBUSY; - H8300_GPIO_DDR(H8300_GPIO_P8, bitmask, H8300_GPIO_INPUT); - break; - case EXT_IRQ4: - case EXT_IRQ5: - if (H8300_GPIO_RESERVE(H8300_GPIO_P9, bitmask) == 0) - return -EBUSY; - H8300_GPIO_DDR(H8300_GPIO_P9, bitmask, H8300_GPIO_INPUT); - break; - } - - return 0; -} - -void h8300_disable_irq_pin(unsigned int irq) -{ - int bitmask; - if (irq < EXT_IRQ0 || irq > EXT_IRQ5) - return; - - /* disable interrupt & release IRQ pin */ - bitmask = 1 << (irq - EXT_IRQ0); - switch(irq) { - case EXT_IRQ0: - case EXT_IRQ1: - case EXT_IRQ2: - case EXT_IRQ3: - *(volatile unsigned char *)IER &= ~bitmask; - H8300_GPIO_FREE(H8300_GPIO_P8, bitmask); - break ; - case EXT_IRQ4: - case EXT_IRQ5: - *(volatile unsigned char *)IER &= ~bitmask; - H8300_GPIO_FREE(H8300_GPIO_P9, bitmask); - break; - } -} diff --git a/trunk/arch/h8300/platform/h8s/entry.S b/trunk/arch/h8300/platform/h8s/entry.S index aeb2e9faa9b2..f3d6b8e8f959 100644 --- a/trunk/arch/h8300/platform/h8s/entry.S +++ b/trunk/arch/h8300/platform/h8s/entry.S @@ -31,12 +31,13 @@ mov.l er0,@-sp stc ccr,r0l /* check kernel mode */ - orc #0x10,ccr btst #4,r0l bne 5f - mov.l sp,@SYMBOL_NAME(sw_usp) /* user mode */ - mov.l @sp,er0 + /* user mode */ + mov.l sp,@SYMBOL_NAME(sw_usp) + mov.l @sp,er0 /* restore saved er0 */ + orc #0x10,ccr /* switch kernel stack */ mov.l @SYMBOL_NAME(sw_ksp),sp sub.l #(LRET-LORIG),sp /* allocate LORIG - LRET */ stm.l er0-er3,@-sp @@ -55,8 +56,9 @@ mov.l er0,@(LER0-LER3:16,sp) /* copy ER0 */ bra 6f 5: - mov.l @sp,er0 /* kernel mode */ - subs #2,sp /* dummy ccr */ + /* kernel mode */ + mov.l @sp,er0 /* restore saved er0 */ + subs #2,sp /* set dummy ccr */ stm.l er0-er3,@-sp mov.w @(LRET-LER3:16,sp),r1 /* copy old ccr */ mov.b r1h,r1l @@ -94,6 +96,7 @@ mov.l @sp+,er1 add.l #(LRET-LER1),sp /* remove LORIG - LRET */ mov.l sp,@SYMBOL_NAME(sw_ksp) + andc #0xef,ccr /* switch to user mode */ mov.l er0,sp bra 8f 7: @@ -173,9 +176,6 @@ SYMBOL_NAME_LABEL(interrupt_entry) SYMBOL_NAME_LABEL(system_call) subs #4,sp /* dummy LVEC */ SAVE_ALL - mov.w @(LCCR:16,sp),r1 - bset #4,r1l - ldc r1l,ccr /* restore ccr */ mov.l er0,er4 mov.l #-ENOSYS,er0 mov.l er0,@(LER0:16,sp) @@ -198,6 +198,7 @@ SYMBOL_NAME_LABEL(system_call) mov.l @(LER1:16,sp),er0 mov.l @(LER2:16,sp),er1 mov.l @(LER3:16,sp),er2 + andc #0x7f,ccr jsr @er4 mov.l er0,@(LER0:16,sp) /* save the return value */ #if defined(CONFIG_SYSCALL_PRINT) diff --git a/trunk/arch/i386/Kconfig b/trunk/arch/i386/Kconfig index a9af760c7e5f..64ad10f984a1 100644 --- a/trunk/arch/i386/Kconfig +++ b/trunk/arch/i386/Kconfig @@ -79,6 +79,10 @@ config ARCH_MAY_HAVE_PC_FDC bool default y +config ARCH_USES_SLAB_PAGE_STRUCT + bool + default y + config DMI bool default y diff --git a/trunk/arch/i386/kernel/Makefile b/trunk/arch/i386/kernel/Makefile index 4f98516b9f94..91cff8dc9e1a 100644 --- a/trunk/arch/i386/kernel/Makefile +++ b/trunk/arch/i386/kernel/Makefile @@ -34,6 +34,7 @@ obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat.o obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o +obj-$(CONFIG_SERIAL_8250) += legacy_serial.o obj-$(CONFIG_VM86) += vm86.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_HPET_TIMER) += hpet.o diff --git a/trunk/arch/i386/kernel/alternative.c b/trunk/arch/i386/kernel/alternative.c index e5cec6685cc5..d8cda14fff8b 100644 --- a/trunk/arch/i386/kernel/alternative.c +++ b/trunk/arch/i386/kernel/alternative.c @@ -390,8 +390,8 @@ void __init alternative_instructions(void) _text, _etext); } free_init_pages("SMP alternatives", - __pa_symbol(&__smp_locks), - __pa_symbol(&__smp_locks_end)); + (unsigned long)__smp_locks, + (unsigned long)__smp_locks_end); } else { alternatives_smp_module_add(NULL, "core kernel", __smp_locks, __smp_locks_end, diff --git a/trunk/arch/i386/kernel/apic.c b/trunk/arch/i386/kernel/apic.c index aca054cc0552..67824f3bb974 100644 --- a/trunk/arch/i386/kernel/apic.c +++ b/trunk/arch/i386/kernel/apic.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/kernel/apm.c b/trunk/arch/i386/kernel/apm.c index 367ff1d930cb..4112afe712b9 100644 --- a/trunk/arch/i386/kernel/apm.c +++ b/trunk/arch/i386/kernel/apm.c @@ -223,7 +223,6 @@ #include #include #include -#include #include #include #include @@ -1173,7 +1172,7 @@ static void reinit_timer(void) unsigned long flags; spin_lock_irqsave(&i8253_lock, flags); - /* set the clock to 100 Hz */ + /* set the clock to HZ */ outb_p(0x34, PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */ udelay(10); outb_p(LATCH & 0xff, PIT_CH0); /* LSB */ diff --git a/trunk/arch/i386/kernel/crash.c b/trunk/arch/i386/kernel/crash.c index a5e0e990ea95..53589d1b1a05 100644 --- a/trunk/arch/i386/kernel/crash.c +++ b/trunk/arch/i386/kernel/crash.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include diff --git a/trunk/arch/i386/kernel/efi.c b/trunk/arch/i386/kernel/efi.c index dd9e7faafa7c..a1808022ea19 100644 --- a/trunk/arch/i386/kernel/efi.c +++ b/trunk/arch/i386/kernel/efi.c @@ -347,14 +347,12 @@ void __init efi_init(void) printk(KERN_ERR PFX "Woah! Couldn't map the EFI system table.\n"); if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) printk(KERN_ERR PFX "Woah! EFI system table signature incorrect\n"); - if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0) - printk(KERN_ERR PFX - "Warning: EFI system table major version mismatch: " - "got %d.%02d, expected %d.%02d\n", + if ((efi.systab->hdr.revision >> 16) == 0) + printk(KERN_ERR PFX "Warning: EFI system table version " + "%d.%02d, expected 1.00 or greater\n", efi.systab->hdr.revision >> 16, - efi.systab->hdr.revision & 0xffff, - EFI_SYSTEM_TABLE_REVISION >> 16, - EFI_SYSTEM_TABLE_REVISION & 0xffff); + efi.systab->hdr.revision & 0xffff); + /* * Grab some details from the system table */ diff --git a/trunk/arch/i386/kernel/i8259.c b/trunk/arch/i386/kernel/i8259.c index 03abfdb1a6e4..0499cbe9871a 100644 --- a/trunk/arch/i386/kernel/i8259.c +++ b/trunk/arch/i386/kernel/i8259.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/kernel/io_apic.c b/trunk/arch/i386/kernel/io_apic.c index 1b623cda3a64..7f8b7af2b95f 100644 --- a/trunk/arch/i386/kernel/io_apic.c +++ b/trunk/arch/i386/kernel/io_apic.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/kernel/ioport.c b/trunk/arch/i386/kernel/ioport.c index d1e42e0dbe67..3d310a946d76 100644 --- a/trunk/arch/i386/kernel/ioport.c +++ b/trunk/arch/i386/kernel/ioport.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/kernel/kprobes.c b/trunk/arch/i386/kernel/kprobes.c index b545bc746fce..dde828a333c3 100644 --- a/trunk/arch/i386/kernel/kprobes.c +++ b/trunk/arch/i386/kernel/kprobes.c @@ -31,8 +31,8 @@ #include #include #include +#include #include -#include #include #include @@ -226,24 +226,15 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) } /* Called with kretprobe_lock held */ -void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, +void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { unsigned long *sara = (unsigned long *)®s->esp; - struct kretprobe_instance *ri; + ri->ret_addr = (kprobe_opcode_t *) *sara; - if ((ri = get_free_rp_inst(rp)) != NULL) { - ri->rp = rp; - ri->task = current; - ri->ret_addr = (kprobe_opcode_t *) *sara; - - /* Replace the return addr with trampoline addr */ - *sara = (unsigned long) &kretprobe_trampoline; - add_rp_inst(ri); - } else { - rp->nmissed++; - } + /* Replace the return addr with trampoline addr */ + *sara = (unsigned long) &kretprobe_trampoline; } /* @@ -449,8 +440,7 @@ fastcall void *__kprobes trampoline_handler(struct pt_regs *regs) break; } - BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); - + kretprobe_assert(ri, orig_ret_address, trampoline_address); spin_unlock_irqrestore(&kretprobe_lock, flags); hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { @@ -753,6 +743,11 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) return 0; } +int __kprobes arch_trampoline_kprobe(struct kprobe *p) +{ + return 0; +} + int __init arch_init_kprobes(void) { return 0; diff --git a/trunk/arch/i386/kernel/ldt.c b/trunk/arch/i386/kernel/ldt.c index b410e5fb034f..e0b2d17f4f10 100644 --- a/trunk/arch/i386/kernel/ldt.c +++ b/trunk/arch/i386/kernel/ldt.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/i386/kernel/legacy_serial.c b/trunk/arch/i386/kernel/legacy_serial.c new file mode 100644 index 000000000000..21510118544e --- /dev/null +++ b/trunk/arch/i386/kernel/legacy_serial.c @@ -0,0 +1,67 @@ +/* + * Legacy COM port devices for x86 platforms without PNPBIOS or ACPI. + * Data taken from include/asm-i386/serial.h. + * + * (c) Copyright 2007 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas + * + * 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 +#include +#include +#include + +/* Standard COM flags (except for COM4, because of the 8514 problem) */ +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ) +#define COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ) +#else +#define COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST) +#define COM4_FLAGS UPF_BOOT_AUTOCONF +#endif + +#define PORT(_base,_irq,_flags) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = _flags, \ + } + +static struct plat_serial8250_port x86_com_data[] = { + PORT(0x3F8, 4, COM_FLAGS), + PORT(0x2F8, 3, COM_FLAGS), + PORT(0x3E8, 4, COM_FLAGS), + PORT(0x2E8, 3, COM4_FLAGS), + { }, +}; + +static struct platform_device x86_com_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = x86_com_data, + }, +}; + +static int force_legacy_probe; +module_param_named(force, force_legacy_probe, bool, 0); +MODULE_PARM_DESC(force, "Force legacy serial port probe"); + +static int __init serial8250_x86_com_init(void) +{ + if (pnp_platform_devices && !force_legacy_probe) + return -ENODEV; + + return platform_device_register(&x86_com_device); +} + +module_init(serial8250_x86_com_init); + +MODULE_AUTHOR("Bjorn Helgaas"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic 8250/16x50 legacy probe module"); diff --git a/trunk/arch/i386/kernel/mpparse.c b/trunk/arch/i386/kernel/mpparse.c index 0952eccd8f28..13abb4ebfb79 100644 --- a/trunk/arch/i386/kernel/mpparse.c +++ b/trunk/arch/i386/kernel/mpparse.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/kernel/msr.c b/trunk/arch/i386/kernel/msr.c index bcaa6e9b6197..8cd0a91ce107 100644 --- a/trunk/arch/i386/kernel/msr.c +++ b/trunk/arch/i386/kernel/msr.c @@ -45,104 +45,6 @@ static struct class *msr_class; -static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) -{ - int err; - - err = wrmsr_safe(reg, eax, edx); - if (err) - err = -EIO; - return err; -} - -static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) -{ - int err; - - err = rdmsr_safe(reg, eax, edx); - if (err) - err = -EIO; - return err; -} - -#ifdef CONFIG_SMP - -struct msr_command { - int err; - u32 reg; - u32 data[2]; -}; - -static void msr_smp_wrmsr(void *cmd_block) -{ - struct msr_command *cmd = (struct msr_command *)cmd_block; - - cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]); -} - -static void msr_smp_rdmsr(void *cmd_block) -{ - struct msr_command *cmd = (struct msr_command *)cmd_block; - - cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); -} - -static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) -{ - struct msr_command cmd; - int ret; - - preempt_disable(); - if (cpu == smp_processor_id()) { - ret = wrmsr_eio(reg, eax, edx); - } else { - cmd.reg = reg; - cmd.data[0] = eax; - cmd.data[1] = edx; - - smp_call_function_single(cpu, msr_smp_wrmsr, &cmd, 1, 1); - ret = cmd.err; - } - preempt_enable(); - return ret; -} - -static inline int do_rdmsr(int cpu, u32 reg, u32 * eax, u32 * edx) -{ - struct msr_command cmd; - int ret; - - preempt_disable(); - if (cpu == smp_processor_id()) { - ret = rdmsr_eio(reg, eax, edx); - } else { - cmd.reg = reg; - - smp_call_function_single(cpu, msr_smp_rdmsr, &cmd, 1, 1); - - *eax = cmd.data[0]; - *edx = cmd.data[1]; - - ret = cmd.err; - } - preempt_enable(); - return ret; -} - -#else /* ! CONFIG_SMP */ - -static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) -{ - return wrmsr_eio(reg, eax, edx); -} - -static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) -{ - return rdmsr_eio(reg, eax, edx); -} - -#endif /* ! CONFIG_SMP */ - static loff_t msr_seek(struct file *file, loff_t offset, int orig) { loff_t ret = -EINVAL; @@ -174,9 +76,9 @@ static ssize_t msr_read(struct file *file, char __user * buf, return -EINVAL; /* Invalid chunk size */ for (; count; count -= 8) { - err = do_rdmsr(cpu, reg, &data[0], &data[1]); + err = rdmsr_safe_on_cpu(cpu, reg, &data[0], &data[1]); if (err) - return err; + return -EIO; if (copy_to_user(tmp, &data, 8)) return -EFAULT; tmp += 2; @@ -200,9 +102,9 @@ static ssize_t msr_write(struct file *file, const char __user *buf, for (; count; count -= 8) { if (copy_from_user(&data, tmp, 8)) return -EFAULT; - err = do_wrmsr(cpu, reg, data[0], data[1]); + err = wrmsr_safe_on_cpu(cpu, reg, data[0], data[1]); if (err) - return err; + return -EIO; tmp += 2; } diff --git a/trunk/arch/i386/kernel/nmi.c b/trunk/arch/i386/kernel/nmi.c index 33cf2f3c444f..fba121f7973f 100644 --- a/trunk/arch/i386/kernel/nmi.c +++ b/trunk/arch/i386/kernel/nmi.c @@ -23,10 +23,10 @@ #include #include #include +#include #include #include -#include #include "mach_traps.h" diff --git a/trunk/arch/i386/kernel/pci-dma.c b/trunk/arch/i386/kernel/pci-dma.c index 3ebcea033623..30b754f7cbec 100644 --- a/trunk/arch/i386/kernel/pci-dma.c +++ b/trunk/arch/i386/kernel/pci-dma.c @@ -77,7 +77,7 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, { void __iomem *mem_base = NULL; int pages = size >> PAGE_SHIFT; - int bitmap_size = (pages + 31)/32; + int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) goto out; diff --git a/trunk/arch/i386/kernel/process.c b/trunk/arch/i386/kernel/process.c index 61999479b7a4..d76d9bc33b30 100644 --- a/trunk/arch/i386/kernel/process.c +++ b/trunk/arch/i386/kernel/process.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/kernel/ptrace.c b/trunk/arch/i386/kernel/ptrace.c index 4a8f8a259723..0c0ceec5de00 100644 --- a/trunk/arch/i386/kernel/ptrace.c +++ b/trunk/arch/i386/kernel/ptrace.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/kernel/signal.c b/trunk/arch/i386/kernel/signal.c index 4f99e870c986..d574e38f0f77 100644 --- a/trunk/arch/i386/kernel/signal.c +++ b/trunk/arch/i386/kernel/signal.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/kernel/smp.c b/trunk/arch/i386/kernel/smp.c index 89a45a9ddcd4..93f202a855fa 100644 --- a/trunk/arch/i386/kernel/smp.c +++ b/trunk/arch/i386/kernel/smp.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/kernel/smpboot.c b/trunk/arch/i386/kernel/smpboot.c index a4b7ad283f49..b92cc4e8b3bb 100644 --- a/trunk/arch/i386/kernel/smpboot.c +++ b/trunk/arch/i386/kernel/smpboot.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/kernel/sys_i386.c b/trunk/arch/i386/kernel/sys_i386.c index 4048397f1740..e5dcb9379018 100644 --- a/trunk/arch/i386/kernel/sys_i386.c +++ b/trunk/arch/i386/kernel/sys_i386.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/kernel/syscall_table.S b/trunk/arch/i386/kernel/syscall_table.S index 2697e9210e92..0772678ceecf 100644 --- a/trunk/arch/i386/kernel/syscall_table.S +++ b/trunk/arch/i386/kernel/syscall_table.S @@ -319,3 +319,4 @@ ENTRY(sys_call_table) .long sys_move_pages .long sys_getcpu .long sys_epoll_pwait + .long sys_utimensat /* 320 */ diff --git a/trunk/arch/i386/kernel/traps.c b/trunk/arch/i386/kernel/traps.c index f21b41e7770c..4bec0cbf407a 100644 --- a/trunk/arch/i386/kernel/traps.c +++ b/trunk/arch/i386/kernel/traps.c @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include #include @@ -95,20 +95,6 @@ asmlinkage void machine_check(void); int kstack_depth_to_print = 24; static unsigned int code_bytes = 64; -ATOMIC_NOTIFIER_HEAD(i386die_chain); - -int register_die_notifier(struct notifier_block *nb) -{ - vmalloc_sync_all(); - return atomic_notifier_chain_register(&i386die_chain, nb); -} -EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */ - -int unregister_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&i386die_chain, nb); -} -EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) { @@ -747,6 +733,11 @@ static __kprobes void default_do_nmi(struct pt_regs * regs) */ if (nmi_watchdog_tick(regs, reason)) return; +#endif + if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0) + == NOTIFY_STOP) + return; +#ifdef CONFIG_X86_LOCAL_APIC if (!do_nmi_callback(regs, smp_processor_id())) #endif unknown_nmi_error(reason, regs); diff --git a/trunk/arch/i386/kernel/vm86.c b/trunk/arch/i386/kernel/vm86.c index d1b8f2b7aea6..f2dcd1d27c0a 100644 --- a/trunk/arch/i386/kernel/vm86.c +++ b/trunk/arch/i386/kernel/vm86.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/lib/msr-on-cpu.c b/trunk/arch/i386/lib/msr-on-cpu.c index 1c46bda409ff..7767962f25d3 100644 --- a/trunk/arch/i386/lib/msr-on-cpu.c +++ b/trunk/arch/i386/lib/msr-on-cpu.c @@ -6,6 +6,7 @@ struct msr_info { u32 msr_no; u32 l, h; + int err; }; static void __rdmsr_on_cpu(void *info) @@ -15,20 +16,38 @@ static void __rdmsr_on_cpu(void *info) rdmsr(rv->msr_no, rv->l, rv->h); } -void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) +static void __rdmsr_safe_on_cpu(void *info) { + struct msr_info *rv = info; + + rv->err = rdmsr_safe(rv->msr_no, &rv->l, &rv->h); +} + +static int _rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h, int safe) +{ + int err = 0; preempt_disable(); if (smp_processor_id() == cpu) - rdmsr(msr_no, *l, *h); + if (safe) + err = rdmsr_safe(msr_no, l, h); + else + rdmsr(msr_no, *l, *h); else { struct msr_info rv; rv.msr_no = msr_no; - smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 0, 1); + if (safe) { + smp_call_function_single(cpu, __rdmsr_safe_on_cpu, + &rv, 0, 1); + err = rv.err; + } else { + smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 0, 1); + } *l = rv.l; *h = rv.h; } preempt_enable(); + return err; } static void __wrmsr_on_cpu(void *info) @@ -38,21 +57,63 @@ static void __wrmsr_on_cpu(void *info) wrmsr(rv->msr_no, rv->l, rv->h); } -void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) +static void __wrmsr_safe_on_cpu(void *info) { + struct msr_info *rv = info; + + rv->err = wrmsr_safe(rv->msr_no, rv->l, rv->h); +} + +static int _wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h, int safe) +{ + int err = 0; preempt_disable(); if (smp_processor_id() == cpu) - wrmsr(msr_no, l, h); + if (safe) + err = wrmsr_safe(msr_no, l, h); + else + wrmsr(msr_no, l, h); else { struct msr_info rv; rv.msr_no = msr_no; rv.l = l; rv.h = h; - smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 0, 1); + if (safe) { + smp_call_function_single(cpu, __wrmsr_safe_on_cpu, + &rv, 0, 1); + err = rv.err; + } else { + smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 0, 1); + } } preempt_enable(); + return err; +} + +void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) +{ + _wrmsr_on_cpu(cpu, msr_no, l, h, 0); +} + +void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) +{ + _rdmsr_on_cpu(cpu, msr_no, l, h, 0); +} + +/* These "safe" variants are slower and should be used when the target MSR + may not actually exist. */ +int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) +{ + return _wrmsr_on_cpu(cpu, msr_no, l, h, 1); +} + +int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) +{ + return _rdmsr_on_cpu(cpu, msr_no, l, h, 1); } EXPORT_SYMBOL(rdmsr_on_cpu); EXPORT_SYMBOL(wrmsr_on_cpu); +EXPORT_SYMBOL(rdmsr_safe_on_cpu); +EXPORT_SYMBOL(wrmsr_safe_on_cpu); diff --git a/trunk/arch/i386/mach-default/setup.c b/trunk/arch/i386/mach-default/setup.c index c78816210706..7f635c7a2381 100644 --- a/trunk/arch/i386/mach-default/setup.c +++ b/trunk/arch/i386/mach-default/setup.c @@ -81,7 +81,7 @@ void __init trap_init_hook(void) static struct irqaction irq0 = { .handler = timer_interrupt, - .flags = IRQF_DISABLED | IRQF_NOBALANCING, + .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL, .mask = CPU_MASK_NONE, .name = "timer" }; diff --git a/trunk/arch/i386/mach-visws/setup.c b/trunk/arch/i386/mach-visws/setup.c index 233ee20907b9..1f81f10e03a0 100644 --- a/trunk/arch/i386/mach-visws/setup.c +++ b/trunk/arch/i386/mach-visws/setup.c @@ -116,7 +116,7 @@ void __init pre_setup_arch_hook() static struct irqaction irq0 = { .handler = timer_interrupt, - .flags = IRQF_DISABLED, + .flags = IRQF_DISABLED | IRQF_IRQPOLL, .name = "timer", }; diff --git a/trunk/arch/i386/mach-visws/visws_apic.c b/trunk/arch/i386/mach-visws/visws_apic.c index 38c2b13124d9..710faf71a650 100644 --- a/trunk/arch/i386/mach-visws/visws_apic.c +++ b/trunk/arch/i386/mach-visws/visws_apic.c @@ -18,7 +18,6 @@ #include #include -#include #include #include diff --git a/trunk/arch/i386/mach-voyager/setup.c b/trunk/arch/i386/mach-voyager/setup.c index 447bb105cf58..2b55694e6400 100644 --- a/trunk/arch/i386/mach-voyager/setup.c +++ b/trunk/arch/i386/mach-voyager/setup.c @@ -42,7 +42,7 @@ void __init trap_init_hook(void) static struct irqaction irq0 = { .handler = timer_interrupt, - .flags = IRQF_DISABLED | IRQF_NOBALANCING, + .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL, .mask = CPU_MASK_NONE, .name = "timer" }; diff --git a/trunk/arch/i386/mach-voyager/voyager_smp.c b/trunk/arch/i386/mach-voyager/voyager_smp.c index 1a5e448a29c7..50d9c52070b1 100644 --- a/trunk/arch/i386/mach-voyager/voyager_smp.c +++ b/trunk/arch/i386/mach-voyager/voyager_smp.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/mach-voyager/voyager_thread.c b/trunk/arch/i386/mach-voyager/voyager_thread.c index fdc1d926fb2a..b4b24e0e45e1 100644 --- a/trunk/arch/i386/mach-voyager/voyager_thread.c +++ b/trunk/arch/i386/mach-voyager/voyager_thread.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/i386/mm/fault.c b/trunk/arch/i386/mm/fault.c index f534c29e80b2..29d7d61543a1 100644 --- a/trunk/arch/i386/mm/fault.c +++ b/trunk/arch/i386/mm/fault.c @@ -14,20 +14,20 @@ #include #include #include -#include #include #include #include #include /* For unblank_screen() */ #include #include /* for max_low_pfn */ +#include #include #include #include +#include #include #include -#include #include extern void die(const char *,struct pt_regs *,long); diff --git a/trunk/arch/i386/mm/hugetlbpage.c b/trunk/arch/i386/mm/hugetlbpage.c index 34728e4afe48..efdf95ac8031 100644 --- a/trunk/arch/i386/mm/hugetlbpage.c +++ b/trunk/arch/i386/mm/hugetlbpage.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -367,6 +366,12 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, if (len > TASK_SIZE) return -ENOMEM; + if (flags & MAP_FIXED) { + if (prepare_hugepage_range(addr, len, pgoff)) + return -EINVAL; + return addr; + } + if (addr) { addr = ALIGN(addr, HPAGE_SIZE); vma = find_vma(mm, addr); diff --git a/trunk/arch/i386/mm/init.c b/trunk/arch/i386/mm/init.c index dbe16f63a566..c50782efa5c3 100644 --- a/trunk/arch/i386/mm/init.c +++ b/trunk/arch/i386/mm/init.c @@ -751,12 +751,9 @@ void __init pgtable_cache_init(void) pmd_cache = kmem_cache_create("pmd", PTRS_PER_PMD*sizeof(pmd_t), PTRS_PER_PMD*sizeof(pmd_t), - 0, + SLAB_PANIC, pmd_ctor, NULL); - if (!pmd_cache) - panic("pgtable_cache_init(): cannot create pmd cache"); - if (!SHARED_KERNEL_PMD) { /* If we're in PAE mode and have a non-shared kernel pmd, then the pgd size must be a @@ -770,11 +767,9 @@ void __init pgtable_cache_init(void) pgd_cache = kmem_cache_create("pgd", pgd_size, pgd_size, - 0, + SLAB_PANIC, pgd_ctor, (!SHARED_KERNEL_PMD) ? pgd_dtor : NULL); - if (!pgd_cache) - panic("pgtable_cache_init(): Cannot create pgd cache"); } /* @@ -843,11 +838,10 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) unsigned long addr; for (addr = begin; addr < end; addr += PAGE_SIZE) { - struct page *page = pfn_to_page(addr >> PAGE_SHIFT); - ClearPageReserved(page); - init_page_count(page); - memset(page_address(page), POISON_FREE_INITMEM, PAGE_SIZE); - __free_page(page); + ClearPageReserved(virt_to_page(addr)); + init_page_count(virt_to_page(addr)); + memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); + free_page(addr); totalram_pages++; } printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); @@ -856,14 +850,14 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) void free_initmem(void) { free_init_pages("unused kernel memory", - __pa_symbol(&__init_begin), - __pa_symbol(&__init_end)); + (unsigned long)(&__init_begin), + (unsigned long)(&__init_end)); } #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { - free_init_pages("initrd memory", __pa(start), __pa(end)); + free_init_pages("initrd memory", start, end); } #endif diff --git a/trunk/arch/i386/oprofile/nmi_int.c b/trunk/arch/i386/oprofile/nmi_int.c index 695f737516ae..8e185208dfd4 100644 --- a/trunk/arch/i386/oprofile/nmi_int.c +++ b/trunk/arch/i386/oprofile/nmi_int.c @@ -14,10 +14,10 @@ #include #include #include +#include #include #include #include -#include #include "op_counter.h" #include "op_x86_model.h" diff --git a/trunk/arch/i386/oprofile/nmi_timer_int.c b/trunk/arch/i386/oprofile/nmi_timer_int.c index abf0ba52a635..1418e36ae7ab 100644 --- a/trunk/arch/i386/oprofile/nmi_timer_int.c +++ b/trunk/arch/i386/oprofile/nmi_timer_int.c @@ -12,12 +12,11 @@ #include #include #include - +#include #include #include #include -#include static int profile_timer_exceptions_notify(struct notifier_block *self, unsigned long val, void *data) diff --git a/trunk/arch/ia64/Kconfig b/trunk/arch/ia64/Kconfig index 3b71f97d0b60..e23af4b6ae8c 100644 --- a/trunk/arch/ia64/Kconfig +++ b/trunk/arch/ia64/Kconfig @@ -439,6 +439,16 @@ config IA64_PALINFO To use this option, you have to ensure that the "/proc file system support" (CONFIG_PROC_FS) is enabled, too. +config IA64_MC_ERR_INJECT + tristate "MC error injection support" + help + Selets whether support for MC error injection. By enabling the + support, kernel provide sysfs interface for user application to + call MC error injection PAL procedure to inject various errors. + This is a useful tool for MCA testing. + + If you're unsure, do not select this option. + config SGI_SN def_bool y if (IA64_SGI_SN2 || IA64_GENERIC) diff --git a/trunk/arch/ia64/defconfig b/trunk/arch/ia64/defconfig index 153bfdc0182d..90bd9601cdde 100644 --- a/trunk/arch/ia64/defconfig +++ b/trunk/arch/ia64/defconfig @@ -164,6 +164,7 @@ CONFIG_COMPAT=y CONFIG_IA64_MCA_RECOVERY=y CONFIG_PERFMON=y CONFIG_IA64_PALINFO=y +# CONFIG_MC_ERR_INJECT is not set CONFIG_SGI_SN=y # CONFIG_IA64_ESI is not set diff --git a/trunk/arch/ia64/hp/sim/boot/fw-emu.c b/trunk/arch/ia64/hp/sim/boot/fw-emu.c index 5a0a7afcfc3a..300acd913d9c 100644 --- a/trunk/arch/ia64/hp/sim/boot/fw-emu.c +++ b/trunk/arch/ia64/hp/sim/boot/fw-emu.c @@ -287,7 +287,7 @@ sys_fw_init (const char *args, int arglen) memset(efi_systab, 0, sizeof(efi_systab)); efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; - efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION; + efi_systab->hdr.revision = ((1 << 16) | 00); efi_systab->hdr.headersize = sizeof(efi_systab->hdr); efi_systab->fw_vendor = __pa("H\0e\0w\0l\0e\0t\0t\0-\0P\0a\0c\0k\0a\0r\0d\0\0"); efi_systab->fw_revision = 1; diff --git a/trunk/arch/ia64/ia32/ia32_ldt.c b/trunk/arch/ia64/ia32/ia32_ldt.c index a152738c7d0d..16d51c146849 100644 --- a/trunk/arch/ia64/ia32/ia32_ldt.c +++ b/trunk/arch/ia64/ia32/ia32_ldt.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/ia64/ia32/ia32_signal.c b/trunk/arch/ia64/ia32/ia32_signal.c index b3355a9ca2c3..10510e585204 100644 --- a/trunk/arch/ia64/ia32/ia32_signal.c +++ b/trunk/arch/ia64/ia32/ia32_signal.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/ia64/ia32/ia32_support.c b/trunk/arch/ia64/ia32/ia32_support.c index 6af400a12ca1..beea7a0b9dc6 100644 --- a/trunk/arch/ia64/ia32/ia32_support.c +++ b/trunk/arch/ia64/ia32/ia32_support.c @@ -252,10 +252,8 @@ ia32_init (void) extern struct kmem_cache *partial_page_cachep; partial_page_cachep = kmem_cache_create("partial_page_cache", - sizeof(struct partial_page), 0, 0, - NULL, NULL); - if (!partial_page_cachep) - panic("Cannot create partial page SLAB cache"); + sizeof(struct partial_page), + 0, SLAB_PANIC, NULL, NULL); } #endif return 0; diff --git a/trunk/arch/ia64/kernel/Makefile b/trunk/arch/ia64/kernel/Makefile index 098ee605bf5e..33e5a598672d 100644 --- a/trunk/arch/ia64/kernel/Makefile +++ b/trunk/arch/ia64/kernel/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o obj-$(CONFIG_AUDIT) += audit.o obj-$(CONFIG_PCI_MSI) += msi_ia64.o mca_recovery-y += mca_drv.o mca_drv_asm.o +obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o obj-$(CONFIG_IA64_ESI) += esi.o ifneq ($(CONFIG_IA64_ESI),) diff --git a/trunk/arch/ia64/kernel/crash.c b/trunk/arch/ia64/kernel/crash.c index 80a94e707827..aeb79fb28f0b 100644 --- a/trunk/arch/ia64/kernel/crash.c +++ b/trunk/arch/ia64/kernel/crash.c @@ -16,8 +16,8 @@ #include #include #include +#include -#include #include int kdump_status[NR_CPUS]; @@ -74,7 +74,7 @@ crash_save_this_cpu(void) buf = (u64 *) per_cpu_ptr(crash_notes, cpu); if (!buf) return; - buf = append_elf_note(buf, "CORE", NT_PRSTATUS, prstatus, + buf = append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS, prstatus, sizeof(*prstatus)); final_note(buf); } diff --git a/trunk/arch/ia64/kernel/efi.c b/trunk/arch/ia64/kernel/efi.c index f45f91d38cab..75ec3478d8a2 100644 --- a/trunk/arch/ia64/kernel/efi.c +++ b/trunk/arch/ia64/kernel/efi.c @@ -445,11 +445,11 @@ efi_init (void) panic("Woah! Can't find EFI system table.\n"); if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) panic("Woah! EFI system table signature incorrect\n"); - if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0) - printk(KERN_WARNING "Warning: EFI system table major version mismatch: " - "got %d.%02d, expected %d.%02d\n", - efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, - EFI_SYSTEM_TABLE_REVISION >> 16, EFI_SYSTEM_TABLE_REVISION & 0xffff); + if ((efi.systab->hdr.revision >> 16) == 0) + printk(KERN_WARNING "Warning: EFI system table version " + "%d.%02d, expected 1.00 or greater\n", + efi.systab->hdr.revision >> 16, + efi.systab->hdr.revision & 0xffff); config_tables = __va(efi.systab->tables); @@ -660,6 +660,29 @@ efi_memory_descriptor (unsigned long phys_addr) return NULL; } +static int +efi_memmap_intersects (unsigned long phys_addr, unsigned long size) +{ + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + u64 efi_desc_size; + unsigned long end; + + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; + + end = phys_addr + size; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + + if (md->phys_addr < end && efi_md_end(md) > phys_addr) + return 1; + } + return 0; +} + u32 efi_mem_type (unsigned long phys_addr) { @@ -766,11 +789,28 @@ valid_phys_addr_range (unsigned long phys_addr, unsigned long size) int valid_mmap_phys_addr_range (unsigned long pfn, unsigned long size) { + unsigned long phys_addr = pfn << PAGE_SHIFT; + u64 attr; + + attr = efi_mem_attribute(phys_addr, size); + /* - * MMIO regions are often missing from the EFI memory map. - * We must allow mmap of them for programs like X, so we - * currently can't do any useful validation. + * /dev/mem mmap uses normal user pages, so we don't need the entire + * granule, but the entire region we're mapping must support the same + * attribute. */ + if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC) + return 1; + + /* + * Intel firmware doesn't tell us about all the MMIO regions, so + * in general we have to allow mmap requests. But if EFI *does* + * tell us about anything inside this region, we should deny it. + * The user can always map a smaller region to avoid the overlap. + */ + if (efi_memmap_intersects(phys_addr, size)) + return 0; + return 1; } diff --git a/trunk/arch/ia64/kernel/entry.S b/trunk/arch/ia64/kernel/entry.S index e7873eeae448..55fd2d5471e1 100644 --- a/trunk/arch/ia64/kernel/entry.S +++ b/trunk/arch/ia64/kernel/entry.S @@ -767,7 +767,7 @@ ENTRY(ia64_leave_syscall) ld8.fill r15=[r3] // M0|1 restore r15 mov b6=r18 // I0 restore b6 - addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 // A + LOAD_PHYS_STACK_REG_SIZE(r17) mov f9=f0 // F clear f9 (pKStk) br.cond.dpnt.many skip_rbs_switch // B @@ -775,7 +775,6 @@ ENTRY(ia64_leave_syscall) shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition cover // B add current frame into dirty partition & set cr.ifs ;; -(pUStk) ld4 r17=[r17] // M0|1 r17 = cpu_data->phys_stacked_size_p8 mov r19=ar.bsp // M2 get new backing store pointer mov f10=f0 // F clear f10 @@ -953,9 +952,7 @@ GLOBAL_ENTRY(ia64_leave_kernel) shr.u r18=r19,16 // get byte size of existing "dirty" partition ;; mov r16=ar.bsp // get existing backing store pointer - addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 - ;; - ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 + LOAD_PHYS_STACK_REG_SIZE(r17) (pKStk) br.cond.dpnt skip_rbs_switch /* diff --git a/trunk/arch/ia64/kernel/err_inject.c b/trunk/arch/ia64/kernel/err_inject.c new file mode 100644 index 000000000000..d3e9f33e8bdd --- /dev/null +++ b/trunk/arch/ia64/kernel/err_inject.c @@ -0,0 +1,293 @@ +/* + * err_inject.c - + * 1.) Inject errors to a processor. + * 2.) Query error injection capabilities. + * This driver along with user space code can be acting as an error + * injection tool. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Written by: Fenghua Yu , Intel Corporation + * Copyright (C) 2006, Intel Corp. All rights reserved. + * + */ +#include +#include +#include +#include +#include + +#define ERR_INJ_DEBUG + +#define ERR_DATA_BUFFER_SIZE 3 // Three 8-byte; + +#define define_one_ro(name) \ +static SYSDEV_ATTR(name, 0444, show_##name, NULL) + +#define define_one_rw(name) \ +static SYSDEV_ATTR(name, 0644, show_##name, store_##name) + +static u64 call_start[NR_CPUS]; +static u64 phys_addr[NR_CPUS]; +static u64 err_type_info[NR_CPUS]; +static u64 err_struct_info[NR_CPUS]; +static struct { + u64 data1; + u64 data2; + u64 data3; +} __attribute__((__aligned__(16))) err_data_buffer[NR_CPUS]; +static s64 status[NR_CPUS]; +static u64 capabilities[NR_CPUS]; +static u64 resources[NR_CPUS]; + +#define show(name) \ +static ssize_t \ +show_##name(struct sys_device *dev, char *buf) \ +{ \ + u32 cpu=dev->id; \ + return sprintf(buf, "%lx\n", name[cpu]); \ +} + +#define store(name) \ +static ssize_t \ +store_##name(struct sys_device *dev, const char *buf, size_t size) \ +{ \ + unsigned int cpu=dev->id; \ + name[cpu] = simple_strtoull(buf, NULL, 16); \ + return size; \ +} + +show(call_start) + +/* It's user's responsibility to call the PAL procedure on a specific + * processor. The cpu number in driver is only used for storing data. + */ +static ssize_t +store_call_start(struct sys_device *dev, const char *buf, size_t size) +{ + unsigned int cpu=dev->id; + unsigned long call_start = simple_strtoull(buf, NULL, 16); + +#ifdef ERR_INJ_DEBUG + printk(KERN_DEBUG "pal_mc_err_inject for cpu%d:\n", cpu); + printk(KERN_DEBUG "err_type_info=%lx,\n", err_type_info[cpu]); + printk(KERN_DEBUG "err_struct_info=%lx,\n", err_struct_info[cpu]); + printk(KERN_DEBUG "err_data_buffer=%lx, %lx, %lx.\n", + err_data_buffer[cpu].data1, + err_data_buffer[cpu].data2, + err_data_buffer[cpu].data3); +#endif + switch (call_start) { + case 0: /* Do nothing. */ + break; + case 1: /* Call pal_mc_error_inject in physical mode. */ + status[cpu]=ia64_pal_mc_error_inject_phys(err_type_info[cpu], + err_struct_info[cpu], + ia64_tpa(&err_data_buffer[cpu]), + &capabilities[cpu], + &resources[cpu]); + break; + case 2: /* Call pal_mc_error_inject in virtual mode. */ + status[cpu]=ia64_pal_mc_error_inject_virt(err_type_info[cpu], + err_struct_info[cpu], + ia64_tpa(&err_data_buffer[cpu]), + &capabilities[cpu], + &resources[cpu]); + break; + default: + status[cpu] = -EINVAL; + break; + } + +#ifdef ERR_INJ_DEBUG + printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]); + printk(KERN_DEBUG "capapbilities=%lx,\n", capabilities[cpu]); + printk(KERN_DEBUG "resources=%lx\n", resources[cpu]); +#endif + return size; +} + +show(err_type_info) +store(err_type_info) + +static ssize_t +show_virtual_to_phys(struct sys_device *dev, char *buf) +{ + unsigned int cpu=dev->id; + return sprintf(buf, "%lx\n", phys_addr[cpu]); +} + +static ssize_t +store_virtual_to_phys(struct sys_device *dev, const char *buf, size_t size) +{ + unsigned int cpu=dev->id; + u64 virt_addr=simple_strtoull(buf, NULL, 16); + int ret; + + ret = get_user_pages(current, current->mm, virt_addr, + 1, VM_READ, 0, NULL, NULL); + if (ret<=0) { +#ifdef ERR_INJ_DEBUG + printk("Virtual address %lx is not existing.\n",virt_addr); +#endif + return -EINVAL; + } + + phys_addr[cpu] = ia64_tpa(virt_addr); + return size; +} + +show(err_struct_info) +store(err_struct_info) + +static ssize_t +show_err_data_buffer(struct sys_device *dev, char *buf) +{ + unsigned int cpu=dev->id; + + return sprintf(buf, "%lx, %lx, %lx\n", + err_data_buffer[cpu].data1, + err_data_buffer[cpu].data2, + err_data_buffer[cpu].data3); +} + +static ssize_t +store_err_data_buffer(struct sys_device *dev, const char *buf, size_t size) +{ + unsigned int cpu=dev->id; + int ret; + +#ifdef ERR_INJ_DEBUG + printk("write err_data_buffer=[%lx,%lx,%lx] on cpu%d\n", + err_data_buffer[cpu].data1, + err_data_buffer[cpu].data2, + err_data_buffer[cpu].data3, + cpu); +#endif + ret=sscanf(buf, "%lx, %lx, %lx", + &err_data_buffer[cpu].data1, + &err_data_buffer[cpu].data2, + &err_data_buffer[cpu].data3); + if (ret!=ERR_DATA_BUFFER_SIZE) + return -EINVAL; + + return size; +} + +show(status) +show(capabilities) +show(resources) + +define_one_rw(call_start); +define_one_rw(err_type_info); +define_one_rw(err_struct_info); +define_one_rw(err_data_buffer); +define_one_rw(virtual_to_phys); +define_one_ro(status); +define_one_ro(capabilities); +define_one_ro(resources); + +static struct attribute *default_attrs[] = { + &attr_call_start.attr, + &attr_virtual_to_phys.attr, + &attr_err_type_info.attr, + &attr_err_struct_info.attr, + &attr_err_data_buffer.attr, + &attr_status.attr, + &attr_capabilities.attr, + &attr_resources.attr, + NULL +}; + +static struct attribute_group err_inject_attr_group = { + .attrs = default_attrs, + .name = "err_inject" +}; +/* Add/Remove err_inject interface for CPU device */ +static int __cpuinit err_inject_add_dev(struct sys_device * sys_dev) +{ + return sysfs_create_group(&sys_dev->kobj, &err_inject_attr_group); +} + +static int __cpuinit err_inject_remove_dev(struct sys_device * sys_dev) +{ + sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group); + return 0; +} +static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + struct sys_device *sys_dev; + + sys_dev = get_cpu_sysdev(cpu); + switch (action) { + case CPU_ONLINE: + err_inject_add_dev(sys_dev); + break; + case CPU_DEAD: + err_inject_remove_dev(sys_dev); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata err_inject_cpu_notifier = +{ + .notifier_call = err_inject_cpu_callback, +}; + +static int __init +err_inject_init(void) +{ + int i; + +#ifdef ERR_INJ_DEBUG + printk(KERN_INFO "Enter error injection driver.\n"); +#endif + for_each_online_cpu(i) { + err_inject_cpu_callback(&err_inject_cpu_notifier, CPU_ONLINE, + (void *)(long)i); + } + + register_hotcpu_notifier(&err_inject_cpu_notifier); + + return 0; +} + +static void __exit +err_inject_exit(void) +{ + int i; + struct sys_device *sys_dev; + +#ifdef ERR_INJ_DEBUG + printk(KERN_INFO "Exit error injection driver.\n"); +#endif + for_each_online_cpu(i) { + sys_dev = get_cpu_sysdev(i); + sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group); + } + unregister_hotcpu_notifier(&err_inject_cpu_notifier); +} + +module_init(err_inject_init); +module_exit(err_inject_exit); + +MODULE_AUTHOR("Fenghua Yu "); +MODULE_DESCRIPTION("MC error injection kenrel sysfs interface"); +MODULE_LICENSE("GPL"); diff --git a/trunk/arch/ia64/kernel/iosapic.c b/trunk/arch/ia64/kernel/iosapic.c index dcfbf3e7a9ef..93d9ab14ba24 100644 --- a/trunk/arch/ia64/kernel/iosapic.c +++ b/trunk/arch/ia64/kernel/iosapic.c @@ -87,7 +87,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/ia64/kernel/irq_ia64.c b/trunk/arch/ia64/kernel/irq_ia64.c index 456f57b087ca..1c5044a80958 100644 --- a/trunk/arch/ia64/kernel/irq_ia64.c +++ b/trunk/arch/ia64/kernel/irq_ia64.c @@ -27,7 +27,6 @@ #include /* for rand_initialize_irq() */ #include #include -#include #include #include #include diff --git a/trunk/arch/ia64/kernel/ivt.S b/trunk/arch/ia64/kernel/ivt.S index 6b7fcbd3f6f1..34f44d8be00d 100644 --- a/trunk/arch/ia64/kernel/ivt.S +++ b/trunk/arch/ia64/kernel/ivt.S @@ -374,6 +374,7 @@ ENTRY(alt_dtlb_miss) movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) mov r21=cr.ipsr mov r31=pr + mov r24=PERCPU_ADDR ;; #ifdef CONFIG_DISABLE_VHPT shr.u r22=r16,61 // get the region number into r21 @@ -386,22 +387,30 @@ ENTRY(alt_dtlb_miss) (p8) mov r29=b0 // save b0 (p8) br.cond.dptk dtlb_fault #endif + cmp.ge p10,p11=r16,r24 // access to per_cpu_data? + tbit.z p12,p0=r16,61 // access to region 6? + mov r25=PERCPU_PAGE_SHIFT << 2 + mov r26=PERCPU_PAGE_SIZE + nop.m 0 + nop.b 0 + ;; +(p10) mov r19=IA64_KR(PER_CPU_DATA) +(p11) and r19=r19,r16 // clear non-ppn fields extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl and r22=IA64_ISR_CODE_MASK,r20 // get the isr.code field tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? - shr.u r18=r16,57 // move address bit 61 to bit 4 - and r19=r19,r16 // clear ed, reserved bits, and PTE control bits tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on? ;; - andcm r18=0x10,r18 // bit 4=~address-bit(61) +(p10) sub r19=r19,r26 +(p10) mov cr.itir=r25 cmp.ne p8,p0=r0,r23 (p9) cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22 // check isr.code field +(p12) dep r17=-1,r17,4,1 // set ma=UC for region 6 addr (p8) br.cond.spnt page_fault dep r21=-1,r21,IA64_PSR_ED_BIT,1 - or r19=r19,r17 // insert PTE control bits into r19 ;; - or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 + or r19=r19,r17 // insert PTE control bits into r19 (p6) mov cr.ipsr=r21 ;; (p7) itc.d r19 // insert the TLB entry diff --git a/trunk/arch/ia64/kernel/kprobes.c b/trunk/arch/ia64/kernel/kprobes.c index 6cb56dd4056d..4f5fd0960ba7 100644 --- a/trunk/arch/ia64/kernel/kprobes.c +++ b/trunk/arch/ia64/kernel/kprobes.c @@ -29,9 +29,9 @@ #include #include #include +#include #include -#include #include #include @@ -444,7 +444,8 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) break; } - BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); + kretprobe_assert(ri, orig_ret_address, trampoline_address); + regs->cr_iip = orig_ret_address; reset_current_kprobe(); @@ -464,23 +465,13 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) } /* Called with kretprobe_lock held */ -void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, +void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { - struct kretprobe_instance *ri; - - if ((ri = get_free_rp_inst(rp)) != NULL) { - ri->rp = rp; - ri->task = current; - ri->ret_addr = (kprobe_opcode_t *)regs->b0; - - /* Replace the return addr with trampoline addr */ - regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip; + ri->ret_addr = (kprobe_opcode_t *)regs->b0; - add_rp_inst(ri); - } else { - rp->nmissed++; - } + /* Replace the return addr with trampoline addr */ + regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip; } int __kprobes arch_prepare_kprobe(struct kprobe *p) @@ -1021,3 +1012,12 @@ int __init arch_init_kprobes(void) (kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip; return register_kprobe(&trampoline_p); } + +int __kprobes arch_trampoline_kprobe(struct kprobe *p) +{ + if (p->addr == + (kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip) + return 1; + + return 0; +} diff --git a/trunk/arch/ia64/kernel/mca.c b/trunk/arch/ia64/kernel/mca.c index 491687f84fb5..1d7cc7e2ce32 100644 --- a/trunk/arch/ia64/kernel/mca.c +++ b/trunk/arch/ia64/kernel/mca.c @@ -63,7 +63,6 @@ #include #include #include -#include #include #include #include @@ -72,9 +71,9 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/trunk/arch/ia64/kernel/mca_asm.S b/trunk/arch/ia64/kernel/mca_asm.S index c6b607c00dee..8c9c26aa6ae0 100644 --- a/trunk/arch/ia64/kernel/mca_asm.S +++ b/trunk/arch/ia64/kernel/mca_asm.S @@ -101,14 +101,6 @@ ia64_do_tlb_purge: ;; srlz.d ;; - // 2. Purge DTR for PERCPU data. - movl r16=PERCPU_ADDR - mov r18=PERCPU_PAGE_SHIFT<<2 - ;; - ptr.d r16,r18 - ;; - srlz.d - ;; // 3. Purge ITR for PAL code. GET_THIS_PADDR(r2, ia64_mca_pal_base) ;; @@ -196,22 +188,6 @@ ia64_reload_tr: srlz.i srlz.d ;; - // 2. Reload DTR register for PERCPU data. - GET_THIS_PADDR(r2, ia64_mca_per_cpu_pte) - ;; - movl r16=PERCPU_ADDR // vaddr - movl r18=PERCPU_PAGE_SHIFT<<2 - ;; - mov cr.itir=r18 - mov cr.ifa=r16 - ;; - ld8 r18=[r2] // load per-CPU PTE - mov r16=IA64_TR_PERCPU_DATA; - ;; - itr.d dtr[r16]=r18 - ;; - srlz.d - ;; // 3. Reload ITR for PAL code. GET_THIS_PADDR(r2, ia64_mca_pal_pte) ;; diff --git a/trunk/arch/ia64/kernel/mca_drv.c b/trunk/arch/ia64/kernel/mca_drv.c index 832cf1e647e8..70b8bdbb7e6f 100644 --- a/trunk/arch/ia64/kernel/mca_drv.c +++ b/trunk/arch/ia64/kernel/mca_drv.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/ia64/kernel/patch.c b/trunk/arch/ia64/kernel/patch.c index bc11bb096f58..e796e29f8e15 100644 --- a/trunk/arch/ia64/kernel/patch.c +++ b/trunk/arch/ia64/kernel/patch.c @@ -195,3 +195,23 @@ ia64_patch_gate (void) ia64_patch_vtop(START(vtop), END(vtop)); ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9)); } + +void ia64_patch_phys_stack_reg(unsigned long val) +{ + s32 * offp = (s32 *) __start___phys_stack_reg_patchlist; + s32 * end = (s32 *) __end___phys_stack_reg_patchlist; + u64 ip, mask, imm; + + /* see instruction format A4: adds r1 = imm13, r3 */ + mask = (0x3fUL << 27) | (0x7f << 13); + imm = (((val >> 7) & 0x3f) << 27) | (val & 0x7f) << 13; + + while (offp < end) { + ip = (u64) offp + *offp; + ia64_patch(ip, mask, imm); + ia64_fc(ip); + ++offp; + } + ia64_sync_i(); + ia64_srlz_i(); +} diff --git a/trunk/arch/ia64/kernel/perfmon.c b/trunk/arch/ia64/kernel/perfmon.c index abc7ad035886..e7191ca30b16 100644 --- a/trunk/arch/ia64/kernel/perfmon.c +++ b/trunk/arch/ia64/kernel/perfmon.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/ia64/kernel/process.c b/trunk/arch/ia64/kernel/process.c index ae96d4176995..8bb571a8a738 100644 --- a/trunk/arch/ia64/kernel/process.c +++ b/trunk/arch/ia64/kernel/process.c @@ -20,20 +20,19 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include #include #include -#include #include #include #include diff --git a/trunk/arch/ia64/kernel/salinfo.c b/trunk/arch/ia64/kernel/salinfo.c index af9f8754d847..a51f1d0bfb70 100644 --- a/trunk/arch/ia64/kernel/salinfo.c +++ b/trunk/arch/ia64/kernel/salinfo.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/ia64/kernel/setup.c b/trunk/arch/ia64/kernel/setup.c index dc7dd7648ec5..6e19da122ae3 100644 --- a/trunk/arch/ia64/kernel/setup.c +++ b/trunk/arch/ia64/kernel/setup.c @@ -75,7 +75,6 @@ extern void ia64_setup_printk_clock(void); DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info); DEFINE_PER_CPU(unsigned long, local_per_cpu_offset); -DEFINE_PER_CPU(unsigned long, ia64_phys_stacked_size_p8); unsigned long ia64_cycles_per_usec; struct ia64_boot_param *ia64_boot_param; struct screen_info screen_info; @@ -869,6 +868,7 @@ void __cpuinit cpu_init (void) { extern void __cpuinit ia64_mmu_init (void *); + static unsigned long max_num_phys_stacked = IA64_NUM_PHYS_STACK_REG; unsigned long num_phys_stacked; pal_vm_info_2_u_t vmi; unsigned int max_ctx; @@ -982,7 +982,10 @@ cpu_init (void) num_phys_stacked = 96; } /* size of physical stacked register partition plus 8 bytes: */ - __get_cpu_var(ia64_phys_stacked_size_p8) = num_phys_stacked*8 + 8; + if (num_phys_stacked > max_num_phys_stacked) { + ia64_patch_phys_stack_reg(num_phys_stacked*8 + 8); + max_num_phys_stacked = num_phys_stacked; + } platform_cpu_init(); pm_idle = default_idle; } diff --git a/trunk/arch/ia64/kernel/signal.c b/trunk/arch/ia64/kernel/signal.c index 77f8b49c7882..0dcd56da6001 100644 --- a/trunk/arch/ia64/kernel/signal.c +++ b/trunk/arch/ia64/kernel/signal.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/ia64/kernel/smpboot.c b/trunk/arch/ia64/kernel/smpboot.c index ff7df439da6d..a44792d0f3a9 100644 --- a/trunk/arch/ia64/kernel/smpboot.c +++ b/trunk/arch/ia64/kernel/smpboot.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/ia64/kernel/sys_ia64.c b/trunk/arch/ia64/kernel/sys_ia64.c index 9ef62a3fbfad..1eda194b9559 100644 --- a/trunk/arch/ia64/kernel/sys_ia64.c +++ b/trunk/arch/ia64/kernel/sys_ia64.c @@ -13,7 +13,6 @@ #include #include /* doh, must come after sched.h... */ #include -#include #include #include #include @@ -33,6 +32,13 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len if (len > RGN_MAP_LIMIT) return -ENOMEM; + /* handle fixed mapping: prevent overlap with huge pages */ + if (flags & MAP_FIXED) { + if (is_hugepage_only_range(mm, addr, len)) + return -EINVAL; + return addr; + } + #ifdef CONFIG_HUGETLB_PAGE if (REGION_NUMBER(addr) == RGN_HPAGE) addr = 0; diff --git a/trunk/arch/ia64/kernel/time.c b/trunk/arch/ia64/kernel/time.c index 39e0cd3a0884..a06667c7acc0 100644 --- a/trunk/arch/ia64/kernel/time.c +++ b/trunk/arch/ia64/kernel/time.c @@ -235,7 +235,7 @@ ia64_init_itm (void) static struct irqaction timer_irqaction = { .handler = timer_interrupt, - .flags = IRQF_DISABLED, + .flags = IRQF_DISABLED | IRQF_IRQPOLL, .name = "timer" }; diff --git a/trunk/arch/ia64/kernel/traps.c b/trunk/arch/ia64/kernel/traps.c index 765cbe5ba6ae..5bfb8be02b70 100644 --- a/trunk/arch/ia64/kernel/traps.c +++ b/trunk/arch/ia64/kernel/traps.c @@ -16,33 +16,17 @@ #include #include #include /* for ssleep() */ +#include #include #include #include #include #include -#include fpswa_interface_t *fpswa_interface; EXPORT_SYMBOL(fpswa_interface); -ATOMIC_NOTIFIER_HEAD(ia64die_chain); - -int -register_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&ia64die_chain, nb); -} -EXPORT_SYMBOL_GPL(register_die_notifier); - -int -unregister_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&ia64die_chain, nb); -} -EXPORT_SYMBOL_GPL(unregister_die_notifier); - void __init trap_init (void) { diff --git a/trunk/arch/ia64/kernel/unaligned.c b/trunk/arch/ia64/kernel/unaligned.c index 1e357550c776..fe6aa5a9f8fa 100644 --- a/trunk/arch/ia64/kernel/unaligned.c +++ b/trunk/arch/ia64/kernel/unaligned.c @@ -15,7 +15,6 @@ */ #include #include -#include #include #include diff --git a/trunk/arch/ia64/kernel/vmlinux.lds.S b/trunk/arch/ia64/kernel/vmlinux.lds.S index 25dd55e4db24..692382642118 100644 --- a/trunk/arch/ia64/kernel/vmlinux.lds.S +++ b/trunk/arch/ia64/kernel/vmlinux.lds.S @@ -78,6 +78,13 @@ SECTIONS __stop___mca_table = .; } + .data.patch.phys_stack_reg : AT(ADDR(.data.patch.phys_stack_reg) - LOAD_OFFSET) + { + __start___phys_stack_reg_patchlist = .; + *(.data.patch.phys_stack_reg) + __end___phys_stack_reg_patchlist = .; + } + /* Global data */ _data = .; diff --git a/trunk/arch/ia64/mm/discontig.c b/trunk/arch/ia64/mm/discontig.c index 872da7a2accd..94844442812a 100644 --- a/trunk/arch/ia64/mm/discontig.c +++ b/trunk/arch/ia64/mm/discontig.c @@ -693,6 +693,7 @@ void __init paging_init(void) zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); } +#ifdef CONFIG_MEMORY_HOTPLUG pg_data_t *arch_alloc_nodedata(int nid) { unsigned long size = compute_pernodesize(nid); @@ -710,3 +711,4 @@ void arch_refresh_nodedata(int update_node, pg_data_t *update_pgdat) pgdat_list[update_node] = update_pgdat; scatter_node_data(); } +#endif diff --git a/trunk/arch/ia64/mm/fault.c b/trunk/arch/ia64/mm/fault.c index 59f3ab937615..21658e02116c 100644 --- a/trunk/arch/ia64/mm/fault.c +++ b/trunk/arch/ia64/mm/fault.c @@ -7,15 +7,14 @@ #include #include #include -#include #include #include +#include #include #include #include #include -#include extern void die (char *, struct pt_regs *, long); diff --git a/trunk/arch/ia64/mm/hugetlbpage.c b/trunk/arch/ia64/mm/hugetlbpage.c index 0c7e94edc20e..1346b7f05397 100644 --- a/trunk/arch/ia64/mm/hugetlbpage.c +++ b/trunk/arch/ia64/mm/hugetlbpage.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -148,6 +147,14 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, u return -ENOMEM; if (len & ~HPAGE_MASK) return -EINVAL; + + /* Handle MAP_FIXED */ + if (flags & MAP_FIXED) { + if (prepare_hugepage_range(addr, len, pgoff)) + return -EINVAL; + return addr; + } + /* This code assumes that RGN_HPAGE != 0. */ if ((REGION_NUMBER(addr) != RGN_HPAGE) || (addr & (HPAGE_SIZE - 1))) addr = HPAGE_REGION_BASE; diff --git a/trunk/arch/ia64/mm/init.c b/trunk/arch/ia64/mm/init.c index 4f36987eea72..cffb1e8325e8 100644 --- a/trunk/arch/ia64/mm/init.c +++ b/trunk/arch/ia64/mm/init.c @@ -121,7 +121,7 @@ lazy_mmu_prot_update (pte_t pte) return; /* i-cache is already coherent with d-cache */ if (PageCompound(page)) { - order = (unsigned long) (page[1].lru.prev); + order = compound_order(page); flush_icache_range(addr, addr + (1UL << order << PAGE_SHIFT)); } else @@ -355,7 +355,7 @@ setup_gate (void) void __devinit ia64_mmu_init (void *my_cpu_data) { - unsigned long psr, pta, impl_va_bits; + unsigned long pta, impl_va_bits; extern void __devinit tlb_init (void); #ifdef CONFIG_DISABLE_VHPT @@ -364,15 +364,6 @@ ia64_mmu_init (void *my_cpu_data) # define VHPT_ENABLE_BIT 1 #endif - /* Pin mapping for percpu area into TLB */ - psr = ia64_clear_ic(); - ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, - pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)), - PERCPU_PAGE_SHIFT); - - ia64_set_psr(psr); - ia64_srlz_i(); - /* * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped * address space. The IA-64 architecture guarantees that at least 50 bits of diff --git a/trunk/arch/ia64/mm/ioremap.c b/trunk/arch/ia64/mm/ioremap.c index 4280c074d64e..2a140627dfd6 100644 --- a/trunk/arch/ia64/mm/ioremap.c +++ b/trunk/arch/ia64/mm/ioremap.c @@ -1,5 +1,5 @@ /* - * (c) Copyright 2006 Hewlett-Packard Development Company, L.P. + * (c) Copyright 2006, 2007 Hewlett-Packard Development Company, L.P. * Bjorn Helgaas * * This program is free software; you can redistribute it and/or modify @@ -10,51 +10,101 @@ #include #include #include +#include +#include #include #include static inline void __iomem * -__ioremap (unsigned long offset, unsigned long size) +__ioremap (unsigned long phys_addr) { - return (void __iomem *) (__IA64_UNCACHED_OFFSET | offset); + return (void __iomem *) (__IA64_UNCACHED_OFFSET | phys_addr); } void __iomem * -ioremap (unsigned long offset, unsigned long size) +ioremap (unsigned long phys_addr, unsigned long size) { + void __iomem *addr; + struct vm_struct *area; + unsigned long offset; + pgprot_t prot; u64 attr; unsigned long gran_base, gran_size; + unsigned long page_base; /* * For things in kern_memmap, we must use the same attribute * as the rest of the kernel. For more details, see * Documentation/ia64/aliasing.txt. */ - attr = kern_mem_attribute(offset, size); + attr = kern_mem_attribute(phys_addr, size); if (attr & EFI_MEMORY_WB) - return (void __iomem *) phys_to_virt(offset); + return (void __iomem *) phys_to_virt(phys_addr); else if (attr & EFI_MEMORY_UC) - return __ioremap(offset, size); + return __ioremap(phys_addr); /* * Some chipsets don't support UC access to memory. If * WB is supported for the whole granule, we prefer that. */ - gran_base = GRANULEROUNDDOWN(offset); - gran_size = GRANULEROUNDUP(offset + size) - gran_base; + gran_base = GRANULEROUNDDOWN(phys_addr); + gran_size = GRANULEROUNDUP(phys_addr + size) - gran_base; if (efi_mem_attribute(gran_base, gran_size) & EFI_MEMORY_WB) - return (void __iomem *) phys_to_virt(offset); + return (void __iomem *) phys_to_virt(phys_addr); - return __ioremap(offset, size); + /* + * WB is not supported for the whole granule, so we can't use + * the region 7 identity mapping. If we can safely cover the + * area with kernel page table mappings, we can use those + * instead. + */ + page_base = phys_addr & PAGE_MASK; + size = PAGE_ALIGN(phys_addr + size) - page_base; + if (efi_mem_attribute(page_base, size) & EFI_MEMORY_WB) { + prot = PAGE_KERNEL; + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + + /* + * Ok, go for it.. + */ + area = get_vm_area(size, VM_IOREMAP); + if (!area) + return NULL; + + area->phys_addr = phys_addr; + addr = (void __iomem *) area->addr; + if (ioremap_page_range((unsigned long) addr, + (unsigned long) addr + size, phys_addr, prot)) { + vunmap((void __force *) addr); + return NULL; + } + + return (void __iomem *) (offset + (char __iomem *)addr); + } + + return __ioremap(phys_addr); } EXPORT_SYMBOL(ioremap); void __iomem * -ioremap_nocache (unsigned long offset, unsigned long size) +ioremap_nocache (unsigned long phys_addr, unsigned long size) { - if (kern_mem_attribute(offset, size) & EFI_MEMORY_WB) + if (kern_mem_attribute(phys_addr, size) & EFI_MEMORY_WB) return NULL; - return __ioremap(offset, size); + return __ioremap(phys_addr); } EXPORT_SYMBOL(ioremap_nocache); + +void +iounmap (volatile void __iomem *addr) +{ + if (REGION_NUMBER(addr) == RGN_GATE) + vunmap((void *) ((unsigned long) addr & PAGE_MASK)); +} +EXPORT_SYMBOL(iounmap); diff --git a/trunk/arch/ia64/pci/pci.c b/trunk/arch/ia64/pci/pci.c index 0e83f3b419b5..3549f3b42592 100644 --- a/trunk/arch/ia64/pci/pci.c +++ b/trunk/arch/ia64/pci/pci.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -659,8 +658,6 @@ pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma) return -EINVAL; prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size, vma->vm_page_prot); - if (pgprot_val(prot) != pgprot_val(pgprot_noncached(vma->vm_page_prot))) - return -EINVAL; addr = pci_get_legacy_mem(bus); if (IS_ERR(addr)) diff --git a/trunk/arch/ia64/sn/kernel/xpc_main.c b/trunk/arch/ia64/sn/kernel/xpc_main.c index 68355ef6f841..e336e1692a73 100644 --- a/trunk/arch/ia64/sn/kernel/xpc_main.c +++ b/trunk/arch/ia64/sn/kernel/xpc_main.c @@ -55,9 +55,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -1332,7 +1332,7 @@ xpc_init(void) dev_warn(xpc_part, "can't register reboot notifier\n"); } - /* add ourselves to the die_notifier list (i.e., ia64die_chain) */ + /* add ourselves to the die_notifier list */ ret = register_die_notifier(&xpc_die_notifier); if (ret != 0) { dev_warn(xpc_part, "can't register die notifier\n"); diff --git a/trunk/arch/m32r/kernel/m32r_ksyms.c b/trunk/arch/m32r/kernel/m32r_ksyms.c index 8cbbb0b11e0c..41a4c95e06d6 100644 --- a/trunk/arch/m32r/kernel/m32r_ksyms.c +++ b/trunk/arch/m32r/kernel/m32r_ksyms.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/m32r/kernel/signal.c b/trunk/arch/m32r/kernel/signal.c index 4b156054baa6..916faf6070af 100644 --- a/trunk/arch/m32r/kernel/signal.c +++ b/trunk/arch/m32r/kernel/signal.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/m32r/kernel/smpboot.c b/trunk/arch/m32r/kernel/smpboot.c index 48d376f47e1a..3eb305953497 100644 --- a/trunk/arch/m32r/kernel/smpboot.c +++ b/trunk/arch/m32r/kernel/smpboot.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/m32r/kernel/sys_m32r.c b/trunk/arch/m32r/kernel/sys_m32r.c index b4e7bcb43540..bda85548de6c 100644 --- a/trunk/arch/m32r/kernel/sys_m32r.c +++ b/trunk/arch/m32r/kernel/sys_m32r.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/m32r/mm/fault-nommu.c b/trunk/arch/m32r/mm/fault-nommu.c index 9880abac3f54..88469178ea6b 100644 --- a/trunk/arch/m32r/mm/fault-nommu.c +++ b/trunk/arch/m32r/mm/fault-nommu.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include /* For unblank_screen() */ diff --git a/trunk/arch/m32r/mm/fault.c b/trunk/arch/m32r/mm/fault.c index 037d58e82fb5..f3935ba24946 100644 --- a/trunk/arch/m32r/mm/fault.c +++ b/trunk/arch/m32r/mm/fault.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/m68k/amiga/amiints.c b/trunk/arch/m68k/amiga/amiints.c index 28d95cfe8ac0..907a5533c845 100644 --- a/trunk/arch/m68k/amiga/amiints.c +++ b/trunk/arch/m68k/amiga/amiints.c @@ -54,7 +54,7 @@ static irqreturn_t ami_int5(int irq, void *dev_id); static struct irq_controller amiga_irq_controller = { .name = "amiga", - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(amiga_irq_controller.lock), .enable = amiga_enable_irq, .disable = amiga_disable_irq, }; diff --git a/trunk/arch/m68k/amiga/cia.c b/trunk/arch/m68k/amiga/cia.c index 7a20058eb380..c4a4ffd45bc0 100644 --- a/trunk/arch/m68k/amiga/cia.c +++ b/trunk/arch/m68k/amiga/cia.c @@ -123,7 +123,7 @@ static void cia_disable_irq(unsigned int irq) static struct irq_controller cia_irq_controller = { .name = "cia", - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(cia_irq_controller.lock), .enable = cia_enable_irq, .disable = cia_disable_irq, }; @@ -160,7 +160,7 @@ static void auto_disable_irq(unsigned int irq) static struct irq_controller auto_irq_controller = { .name = "auto", - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(auto_irq_controller.lock), .enable = auto_enable_irq, .disable = auto_disable_irq, }; diff --git a/trunk/arch/m68k/apollo/dn_ints.c b/trunk/arch/m68k/apollo/dn_ints.c index 4274af125998..13bd41bed28e 100644 --- a/trunk/arch/m68k/apollo/dn_ints.c +++ b/trunk/arch/m68k/apollo/dn_ints.c @@ -31,7 +31,7 @@ void apollo_irq_shutdown(unsigned int irq) static struct irq_controller apollo_irq_controller = { .name = "apollo", - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(apollo_irq_controller.lock), .startup = apollo_irq_startup, .shutdown = apollo_irq_shutdown, }; diff --git a/trunk/arch/m68k/atari/ataints.c b/trunk/arch/m68k/atari/ataints.c index 7f812641790c..b85ca22024c1 100644 --- a/trunk/arch/m68k/atari/ataints.c +++ b/trunk/arch/m68k/atari/ataints.c @@ -339,7 +339,7 @@ static void atari_shutdown_irq(unsigned int irq) static struct irq_controller atari_irq_controller = { .name = "atari", - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(atari_irq_controller.lock), .startup = atari_startup_irq, .shutdown = atari_shutdown_irq, .enable = atari_enable_irq, diff --git a/trunk/arch/m68k/atari/atasound.h b/trunk/arch/m68k/atari/atasound.h deleted file mode 100644 index 1362762b8c0f..000000000000 --- a/trunk/arch/m68k/atari/atasound.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Minor numbers for the sound driver. - * - * Unfortunately Creative called the codec chip of SB as a DSP. For this - * reason the /dev/dsp is reserved for digitized audio use. There is a - * device for true DSP processors but it will be called something else. - * In v3.0 it's /dev/sndproc but this could be a temporary solution. - */ - -#define SND_NDEVS 256 /* Number of supported devices */ -#define SND_DEV_CTL 0 /* Control port /dev/mixer */ -#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM - synthesizer and MIDI output) */ -#define SND_DEV_MIDIN 2 /* Raw midi access */ -#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ -#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ -#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ -#define SND_DEV_STATUS 6 /* /dev/sndstat */ -/* #7 not in use now. Was in 2.4. Free for use after v3.0. */ -#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ -#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ -#define SND_DEV_PSS SND_DEV_SNDPROC - -#define DSP_DEFAULT_SPEED 8000 - -#define ON 1 -#define OFF 0 - -#define MAX_AUDIO_DEV 5 -#define MAX_MIXER_DEV 2 -#define MAX_SYNTH_DEV 3 -#define MAX_MIDI_DEV 6 -#define MAX_TIMER_DEV 3 diff --git a/trunk/arch/m68k/kernel/ints.c b/trunk/arch/m68k/kernel/ints.c index b66c97c904b3..60d4d75f5798 100644 --- a/trunk/arch/m68k/kernel/ints.c +++ b/trunk/arch/m68k/kernel/ints.c @@ -59,14 +59,14 @@ static int m68k_first_user_vec; static struct irq_controller auto_irq_controller = { .name = "auto", - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(auto_irq_controller.lock), .startup = m68k_irq_startup, .shutdown = m68k_irq_shutdown, }; static struct irq_controller user_irq_controller = { .name = "user", - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(user_irq_controller.lock), .startup = m68k_irq_startup, .shutdown = m68k_irq_shutdown, }; diff --git a/trunk/arch/m68k/kernel/ptrace.c b/trunk/arch/m68k/kernel/ptrace.c index 7fd2720c3841..cdba9fd6d82f 100644 --- a/trunk/arch/m68k/kernel/ptrace.c +++ b/trunk/arch/m68k/kernel/ptrace.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/m68k/mac/macints.c b/trunk/arch/m68k/mac/macints.c index f6fcd754d8f6..0fc72d8f786e 100644 --- a/trunk/arch/m68k/mac/macints.c +++ b/trunk/arch/m68k/mac/macints.c @@ -219,7 +219,7 @@ static void mac_disable_irq(unsigned int irq); static struct irq_controller mac_irq_controller = { .name = "mac", - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(mac_irq_controller.lock), .enable = mac_enable_irq, .disable = mac_disable_irq, }; diff --git a/trunk/arch/m68k/mvme16x/rtc.c b/trunk/arch/m68k/mvme16x/rtc.c index 272d47eac58d..e341387787ab 100644 --- a/trunk/arch/m68k/mvme16x/rtc.c +++ b/trunk/arch/m68k/mvme16x/rtc.c @@ -16,7 +16,6 @@ #include #include #include /* For struct rtc_time and ioctls, etc */ -#include #include #include diff --git a/trunk/arch/m68k/q40/q40ints.c b/trunk/arch/m68k/q40/q40ints.c index 31cc07d8cec4..2fb25ae46a8a 100644 --- a/trunk/arch/m68k/q40/q40ints.c +++ b/trunk/arch/m68k/q40/q40ints.c @@ -59,7 +59,7 @@ static void q40_irq_shutdown(unsigned int irq) static struct irq_controller q40_irq_controller = { .name = "q40", - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(q40_irq_controller.lock), .startup = q40_irq_startup, .shutdown = q40_irq_shutdown, .enable = q40_enable_irq, diff --git a/trunk/arch/m68k/sun3/sun3ints.c b/trunk/arch/m68k/sun3/sun3ints.c index 4232a2c2fae9..50df34bf80e3 100644 --- a/trunk/arch/m68k/sun3/sun3ints.c +++ b/trunk/arch/m68k/sun3/sun3ints.c @@ -90,7 +90,7 @@ static void sun3_inthandle(unsigned int irq, struct pt_regs *fp) static struct irq_controller sun3_irq_controller = { .name = "sun3", - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(sun3_irq_controller.lock), .startup = m68k_irq_startup, .shutdown = m68k_irq_shutdown, .enable = sun3_enable_irq, diff --git a/trunk/arch/m68knommu/kernel/ptrace.c b/trunk/arch/m68knommu/kernel/ptrace.c index 72d349623575..f54b6a3dfecb 100644 --- a/trunk/arch/m68knommu/kernel/ptrace.c +++ b/trunk/arch/m68knommu/kernel/ptrace.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/m68knommu/kernel/sys_m68k.c b/trunk/arch/m68knommu/kernel/sys_m68k.c index 3265b2d734db..48e6b33e8b44 100644 --- a/trunk/arch/m68knommu/kernel/sys_m68k.c +++ b/trunk/arch/m68knommu/kernel/sys_m68k.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/Kconfig b/trunk/arch/mips/Kconfig index 130d825e5438..b7cb048bc771 100644 --- a/trunk/arch/mips/Kconfig +++ b/trunk/arch/mips/Kconfig @@ -784,7 +784,6 @@ config TOSHIBA_RBTX4927 select HAS_TXX9_SERIAL select HW_HAS_PCI select I8259 - select ISA select SWAP_IO_SPACE select SYS_HAS_CPU_TX49XX select SYS_SUPPORTS_32BIT_KERNEL @@ -806,7 +805,6 @@ config TOSHIBA_RBTX4938 select HAS_TXX9_SERIAL select HW_HAS_PCI select I8259 - select ISA select SWAP_IO_SPACE select SYS_HAS_CPU_TX49XX select SYS_SUPPORTS_32BIT_KERNEL @@ -1042,6 +1040,9 @@ config SOC_AU1X00 select SYS_SUPPORTS_APM_EMULATION select SYS_SUPPORTS_KGDB +config SERIAL_RM9000 + bool + config PNX8550 bool select SOC_PNX8550 diff --git a/trunk/arch/mips/configs/rbhma4500_defconfig b/trunk/arch/mips/configs/rbhma4500_defconfig index 29e0df9f4be0..7d0f2174614e 100644 --- a/trunk/arch/mips/configs/rbhma4500_defconfig +++ b/trunk/arch/mips/configs/rbhma4500_defconfig @@ -245,7 +245,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_HW_HAS_PCI=y CONFIG_PCI=y -CONFIG_ISA=y CONFIG_MMU=y # @@ -573,7 +572,6 @@ CONFIG_MTD_CFI_UTIL=y # # Plug and Play support # -# CONFIG_PNP is not set # CONFIG_PNPACPI is not set # @@ -658,7 +656,6 @@ CONFIG_BLK_DEV_IT8213=m # CONFIG_BLK_DEV_VIA82CXXX is not set CONFIG_BLK_DEV_TC86C001=m # CONFIG_IDE_ARM is not set -# CONFIG_IDE_CHIPSETS is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set # CONFIG_IDEDMA_AUTO is not set @@ -676,11 +673,6 @@ CONFIG_RAID_ATTRS=m # # CONFIG_ATA is not set -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set - # # Multi-device support (RAID and LVM) # @@ -742,37 +734,20 @@ CONFIG_NET_ETHERNET=y # CONFIG_SUNGEM is not set # CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set -# CONFIG_NET_VENDOR_SMC is not set # CONFIG_DM9000 is not set -# CONFIG_NET_VENDOR_RACAL is not set # # Tulip family network device support # # CONFIG_NET_TULIP is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_HP100 is not set -CONFIG_NET_ISA=y -# CONFIG_E2100 is not set -# CONFIG_EWRK3 is not set -# CONFIG_EEXPRESS is not set -# CONFIG_EEXPRESS_PRO is not set -# CONFIG_HPLAN_PLUS is not set -# CONFIG_HPLAN is not set -# CONFIG_LP486E is not set -# CONFIG_ETH16I is not set CONFIG_NE2000=y -# CONFIG_SEEQ8005 is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_AMD8111_ETH is not set # CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set # CONFIG_B44 is not set # CONFIG_FORCEDETH is not set -# CONFIG_CS89x0 is not set # CONFIG_DGRS is not set # CONFIG_EEPRO100 is not set # CONFIG_E100 is not set @@ -833,8 +808,6 @@ CONFIG_NET_RADIO=y # Obsolete Wireless cards support (pre-802.11) # # CONFIG_STRIP is not set -# CONFIG_ARLAN is not set -# CONFIG_WAVELAN is not set # # Wireless 802.11b ISA/PCI cards support @@ -920,9 +893,6 @@ CONFIG_KEYBOARD_ATKBD=y CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y # CONFIG_MOUSE_SERIAL is not set -# CONFIG_MOUSE_INPORT is not set -# CONFIG_MOUSE_LOGIBM is not set -# CONFIG_MOUSE_PC110PAD is not set # CONFIG_MOUSE_VSXXXAA is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TOUCHSCREEN is not set @@ -1072,7 +1042,6 @@ CONFIG_FB_ATY_CT=y # CONFIG_VGA_CONSOLE=y # CONFIG_VGACON_SOFT_SCROLLBACK is not set -# CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y # CONFIG_FRAMEBUFFER_CONSOLE is not set diff --git a/trunk/arch/mips/kernel/early_printk.c b/trunk/arch/mips/kernel/early_printk.c index 304efdc5682f..4fa54b230c09 100644 --- a/trunk/arch/mips/kernel/early_printk.c +++ b/trunk/arch/mips/kernel/early_printk.c @@ -33,8 +33,3 @@ void __init setup_early_printk(void) { register_console(&early_console); } - -void __init disable_early_printk(void) -{ - unregister_console(&early_console); -} diff --git a/trunk/arch/mips/kernel/irixelf.c b/trunk/arch/mips/kernel/irixelf.c index 3cc25c05d367..403d96f99e77 100644 --- a/trunk/arch/mips/kernel/irixelf.c +++ b/trunk/arch/mips/kernel/irixelf.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/mips/kernel/irixioctl.c b/trunk/arch/mips/kernel/irixioctl.c index e2863821a3dd..30f9eb09db3f 100644 --- a/trunk/arch/mips/kernel/irixioctl.c +++ b/trunk/arch/mips/kernel/irixioctl.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/kernel/irixsig.c b/trunk/arch/mips/kernel/irixsig.c index 2132485caa74..6980deb6dced 100644 --- a/trunk/arch/mips/kernel/irixsig.c +++ b/trunk/arch/mips/kernel/irixsig.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/kernel/ptrace.c b/trunk/arch/mips/kernel/ptrace.c index 201ae194d1b8..b5a7b46bbc49 100644 --- a/trunk/arch/mips/kernel/ptrace.c +++ b/trunk/arch/mips/kernel/ptrace.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/kernel/signal.c b/trunk/arch/mips/kernel/signal.c index 07d67309451a..2a08ce41bf2b 100644 --- a/trunk/arch/mips/kernel/signal.c +++ b/trunk/arch/mips/kernel/signal.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/kernel/signal32.c b/trunk/arch/mips/kernel/signal32.c index b9a014411f83..003f8152b9ed 100644 --- a/trunk/arch/mips/kernel/signal32.c +++ b/trunk/arch/mips/kernel/signal32.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/kernel/signal_n32.c b/trunk/arch/mips/kernel/signal_n32.c index a9202fa95987..4cf9ff24d1f7 100644 --- a/trunk/arch/mips/kernel/signal_n32.c +++ b/trunk/arch/mips/kernel/signal_n32.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/kernel/stacktrace.c b/trunk/arch/mips/kernel/stacktrace.c index a586aba337a7..ebd9db8d1ece 100644 --- a/trunk/arch/mips/kernel/stacktrace.c +++ b/trunk/arch/mips/kernel/stacktrace.c @@ -31,8 +31,7 @@ static void save_raw_context_stack(struct stack_trace *trace, } } -static void save_context_stack(struct stack_trace *trace, - struct task_struct *task, struct pt_regs *regs) +static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs) { unsigned long sp = regs->regs[29]; #ifdef CONFIG_KALLSYMS @@ -41,7 +40,7 @@ static void save_context_stack(struct stack_trace *trace, if (raw_show_trace || !__kernel_text_address(pc)) { unsigned long stack_page = - (unsigned long)task_stack_page(task); + (unsigned long)task_stack_page(current); if (stack_page && sp >= stack_page && sp <= stack_page + THREAD_SIZE - 32) save_raw_context_stack(trace, sp); @@ -54,7 +53,7 @@ static void save_context_stack(struct stack_trace *trace, trace->entries[trace->nr_entries++] = pc; if (trace->nr_entries >= trace->max_entries) break; - pc = unwind_stack(task, &sp, pc, &ra); + pc = unwind_stack(current, &sp, pc, &ra); } while (pc); #else save_raw_context_stack(trace, sp); @@ -64,22 +63,13 @@ static void save_context_stack(struct stack_trace *trace, /* * Save stack-backtrace addresses into a stack_trace buffer. */ -void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +void save_stack_trace(struct stack_trace *trace) { struct pt_regs dummyregs; struct pt_regs *regs = &dummyregs; WARN_ON(trace->nr_entries || !trace->max_entries); - if (task && task != current) { - regs->regs[29] = task->thread.reg29; - regs->regs[31] = 0; - regs->cp0_epc = task->thread.reg31; - } else { - if (!task) - task = current; - prepare_frametrace(regs); - } - - save_context_stack(trace, task, regs); + prepare_frametrace(regs); + save_context_stack(trace, regs); } diff --git a/trunk/arch/mips/kernel/syscall.c b/trunk/arch/mips/kernel/syscall.c index 26e1a7e78d13..9dd5a2df8eac 100644 --- a/trunk/arch/mips/kernel/syscall.c +++ b/trunk/arch/mips/kernel/syscall.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/kernel/traps.c b/trunk/arch/mips/kernel/traps.c index 493cb29b8a42..ff45a4b8fbaa 100644 --- a/trunk/arch/mips/kernel/traps.c +++ b/trunk/arch/mips/kernel/traps.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/kernel/unaligned.c b/trunk/arch/mips/kernel/unaligned.c index 24b7b053cfe9..a7d49ae805b4 100644 --- a/trunk/arch/mips/kernel/unaligned.c +++ b/trunk/arch/mips/kernel/unaligned.c @@ -76,7 +76,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/mips/math-emu/dsemul.c b/trunk/arch/mips/math-emu/dsemul.c index 8079f3d1eca0..ea6ba7248489 100644 --- a/trunk/arch/mips/math-emu/dsemul.c +++ b/trunk/arch/mips/math-emu/dsemul.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/mips/mm/fault.c b/trunk/arch/mips/mm/fault.c index f9c595dceba9..7ebea331edb8 100644 --- a/trunk/arch/mips/mm/fault.c +++ b/trunk/arch/mips/mm/fault.c @@ -16,7 +16,6 @@ #include #include #include -#include #include /* For unblank_screen() */ #include diff --git a/trunk/arch/mips/pmc-sierra/msp71xx/msp_serial.c b/trunk/arch/mips/pmc-sierra/msp71xx/msp_serial.c new file mode 100644 index 000000000000..c41b53faa8f6 --- /dev/null +++ b/trunk/arch/mips/pmc-sierra/msp71xx/msp_serial.c @@ -0,0 +1,165 @@ +/* + * The setup file for serial related hardware on PMC-Sierra MSP processors. + * + * Copyright 2005 PMC-Sierra, 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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 +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_KGDB +/* + * kgdb uses serial port 1 so the console can remain on port 0. + * To use port 0 change the definition to read as follows: + * #define DEBUG_PORT_BASE KSEG1ADDR(MSP_UART0_BASE) + */ +#define DEBUG_PORT_BASE KSEG1ADDR(MSP_UART1_BASE) + +int putDebugChar(char c) +{ + volatile uint32_t *uart = (volatile uint32_t *)DEBUG_PORT_BASE; + uint32_t val = (uint32_t)c; + + local_irq_disable(); + while( !(uart[5] & 0x20) ); /* Wait for TXRDY */ + uart[0] = val; + while( !(uart[5] & 0x20) ); /* Wait for TXRDY */ + local_irq_enable(); + + return 1; +} + +char getDebugChar(void) +{ + volatile uint32_t *uart = (volatile uint32_t *)DEBUG_PORT_BASE; + uint32_t val; + + while( !(uart[5] & 0x01) ); /* Wait for RXRDY */ + val = uart[0]; + + return (char)val; +} + +void initDebugPort(unsigned int uartclk, unsigned int baudrate) +{ + unsigned int baud_divisor = (uartclk + 8 * baudrate)/(16 * baudrate); + + /* Enable FIFOs */ + writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_4, + (char *)DEBUG_PORT_BASE + (UART_FCR * 4)); + + /* Select brtc divisor */ + writeb(UART_LCR_DLAB, (char *)DEBUG_PORT_BASE + (UART_LCR * 4)); + + /* Store divisor lsb */ + writeb(baud_divisor, (char *)DEBUG_PORT_BASE + (UART_TX * 4)); + + /* Store divisor msb */ + writeb(baud_divisor >> 8, (char *)DEBUG_PORT_BASE + (UART_IER * 4)); + + /* Set 8N1 mode */ + writeb(UART_LCR_WLEN8, (char *)DEBUG_PORT_BASE + (UART_LCR * 4)); + + /* Disable flow control */ + writeb(0, (char *)DEBUG_PORT_BASE + (UART_MCR * 4)); + + /* Disable receive interrupt(!) */ + writeb(0, (char *)DEBUG_PORT_BASE + (UART_IER * 4)); +} +#endif + +void __init msp_serial_setup(void) +{ + char *s; + char *endp; + struct uart_port up; + unsigned int uartclk; + + memset(&up, 0, sizeof(up)); + + /* Check if clock was specified in environment */ + s = prom_getenv("uartfreqhz"); + if(!(s && *s && (uartclk = simple_strtoul(s, &endp, 10)) && *endp == 0)) + uartclk = MSP_BASE_BAUD; + ppfinit("UART clock set to %d\n", uartclk); + + /* Initialize first serial port */ + up.mapbase = MSP_UART0_BASE; + up.membase = ioremap_nocache(up.mapbase,MSP_UART_REG_LEN); + up.irq = MSP_INT_UART0; + up.uartclk = uartclk; + up.regshift = 2; + up.iotype = UPIO_DWAPB; /* UPIO_MEM like */ + up.flags = STD_COM_FLAGS; + up.type = PORT_16550A; + up.line = 0; + up.private_data = (void*)UART0_STATUS_REG; + if (early_serial_setup(&up)) + printk(KERN_ERR "Early serial init of port 0 failed\n"); + + /* Initialize the second serial port, if one exists */ + switch (mips_machtype) { + case MACH_MSP4200_EVAL: + case MACH_MSP4200_GW: + case MACH_MSP4200_FPGA: + case MACH_MSP7120_EVAL: + case MACH_MSP7120_GW: + case MACH_MSP7120_FPGA: + /* Enable UART1 on MSP4200 and MSP7120 */ + *GPIO_CFG2_REG = 0x00002299; + +#ifdef CONFIG_KGDB + /* Initialize UART1 for kgdb since PMON doesn't */ + if( DEBUG_PORT_BASE == KSEG1ADDR(MSP_UART1_BASE) ) { + if( mips_machtype == MACH_MSP4200_FPGA + || mips_machtype == MACH_MSP7120_FPGA ) + initDebugPort(uartclk,19200); + else + initDebugPort(uartclk,57600); + } +#endif + break; + + default: + return; /* No second serial port, good-bye. */ + } + + up.mapbase = MSP_UART1_BASE; + up.membase = ioremap_nocache(up.mapbase,MSP_UART_REG_LEN); + up.irq = MSP_INT_UART1; + up.line = 1; + up.private_data = (void*)UART1_STATUS_REG; + if (early_serial_setup(&up)) + printk(KERN_ERR "Early serial init of port 1 failed\n"); +} diff --git a/trunk/arch/mips/sgi-ip27/ip27-irq.c b/trunk/arch/mips/sgi-ip27/ip27-irq.c index 60ade7690e09..ba8e0794630c 100644 --- a/trunk/arch/mips/sgi-ip27/ip27-irq.c +++ b/trunk/arch/mips/sgi-ip27/ip27-irq.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/sni/irq.c b/trunk/arch/mips/sni/irq.c index ad5fc471a004..9ccffdfb8289 100644 --- a/trunk/arch/mips/sni/irq.c +++ b/trunk/arch/mips/sni/irq.c @@ -42,7 +42,7 @@ static irqreturn_t sni_isa_irq_handler(int dummy, void *p) struct irqaction sni_isa_irq = { .handler = sni_isa_irq_handler, .name = "ISA", - .flags = SA_SHIRQ + .flags = IRQF_SHARED }; /* diff --git a/trunk/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/trunk/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c index 0f7576dfd141..a0c11efeaeeb 100644 --- a/trunk/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +++ b/trunk/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c @@ -1049,3 +1049,22 @@ static int __init toshiba_rbtx4927_rtc_init(void) return IS_ERR(dev) ? PTR_ERR(dev) : 0; } device_initcall(toshiba_rbtx4927_rtc_init); + +static int __init rbtx4927_ne_init(void) +{ + static struct resource __initdata res[] = { + { + .start = RBTX4927_RTL_8019_BASE, + .end = RBTX4927_RTL_8019_BASE + 0x20 - 1, + .flags = IORESOURCE_IO, + }, { + .start = RBTX4927_RTL_8019_IRQ, + .flags = IORESOURCE_IRQ, + } + }; + struct platform_device *dev = + platform_device_register_simple("ne", -1, + res, ARRAY_SIZE(res)); + return IS_ERR(dev) ? PTR_ERR(dev) : 0; +} +device_initcall(rbtx4927_ne_init); diff --git a/trunk/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/trunk/arch/mips/tx4938/toshiba_rbtx4938/setup.c index 66163ba452c8..f5d1ce739fcc 100644 --- a/trunk/arch/mips/tx4938/toshiba_rbtx4938/setup.c +++ b/trunk/arch/mips/tx4938/toshiba_rbtx4938/setup.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -1037,3 +1038,22 @@ static int __init tx4938_spi_proc_setup(void) __initcall(tx4938_spi_proc_setup); #endif + +static int __init rbtx4938_ne_init(void) +{ + struct resource res[] = { + { + .start = RBTX4938_RTL_8019_BASE, + .end = RBTX4938_RTL_8019_BASE + 0x20 - 1, + .flags = IORESOURCE_IO, + }, { + .start = RBTX4938_RTL_8019_IRQ, + .flags = IORESOURCE_IRQ, + } + }; + struct platform_device *dev = + platform_device_register_simple("ne", -1, + res, ARRAY_SIZE(res)); + return IS_ERR(dev) ? PTR_ERR(dev) : 0; +} +device_initcall(rbtx4938_ne_init); diff --git a/trunk/arch/parisc/hpux/fs.c b/trunk/arch/parisc/hpux/fs.c index c7a81a2c014c..d86e15776779 100644 --- a/trunk/arch/parisc/hpux/fs.c +++ b/trunk/arch/parisc/hpux/fs.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/parisc/hpux/ioctl.c b/trunk/arch/parisc/hpux/ioctl.c index b34b4f3c60ec..dede4765852e 100644 --- a/trunk/arch/parisc/hpux/ioctl.c +++ b/trunk/arch/parisc/hpux/ioctl.c @@ -34,7 +34,6 @@ */ #include -#include #include #include #include diff --git a/trunk/arch/parisc/kernel/irq.c b/trunk/arch/parisc/kernel/irq.c index e9d09b020e86..c5c9125dacec 100644 --- a/trunk/arch/parisc/kernel/irq.c +++ b/trunk/arch/parisc/kernel/irq.c @@ -388,7 +388,7 @@ void do_cpu_irq_mask(struct pt_regs *regs) static struct irqaction timer_action = { .handler = timer_interrupt, .name = "timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL, }; #ifdef CONFIG_SMP diff --git a/trunk/arch/parisc/kernel/ptrace.c b/trunk/arch/parisc/kernel/ptrace.c index 0d0d617b6f21..8a0db376e91e 100644 --- a/trunk/arch/parisc/kernel/ptrace.c +++ b/trunk/arch/parisc/kernel/ptrace.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/parisc/kernel/signal.c b/trunk/arch/parisc/kernel/signal.c index 9784e405f849..fb35ebc0c4da 100644 --- a/trunk/arch/parisc/kernel/signal.c +++ b/trunk/arch/parisc/kernel/signal.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/parisc/kernel/signal32.c b/trunk/arch/parisc/kernel/signal32.c index 1c1a37f73053..db94affe5c71 100644 --- a/trunk/arch/parisc/kernel/signal32.c +++ b/trunk/arch/parisc/kernel/signal32.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/parisc/kernel/sys_parisc.c b/trunk/arch/parisc/kernel/sys_parisc.c index 512642d8f707..4f589216b39e 100644 --- a/trunk/arch/parisc/kernel/sys_parisc.c +++ b/trunk/arch/parisc/kernel/sys_parisc.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -106,6 +105,11 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, { if (len > TASK_SIZE) return -ENOMEM; + /* Might want to check for cache aliasing issues for MAP_FIXED case + * like ARM or MIPS ??? --BenH. + */ + if (flags & MAP_FIXED) + return addr; if (!addr) addr = TASK_UNMAPPED_BASE; diff --git a/trunk/arch/parisc/kernel/traps.c b/trunk/arch/parisc/kernel/traps.c index 55bc1471967d..745ff741490a 100644 --- a/trunk/arch/parisc/kernel/traps.c +++ b/trunk/arch/parisc/kernel/traps.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/parisc/kernel/unwind.c b/trunk/arch/parisc/kernel/unwind.c index 5f75b3e65986..89c03707eccc 100644 --- a/trunk/arch/parisc/kernel/unwind.c +++ b/trunk/arch/parisc/kernel/unwind.c @@ -216,11 +216,8 @@ static void unwind_frame_regs(struct unwind_frame_info *info) /* Handle some frequent special cases.... */ { char symname[KSYM_NAME_LEN+1]; - char *modname; - unsigned long symsize, offset; - kallsyms_lookup(info->ip, &symsize, &offset, - &modname, symname); + kallsyms_lookup(info->ip, NULL, NULL, NULL, symname); dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname); diff --git a/trunk/arch/powerpc/Kconfig b/trunk/arch/powerpc/Kconfig index a54a9a2e36f3..808d2ef80e2f 100644 --- a/trunk/arch/powerpc/Kconfig +++ b/trunk/arch/powerpc/Kconfig @@ -117,12 +117,33 @@ config GENERIC_BUG default y depends on BUG +config SYS_SUPPORTS_APM_EMULATION + bool + +# +# Powerpc uses the slab allocator to manage its ptes and the +# page structs of ptes are used for splitting the page table +# lock for configurations supporting more than SPLIT_PTLOCK_CPUS. +# +# In that special configuration the page structs of slabs are modified. +# This setting disables the selection of SLUB as a slab allocator. +# +config ARCH_USES_SLAB_PAGE_STRUCT + bool + default y + depends on SPLIT_PTLOCK_CPUS <= NR_CPUS + config DEFAULT_UIMAGE bool help Used to allow a board to specify it wants a uImage built by default default n +config PPC64_SWSUSP + bool + depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL)) + default y + menu "Processor support" choice prompt "Processor Type" @@ -193,6 +214,7 @@ config 40x config 44x bool "AMCC 44x" select PPC_DCR_NATIVE + select WANT_DEVICE_TREE config E200 bool "Freescale e200" @@ -257,9 +279,14 @@ config PPC_OF_PLATFORM_PCI depends on PPC64 # not supported on 32 bits yet default n +config 4xx + bool + depends on 40x || 44x + default y + config BOOKE bool - depends on E200 || E500 + depends on E200 || E500 || 44x default y config FSL_BOOKE @@ -656,11 +683,12 @@ config MCA config PCI bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \ || PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \ - || MPC7448HPC2 || PPC_PS3 + || MPC7448HPC2 || PPC_PS3 || PPC_HOLLY default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx \ && !PPC_85xx && !PPC_86xx default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS default PCI_QSPAN if !4xx && !CPM2 && 8xx + select ARCH_SUPPORTS_MSI help Find out whether your system includes a PCI bus. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside diff --git a/trunk/arch/powerpc/Kconfig.debug b/trunk/arch/powerpc/Kconfig.debug index 86aa3745af7f..f70e795c262e 100644 --- a/trunk/arch/powerpc/Kconfig.debug +++ b/trunk/arch/powerpc/Kconfig.debug @@ -139,10 +139,6 @@ config BOOTX_TEXT Say Y here to see progress messages from the boot firmware in text mode. Requires either BootX or Open Firmware. -config SERIAL_TEXT_DEBUG - bool "Support for early boot texts over serial port" - depends on 4xx - config PPC_EARLY_DEBUG bool "Early debugging (dangerous)" @@ -207,6 +203,24 @@ config PPC_EARLY_DEBUG_BEAT help Select this to enable early debugging for Celleb with Beat. +config PPC_EARLY_DEBUG_44x + bool "Early serial debugging for IBM/AMCC 44x CPUs" + depends on 44x + select PPC_UDBG_16550 + help + Select this to enable early debugging for IBM 44x chips via the + inbuilt serial port. + endchoice +config PPC_EARLY_DEBUG_44x_PHYSLOW + hex "Low 32 bits of early debug UART physical address" + depends PPC_EARLY_DEBUG_44x + default "0x40000200" + +config PPC_EARLY_DEBUG_44x_PHYSHIGH + hex "EPRN of early debug UART physical address" + depends PPC_EARLY_DEBUG_44x + default "0x1" + endmenu diff --git a/trunk/arch/powerpc/Makefile b/trunk/arch/powerpc/Makefile index 794992025d8d..81a531d84ff9 100644 --- a/trunk/arch/powerpc/Makefile +++ b/trunk/arch/powerpc/Makefile @@ -148,7 +148,7 @@ all: $(KBUILD_IMAGE) CPPFLAGS_vmlinux.lds := -Upowerpc -BOOT_TARGETS = zImage zImage.initrd uImage cuImage +BOOT_TARGETS = zImage zImage.initrd uImage PHONY += $(BOOT_TARGETS) diff --git a/trunk/arch/powerpc/boot/44x.c b/trunk/arch/powerpc/boot/44x.c new file mode 100644 index 000000000000..d51377d9024f --- /dev/null +++ b/trunk/arch/powerpc/boot/44x.c @@ -0,0 +1,40 @@ +/* + * Copyright 2007 David Gibson, IBM Corporation. + * + * Based on earlier code: + * Matt Porter + * Copyright 2002-2005 MontaVista Software Inc. + * + * Eugene Surovegin or + * Copyright (c) 2003, 2004 Zultys Technologies + * + * 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 +#include "types.h" +#include "string.h" +#include "stdio.h" +#include "ops.h" +#include "reg.h" +#include "dcr.h" + +/* Read the 44x memory controller to get size of system memory. */ +void ibm44x_fixup_memsize(void) +{ + int i; + unsigned long memsize, bank_config; + + memsize = 0; + for (i = 0; i < ARRAY_SIZE(sdram_bxcr); i++) { + mtdcr(DCRN_SDRAM0_CFGADDR, sdram_bxcr[i]); + bank_config = mfdcr(DCRN_SDRAM0_CFGDATA); + + if (bank_config & SDRAM_CONFIG_BANK_ENABLE) + memsize += SDRAM_CONFIG_BANK_SIZE(bank_config); + } + + dt_fixup_memory(0, memsize); +} diff --git a/trunk/arch/powerpc/boot/44x.h b/trunk/arch/powerpc/boot/44x.h new file mode 100644 index 000000000000..7b129ad043e1 --- /dev/null +++ b/trunk/arch/powerpc/boot/44x.h @@ -0,0 +1,16 @@ +/* + * PowerPC 44x related functions + * + * Copyright 2007 David Gibson, IBM Corporation. + * + * 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 _PPC_BOOT_44X_H_ +#define _PPC_BOOT_44X_H_ + +void ibm44x_fixup_memsize(void); +void ebony_init(void *mac0, void *mac1); + +#endif /* _PPC_BOOT_44X_H_ */ diff --git a/trunk/arch/powerpc/boot/Makefile b/trunk/arch/powerpc/boot/Makefile index 3716594ea33e..5c384aad1184 100644 --- a/trunk/arch/powerpc/boot/Makefile +++ b/trunk/arch/powerpc/boot/Makefile @@ -37,13 +37,15 @@ zlib := inffast.c inflate.c inftrees.c zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h zliblinuxheader := zlib.h zconf.h zutil.h -$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) \ - $(addprefix $(obj)/,$(zlibheader)) +$(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \ + $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader)) src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ ns16550.c serial.c simple_alloc.c div64.S util.S \ - gunzip_util.c elf_util.c $(zlib) devtree.c -src-plat := of.c cuboot-83xx.c cuboot-85xx.c + gunzip_util.c elf_util.c $(zlib) devtree.c \ + 44x.c ebony.c +src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \ + cuboot-ebony.c treeboot-ebony.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) @@ -129,7 +131,14 @@ image-$(CONFIG_PPC_CELLEB) += zImage.pseries image-$(CONFIG_PPC_CHRP) += zImage.chrp image-$(CONFIG_PPC_EFIKA) += zImage.chrp image-$(CONFIG_PPC_PMAC) += zImage.pmac -image-$(CONFIG_DEFAULT_UIMAGE) += uImage cuImage +image-$(CONFIG_PPC_HOLLY) += zImage.holly-elf +image-$(CONFIG_DEFAULT_UIMAGE) += uImage + +ifneq ($(CONFIG_DEVICE_TREE),"") +image-$(CONFIG_PPC_83xx) += cuImage.83xx +image-$(CONFIG_PPC_85xx) += cuImage.85xx +image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony +endif # For 32-bit powermacs, build the COFF and miboot images # as well as the ELF images. @@ -138,7 +147,8 @@ image-$(CONFIG_PPC_PMAC) += zImage.coff zImage.miboot endif initrd- := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-)) -initrd-y := $(patsubst zImage%, zImage.initrd%, $(image-y)) +initrd-y := $(patsubst zImage%, zImage.initrd%, \ + $(patsubst treeImage%, treeImage.initrd%, $(image-y))) initrd-y := $(filter-out $(image-y), $(initrd-y)) targets += $(image-y) $(initrd-y) @@ -159,18 +169,27 @@ $(obj)/zImage.ps3: vmlinux $(obj)/zImage.initrd.ps3: vmlinux @echo " WARNING zImage.initrd.ps3 not supported (yet)" +$(obj)/zImage.holly-elf: vmlinux $(wrapperbits) + $(call if_changed,wrap,holly,$(obj)/dts/holly.dts,,) + +$(obj)/zImage.initrd.holly-elf: vmlinux $(wrapperbits) $(obj)/ramdisk.image.gz + $(call if_changed,wrap,holly,$(obj)/dts/holly.dts,,$(obj)/ramdisk.image.gz) + $(obj)/uImage: vmlinux $(wrapperbits) $(call if_changed,wrap,uboot) -cuboot-plat-$(CONFIG_83xx) += 83xx -cuboot-plat-$(CONFIG_85xx) += 85xx -cuboot-plat-y += unknown-platform - +# CONFIG_DEVICE_TREE will have "" around it, make sure to strip them dts = $(if $(shell echo $(CONFIG_DEVICE_TREE) | grep '^/'),\ - ,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE) + ,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE:"%"=%) + +$(obj)/cuImage.%: vmlinux $(dts) $(wrapperbits) + $(call if_changed,wrap,cuboot-$*,$(dts)) + +$(obj)/treeImage.%: vmlinux $(dts) $(wrapperbits) + $(call if_changed,wrap,treeboot-$*,$(dts)) -$(obj)/cuImage: vmlinux $(wrapperbits) - $(call if_changed,wrap,cuboot-$(word 1,$(cuboot-plat-y)),$(dts)) +$(obj)/treeImage.initrd.%: vmlinux $(dts) $(wrapperbits) + $(call if_changed,wrap,treeboot-$*,$(dts),,$(obj)/ramdisk.image.gz) $(obj)/zImage: $(addprefix $(obj)/, $(image-y)) @rm -f $@; ln $< $@ @@ -181,8 +200,8 @@ install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y)) sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" $< # anything not in $(targets) -clean-files += $(image-) $(initrd-) zImage zImage.initrd \ - cuImage.elf cuImage.bin.gz +clean-files += $(image-) $(initrd-) zImage zImage.initrd cuImage.* \ + treeImage.* # clean up files cached by wrapper clean-kernel := vmlinux.strip vmlinux.bin diff --git a/trunk/arch/powerpc/boot/cuboot-ebony.c b/trunk/arch/powerpc/boot/cuboot-ebony.c new file mode 100644 index 000000000000..4464c5f67acb --- /dev/null +++ b/trunk/arch/powerpc/boot/cuboot-ebony.c @@ -0,0 +1,42 @@ +/* + * Old U-boot compatibility for Ebony + * + * Author: David Gibson + * + * Copyright 2007 David Gibson, IBM Corporatio. + * Based on cuboot-83xx.c, which is: + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include "ops.h" +#include "stdio.h" +#include "44x.h" + +#define TARGET_44x +#include "ppcboot.h" + +static bd_t bd; +extern char _end[]; + +BSS_STACK(4096); + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize; + unsigned long avail_ram = end_of_ram - (unsigned long)_end; + + memcpy(&bd, (bd_t *)r3, sizeof(bd)); + loader_info.initrd_addr = r4; + loader_info.initrd_size = r4 ? r5 : 0; + loader_info.cmdline = (char *)r6; + loader_info.cmdline_len = r7 - r6; + + simple_alloc_init(_end, avail_ram, 32, 64); + + ebony_init(&bd.bi_enetaddr, &bd.bi_enet1addr); +} diff --git a/trunk/arch/powerpc/boot/dcr.h b/trunk/arch/powerpc/boot/dcr.h new file mode 100644 index 000000000000..877bc97b1e97 --- /dev/null +++ b/trunk/arch/powerpc/boot/dcr.h @@ -0,0 +1,87 @@ +#ifndef _PPC_BOOT_DCR_H_ +#define _PPC_BOOT_DCR_H_ + +#define mfdcr(rn) \ + ({ \ + unsigned long rval; \ + asm volatile("mfdcr %0,%1" : "=r"(rval) : "i"(rn)); \ + rval; \ + }) +#define mtdcr(rn, val) \ + asm volatile("mtdcr %0,%1" : : "i"(rn), "r"(val)) + +/* 440GP/440GX SDRAM controller DCRs */ +#define DCRN_SDRAM0_CFGADDR 0x010 +#define DCRN_SDRAM0_CFGDATA 0x011 + +#define SDRAM0_B0CR 0x40 +#define SDRAM0_B1CR 0x44 +#define SDRAM0_B2CR 0x48 +#define SDRAM0_B3CR 0x4c + +static const unsigned long sdram_bxcr[] = { SDRAM0_B0CR, SDRAM0_B1CR, SDRAM0_B2CR, SDRAM0_B3CR }; + +#define SDRAM_CONFIG_BANK_ENABLE 0x00000001 +#define SDRAM_CONFIG_SIZE_MASK 0x000e0000 +#define SDRAM_CONFIG_BANK_SIZE(reg) \ + (0x00400000 << ((reg & SDRAM_CONFIG_SIZE_MASK) >> 17)) + +/* 440GP Clock, PM, chip control */ +#define DCRN_CPC0_SR 0x0b0 +#define DCRN_CPC0_ER 0x0b1 +#define DCRN_CPC0_FR 0x0b2 +#define DCRN_CPC0_SYS0 0x0e0 +#define CPC0_SYS0_TUNE 0xffc00000 +#define CPC0_SYS0_FBDV_MASK 0x003c0000 +#define CPC0_SYS0_FWDVA_MASK 0x00038000 +#define CPC0_SYS0_FWDVB_MASK 0x00007000 +#define CPC0_SYS0_OPDV_MASK 0x00000c00 +#define CPC0_SYS0_EPDV_MASK 0x00000300 +/* Helper macros to compute the actual clock divider values from the + * encodings in the CPC0 register */ +#define CPC0_SYS0_FBDV(reg) \ + ((((((reg) & CPC0_SYS0_FBDV_MASK) >> 18) - 1) & 0xf) + 1) +#define CPC0_SYS0_FWDVA(reg) \ + (8 - (((reg) & CPC0_SYS0_FWDVA_MASK) >> 15)) +#define CPC0_SYS0_FWDVB(reg) \ + (8 - (((reg) & CPC0_SYS0_FWDVB_MASK) >> 12)) +#define CPC0_SYS0_OPDV(reg) \ + ((((reg) & CPC0_SYS0_OPDV_MASK) >> 10) + 1) +#define CPC0_SYS0_EPDV(reg) \ + ((((reg) & CPC0_SYS0_EPDV_MASK) >> 8) + 1) +#define CPC0_SYS0_EXTSL 0x00000080 +#define CPC0_SYS0_RW_MASK 0x00000060 +#define CPC0_SYS0_RL 0x00000010 +#define CPC0_SYS0_ZMIISL_MASK 0x0000000c +#define CPC0_SYS0_BYPASS 0x00000002 +#define CPC0_SYS0_NTO1 0x00000001 +#define DCRN_CPC0_SYS1 0x0e1 +#define DCRN_CPC0_CUST0 0x0e2 +#define DCRN_CPC0_CUST1 0x0e3 +#define DCRN_CPC0_STRP0 0x0e4 +#define DCRN_CPC0_STRP1 0x0e5 +#define DCRN_CPC0_STRP2 0x0e6 +#define DCRN_CPC0_STRP3 0x0e7 +#define DCRN_CPC0_GPIO 0x0e8 +#define DCRN_CPC0_PLB 0x0e9 +#define DCRN_CPC0_CR1 0x0ea +#define DCRN_CPC0_CR0 0x0eb +#define CPC0_CR0_SWE 0x80000000 +#define CPC0_CR0_CETE 0x40000000 +#define CPC0_CR0_U1FCS 0x20000000 +#define CPC0_CR0_U0DTE 0x10000000 +#define CPC0_CR0_U0DRE 0x08000000 +#define CPC0_CR0_U0DC 0x04000000 +#define CPC0_CR0_U1DTE 0x02000000 +#define CPC0_CR0_U1DRE 0x01000000 +#define CPC0_CR0_U1DC 0x00800000 +#define CPC0_CR0_U0EC 0x00400000 +#define CPC0_CR0_U1EC 0x00200000 +#define CPC0_CR0_UDIV_MASK 0x001f0000 +#define CPC0_CR0_UDIV(reg) \ + ((((reg) & CPC0_CR0_UDIV_MASK) >> 16) + 1) +#define DCRN_CPC0_MIRQ0 0x0ec +#define DCRN_CPC0_MIRQ1 0x0ed +#define DCRN_CPC0_JTAGID 0x0ef + +#endif /* _PPC_BOOT_DCR_H_ */ diff --git a/trunk/arch/powerpc/boot/dts/ebony.dts b/trunk/arch/powerpc/boot/dts/ebony.dts new file mode 100644 index 000000000000..b67918651c48 --- /dev/null +++ b/trunk/arch/powerpc/boot/dts/ebony.dts @@ -0,0 +1,307 @@ +/* + * Device Tree Source for IBM Ebony + * + * Copyright (c) 2006, 2007 IBM Corp. + * Josh Boyer , David Gibson + * + * FIXME: Draft only! + * + * 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. + * + * To build: + * dtc -I dts -O asm -o ebony.S -b 0 ebony.dts + * dtc -I dts -O dtb -o ebony.dtb -b 0 ebony.dts + */ + +/ { + #address-cells = <2>; + #size-cells = <1>; + model = "ibm,ebony"; + compatible = "ibm,ebony"; + dcr-parent = <&/cpus/PowerPC,440GP@0>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,440GP@0 { + device_type = "cpu"; + reg = <0>; + clock-frequency = <0>; // Filled in by zImage + timebase-frequency = <0>; // Filled in by zImage + i-cache-line-size = <32>; + d-cache-line-size = <32>; + i-cache-size = <0>; + d-cache-size = <0>; + dcr-controller; + dcr-access-method = "native"; + }; + }; + + memory { + device_type = "memory"; + reg = <0 0 0>; // Filled in by zImage + }; + + UIC0: interrupt-controller0 { + device_type = "ibm,uic"; + compatible = "ibm,uic-440gp", "ibm,uic"; + interrupt-controller; + cell-index = <0>; + dcr-reg = <0c0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + + }; + + UIC1: interrupt-controller1 { + device_type = "ibm,uic"; + compatible = "ibm,uic-440gp", "ibm,uic"; + interrupt-controller; + cell-index = <1>; + dcr-reg = <0d0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + interrupts = <1e 4 1f 4>; /* cascade */ + interrupt-parent = <&UIC0>; + }; + + CPC0: cpc { + device_type = "ibm,cpc"; + compatible = "ibm,cpc-440gp"; + dcr-reg = <0b0 003 0e0 010>; + // FIXME: anything else? + }; + + plb { + device_type = "ibm,plb"; + compatible = "ibm,plb-440gp", "ibm,plb4"; + #address-cells = <2>; + #size-cells = <1>; + ranges; + clock-frequency = <0>; // Filled in by zImage + + SDRAM0: sdram { + device_type = "memory-controller"; + compatible = "ibm,sdram-440gp", "ibm,sdram"; + dcr-reg = <010 2>; + // FIXME: anything else? + }; + + DMA0: dma { + // FIXME: ??? + device_type = "ibm,dma-4xx"; + compatible = "ibm,dma-440gp", "ibm,dma-4xx"; + dcr-reg = <100 027>; + }; + + MAL0: mcmal { + device_type = "mcmal-dma"; + compatible = "ibm,mcmal-440gp", "ibm,mcmal"; + dcr-reg = <180 62>; + num-tx-chans = <4>; + num-rx-chans = <4>; + interrupt-parent = <&MAL0>; + interrupts = <0 1 2 3 4>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = ; + interrupt-map-mask = ; + }; + + POB0: opb { + device_type = "ibm,opb"; + compatible = "ibm,opb-440gp", "ibm,opb"; + #address-cells = <1>; + #size-cells = <1>; + /* Wish there was a nicer way of specifying a full 32-bit + range */ + ranges = <00000000 1 00000000 80000000 + 80000000 1 80000000 80000000>; + dcr-reg = <090 00b>; + interrupt-parent = <&UIC1>; + interrupts = <7 4>; + clock-frequency = <0>; // Filled in by zImage + + EBC0: ebc { + device_type = "ibm,ebc"; + compatible = "ibm,ebc-440gp"; + dcr-reg = <012 2>; + #address-cells = <2>; + #size-cells = <1>; + clock-frequency = <0>; // Filled in by zImage + ranges = <0 00000000 fff00000 100000 + 1 00000000 48000000 100000 + 2 00000000 ff800000 400000 + 3 00000000 48200000 100000 + 7 00000000 48300000 100000>; + interrupts = <5 4>; + interrupt-parent = <&UIC1>; + + small-flash@0,0 { + device_type = "rom"; + compatible = "direct-mapped"; + probe-type = "JEDEC"; + bank-width = <1>; + partitions = <0 80000>; + partition-names = "OpenBIOS"; + reg = <0 80000 80000>; + }; + + ds1743@1,0 { + /* NVRAM & RTC */ + device_type = "nvram"; + compatible = "ds1743"; + reg = <1 0 2000>; + }; + + large-flash@2,0 { + device_type = "rom"; + compatible = "direct-mapped"; + probe-type = "JEDEC"; + bank-width = <1>; + partitions = <0 380000 + 280000 80000>; + partition-names = "fs", "firmware"; + reg = <2 0 400000>; + }; + + ir@3,0 { + reg = <3 0 10>; + }; + + fpga@7,0 { + compatible = "Ebony-FPGA"; + reg = <7 0 10>; + }; + }; + + UART0: serial@40000200 { + device_type = "serial"; + compatible = "ns16550"; + reg = <40000200 8>; + virtual-reg = ; + clock-frequency = ; + current-speed = <2580>; + interrupt-parent = <&UIC0>; + interrupts = <0 4>; + }; + + UART1: serial@40000300 { + device_type = "serial"; + compatible = "ns16550"; + reg = <40000300 8>; + virtual-reg = ; + clock-frequency = ; + current-speed = <2580>; + interrupt-parent = <&UIC0>; + interrupts = <1 4>; + }; + + IIC0: i2c@40000400 { + /* FIXME */ + device_type = "i2c"; + compatible = "ibm,iic-440gp", "ibm,iic"; + reg = <40000400 14>; + interrupt-parent = <&UIC0>; + interrupts = <2 4>; + }; + IIC1: i2c@40000500 { + /* FIXME */ + device_type = "i2c"; + compatible = "ibm,iic-440gp", "ibm,iic"; + reg = <40000500 14>; + interrupt-parent = <&UIC0>; + interrupts = <3 4>; + }; + + GPIO0: gpio@40000700 { + /* FIXME */ + device_type = "gpio"; + compatible = "ibm,gpio-440gp"; + reg = <40000700 20>; + }; + + ZMII0: emac-zmii@40000780 { + device_type = "emac-zmii"; + compatible = "ibm,zmii-440gp", "ibm,zmii"; + reg = <40000780 c>; + }; + + EMAC0: ethernet@40000800 { + linux,network-index = <0>; + device_type = "network"; + compatible = "ibm,emac-440gp", "ibm,emac"; + interrupt-parent = <&UIC1>; + interrupts = <1c 4 1d 4>; + reg = <40000800 70>; + local-mac-address = [000000000000]; // Filled in by zImage + mal-device = <&MAL0>; + mal-tx-channel = <0 1>; + mal-rx-channel = <0>; + cell-index = <0>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rmii"; + phy-map = <00000001>; + zmii-device = <&ZMII0>; + zmii-channel = <0>; + }; + EMAC1: ethernet@40000900 { + linux,network-index = <1>; + device_type = "network"; + compatible = "ibm,emac-440gp", "ibm,emac"; + interrupt-parent = <&UIC1>; + interrupts = <1e 4 1f 4>; + reg = <40000900 70>; + local-mac-address = [000000000000]; // Filled in by zImage + mal-device = <&MAL0>; + mal-tx-channel = <2 3>; + mal-rx-channel = <1>; + cell-index = <1>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rmii"; + phy-map = <00000001>; + zmii-device = <&ZMII0>; + zmii-channel = <1>; + }; + + + GPT0: gpt@40000a00 { + /* FIXME */ + reg = <40000a00 d4>; + interrupt-parent = <&UIC0>; + interrupts = <12 4 13 4 14 4 15 4 16 4>; + }; + + }; + + PCIX0: pci@1234 { + device_type = "pci"; + /* FIXME */ + reg = <2 0ec00000 8 + 2 0ec80000 f0 + 2 0ec80100 fc>; + }; + }; + + chosen { + linux,stdout-path = "/plb/opb/serial@40000200"; +// linux,initrd-start = <0>; /* FIXME */ +// linux,initrd-end = <0>; +// bootargs = ""; + }; +}; + diff --git a/trunk/arch/powerpc/boot/dts/holly.dts b/trunk/arch/powerpc/boot/dts/holly.dts new file mode 100644 index 000000000000..254499b107f4 --- /dev/null +++ b/trunk/arch/powerpc/boot/dts/holly.dts @@ -0,0 +1,198 @@ +/* + * Device Tree Source for IBM Holly (PPC 750CL with TSI controller) + * Copyright 2007, IBM Corporation + * + * Stephen Winiecki + * Josh Boyer + * + * 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. + * + * To build: + * dtc -I dts -O asm -o holly.S -b 0 holly.dts + * dtc -I dts -O dtb -o holly.dtb -b 0 holly.dts + */ + +/ { + model = "41K7339"; + compatible = "ibm,holly"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells =<0>; + PowerPC,750CL@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <20>; + i-cache-line-size = <20>; + d-cache-size = <8000>; + i-cache-size = <8000>; + d-cache-sets = <80>; + i-cache-sets = <80>; + timebase-frequency = <2faf080>; + clock-frequency = <23c34600>; + bus-frequency = ; + 32-bit; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <00000000 20000000>; + }; + + tsi109@c0000000 { + device_type = "tsi-bridge"; + compatible = "tsi-bridge"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <00000000 c0000000 00010000>; + reg = ; + + i2c@7000 { + device_type = "i2c"; + compatible = "tsi-i2c"; + interrupt-parent = < &/tsi109@c0000000/pic@7400 >; + interrupts = ; + reg = <7000 400>; + }; + + mdio@6000 { + device_type = "mdio"; + compatible = "tsi-ethernet"; + + PHY1: ethernet-phy@6000 { + device_type = "ethernet-phy"; + compatible = "bcm54xx"; + reg = <6000 50>; + phy-id = <1>; + }; + + PHY2: ethernet-phy@6400 { + device_type = "ethernet-phy"; + compatible = "bcm54xx"; + reg = <6000 50>; + phy-id = <2>; + }; + }; + + ethernet@6200 { + device_type = "network"; + compatible = "tsi-ethernet"; + #address-cells = <1>; + #size-cells = <0>; + reg = <6000 200>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = < &/tsi109@c0000000/pic@7400 >; + interrupts = <10 2>; + phy-handle = <&PHY1>; + }; + + ethernet@6600 { + device_type = "network"; + compatible = "tsi-ethernet"; + #address-cells = <1>; + #size-cells = <0>; + reg = <6400 200>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = < &/tsi109@c0000000/pic@7400 >; + interrupts = <11 2>; + phy-handle = <&PHY2>; + }; + + serial@7808 { + device_type = "serial"; + compatible = "ns16550"; + reg = <7808 200>; + virtual-reg = ; + clock-frequency = <3F9C6000>; + current-speed = <1c200>; + interrupt-parent = < &/tsi109@c0000000/pic@7400 >; + interrupts = ; + }; + + serial@7c08 { + device_type = "serial"; + compatible = "ns16550"; + reg = <7c08 200>; + virtual-reg = ; + clock-frequency = <3F9C6000>; + current-speed = <1c200>; + interrupt-parent = < &/tsi109@c0000000/pic@7400 >; + interrupts = ; + }; + + MPIC: pic@7400 { + device_type = "open-pic"; + compatible = "chrp,open-pic"; + interrupt-controller; + #interrupt-cells = <2>; + reg = <7400 400>; + big-endian; + }; + + pci@1000 { + device_type = "pci"; + compatible = "tsi109"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <1000 1000>; + bus-range = <0 0>; + /*----------------------------------------------------+ + | PCI memory range. + | 01 denotes I/O space + | 02 denotes 32-bit memory space + +----------------------------------------------------*/ + ranges = <02000000 0 40000000 40000000 0 10000000 + 01000000 0 00000000 7e000000 0 00010000>; + clock-frequency = <7f28154>; + interrupt-parent = < &/tsi109@c0000000/pic@7400 >; + interrupts = <17 2>; + interrupt-map-mask = ; + /*----------------------------------------------------+ + | The INTA, INTB, INTC, INTD are shared. + +----------------------------------------------------*/ + interrupt-map = < + 0800 0 0 1 &RT0 24 0 + 0800 0 0 2 &RT0 25 0 + 0800 0 0 3 &RT0 26 0 + 0800 0 0 4 &RT0 27 0 + + 1000 0 0 1 &RT0 25 0 + 1000 0 0 2 &RT0 26 0 + 1000 0 0 3 &RT0 27 0 + 1000 0 0 4 &RT0 24 0 + + 1800 0 0 1 &RT0 26 0 + 1800 0 0 2 &RT0 27 0 + 1800 0 0 3 &RT0 24 0 + 1800 0 0 4 &RT0 25 0 + + 2000 0 0 1 &RT0 27 0 + 2000 0 0 2 &RT0 24 0 + 2000 0 0 3 &RT0 25 0 + 2000 0 0 4 &RT0 26 0 + >; + + RT0: router@1180 { + device_type = "pic-router"; + interrupt-controller; + big-endian; + clock-frequency = <0>; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupts = <17 2>; + interrupt-parent = < &/tsi109@c0000000/pic@7400 >; + }; + }; + }; + + chosen { + linux,stdout-path = "/tsi109@c0000000/serial@7808"; + bootargs = "console=ttyS0,115200"; + }; +}; diff --git a/trunk/arch/powerpc/boot/dts/lite5200.dts b/trunk/arch/powerpc/boot/dts/lite5200.dts index ba54c6b40a09..e13ac6ef05a9 100644 --- a/trunk/arch/powerpc/boot/dts/lite5200.dts +++ b/trunk/arch/powerpc/boot/dts/lite5200.dts @@ -48,6 +48,7 @@ soc5200@f0000000 { model = "fsl,mpc5200"; + compatible = "mpc5200"; revision = "" // from bootloader #interrupt-cells = <3>; device_type = "soc"; @@ -166,7 +167,7 @@ device_type = "mscan"; compatible = "mpc5200-mscan"; cell-index = <1>; - interrupts = <1 12 0>; + interrupts = <2 12 0>; interrupt-parent = <500>; reg = <980 80>; }; @@ -178,7 +179,7 @@ interrupt-parent = <500>; }; - gpio-wkup@b00 { + gpio-wkup@c00 { compatible = "mpc5200-gpio-wkup"; reg = ; interrupts = <1 8 0 0 3 0>; @@ -317,20 +318,22 @@ i2c@3d00 { device_type = "i2c"; - compatible = "mpc5200-i2c"; + compatible = "mpc5200-i2c\0fsl-i2c"; cell-index = <0>; reg = <3d00 40>; interrupts = <2 f 0>; interrupt-parent = <500>; + fsl5200-clocking; }; i2c@3d40 { device_type = "i2c"; - compatible = "mpc5200-i2c"; + compatible = "mpc5200-i2c\0fsl-i2c"; cell-index = <1>; reg = <3d40 40>; interrupts = <2 10 0>; interrupt-parent = <500>; + fsl5200-clocking; }; sram@8000 { device_type = "sram"; diff --git a/trunk/arch/powerpc/boot/dts/lite5200b.dts b/trunk/arch/powerpc/boot/dts/lite5200b.dts index 2e003081b0d3..00211b39a342 100644 --- a/trunk/arch/powerpc/boot/dts/lite5200b.dts +++ b/trunk/arch/powerpc/boot/dts/lite5200b.dts @@ -48,6 +48,7 @@ soc5200@f0000000 { model = "fsl,mpc5200b"; + compatible = "mpc5200"; revision = ""; // from bootloader #interrupt-cells = <3>; device_type = "soc"; @@ -166,7 +167,7 @@ device_type = "mscan"; compatible = "mpc5200b-mscan\0mpc5200-mscan"; cell-index = <1>; - interrupts = <1 12 0>; + interrupts = <2 12 0>; interrupt-parent = <500>; reg = <980 80>; }; @@ -178,7 +179,7 @@ interrupt-parent = <500>; }; - gpio-wkup@b00 { + gpio-wkup@c00 { compatible = "mpc5200b-gpio-wkup\0mpc5200-gpio-wkup"; reg = ; interrupts = <1 8 0 0 3 0>; @@ -322,20 +323,22 @@ i2c@3d00 { device_type = "i2c"; - compatible = "mpc5200b-i2c\0mpc5200-i2c"; + compatible = "mpc5200b-i2c\0mpc5200-i2c\0fsl-i2c"; cell-index = <0>; reg = <3d00 40>; interrupts = <2 f 0>; interrupt-parent = <500>; + fsl5200-clocking; }; i2c@3d40 { device_type = "i2c"; - compatible = "mpc5200b-i2c\0mpc5200-i2c"; + compatible = "mpc5200b-i2c\0mpc5200-i2c\0fsl-i2c"; cell-index = <1>; reg = <3d40 40>; interrupts = <2 10 0>; interrupt-parent = <500>; + fsl5200-clocking; }; sram@8000 { device_type = "sram"; diff --git a/trunk/arch/powerpc/boot/dts/mpc832x_mds.dts b/trunk/arch/powerpc/boot/dts/mpc832x_mds.dts index c798491f4cd0..93b760696010 100644 --- a/trunk/arch/powerpc/boot/dts/mpc832x_mds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc832x_mds.dts @@ -306,14 +306,12 @@ interrupts = <11 8>; reg = <3>; device_type = "ethernet-phy"; - interface = <3>; //ENET_100_MII }; phy4: ethernet-phy@04 { interrupt-parent = < &ipic >; interrupts = <12 8>; reg = <4>; device_type = "ethernet-phy"; - interface = <3>; }; }; diff --git a/trunk/arch/powerpc/boot/dts/mpc832x_rdb.dts b/trunk/arch/powerpc/boot/dts/mpc832x_rdb.dts index b55bced1593d..be4c35784e49 100644 --- a/trunk/arch/powerpc/boot/dts/mpc832x_rdb.dts +++ b/trunk/arch/powerpc/boot/dts/mpc832x_rdb.dts @@ -265,14 +265,12 @@ interrupts = <0>; reg = <0>; device_type = "ethernet-phy"; - interface = <3>; //ENET_100_MII }; phy04:ethernet-phy@04 { interrupt-parent = <&pic>; interrupts = <0>; reg = <4>; device_type = "ethernet-phy"; - interface = <3>; }; }; diff --git a/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts b/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts index 7f578eb57082..38c8594df3a4 100644 --- a/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts @@ -305,6 +305,7 @@ rx-clock = <0>; tx-clock = <19>; phy-handle = < &phy0 >; + phy-connection-type = "rgmii-id"; pio-handle = < &pio1 >; }; @@ -320,6 +321,7 @@ rx-clock = <0>; tx-clock = <14>; phy-handle = < &phy1 >; + phy-connection-type = "rgmii-id"; pio-handle = < &pio2 >; }; @@ -335,14 +337,12 @@ interrupts = <11 8>; reg = <0>; device_type = "ethernet-phy"; - interface = <6>; //ENET_1000_GMII }; phy1: ethernet-phy@01 { interrupt-parent = < &ipic >; interrupts = <12 8>; reg = <1>; device_type = "ethernet-phy"; - interface = <6>; }; }; diff --git a/trunk/arch/powerpc/boot/dts/mpc8568mds.dts b/trunk/arch/powerpc/boot/dts/mpc8568mds.dts index 7361b36749cb..948a3b61bd4a 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8568mds.dts @@ -288,6 +288,7 @@ rx-clock = <0>; tx-clock = <19>; phy-handle = <&qe_phy0>; + phy-connection-type = "gmii"; pio-handle = <&pio1>; }; @@ -303,6 +304,7 @@ rx-clock = <0>; tx-clock = <14>; phy-handle = <&qe_phy1>; + phy-connection-type = "gmii"; pio-handle = <&pio2>; }; @@ -320,28 +322,24 @@ interrupts = <31 1>; reg = <0>; device_type = "ethernet-phy"; - interface = <6>; //ENET_1000_GMII }; qe_phy1: ethernet-phy@01 { interrupt-parent = <&mpic>; interrupts = <32 1>; reg = <1>; device_type = "ethernet-phy"; - interface = <6>; }; qe_phy2: ethernet-phy@02 { interrupt-parent = <&mpic>; interrupts = <31 1>; reg = <2>; device_type = "ethernet-phy"; - interface = <6>; //ENET_1000_GMII }; qe_phy3: ethernet-phy@03 { interrupt-parent = <&mpic>; interrupts = <32 1>; reg = <3>; device_type = "ethernet-phy"; - interface = <6>; //ENET_1000_GMII }; }; diff --git a/trunk/arch/powerpc/boot/ebony.c b/trunk/arch/powerpc/boot/ebony.c new file mode 100644 index 000000000000..b1251ee7a102 --- /dev/null +++ b/trunk/arch/powerpc/boot/ebony.c @@ -0,0 +1,129 @@ +/* + * Copyright 2007 David Gibson, IBM Corporation. + * + * Based on earlier code: + * Copyright (C) Paul Mackerras 1997. + * + * Matt Porter + * Copyright 2002-2005 MontaVista Software Inc. + * + * Eugene Surovegin or + * Copyright (c) 2003, 2004 Zultys Technologies + * + * 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 +#include +#include "types.h" +#include "elf.h" +#include "string.h" +#include "stdio.h" +#include "page.h" +#include "ops.h" +#include "reg.h" +#include "dcr.h" +#include "44x.h" + +extern char _dtb_start[]; +extern char _dtb_end[]; + +static u8 *ebony_mac0, *ebony_mac1; + +/* Calculate 440GP clocks */ +void ibm440gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk) +{ + u32 sys0 = mfdcr(DCRN_CPC0_SYS0); + u32 cr0 = mfdcr(DCRN_CPC0_CR0); + u32 cpu, plb, opb, ebc, tb, uart0, uart1, m; + u32 opdv = CPC0_SYS0_OPDV(sys0); + u32 epdv = CPC0_SYS0_EPDV(sys0); + + if (sys0 & CPC0_SYS0_BYPASS) { + /* Bypass system PLL */ + cpu = plb = sysclk; + } else { + if (sys0 & CPC0_SYS0_EXTSL) + /* PerClk */ + m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv; + else + /* CPU clock */ + m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0); + cpu = sysclk * m / CPC0_SYS0_FWDVA(sys0); + plb = sysclk * m / CPC0_SYS0_FWDVB(sys0); + } + + opb = plb / opdv; + ebc = opb / epdv; + + /* FIXME: Check if this is for all 440GP, or just Ebony */ + if ((mfpvr() & 0xf0000fff) == 0x40000440) + /* Rev. B 440GP, use external system clock */ + tb = sysclk; + else + /* Rev. C 440GP, errata force us to use internal clock */ + tb = cpu; + + if (cr0 & CPC0_CR0_U0EC) + /* External UART clock */ + uart0 = ser_clk; + else + /* Internal UART clock */ + uart0 = plb / CPC0_CR0_UDIV(cr0); + + if (cr0 & CPC0_CR0_U1EC) + /* External UART clock */ + uart1 = ser_clk; + else + /* Internal UART clock */ + uart1 = plb / CPC0_CR0_UDIV(cr0); + + printf("PPC440GP: SysClk = %dMHz (%x)\n\r", + (sysclk + 500000) / 1000000, sysclk); + + dt_fixup_cpu_clocks(cpu, tb, 0); + + dt_fixup_clock("/plb", plb); + dt_fixup_clock("/plb/opb", opb); + dt_fixup_clock("/plb/opb/ebc", ebc); + dt_fixup_clock("/plb/opb/serial@40000200", uart0); + dt_fixup_clock("/plb/opb/serial@40000300", uart1); +} + +static void ebony_fixups(void) +{ + // FIXME: sysclk should be derived by reading the FPGA registers + unsigned long sysclk = 33000000; + + ibm440gp_fixup_clocks(sysclk, 6 * 1843200); + ibm44x_fixup_memsize(); + dt_fixup_mac_addresses(ebony_mac0, ebony_mac1); +} + +#define SPRN_DBCR0 0x134 +#define DBCR0_RST_SYSTEM 0x30000000 + +static void ebony_exit(void) +{ + unsigned long tmp; + + asm volatile ( + "mfspr %0,%1\n" + "oris %0,%0,%2@h\n" + "mtspr %1,%0" + : "=&r"(tmp) : "i"(SPRN_DBCR0), "i"(DBCR0_RST_SYSTEM) + ); + +} + +void ebony_init(void *mac0, void *mac1) +{ + platform_ops.fixups = ebony_fixups; + platform_ops.exit = ebony_exit; + ebony_mac0 = mac0; + ebony_mac1 = mac1; + ft_init(_dtb_start, _dtb_end - _dtb_start, 32); + serial_console_init(); +} diff --git a/trunk/arch/powerpc/boot/holly.c b/trunk/arch/powerpc/boot/holly.c new file mode 100644 index 000000000000..7d6539f5e22c --- /dev/null +++ b/trunk/arch/powerpc/boot/holly.c @@ -0,0 +1,38 @@ +/* + * Copyright 2007 IBM Corporation + * + * Stephen Winiecki + * Josh Boyer + * + * Based on earlier code: + * Copyright (C) Paul Mackerras 1997. + * + * 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 +#include +#include "types.h" +#include "elf.h" +#include "string.h" +#include "stdio.h" +#include "page.h" +#include "ops.h" +#include "io.h" + +extern char _start[]; +extern char _end[]; +extern char _dtb_start[]; +extern char _dtb_end[]; + +BSS_STACK(4096); + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5) +{ + u32 heapsize = 0x8000000 - (u32)_end; /* 128M */ + + simple_alloc_init(_end, heapsize, 32, 64); + ft_init(_dtb_start, 0, 4); + serial_console_init(); +} diff --git a/trunk/arch/powerpc/boot/mktree.c b/trunk/arch/powerpc/boot/mktree.c index 4cb892993651..45d06a8c7cd1 100644 --- a/trunk/arch/powerpc/boot/mktree.c +++ b/trunk/arch/powerpc/boot/mktree.c @@ -46,8 +46,8 @@ int main(int argc, char *argv[]) struct stat st; boot_block_t bt; - if (argc < 3) { - fprintf(stderr, "usage: %s [entry-point]\n",argv[0]); + if (argc < 5) { + fprintf(stderr, "usage: %s \n",argv[0]); exit(1); } @@ -61,10 +61,8 @@ int main(int argc, char *argv[]) bt.bb_magic = htonl(0x0052504F); /* If we have the optional entry point parameter, use it */ - if (argc == 4) - bt.bb_dest = bt.bb_entry_point = htonl(strtoul(argv[3], NULL, 0)); - else - bt.bb_dest = bt.bb_entry_point = htonl(0x500000); + bt.bb_dest = htonl(strtoul(argv[3], NULL, 0)); + bt.bb_entry_point = htonl(strtoul(argv[4], NULL, 0)); /* We know these from the linker command. * ...and then move it up into memory a little more so the diff --git a/trunk/arch/powerpc/boot/treeboot-ebony.c b/trunk/arch/powerpc/boot/treeboot-ebony.c new file mode 100644 index 000000000000..8436a9c55192 --- /dev/null +++ b/trunk/arch/powerpc/boot/treeboot-ebony.c @@ -0,0 +1,34 @@ +/* + * Old U-boot compatibility for Ebony + * + * Author: David Gibson + * + * Copyright 2007 David Gibson, IBM Corporatio. + * Based on cuboot-83xx.c, which is: + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include "ops.h" +#include "stdio.h" +#include "44x.h" + +extern char _end[]; + +BSS_STACK(4096); + +#define OPENBIOS_MAC_BASE 0xfffffe0c +#define OPENBIOS_MAC_OFFSET 0xc + +void platform_init(void) +{ + unsigned long end_of_ram = 0x8000000; + unsigned long avail_ram = end_of_ram - (unsigned long)_end; + + simple_alloc_init(_end, avail_ram, 32, 64); + ebony_init((u8 *)OPENBIOS_MAC_BASE, + (u8 *)(OPENBIOS_MAC_BASE + OPENBIOS_MAC_OFFSET)); +} diff --git a/trunk/arch/powerpc/boot/wrapper b/trunk/arch/powerpc/boot/wrapper index 5cedd901201f..2ed8b8b3f0ec 100755 --- a/trunk/arch/powerpc/boot/wrapper +++ b/trunk/arch/powerpc/boot/wrapper @@ -163,20 +163,19 @@ fi vmz="$vmz$gzip" -case "$platform" in -uboot|cuboot*) - version=`${CROSS}strings "$kernel" | grep '^Linux version [-0-9.]' | \ - cut -d' ' -f3` - if [ -n "$version" ]; then - version="-n Linux-$version" - fi -esac +# Extract kernel version information, some platforms want to include +# it in the image header +version=`${CROSS}strings "$kernel" | grep '^Linux version [-0-9.]' | \ + cut -d' ' -f3` +if [ -n "$version" ]; then + uboot_version="-n Linux-$version" +fi case "$platform" in uboot) rm -f "$ofile" mkimage -A ppc -O linux -T kernel -C gzip -a 00000000 -e 00000000 \ - $version -d "$vmz" "$ofile" + $uboot_version -d "$vmz" "$ofile" if [ -z "$cacheit" ]; then rm -f "$vmz" fi @@ -212,25 +211,32 @@ if [ "$platform" != "miboot" ]; then rm $tmp fi +# Some platforms need the zImage's entry point and base address +base=0x`${CROSS}nm "$ofile" | grep ' _start$' | cut -d' ' -f1` +entry=`${CROSS}objdump -f "$ofile" | grep '^start address ' | cut -d' ' -f3` + # post-processing needed for some platforms case "$platform" in pseries|chrp) $object/addnote "$ofile" ;; pmaccoff) - entry=`objdump -f "$ofile" | grep '^start address ' | \ - cut -d' ' -f3` ${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile" $object/hack-coff "$ofile" ;; cuboot*) - base=`${CROSS}nm "$ofile" | grep ' _start$' | cut -d' ' -f1` - entry=`${CROSS}objdump -f "$ofile" | grep '^start address ' | \ - cut -d' ' -f3` mv "$ofile" "$ofile".elf ${CROSS}objcopy -O binary "$ofile".elf "$ofile".bin gzip -f -9 "$ofile".bin mkimage -A ppc -O linux -T kernel -C gzip -a "$base" -e "$entry" \ - $version -d "$ofile".bin.gz "$ofile" + $uboot_version -d "$ofile".bin.gz "$ofile" + ;; +treeboot*) + mv "$ofile" "$ofile.elf" + $object/mktree "$ofile.elf" "$ofile" "$base" "$entry" + if [ -z "$cacheit" ]; then + rm -f "$ofile.elf" + fi + exit 0 ;; esac diff --git a/trunk/arch/powerpc/configs/ebony_defconfig b/trunk/arch/powerpc/configs/ebony_defconfig new file mode 100644 index 000000000000..c3b96ef3c2d1 --- /dev/null +++ b/trunk/arch/powerpc/configs/ebony_defconfig @@ -0,0 +1,905 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.21 +# Fri May 4 13:47:08 2007 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +# CONFIG_PPC_UDBG_16550 is not set +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +# CONFIG_DEFAULT_UIMAGE is not set + +# +# Processor support +# +# CONFIG_CLASSIC32 is not set +# CONFIG_PPC_82xx is not set +# CONFIG_PPC_83xx is not set +# 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=y +# CONFIG_E200 is not set +CONFIG_PPC_DCR_NATIVE=y +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_DCR=y +CONFIG_4xx=y +CONFIG_BOOKE=y +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y +CONFIG_NOT_COHERENT_CACHE=y +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_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +# 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_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_EXTRA_PASS=y +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=y +# 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=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Platform support +# +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_MPC5200 is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +CONFIG_EBONY=y +CONFIG_440GP=y +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPM2 is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_MATH_EMULATION=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +CONFIG_SECCOMP=y +CONFIG_WANT_DEVICE_TREE=y +CONFIG_DEVICE_TREE="ebony.dts" +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_PPC_INDIRECT_PCI=y +# CONFIG_PPC_INDIRECT_PCI_BE is not set +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_CONSISTENT_START=0xff100000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_BOOT_LOAD=0x01000000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +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=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# 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_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNPACPI is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=35000 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE 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 +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set + +# +# 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 + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set +CONFIG_IBM_NEW_EMAC=y +CONFIG_IBM_NEW_EMAC_RXB=128 +CONFIG_IBM_NEW_EMAC_TXB=64 +CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32 +CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256 +CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0 +# CONFIG_IBM_NEW_EMAC_DEBUG is not set +CONFIG_IBM_NEW_EMAC_ZMII=y +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_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 + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +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=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_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 + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Auxiliary Display support +# + +# +# Virtualization +# + +# +# 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_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_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=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=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_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 is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set +# CONFIG_UCC_SLOW is not set +# CONFIG_UCC_FAST 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_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS 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 +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUGGER is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_SERIAL_TEXT_DEBUG is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_PCBC=y +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_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 +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff --git a/trunk/arch/powerpc/configs/holly_defconfig b/trunk/arch/powerpc/configs/holly_defconfig new file mode 100644 index 000000000000..be633b9b57c3 --- /dev/null +++ b/trunk/arch/powerpc/configs/holly_defconfig @@ -0,0 +1,1070 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.21 +# Sat May 5 11:02:35 2007 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_IRQ_PER_CPU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +# CONFIG_DEFAULT_UIMAGE is not set + +# +# Processor support +# +CONFIG_CLASSIC32=y +# CONFIG_PPC_82xx is not set +# CONFIG_PPC_83xx is not set +# 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_E200 is not set +CONFIG_6xx=y +CONFIG_PPC_FPU=y +# CONFIG_PPC_DCR_NATIVE is not set +# CONFIG_PPC_DCR_MMIO is not set +# CONFIG_ALTIVEC is not set +CONFIG_PPC_STD_MMU=y +CONFIG_PPC_STD_MMU_32=y +# CONFIG_SMP is not set +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_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=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 is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# +CONFIG_BLOCK=y +CONFIG_LBD=y +# 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=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Platform support +# +# CONFIG_PPC_MULTIPLATFORM is not set +CONFIG_EMBEDDED6xx=y +# CONFIG_APUS is not set +# CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_MPC5200 is not set +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +# CONFIG_LINKSTATION is not set +# CONFIG_MPC7448HPC2 is not set +CONFIG_PPC_HOLLY=y +CONFIG_TSI108_BRIDGE=y +CONFIG_MPIC=y +CONFIG_MPIC_WEIRD=y +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_TAU is not set +# CONFIG_CPM2 is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +# CONFIG_SECCOMP is not set +# CONFIG_WANT_DEVICE_TREE is not set +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_PPC_INDIRECT_PCI is not set +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=y +# 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 +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# 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_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT 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_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNPACPI is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# 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_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=131072 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE 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 is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_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_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_ESP_CORE is not set +# CONFIG_SCSI_SRP is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_PLATFORM is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set + +# +# 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 + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_FIXED_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_VORTEX=y +# CONFIG_TYPHOON is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +CONFIG_TSI108_ETH=y +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set + +# +# 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 +# CONFIG_NETXEN_NIC is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# 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 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +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=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_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=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_FB is not set +# CONFIG_FB_IBM_GXT4500 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# HID Devices +# +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Auxiliary Display support +# + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS 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_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=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=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set +# CONFIG_UCC_SLOW is not set +# CONFIG_UCC_FAST 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_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set +# CONFIG_KPROBES is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS 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 +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_DEBUGGER=y +CONFIG_XMON=y +CONFIG_XMON_DEFAULT=y +CONFIG_XMON_DISASSEMBLY=y +# CONFIG_BDI_SWITCH is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set diff --git a/trunk/arch/powerpc/configs/mpc832x_mds_defconfig b/trunk/arch/powerpc/configs/mpc832x_mds_defconfig index e1b36de6b38c..83192c0dc5bb 100644 --- a/trunk/arch/powerpc/configs/mpc832x_mds_defconfig +++ b/trunk/arch/powerpc/configs/mpc832x_mds_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc5 -# Tue Jan 30 14:27:25 2007 +# Linux kernel version: 2.6.21-rc5 +# Mon Apr 9 16:09:16 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 @@ -71,6 +72,7 @@ CONFIG_SYSVIPC=y # CONFIG_IKCONFIG is not set CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y @@ -123,16 +125,17 @@ CONFIG_DEFAULT_AS=y # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="anticipatory" CONFIG_QUICC_ENGINE=y -CONFIG_PPC_GEN550=y # CONFIG_WANT_EARLY_SERIAL is not set # # Platform support # +# CONFIG_MPC8313_RDB is not set CONFIG_MPC832x_MDS=y -# CONFIG_MPC834x_SYS is not set +# CONFIG_MPC832x_RDB is not set +# CONFIG_MPC834x_MDS is not set # CONFIG_MPC834x_ITX is not set -# CONFIG_MPC8360E_PB is not set +# CONFIG_MPC836x_MDS is not set CONFIG_PPC_MPC832x=y # CONFIG_MPIC is not set @@ -163,6 +166,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 @@ -172,6 +176,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 @@ -220,6 +225,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 @@ -324,6 +330,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # Plug and Play support # +# CONFIG_PNPACPI is not set # # Block devices @@ -342,7 +349,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -482,7 +488,21 @@ CONFIG_NETDEVICES=y # # PHY device support # -# CONFIG_PHYLIB is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +CONFIG_DAVICOM_PHY=y +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_FIXED_PHY is not set # # Ethernet (10 or 100Mbit) @@ -524,11 +544,13 @@ CONFIG_UCC_GETH=y # CONFIG_UGETH_FILTERING is not set # CONFIG_UGETH_TX_ON_DEMOND is not set # CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set # # 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 @@ -621,6 +643,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 @@ -691,6 +714,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 @@ -738,6 +762,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set # CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ADM9240 is not set # CONFIG_SENSORS_ASB100 is not set @@ -778,6 +803,11 @@ CONFIG_HWMON=y # CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + # # Multimedia devices # @@ -791,10 +821,9 @@ CONFIG_HWMON=y # # Graphics support # -CONFIG_FIRMWARE_EDID=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # CONFIG_FB is not set # CONFIG_FB_IBM_GXT4500 is not set -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -805,6 +834,7 @@ CONFIG_FIRMWARE_EDID=y # HID Devices # CONFIG_HID=y +# CONFIG_HID_DEBUG is not set # # USB support @@ -868,6 +898,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y # DMA Devices # +# +# Auxiliary Display support +# + # # Virtualization # @@ -995,11 +1029,7 @@ CONFIG_PARTITION_ADVANCED=y # Distributed Lock Manager # # CONFIG_DLM is not set - -# -# QE Options -# -CONFIG_UCC_SLOW=y +# CONFIG_UCC_SLOW is not set CONFIG_UCC_FAST=y CONFIG_UCC=y @@ -1012,7 +1042,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 @@ -1032,7 +1063,6 @@ CONFIG_ENABLE_MUST_CHECK=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_BOOTX_TEXT is not set -# CONFIG_SERIAL_TEXT_DEBUG is not set # CONFIG_PPC_EARLY_DEBUG is not set # @@ -1061,8 +1091,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 @@ -1076,6 +1108,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/trunk/arch/powerpc/configs/mpc832x_rdb_defconfig b/trunk/arch/powerpc/configs/mpc832x_rdb_defconfig index 56fc0a824458..4a4da875fa4e 100644 --- a/trunk/arch/powerpc/configs/mpc832x_rdb_defconfig +++ b/trunk/arch/powerpc/configs/mpc832x_rdb_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21-rc3 -# Mon Mar 12 17:32:19 2007 +# Linux kernel version: 2.6.21-rc5 +# Mon Apr 9 16:12:43 2007 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -125,7 +125,6 @@ CONFIG_DEFAULT_AS=y # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="anticipatory" CONFIG_QUICC_ENGINE=y -CONFIG_PPC_GEN550=y # CONFIG_WANT_EARLY_SERIAL is not set # @@ -490,7 +489,21 @@ CONFIG_NETDEVICES=y # # PHY device support # -# CONFIG_PHYLIB is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +CONFIG_ICPLUS_PHY=y +# CONFIG_FIXED_PHY is not set # # Ethernet (10 or 100Mbit) @@ -1200,11 +1213,7 @@ CONFIG_NLS_ISO8859_1=y # Distributed Lock Manager # # CONFIG_DLM is not set - -# -# QE Options -# -CONFIG_UCC_SLOW=y +# CONFIG_UCC_SLOW is not set CONFIG_UCC_FAST=y CONFIG_UCC=y @@ -1238,7 +1247,6 @@ CONFIG_ENABLE_MUST_CHECK=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_BOOTX_TEXT is not set -# CONFIG_SERIAL_TEXT_DEBUG is not set # CONFIG_PPC_EARLY_DEBUG is not set # diff --git a/trunk/arch/powerpc/configs/mpc836x_mds_defconfig b/trunk/arch/powerpc/configs/mpc836x_mds_defconfig index 8eb475cd0df0..921a151dc778 100644 --- a/trunk/arch/powerpc/configs/mpc836x_mds_defconfig +++ b/trunk/arch/powerpc/configs/mpc836x_mds_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20 -# Sat Feb 17 10:09:26 2007 +# Linux kernel version: 2.6.21-rc5 +# Mon Apr 9 16:14:05 2007 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -72,6 +72,7 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_IKCONFIG is not set CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y @@ -124,7 +125,6 @@ CONFIG_DEFAULT_AS=y # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="anticipatory" CONFIG_QUICC_ENGINE=y -CONFIG_PPC_GEN550=y # CONFIG_WANT_EARLY_SERIAL is not set # @@ -132,6 +132,7 @@ CONFIG_PPC_GEN550=y # # CONFIG_MPC8313_RDB is not set # CONFIG_MPC832x_MDS is not set +# CONFIG_MPC832x_RDB is not set # CONFIG_MPC834x_MDS is not set # CONFIG_MPC834x_ITX is not set CONFIG_MPC836x_MDS=y @@ -328,6 +329,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # Plug and Play support # +# CONFIG_PNPACPI is not set # # Block devices @@ -346,7 +348,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -486,7 +487,21 @@ CONFIG_NETDEVICES=y # # PHY device support # -# CONFIG_PHYLIB is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +CONFIG_MARVELL_PHY=y +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_FIXED_PHY is not set # # Ethernet (10 or 100Mbit) @@ -528,6 +543,7 @@ CONFIG_UCC_GETH=y # CONFIG_UGETH_FILTERING is not set # CONFIG_UGETH_TX_ON_DEMOND is not set # CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set # # Ethernet (10000 Mbit) @@ -745,6 +761,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set # CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ADM9240 is not set # CONFIG_SENSORS_ASB100 is not set @@ -785,6 +802,11 @@ CONFIG_HWMON=y # CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + # # Multimedia devices # @@ -798,10 +820,9 @@ CONFIG_HWMON=y # # Graphics support # -CONFIG_FIRMWARE_EDID=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # CONFIG_FB is not set # CONFIG_FB_IBM_GXT4500 is not set -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -1007,11 +1028,7 @@ CONFIG_PARTITION_ADVANCED=y # Distributed Lock Manager # # CONFIG_DLM is not set - -# -# QE Options -# -CONFIG_UCC_SLOW=y +# CONFIG_UCC_SLOW is not set CONFIG_UCC_FAST=y CONFIG_UCC=y @@ -1045,7 +1062,6 @@ CONFIG_ENABLE_MUST_CHECK=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_BOOTX_TEXT is not set -# CONFIG_SERIAL_TEXT_DEBUG is not set # CONFIG_PPC_EARLY_DEBUG is not set # diff --git a/trunk/arch/powerpc/configs/ps3_defconfig b/trunk/arch/powerpc/configs/ps3_defconfig index 0345a2ceec59..fd604968f9a2 100644 --- a/trunk/arch/powerpc/configs/ps3_defconfig +++ b/trunk/arch/powerpc/configs/ps3_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20-rc6 -# Thu Jan 25 13:35:34 2007 +# Linux kernel version: 2.6.21 +# Mon Apr 30 12:03:35 2007 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -60,6 +60,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 @@ -69,6 +70,7 @@ CONFIG_SYSVIPC=y # CONFIG_CPUSETS is not set CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y @@ -131,13 +133,36 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_PPC_PSERIES is not set # CONFIG_PPC_ISERIES is not set # CONFIG_PPC_MPC52xx is not set +# CONFIG_PPC_MPC5200 is not set # CONFIG_PPC_PMAC is not set # CONFIG_PPC_MAPLE is not set # CONFIG_PPC_PASEMI is not set +# CONFIG_PPC_CELLEB is not set +CONFIG_PPC_PS3=y + +# +# PS3 Platform Options +# +# CONFIG_PS3_ADVANCED is not set +CONFIG_PS3_HTAB_SIZE=20 +# CONFIG_PS3_DYNAMIC_DMA is not set +CONFIG_PS3_USE_LPAR_ADDR=y +CONFIG_PS3_VUART=y +CONFIG_PS3_PS3AV=y +CONFIG_PS3_SYS_MANAGER=y CONFIG_PPC_CELL=y # CONFIG_PPC_CELL_NATIVE is not set # CONFIG_PPC_IBM_CELL_BLADE is not set -CONFIG_PPC_PS3=y + +# +# Cell Broadband Engine options +# +CONFIG_SPU_FS=y +CONFIG_SPU_BASE=y +# CONFIG_PQ2ADS is not set +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set # CONFIG_U3_DART is not set # CONFIG_PPC_RTAS is not set # CONFIG_MMIO_NVRAM is not set @@ -146,24 +171,7 @@ CONFIG_PPC_PS3=y # CONFIG_PPC_INDIRECT_IO is not set # CONFIG_GENERIC_IOMAP is not set # CONFIG_CPU_FREQ is not set -# CONFIG_WANT_EARLY_SERIAL is not set -# CONFIG_MPIC is not set - -# -# Cell Broadband Engine options -# -CONFIG_SPU_FS=y -CONFIG_SPU_BASE=y -# CONFIG_CBE_RAS is not set - -# -# PS3 Platform Options -# -CONFIG_PS3_HTAB_SIZE=20 -# CONFIG_PS3_DYNAMIC_DMA is not set -CONFIG_PS3_USE_LPAR_ADDR=y -CONFIG_PS3_VUART=y -CONFIG_PS3_PS3AV=y +# CONFIG_CPM2 is not set # # Kernel options @@ -179,10 +187,10 @@ CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_BKL is not set CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y -CONFIG_FORCE_MAX_ZONEORDER=9 +CONFIG_FORCE_MAX_ZONEORDER=13 # CONFIG_IOMMU_VMERGE is not set CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y -# CONFIG_KEXEC is not set +CONFIG_KEXEC=y # CONFIG_CRASH_DUMP is not set # CONFIG_IRQ_ALL_CPUS is not set # CONFIG_NUMA is not set @@ -203,22 +211,22 @@ CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTPLUG_SPARSE=y CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_RESOURCES_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 CONFIG_ARCH_MEMORY_PROBE=y -CONFIG_PPC_64K_PAGES=y +# CONFIG_PPC_64K_PAGES is not set # CONFIG_SCHED_SMT is not set CONFIG_PROC_DEVICETREE=y -CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="root=/dev/sda1 ip=dhcp" +# CONFIG_CMDLINE_BOOL is not set # CONFIG_PM is not set # CONFIG_SECCOMP is not set +# CONFIG_WANT_DEVICE_TREE is not set 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 # CONFIG_PCI is not set # CONFIG_PCI_DOMAINS is not set @@ -240,10 +248,13 @@ CONFIG_NET=y # # Networking options # -# CONFIG_NETDEBUG is not set CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set # CONFIG_NET_KEY is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set @@ -261,7 +272,7 @@ CONFIG_IP_PNP_DHCP=y # 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_TUNNEL=y # CONFIG_INET_XFRM_MODE_TRANSPORT is not set # CONFIG_INET_XFRM_MODE_TUNNEL is not set # CONFIG_INET_XFRM_MODE_BEET is not set @@ -270,9 +281,23 @@ CONFIG_IP_PNP_DHCP=y CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_TCP_MD5SIG is not set -# CONFIG_IPV6 is not set +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set @@ -313,7 +338,31 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_NET_PKTGEN is not set # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set -# CONFIG_BT is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +# CONFIG_BT_RFCOMM_TTY is not set +# CONFIG_BT_BNEP is not set +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_EXT=y # CONFIG_IEEE80211 is not set # @@ -327,16 +376,13 @@ 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 # # Connector - unified userspace <-> kernelspace linker # # CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# # CONFIG_MTD is not set # @@ -347,24 +393,27 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # Plug and Play support # +# CONFIG_PNPACPI is not set # # Block devices # # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set -# CONFIG_BLK_DEV_LOOP 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 is not set -# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=65535 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set # # Misc devices # -# CONFIG_TIFM_CORE is not set # # ATA/ATAPI/MFM/RLL support @@ -388,7 +437,7 @@ CONFIG_BLK_DEV_SD=y # CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set -# CONFIG_CHR_DEV_SG is not set +CONFIG_CHR_DEV_SG=m # CONFIG_CHR_DEV_SCH is not set # @@ -413,6 +462,7 @@ CONFIG_BLK_DEV_SR=y # # CONFIG_ISCSI_TCP is not set # CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_ESP_CORE is not set # # Serial ATA (prod) and Parallel ATA (experimental) drivers @@ -460,7 +510,7 @@ CONFIG_NETDEVICES=y # Ethernet (10 or 100Mbit) # # CONFIG_NET_ETHERNET is not set -CONFIG_MII=y +CONFIG_MII=m # # Ethernet (1000 Mbit) @@ -475,9 +525,10 @@ CONFIG_MII=y # # -# Wireless LAN (non-hamradio) +# Wireless LAN # -# CONFIG_NET_RADIO is not set +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set # # Wan interfaces @@ -551,7 +602,8 @@ CONFIG_HW_CONSOLE=y # Non-8250 serial port support # CONFIG_UNIX98_PTYS=y -# CONFIG_LEGACY_PTYS is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=16 # # IPMI @@ -597,6 +649,11 @@ CONFIG_GEN_RTC=y # CONFIG_HWMON is not set # CONFIG_HWMON_VID is not set +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + # # Multimedia devices # @@ -611,15 +668,22 @@ CONFIG_GEN_RTC=y # # Graphics support # -# CONFIG_FIRMWARE_EDID is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_SVGALIB is not set # CONFIG_FB_MACMODES is not set # CONFIG_FB_BACKLIGHT is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# # CONFIG_FB_OF is not set # CONFIG_FB_VGA16 is not set # CONFIG_FB_S1D13XXX is not set @@ -634,7 +698,7 @@ CONFIG_FB_PS3_DEFAULT_SIZE_M=18 # CONFIG_VGA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y -# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y # CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y @@ -646,17 +710,62 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_LOGO_LINUX_CLUT224=y -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# ALSA PowerMac devices +# + +# +# ALSA PowerMac requires I2C +# + +# +# USB devices +# +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_USX2Y is not set + +# +# SoC audio support +# +# CONFIG_SND_SOC is not set + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set # # HID Devices # CONFIG_HID=y +# CONFIG_HID_DEBUG is not set # # USB support @@ -665,13 +774,13 @@ CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y CONFIG_USB=y -CONFIG_USB_DEBUG=y +# CONFIG_USB_DEBUG is not set # # Miscellaneous USB options # -# CONFIG_USB_DEVICEFS is not set -# CONFIG_USB_BANDWIDTH is not set +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_OTG is not set @@ -704,7 +813,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # # may also be needed; see USB_STORAGE Help for more information # -CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set @@ -720,10 +829,16 @@ CONFIG_USB_STORAGE=y # # USB Input Devices # -CONFIG_USB_HID=y +CONFIG_USB_HID=m # CONFIG_USB_HIDINPUT_POWERBOOK is not set # CONFIG_HID_FF is not set # CONFIG_USB_HIDDEV 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 @@ -736,6 +851,7 @@ CONFIG_USB_HID=y # CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_GTCO is not set # # USB Imaging devices @@ -748,15 +864,16 @@ CONFIG_USB_HID=y # # CONFIG_USB_CATC is not set # CONFIG_USB_KAWETH is not set -# CONFIG_USB_PEGASUS is not set +CONFIG_USB_PEGASUS=m # CONFIG_USB_RTL8150 is not set -CONFIG_USB_USBNET_MII=y -CONFIG_USB_USBNET=y -CONFIG_USB_NET_CDCETHER=y +CONFIG_USB_USBNET_MII=m +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_DM9601 is not set # CONFIG_USB_NET_GL620A is not set # CONFIG_USB_NET_NET1080 is not set # CONFIG_USB_NET_PLUSB is not set -CONFIG_USB_NET_MCS7830=y +CONFIG_USB_NET_MCS7830=m # CONFIG_USB_NET_RNDIS_HOST is not set # CONFIG_USB_NET_CDC_SUBSET is not set # CONFIG_USB_NET_ZAURUS is not set @@ -781,6 +898,7 @@ CONFIG_USB_MON=y # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set # CONFIG_USB_LED is not set # CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set @@ -791,6 +909,8 @@ CONFIG_USB_MON=y # CONFIG_USB_SISUSBVGA is not set # CONFIG_USB_LD is not set # CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set # # USB DSL modem support @@ -845,6 +965,10 @@ CONFIG_USB_MON=y # DMA Devices # +# +# Auxiliary Display support +# + # # Virtualization # @@ -852,7 +976,9 @@ CONFIG_USB_MON=y # # File systems # -# CONFIG_EXT2_FS is not set +CONFIG_EXT2_FS=m +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set @@ -871,27 +997,30 @@ CONFIG_FS_MBCACHE=y # CONFIG_ROMFS_FS is not set CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y -# CONFIG_QUOTA is not set +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set +CONFIG_AUTOFS4_FS=y # CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems # -CONFIG_ISO9660_FS=y +CONFIG_ISO9660_FS=m CONFIG_JOLIET=y # CONFIG_ZISOFS is not set -CONFIG_UDF_FS=y +CONFIG_UDF_FS=m CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems # -CONFIG_FAT_FS=y +CONFIG_FAT_FS=m # CONFIG_MSDOS_FS is not set -CONFIG_VFAT_FS=y +CONFIG_VFAT_FS=m CONFIG_FAT_DEFAULT_CODEPAGE=437 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set @@ -933,7 +1062,7 @@ CONFIG_RAMFS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y # CONFIG_NFS_V3_ACL is not set -# CONFIG_NFS_V4 is not set +CONFIG_NFS_V4=y # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y @@ -941,10 +1070,16 @@ CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y -# CONFIG_RPCSEC_GSS_KRB5 is not set +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y # CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_EXPERIMENTAL is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set @@ -1004,6 +1139,8 @@ CONFIG_NLS_ISO8859_1=y # Distributed Lock Manager # # CONFIG_DLM is not set +# CONFIG_UCC_SLOW is not set +# CONFIG_UCC_FAST is not set # # Library routines @@ -1014,7 +1151,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 @@ -1032,16 +1170,16 @@ 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=17 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set -CONFIG_DEBUG_SLAB=y -# CONFIG_DEBUG_SLAB_LEAK is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_RWSEMS=y CONFIG_DEBUG_SPINLOCK_SLEEP=y # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set @@ -1051,8 +1189,10 @@ CONFIG_DEBUG_INFO=y CONFIG_DEBUG_LIST=y CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set CONFIG_DEBUG_STACKOVERFLOW=y # CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_PAGEALLOC is not set # CONFIG_DEBUGGER is not set CONFIG_IRQSTACKS=y # CONFIG_BOOTX_TEXT is not set @@ -1063,6 +1203,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 @@ -1073,4 +1215,43 @@ CONFIG_PPC_EARLY_DEBUG=y # # Cryptographic options # -# CONFIG_CRYPTO is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=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 +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff --git a/trunk/arch/powerpc/kernel/Makefile b/trunk/arch/powerpc/kernel/Makefile index aa693d0f151a..3e779f07f21b 100644 --- a/trunk/arch/powerpc/kernel/Makefile +++ b/trunk/arch/powerpc/kernel/Makefile @@ -36,8 +36,9 @@ obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o obj-$(CONFIG_TAU) += tau_6xx.o +obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o suspend.o obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o -obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o +obj64-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_64.o swsusp_asm64.o obj32-$(CONFIG_MODULES) += module_32.o ifeq ($(CONFIG_PPC_MERGE),y) @@ -67,6 +68,7 @@ obj-$(CONFIG_MODULES) += $(module-y) pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci32-$(CONFIG_PPC32) := pci_32.o obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y) +obj-$(CONFIG_PCI_MSI) += msi.o kexec-$(CONFIG_PPC64) := machine_kexec_64.o kexec-$(CONFIG_PPC32) := machine_kexec_32.o obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o $(kexec-y) diff --git a/trunk/arch/powerpc/kernel/asm-offsets.c b/trunk/arch/powerpc/kernel/asm-offsets.c index 0c5150c69175..8f48560b7ee2 100644 --- a/trunk/arch/powerpc/kernel/asm-offsets.c +++ b/trunk/arch/powerpc/kernel/asm-offsets.c @@ -21,12 +21,12 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include #include #else #include -#include #endif #include @@ -257,11 +257,11 @@ int main(void) DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore)); -#ifndef CONFIG_PPC64 DEFINE(pbe_address, offsetof(struct pbe, address)); DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); DEFINE(pbe_next, offsetof(struct pbe, next)); +#ifndef CONFIG_PPC64 DEFINE(TASK_SIZE, TASK_SIZE); DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); #endif /* ! CONFIG_PPC64 */ diff --git a/trunk/arch/powerpc/kernel/head_44x.S b/trunk/arch/powerpc/kernel/head_44x.S index a15d4b8cce48..88695963f587 100644 --- a/trunk/arch/powerpc/kernel/head_44x.S +++ b/trunk/arch/powerpc/kernel/head_44x.S @@ -120,8 +120,8 @@ skpinv: addi r4,r4,1 /* Increment */ * Configure and load pinned entry into TLB slot 63. */ - lis r3,KERNELBASE@h /* Load the kernel virtual address */ - ori r3,r3,KERNELBASE@l + lis r3,PAGE_OFFSET@h + ori r3,r3,PAGE_OFFSET@l /* Kernel is at the base of RAM */ li r4, 0 /* Load the kernel physical address */ @@ -172,36 +172,28 @@ skpinv: addi r4,r4,1 /* Increment */ isync 4: -#ifdef CONFIG_SERIAL_TEXT_DEBUG - /* - * Add temporary UART mapping for early debug. - * We can map UART registers wherever we want as long as they don't - * interfere with other system mappings (e.g. with pinned entries). - * For an example of how we handle this - see ocotea.h. --ebs - */ +#ifdef CONFIG_PPC_EARLY_DEBUG_44x + /* Add UART mapping for early debug. */ + /* pageid fields */ - lis r3,UART0_IO_BASE@h - ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_4K + lis r3,PPC44x_EARLY_DEBUG_VIRTADDR@h + ori r3,r3,PPC44x_TLB_VALID|PPC44x_TLB_TS|PPC44x_TLB_64K /* xlat fields */ - lis r4,UART0_PHYS_IO_BASE@h /* RPN depends on SoC */ -#ifndef CONFIG_440EP - ori r4,r4,0x0001 /* ERPN is 1 for second 4GB page */ -#endif + lis r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW@h + ori r4,r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH /* attrib fields */ - li r5,0 - ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G) + li r5,(PPC44x_TLB_SW|PPC44x_TLB_SR|PPC44x_TLB_I|PPC44x_TLB_G) + li r0,62 /* TLB slot 0 */ - li r0,0 /* TLB slot 0 */ - - tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ - tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ - tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ + tlbwe r3,r0,PPC44x_TLB_PAGEID + tlbwe r4,r0,PPC44x_TLB_XLAT + tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Force context change */ isync -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ +#endif /* CONFIG_PPC_EARLY_DEBUG_44x */ /* Establish the interrupt vector offsets */ SET_IVOR(0, CriticalInput); @@ -709,16 +701,6 @@ _GLOBAL(giveup_fpu) blr #endif -/* - * extern void abort(void) - * - * At present, this routine just applies a system reset. - */ -_GLOBAL(abort) - mfspr r13,SPRN_DBCR0 - oris r13,r13,DBCR0_RST_SYSTEM@h - mtspr SPRN_DBCR0,r13 - _GLOBAL(set_context) #ifdef CONFIG_BDI_SWITCH diff --git a/trunk/arch/powerpc/kernel/idle.c b/trunk/arch/powerpc/kernel/idle.c index 6e7f50967bab..a9e9cbd32975 100644 --- a/trunk/arch/powerpc/kernel/idle.c +++ b/trunk/arch/powerpc/kernel/idle.c @@ -33,8 +33,11 @@ #include #ifdef CONFIG_HOTPLUG_CPU +/* this is used for software suspend, and that shuts down + * CPUs even while the system is still booting... */ #define cpu_should_die() (cpu_is_offline(smp_processor_id()) && \ - system_state == SYSTEM_RUNNING) + (system_state == SYSTEM_RUNNING \ + || system_state == SYSTEM_BOOTING)) #else #define cpu_should_die() 0 #endif diff --git a/trunk/arch/powerpc/kernel/idle_power4.S b/trunk/arch/powerpc/kernel/idle_power4.S index ba3195478600..5328709eeedc 100644 --- a/trunk/arch/powerpc/kernel/idle_power4.S +++ b/trunk/arch/powerpc/kernel/idle_power4.S @@ -53,3 +53,24 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) isync b 1b +_GLOBAL(power4_cpu_offline_powersave) + /* Go to NAP now */ + mfmsr r7 + rldicl r0,r7,48,1 + rotldi r0,r0,16 + mtmsrd r0,1 /* hard-disable interrupts */ + li r0,1 + li r6,0 + stb r0,PACAHARDIRQEN(r13) /* we'll hard-enable shortly */ + stb r6,PACASOFTIRQEN(r13) /* soft-disable irqs */ +BEGIN_FTR_SECTION + DSSALL + sync +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) + ori r7,r7,MSR_EE + oris r7,r7,MSR_POW@h + sync + isync + mtmsrd r7 + isync + blr diff --git a/trunk/arch/powerpc/kernel/irq.c b/trunk/arch/powerpc/kernel/irq.c index 6c83fe229e60..9ed4931af164 100644 --- a/trunk/arch/powerpc/kernel/irq.c +++ b/trunk/arch/powerpc/kernel/irq.c @@ -67,6 +67,7 @@ #ifdef CONFIG_PPC64 #include #include +#include #endif int __irq_offset_value; @@ -162,6 +163,16 @@ void local_irq_restore(unsigned long en) local_paca->hard_enabled = en; if ((int)mfspr(SPRN_DEC) < 0) mtspr(SPRN_DEC, 1); + + /* + * Force the delivery of pending soft-disabled interrupts on PS3. + * Any HV call will have this side effect. + */ + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { + u64 tmp; + lv1_get_version_info(&tmp); + } + hard_irq_enable(); } #endif /* CONFIG_PPC64 */ @@ -947,33 +958,6 @@ arch_initcall(irq_late_init); #endif /* CONFIG_PPC_MERGE */ -#ifdef CONFIG_PCI_MSI -int pci_enable_msi(struct pci_dev * pdev) -{ - if (ppc_md.enable_msi) - return ppc_md.enable_msi(pdev); - else - return -1; -} -EXPORT_SYMBOL(pci_enable_msi); - -void pci_disable_msi(struct pci_dev * pdev) -{ - if (ppc_md.disable_msi) - ppc_md.disable_msi(pdev); -} -EXPORT_SYMBOL(pci_disable_msi); - -void pci_scan_msi_device(struct pci_dev *dev) {} -int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;} -void pci_disable_msix(struct pci_dev *dev) {} -void msi_remove_pci_irq_vectors(struct pci_dev *dev) {} -void pci_no_msi(void) {} -EXPORT_SYMBOL(pci_enable_msix); -EXPORT_SYMBOL(pci_disable_msix); - -#endif - #ifdef CONFIG_PPC64 static int __init setup_noirqdistrib(char *str) { diff --git a/trunk/arch/powerpc/kernel/kprobes.c b/trunk/arch/powerpc/kernel/kprobes.c index ef647e7a9dc3..0c96611f02f4 100644 --- a/trunk/arch/powerpc/kernel/kprobes.c +++ b/trunk/arch/powerpc/kernel/kprobes.c @@ -30,8 +30,8 @@ #include #include #include +#include #include -#include #include #include @@ -126,22 +126,13 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, } /* Called with kretprobe_lock held */ -void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, +void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { - struct kretprobe_instance *ri; - - if ((ri = get_free_rp_inst(rp)) != NULL) { - ri->rp = rp; - ri->task = current; - ri->ret_addr = (kprobe_opcode_t *)regs->link; - - /* Replace the return addr with trampoline addr */ - regs->link = (unsigned long)kretprobe_trampoline; - add_rp_inst(ri); - } else { - rp->nmissed++; - } + ri->ret_addr = (kprobe_opcode_t *)regs->link; + + /* Replace the return addr with trampoline addr */ + regs->link = (unsigned long)kretprobe_trampoline; } static int __kprobes kprobe_handler(struct pt_regs *regs) @@ -336,7 +327,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) break; } - BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); + kretprobe_assert(ri, orig_ret_address, trampoline_address); regs->nip = orig_ret_address; reset_current_kprobe(); @@ -410,7 +401,7 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) return 1; } -static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) +int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) { struct kprobe *cur = kprobe_running(); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); @@ -495,14 +486,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, if (post_kprobe_handler(args->regs)) ret = NOTIFY_STOP; break; - case DIE_PAGE_FAULT: - /* kprobe_running() needs smp_processor_id() */ - preempt_disable(); - if (kprobe_running() && - kprobe_fault_handler(args->regs, args->trapnr)) - ret = NOTIFY_STOP; - preempt_enable(); - break; default: break; } @@ -559,3 +542,11 @@ int __init arch_init_kprobes(void) { return register_kprobe(&trampoline_p); } + +int __kprobes arch_trampoline_kprobe(struct kprobe *p) +{ + if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline) + return 1; + + return 0; +} diff --git a/trunk/arch/powerpc/kernel/legacy_serial.c b/trunk/arch/powerpc/kernel/legacy_serial.c index 63dd2c3ad95e..cea8045ba40b 100644 --- a/trunk/arch/powerpc/kernel/legacy_serial.c +++ b/trunk/arch/powerpc/kernel/legacy_serial.c @@ -115,7 +115,8 @@ static int __init add_legacy_soc_port(struct device_node *np, { u64 addr; const u32 *addrp; - upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; + upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ + | UPF_FIXED_PORT; struct device_node *tsi = of_get_parent(np); /* We only support ports that have a clock frequency properly @@ -243,9 +244,9 @@ static int __init add_legacy_pci_port(struct device_node *np, * doesn't work for these settings, you'll have to add your own special * cases here */ - if (device_is_compatible(pci_dev, "pci13a8,152") || - device_is_compatible(pci_dev, "pci13a8,154") || - device_is_compatible(pci_dev, "pci13a8,158")) { + if (of_device_is_compatible(pci_dev, "pci13a8,152") || + of_device_is_compatible(pci_dev, "pci13a8,154") || + of_device_is_compatible(pci_dev, "pci13a8,158")) { addr += 0x200 * lindex; base += 0x200 * lindex; } else { @@ -364,11 +365,11 @@ void __init find_legacy_serial_ports(void) /* Check for known pciclass, and also check wether we have * a device with child nodes for ports or not */ - if (device_is_compatible(np, "pciclass,0700") || - device_is_compatible(np, "pciclass,070002")) + if (of_device_is_compatible(np, "pciclass,0700") || + of_device_is_compatible(np, "pciclass,070002")) pci = np; - else if (device_is_compatible(parent, "pciclass,0700") || - device_is_compatible(parent, "pciclass,070002")) + else if (of_device_is_compatible(parent, "pciclass,0700") || + of_device_is_compatible(parent, "pciclass,070002")) pci = parent; else { of_node_put(parent); diff --git a/trunk/arch/powerpc/kernel/msi.c b/trunk/arch/powerpc/kernel/msi.c new file mode 100644 index 000000000000..c62d1012c013 --- /dev/null +++ b/trunk/arch/powerpc/kernel/msi.c @@ -0,0 +1,38 @@ +/* + * Copyright 2006-2007, Michael Ellerman, 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include + +#include + +int arch_msi_check_device(struct pci_dev* dev, int nvec, int type) +{ + if (!ppc_md.setup_msi_irqs || !ppc_md.teardown_msi_irqs) { + pr_debug("msi: Platform doesn't provide MSI callbacks.\n"); + return -ENOSYS; + } + + if (ppc_md.msi_check_device) { + pr_debug("msi: Using platform check routine.\n"); + return ppc_md.msi_check_device(dev, nvec, type); + } + + return 0; +} + +int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +{ + return ppc_md.setup_msi_irqs(dev, nvec, type); +} + +void arch_teardown_msi_irqs(struct pci_dev *dev) +{ + return ppc_md.teardown_msi_irqs(dev); +} diff --git a/trunk/arch/powerpc/kernel/of_device.c b/trunk/arch/powerpc/kernel/of_device.c index 0c8ea7659d92..a464d67248df 100644 --- a/trunk/arch/powerpc/kernel/of_device.c +++ b/trunk/arch/powerpc/kernel/of_device.c @@ -27,7 +27,7 @@ const struct of_device_id *of_match_node(const struct of_device_id *matches, match &= node->type && !strcmp(matches->type, node->type); if (matches->compatible[0]) - match &= device_is_compatible(node, + match &= of_device_is_compatible(node, matches->compatible); if (match) return matches; @@ -120,8 +120,8 @@ void of_device_unregister(struct of_device *ofdev) } -static ssize_t of_device_get_modalias(struct of_device *ofdev, - char *str, ssize_t len) +ssize_t of_device_get_modalias(struct of_device *ofdev, + char *str, ssize_t len) { const char *compat; int cplen, i; @@ -239,3 +239,4 @@ EXPORT_SYMBOL(of_dev_get); EXPORT_SYMBOL(of_dev_put); EXPORT_SYMBOL(of_release_dev); EXPORT_SYMBOL(of_device_uevent); +EXPORT_SYMBOL(of_device_get_modalias); diff --git a/trunk/arch/powerpc/kernel/of_platform.c b/trunk/arch/powerpc/kernel/of_platform.c index 908ed7926db4..84c34d979a88 100644 --- a/trunk/arch/powerpc/kernel/of_platform.c +++ b/trunk/arch/powerpc/kernel/of_platform.c @@ -29,7 +29,6 @@ #include #include - /* * The list of OF IDs below is used for matching bus types in the * system whose devices are to be exposed as of_platform_devices. diff --git a/trunk/arch/powerpc/kernel/pci_32.c b/trunk/arch/powerpc/kernel/pci_32.c index f022862de344..e66064b5093a 100644 --- a/trunk/arch/powerpc/kernel/pci_32.c +++ b/trunk/arch/powerpc/kernel/pci_32.c @@ -1658,7 +1658,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file, int i; if (page_is_ram(pfn)) - return prot; + return __pgprot(prot); prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; diff --git a/trunk/arch/powerpc/kernel/pci_64.c b/trunk/arch/powerpc/kernel/pci_64.c index 7138092826aa..6d05a1f377b5 100644 --- a/trunk/arch/powerpc/kernel/pci_64.c +++ b/trunk/arch/powerpc/kernel/pci_64.c @@ -1006,8 +1006,9 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, switch ((pci_space >> 24) & 0x3) { case 1: /* I/O space */ - hose->io_base_phys = cpu_phys_addr; - hose->pci_io_size = size; + hose->io_base_phys = cpu_phys_addr - pci_addr; + /* handle from 0 to top of I/O window */ + hose->pci_io_size = pci_addr + size; res = &hose->io_resource; res->flags = IORESOURCE_IO; @@ -1117,8 +1118,8 @@ static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys, } else { /* Root Bus */ res = &hose->io_resource; - *start_phys = hose->io_base_phys; - *start_virt = (unsigned long) hose->io_base_virt; + *start_phys = hose->io_base_phys + res->start; + *start_virt = (unsigned long) hose->io_base_virt + res->start; if (res->end > res->start) *size = res->end - res->start + 1; else { diff --git a/trunk/arch/powerpc/kernel/ppc_ksyms.c b/trunk/arch/powerpc/kernel/ppc_ksyms.c index ff252aaead12..c96fa9bd35a4 100644 --- a/trunk/arch/powerpc/kernel/ppc_ksyms.c +++ b/trunk/arch/powerpc/kernel/ppc_ksyms.c @@ -66,7 +66,6 @@ EXPORT_SYMBOL(clear_pages); EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); -EXPORT_SYMBOL(__div64_32); EXPORT_SYMBOL(do_signal); EXPORT_SYMBOL(transfer_to_handler); diff --git a/trunk/arch/powerpc/kernel/process.c b/trunk/arch/powerpc/kernel/process.c index e509aae2feb3..6e2f03566b0d 100644 --- a/trunk/arch/powerpc/kernel/process.c +++ b/trunk/arch/powerpc/kernel/process.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/powerpc/kernel/prom_init.c b/trunk/arch/powerpc/kernel/prom_init.c index e27d9d1b6e67..d6047c441034 100644 --- a/trunk/arch/powerpc/kernel/prom_init.c +++ b/trunk/arch/powerpc/kernel/prom_init.c @@ -635,6 +635,12 @@ static void __init early_cmdline_parse(void) /* ibm,dynamic-reconfiguration-memory property supported */ #define OV5_DRCONF_MEMORY 0x20 #define OV5_LARGE_PAGES 0x10 /* large pages supported */ +/* PCIe/MSI support. Without MSI full PCIe is not supported */ +#ifdef CONFIG_PCI_MSI +#define OV5_MSI 0x01 /* PCIe/MSI support */ +#else +#define OV5_MSI 0x00 +#endif /* CONFIG_PCI_MSI */ /* * The architecture vector has an array of PVR mask/value pairs, @@ -679,7 +685,7 @@ static unsigned char ibm_architecture_vec[] = { /* option vector 5: PAPR/OF options */ 3 - 2, /* length */ 0, /* don't ignore, don't halt */ - OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY, + OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | OV5_MSI, }; /* Old method - ELF header with PT_NOTE sections */ @@ -967,7 +973,7 @@ static unsigned long __init prom_next_cell(int s, cell_t **cellp) * If problems seem to show up, it would be a good start to track * them down. */ -static void reserve_mem(u64 base, u64 size) +static void __init reserve_mem(u64 base, u64 size) { u64 top = base + size; unsigned long cnt = RELOC(mem_reserve_cnt); @@ -2153,7 +2159,7 @@ static void __init fixup_device_tree_efika(void) 3,12,0, 3,13,0, 3,14,0, 3,15,0 }; struct subst_entry efika_subst_table[] = { { "/", "device_type", prop_cstr("efika") }, - { "/builtin", "compatible", prop_cstr("soc") }, + { "/builtin", "device_type", prop_cstr("soc") }, { "/builtin/ata", "compatible", prop_cstr("mpc5200b-ata\0mpc5200-ata"), }, { "/builtin/bestcomm", "compatible", prop_cstr("mpc5200b-bestcomm\0mpc5200-bestcomm") }, { "/builtin/bestcomm", "interrupts", prop_bcomm_irq, sizeof(prop_bcomm_irq) }, diff --git a/trunk/arch/powerpc/kernel/prom_parse.c b/trunk/arch/powerpc/kernel/prom_parse.c index aa40a5307294..b5c96af955c6 100644 --- a/trunk/arch/powerpc/kernel/prom_parse.c +++ b/trunk/arch/powerpc/kernel/prom_parse.c @@ -1042,3 +1042,28 @@ const void *of_get_mac_address(struct device_node *np) } EXPORT_SYMBOL(of_get_mac_address); +int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) +{ + int irq = irq_of_parse_and_map(dev, index); + + /* Only dereference the resource if both the + * resource and the irq are valid. */ + if (r && irq != NO_IRQ) { + r->start = r->end = irq; + r->flags = IORESOURCE_IRQ; + } + + return irq; +} +EXPORT_SYMBOL_GPL(of_irq_to_resource); + +void __iomem *of_iomap(struct device_node *np, int index) +{ + struct resource res; + + if (of_address_to_resource(np, index, &res)) + return NULL; + + return ioremap(res.start, 1 + res.end - res.start); +} +EXPORT_SYMBOL(of_iomap); diff --git a/trunk/arch/powerpc/kernel/ptrace.c b/trunk/arch/powerpc/kernel/ptrace.c index cc44c7b975aa..f4f391cdd8f5 100644 --- a/trunk/arch/powerpc/kernel/ptrace.c +++ b/trunk/arch/powerpc/kernel/ptrace.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/powerpc/kernel/signal_32.c b/trunk/arch/powerpc/kernel/signal_32.c index 6b405a3f43f9..dd1dca5bfa81 100644 --- a/trunk/arch/powerpc/kernel/signal_32.c +++ b/trunk/arch/powerpc/kernel/signal_32.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/powerpc/kernel/signal_64.c b/trunk/arch/powerpc/kernel/signal_64.c index f72e8e823d78..1ce0ae3f6ffc 100644 --- a/trunk/arch/powerpc/kernel/signal_64.c +++ b/trunk/arch/powerpc/kernel/signal_64.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/powerpc/kernel/smp.c b/trunk/arch/powerpc/kernel/smp.c index d8e503b2e1af..22f1ef1b3100 100644 --- a/trunk/arch/powerpc/kernel/smp.c +++ b/trunk/arch/powerpc/kernel/smp.c @@ -176,10 +176,10 @@ static struct call_data_struct { #define SMP_CALL_TIMEOUT 8 /* - * This function sends a 'generic call function' IPI to all other CPUs - * in the system. + * These functions send a 'generic call function' IPI to other online + * CPUS in the system. * - * [SUMMARY] Run a function on all other CPUs. + * [SUMMARY] Run a function on other CPUs. * The function to run. This must be fast and non-blocking. * An arbitrary pointer to pass to the function. * currently unused. @@ -190,18 +190,26 @@ static struct call_data_struct { * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. */ -int smp_call_function (void (*func) (void *info), void *info, int nonatomic, - int wait) -{ +int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, + int wait, cpumask_t map) +{ struct call_data_struct data; - int ret = -1, cpus; + int ret = -1, num_cpus; + int cpu; u64 timeout; /* Can deadlock when called with interrupts disabled */ WARN_ON(irqs_disabled()); + /* remove 'self' from the map */ + if (cpu_isset(smp_processor_id(), map)) + cpu_clear(smp_processor_id(), map); + + /* sanity check the map, remove any non-online processors. */ + cpus_and(map, map, cpu_online_map); + if (unlikely(smp_ops == NULL)) - return -1; + return ret; data.func = func; data.info = info; @@ -213,40 +221,42 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, spin_lock(&call_lock); /* Must grab online cpu count with preempt disabled, otherwise * it can change. */ - cpus = num_online_cpus() - 1; - if (!cpus) { + num_cpus = num_online_cpus() - 1; + if (!num_cpus || cpus_empty(map)) { ret = 0; goto out; } call_data = &data; smp_wmb(); - /* Send a message to all other CPUs and wait for them to respond */ - smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION); + /* Send a message to all CPUs in the map */ + for_each_cpu_mask(cpu, map) + smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION); timeout = get_tb() + (u64) SMP_CALL_TIMEOUT * tb_ticks_per_sec; - /* Wait for response */ - while (atomic_read(&data.started) != cpus) { + /* Wait for indication that they have received the message */ + while (atomic_read(&data.started) != num_cpus) { HMT_low(); if (get_tb() >= timeout) { printk("smp_call_function on cpu %d: other cpus not " - "responding (%d)\n", smp_processor_id(), - atomic_read(&data.started)); + "responding (%d)\n", smp_processor_id(), + atomic_read(&data.started)); debugger(NULL); goto out; } } + /* optionally wait for the CPUs to complete */ if (wait) { - while (atomic_read(&data.finished) != cpus) { + while (atomic_read(&data.finished) != num_cpus) { HMT_low(); if (get_tb() >= timeout) { printk("smp_call_function on cpu %d: other " - "cpus not finishing (%d/%d)\n", - smp_processor_id(), - atomic_read(&data.finished), - atomic_read(&data.started)); + "cpus not finishing (%d/%d)\n", + smp_processor_id(), + atomic_read(&data.finished), + atomic_read(&data.started)); debugger(NULL); goto out; } @@ -262,8 +272,29 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, return ret; } +int smp_call_function(void (*func) (void *info), void *info, int nonatomic, + int wait) +{ + return smp_call_function_map(func,info,nonatomic,wait,cpu_online_map); +} EXPORT_SYMBOL(smp_call_function); +int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int nonatomic, + int wait) +{ + cpumask_t map=CPU_MASK_NONE; + + if (!cpu_online(cpu)) + return -EINVAL; + + if (cpu == smp_processor_id()) + return -EBUSY; + + cpu_set(cpu, map); + return smp_call_function_map(func,info,nonatomic,wait,map); +} +EXPORT_SYMBOL(smp_call_function_single); + void smp_call_function_interrupt(void) { void (*func) (void *info); diff --git a/trunk/arch/powerpc/kernel/swsusp.c b/trunk/arch/powerpc/kernel/swsusp.c new file mode 100644 index 000000000000..064a7ba4f02c --- /dev/null +++ b/trunk/arch/powerpc/kernel/swsusp.c @@ -0,0 +1,43 @@ +/* + * Common powerpc suspend code for 32 and 64 bits + * + * Copyright 2007 Johannes Berg + * + * 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 +#include +#include +#include +#include + +void save_processor_state(void) +{ + /* + * flush out all the special registers so we don't need + * to save them in the snapshot + */ + flush_fp_to_thread(current); + flush_altivec_to_thread(current); + flush_spe_to_thread(current); + +#ifdef CONFIG_PPC64 + hard_irq_disable(); +#endif + +} + +void restore_processor_state(void) +{ +#ifdef CONFIG_PPC32 + set_context(current->active_mm->context.id, current->active_mm->pgd); +#endif + +#ifdef CONFIG_PPC64 + hard_irq_enable(); +#endif +} diff --git a/trunk/arch/powerpc/kernel/swsusp_64.c b/trunk/arch/powerpc/kernel/swsusp_64.c new file mode 100644 index 000000000000..6f3f0697274e --- /dev/null +++ b/trunk/arch/powerpc/kernel/swsusp_64.c @@ -0,0 +1,24 @@ +/* + * PowerPC 64-bit swsusp implementation + * + * Copyright 2006 Johannes Berg + * + * GPLv2 + */ + +#include +#include +#include +#include + +void do_after_copyback(void) +{ + iommu_restore(); + touch_softlockup_watchdog(); + mb(); +} + +void _iommu_save(void) +{ + iommu_save(); +} diff --git a/trunk/arch/powerpc/kernel/swsusp_asm64.S b/trunk/arch/powerpc/kernel/swsusp_asm64.S new file mode 100644 index 000000000000..e092c3cbdb9b --- /dev/null +++ b/trunk/arch/powerpc/kernel/swsusp_asm64.S @@ -0,0 +1,228 @@ +/* + * PowerPC 64-bit swsusp implementation + * + * Copyright 2006 Johannes Berg + * + * GPLv2 + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Structure for storing CPU registers on the save area. + */ +#define SL_r1 0x00 /* stack pointer */ +#define SL_PC 0x08 +#define SL_MSR 0x10 +#define SL_SDR1 0x18 +#define SL_XER 0x20 +#define SL_TB 0x40 +#define SL_r2 0x48 +#define SL_CR 0x50 +#define SL_LR 0x58 +#define SL_r12 0x60 +#define SL_r13 0x68 +#define SL_r14 0x70 +#define SL_r15 0x78 +#define SL_r16 0x80 +#define SL_r17 0x88 +#define SL_r18 0x90 +#define SL_r19 0x98 +#define SL_r20 0xa0 +#define SL_r21 0xa8 +#define SL_r22 0xb0 +#define SL_r23 0xb8 +#define SL_r24 0xc0 +#define SL_r25 0xc8 +#define SL_r26 0xd0 +#define SL_r27 0xd8 +#define SL_r28 0xe0 +#define SL_r29 0xe8 +#define SL_r30 0xf0 +#define SL_r31 0xf8 +#define SL_SIZE SL_r31+8 + +/* these macros rely on the save area being + * pointed to by r11 */ +#define SAVE_SPECIAL(special) \ + mf##special r0 ;\ + std r0, SL_##special(r11) +#define RESTORE_SPECIAL(special) \ + ld r0, SL_##special(r11) ;\ + mt##special r0 +#define SAVE_REGISTER(reg) \ + std reg, SL_##reg(r11) +#define RESTORE_REGISTER(reg) \ + ld reg, SL_##reg(r11) + +/* space for storing cpu state */ + .section .data + .align 5 +swsusp_save_area: + .space SL_SIZE + + .section ".toc","aw" +swsusp_save_area_ptr: + .tc swsusp_save_area[TC],swsusp_save_area +restore_pblist_ptr: + .tc restore_pblist[TC],restore_pblist + + .section .text + .align 5 +_GLOBAL(swsusp_arch_suspend) + ld r11,swsusp_save_area_ptr@toc(r2) + SAVE_SPECIAL(LR) + SAVE_REGISTER(r1) + SAVE_SPECIAL(CR) + SAVE_SPECIAL(TB) + SAVE_REGISTER(r2) + SAVE_REGISTER(r12) + SAVE_REGISTER(r13) + SAVE_REGISTER(r14) + SAVE_REGISTER(r15) + SAVE_REGISTER(r16) + SAVE_REGISTER(r17) + SAVE_REGISTER(r18) + SAVE_REGISTER(r19) + SAVE_REGISTER(r20) + SAVE_REGISTER(r21) + SAVE_REGISTER(r22) + SAVE_REGISTER(r23) + SAVE_REGISTER(r24) + SAVE_REGISTER(r25) + SAVE_REGISTER(r26) + SAVE_REGISTER(r27) + SAVE_REGISTER(r28) + SAVE_REGISTER(r29) + SAVE_REGISTER(r30) + SAVE_REGISTER(r31) + SAVE_SPECIAL(MSR) + SAVE_SPECIAL(SDR1) + SAVE_SPECIAL(XER) + + /* we push the stack up 128 bytes but don't store the + * stack pointer on the stack like a real stackframe */ + addi r1,r1,-128 + + bl _iommu_save + bl swsusp_save + + /* restore LR */ + ld r11,swsusp_save_area_ptr@toc(r2) + RESTORE_SPECIAL(LR) + addi r1,r1,128 + + blr + +/* Resume code */ +_GLOBAL(swsusp_arch_resume) + /* Stop pending alitvec streams and memory accesses */ +BEGIN_FTR_SECTION + DSSALL +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) + sync + + ld r12,restore_pblist_ptr@toc(r2) + ld r12,0(r12) + + cmpdi r12,0 + beq- nothing_to_copy + li r15,512 +copyloop: + ld r13,pbe_address(r12) + ld r14,pbe_orig_address(r12) + + mtctr r15 + li r10,0 +copy_page_loop: + ldx r0,r10,r13 + stdx r0,r10,r14 + addi r10,r10,8 + bdnz copy_page_loop + + ld r12,pbe_next(r12) + cmpdi r12,0 + bne+ copyloop +nothing_to_copy: + + /* flush caches */ + lis r3, 0x10 + mtctr r3 + li r3, 0 + ori r3, r3, CONFIG_KERNEL_START>>48 + li r0, 48 + sld r3, r3, r0 + li r0, 0 +1: + dcbf r0,r3 + addi r3,r3,0x20 + bdnz 1b + + sync + + tlbia + + ld r11,swsusp_save_area_ptr@toc(r2) + + RESTORE_SPECIAL(CR) + + /* restore timebase */ + /* load saved tb */ + ld r1, SL_TB(r11) + /* get upper 32 bits of it */ + srdi r2, r1, 32 + /* clear tb lower to avoid wrap */ + li r0, 0 + mttbl r0 + /* set tb upper */ + mttbu r2 + /* set tb lower */ + mttbl r1 + + /* restore registers */ + RESTORE_REGISTER(r1) + RESTORE_REGISTER(r2) + RESTORE_REGISTER(r12) + RESTORE_REGISTER(r13) + RESTORE_REGISTER(r14) + RESTORE_REGISTER(r15) + RESTORE_REGISTER(r16) + RESTORE_REGISTER(r17) + RESTORE_REGISTER(r18) + RESTORE_REGISTER(r19) + RESTORE_REGISTER(r20) + RESTORE_REGISTER(r21) + RESTORE_REGISTER(r22) + RESTORE_REGISTER(r23) + RESTORE_REGISTER(r24) + RESTORE_REGISTER(r25) + RESTORE_REGISTER(r26) + RESTORE_REGISTER(r27) + RESTORE_REGISTER(r28) + RESTORE_REGISTER(r29) + RESTORE_REGISTER(r30) + RESTORE_REGISTER(r31) + /* can't use RESTORE_SPECIAL(MSR) */ + ld r0, SL_MSR(r11) + mtmsrd r0, 0 + RESTORE_SPECIAL(SDR1) + RESTORE_SPECIAL(XER) + + sync + + addi r1,r1,-128 + bl slb_flush_and_rebolt + bl do_after_copyback + addi r1,r1,128 + + ld r11,swsusp_save_area_ptr@toc(r2) + RESTORE_SPECIAL(LR) + + li r3, 0 + blr diff --git a/trunk/arch/powerpc/kernel/syscalls.c b/trunk/arch/powerpc/kernel/syscalls.c index d358866b880f..fc6647d332cb 100644 --- a/trunk/arch/powerpc/kernel/syscalls.c +++ b/trunk/arch/powerpc/kernel/syscalls.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/powerpc/kernel/sysfs.c b/trunk/arch/powerpc/kernel/sysfs.c index 933e214c33e8..cae39d9dfe48 100644 --- a/trunk/arch/powerpc/kernel/sysfs.c +++ b/trunk/arch/powerpc/kernel/sysfs.c @@ -499,4 +499,4 @@ static int __init topology_init(void) return 0; } -__initcall(topology_init); +subsys_initcall(topology_init); diff --git a/trunk/arch/powerpc/kernel/traps.c b/trunk/arch/powerpc/kernel/traps.c index f7862224fe85..bf6445ac9f1c 100644 --- a/trunk/arch/powerpc/kernel/traps.c +++ b/trunk/arch/powerpc/kernel/traps.c @@ -33,8 +33,8 @@ #include #include #include +#include -#include #include #include #include @@ -72,20 +72,6 @@ EXPORT_SYMBOL(__debugger_dabr_match); EXPORT_SYMBOL(__debugger_fault_handler); #endif -ATOMIC_NOTIFIER_HEAD(powerpc_die_chain); - -int register_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&powerpc_die_chain, nb); -} -EXPORT_SYMBOL(register_die_notifier); - -int unregister_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&powerpc_die_chain, nb); -} -EXPORT_SYMBOL(unregister_die_notifier); - /* * Trap & Exception support */ diff --git a/trunk/arch/powerpc/kernel/udbg.c b/trunk/arch/powerpc/kernel/udbg.c index 7e0971868fc2..87703df87509 100644 --- a/trunk/arch/powerpc/kernel/udbg.c +++ b/trunk/arch/powerpc/kernel/udbg.c @@ -51,6 +51,9 @@ void __init udbg_early_init(void) udbg_init_pas_realmode(); #elif defined(CONFIG_BOOTX_TEXT) udbg_init_btext(); +#elif defined(CONFIG_PPC_EARLY_DEBUG_44x) + /* PPC44x debug */ + udbg_init_44x_as1(); #endif } @@ -142,29 +145,22 @@ static void udbg_console_write(struct console *con, const char *s, static struct console udbg_console = { .name = "udbg", .write = udbg_console_write, - .flags = CON_PRINTBUFFER | CON_ENABLED, + .flags = CON_PRINTBUFFER | CON_ENABLED | CON_BOOT, .index = -1, }; static int early_console_initialized; -void __init disable_early_printk(void) -{ - if (!early_console_initialized) - return; - if (strstr(boot_command_line, "udbg-immortal")) { - printk(KERN_INFO "early console immortal !\n"); - return; - } - unregister_console(&udbg_console); - early_console_initialized = 0; -} - /* called by setup_system */ void register_early_udbg_console(void) { if (early_console_initialized) return; + + if (strstr(boot_command_line, "udbg-immortal")) { + printk(KERN_INFO "early console immortal !\n"); + udbg_console.flags &= ~CON_BOOT; + } early_console_initialized = 1; register_console(&udbg_console); } diff --git a/trunk/arch/powerpc/kernel/udbg_16550.c b/trunk/arch/powerpc/kernel/udbg_16550.c index a963f657222b..7afab5bcd61a 100644 --- a/trunk/arch/powerpc/kernel/udbg_16550.c +++ b/trunk/arch/powerpc/kernel/udbg_16550.c @@ -191,3 +191,26 @@ void udbg_init_pas_realmode(void) udbg_getc_poll = NULL; } #endif /* CONFIG_PPC_MAPLE */ + +#ifdef CONFIG_PPC_EARLY_DEBUG_44x +#include + +static void udbg_44x_as1_putc(char c) +{ + if (udbg_comport) { + while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0) + /* wait for idle */; + as1_writeb(c, &udbg_comport->thr); eieio(); + if (c == '\n') + udbg_44x_as1_putc('\r'); + } +} + +void __init udbg_init_44x_as1(void) +{ + udbg_comport = + (volatile struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR; + + udbg_putc = udbg_44x_as1_putc; +} +#endif /* CONFIG_PPC_EARLY_DEBUG_44x */ diff --git a/trunk/arch/powerpc/kernel/vdso.c b/trunk/arch/powerpc/kernel/vdso.c index e46c31b36641..4245579edb4e 100644 --- a/trunk/arch/powerpc/kernel/vdso.c +++ b/trunk/arch/powerpc/kernel/vdso.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/powerpc/kernel/vio.c b/trunk/arch/powerpc/kernel/vio.c index b2c1b67a10a7..62c1bc12ea39 100644 --- a/trunk/arch/powerpc/kernel/vio.c +++ b/trunk/arch/powerpc/kernel/vio.c @@ -117,7 +117,7 @@ static const struct vio_device_id *vio_match_device( { while (ids->type[0] != '\0') { if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) && - device_is_compatible(dev->dev.archdata.of_node, + of_device_is_compatible(dev->dev.archdata.of_node, ids->compat)) return ids; ids++; diff --git a/trunk/arch/powerpc/lib/dma-noncoherent.c b/trunk/arch/powerpc/lib/dma-noncoherent.c index 48f3d13a3de5..6656d47841d0 100644 --- a/trunk/arch/powerpc/lib/dma-noncoherent.c +++ b/trunk/arch/powerpc/lib/dma-noncoherent.c @@ -306,13 +306,15 @@ EXPORT_SYMBOL(__dma_free_coherent); static int __init dma_alloc_init(void) { pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte; int ret = 0; do { pgd = pgd_offset(&init_mm, CONSISTENT_BASE); - pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE); + pud = pud_alloc(&init_mm, pgd, CONSISTENT_BASE); + pmd = pmd_alloc(&init_mm, pud, CONSISTENT_BASE); if (!pmd) { printk(KERN_ERR "%s: no pmd tables\n", __func__); ret = -ENOMEM; diff --git a/trunk/arch/powerpc/mm/44x_mmu.c b/trunk/arch/powerpc/mm/44x_mmu.c index 0a0a0487b334..ca4dcb07a939 100644 --- a/trunk/arch/powerpc/mm/44x_mmu.c +++ b/trunk/arch/powerpc/mm/44x_mmu.c @@ -24,73 +24,38 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include - -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include +#include +#include #include "mmu_decl.h" -extern char etext[], _stext[]; - /* Used by the 44x TLB replacement exception handler. * Just needed it declared someplace. */ -unsigned int tlb_44x_index = 0; -unsigned int tlb_44x_hwater = 62; +unsigned int tlb_44x_index; /* = 0 */ +unsigned int tlb_44x_hwater = PPC44x_TLB_SIZE - 1 - PPC44x_EARLY_TLBS; /* * "Pins" a 256MB TLB entry in AS0 for kernel lowmem */ -static void __init -ppc44x_pin_tlb(int slot, unsigned int virt, unsigned int phys) +static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys) { - unsigned long attrib = 0; - - __asm__ __volatile__("\ - clrrwi %2,%2,10\n\ - ori %2,%2,%4\n\ - clrrwi %1,%1,10\n\ - li %0,0\n\ - ori %0,%0,%5\n\ - tlbwe %2,%3,%6\n\ - tlbwe %1,%3,%7\n\ - tlbwe %0,%3,%8" + __asm__ __volatile__( + "tlbwe %2,%3,%4\n" + "tlbwe %1,%3,%5\n" + "tlbwe %0,%3,%6\n" : - : "r" (attrib), "r" (phys), "r" (virt), "r" (slot), - "i" (PPC44x_TLB_VALID | PPC44x_TLB_256M), - "i" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G), + : "r" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G), + "r" (phys), + "r" (virt | PPC44x_TLB_VALID | PPC44x_TLB_256M), + "r" (tlb_44x_hwater--), /* slot for this TLB entry */ "i" (PPC44x_TLB_PAGEID), "i" (PPC44x_TLB_XLAT), "i" (PPC44x_TLB_ATTRIB)); } -/* - * MMU_init_hw does the chip-specific initialization of the MMU hardware. - */ void __init MMU_init_hw(void) { flush_instruction_cache(); @@ -98,22 +63,13 @@ void __init MMU_init_hw(void) unsigned long __init mmu_mapin_ram(void) { - unsigned int pinned_tlbs = 1; - int i; - - /* Determine number of entries necessary to cover lowmem */ - pinned_tlbs = (unsigned int) - (_ALIGN(total_lowmem, PPC_PIN_SIZE) >> PPC44x_PIN_SHIFT); - - /* Write upper watermark to save location */ - tlb_44x_hwater = PPC44x_LOW_SLOT - pinned_tlbs; + unsigned long addr; - /* If necessary, set additional pinned TLBs */ - if (pinned_tlbs > 1) - for (i = (PPC44x_LOW_SLOT-(pinned_tlbs-1)); i < PPC44x_LOW_SLOT; i++) { - unsigned int phys_addr = (PPC44x_LOW_SLOT-i) * PPC_PIN_SIZE; - ppc44x_pin_tlb(i, phys_addr+PAGE_OFFSET, phys_addr); - } + /* Pin in enough TLBs to cover any lowmem not covered by the + * initial 256M mapping established in head_44x.S */ + for (addr = PPC_PIN_SIZE; addr < total_lowmem; + addr += PPC_PIN_SIZE) + ppc44x_pin_tlb(addr + PAGE_OFFSET, addr); return total_lowmem; } diff --git a/trunk/arch/powerpc/mm/fault.c b/trunk/arch/powerpc/mm/fault.c index 03aeb3a46077..bfe901353142 100644 --- a/trunk/arch/powerpc/mm/fault.c +++ b/trunk/arch/powerpc/mm/fault.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -36,40 +37,28 @@ #include #include #include -#include #include -#ifdef CONFIG_KPROBES -ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); -/* Hook to register for page fault notifications */ -int register_page_fault_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); -} - -int unregister_page_fault_notifier(struct notifier_block *nb) +#ifdef CONFIG_KPROBES +static inline int notify_page_fault(struct pt_regs *regs) { - return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); -} + int ret = 0; + + /* kprobe_running() needs smp_processor_id() */ + if (!user_mode(regs)) { + preempt_disable(); + if (kprobe_running() && kprobe_fault_handler(regs, 11)) + ret = 1; + preempt_enable(); + } -static inline int notify_page_fault(enum die_val val, const char *str, - struct pt_regs *regs, long err, int trap, int sig) -{ - struct die_args args = { - .regs = regs, - .str = str, - .err = err, - .trapnr = trap, - .signr = sig - }; - return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); + return ret; } #else -static inline int notify_page_fault(enum die_val val, const char *str, - struct pt_regs *regs, long err, int trap, int sig) +static inline int notify_page_fault(struct pt_regs *regs) { - return NOTIFY_DONE; + return 0; } #endif @@ -175,8 +164,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, is_write = error_code & ESR_DST; #endif /* CONFIG_4xx || CONFIG_BOOKE */ - if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs, error_code, - 11, SIGSEGV) == NOTIFY_STOP) + if (notify_page_fault(regs)) return 0; if (trap == 0x300) { diff --git a/trunk/arch/powerpc/mm/hash_native_64.c b/trunk/arch/powerpc/mm/hash_native_64.c index 79aedaf36f2b..7b7fe2d7b9dc 100644 --- a/trunk/arch/powerpc/mm/hash_native_64.c +++ b/trunk/arch/powerpc/mm/hash_native_64.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef DEBUG_LOW #define DBG_LOW(fmt...) udbg_printf(fmt) @@ -340,31 +341,70 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, local_irq_restore(flags); } -/* - * XXX This need fixing based on page size. It's only used by - * native_hpte_clear() for now which needs fixing too so they - * make a good pair... - */ -static unsigned long slot2va(unsigned long hpte_v, unsigned long slot) -{ - unsigned long avpn = HPTE_V_AVPN_VAL(hpte_v); - unsigned long va; +#define LP_SHIFT 12 +#define LP_BITS 8 +#define LP_MASK(i) ((0xFF >> (i)) << LP_SHIFT) - va = avpn << 23; +static void hpte_decode(hpte_t *hpte, unsigned long slot, + int *psize, unsigned long *va) +{ + unsigned long hpte_r = hpte->r; + unsigned long hpte_v = hpte->v; + unsigned long avpn; + int i, size, shift, penc, avpnm_bits; + + if (!(hpte_v & HPTE_V_LARGE)) + size = MMU_PAGE_4K; + else { + for (i = 0; i < LP_BITS; i++) { + if ((hpte_r & LP_MASK(i+1)) == LP_MASK(i+1)) + break; + } + penc = LP_MASK(i+1) >> LP_SHIFT; + for (size = 0; size < MMU_PAGE_COUNT; size++) { - if (! (hpte_v & HPTE_V_LARGE)) { - unsigned long vpi, pteg; + /* 4K pages are not represented by LP */ + if (size == MMU_PAGE_4K) + continue; - pteg = slot / HPTES_PER_GROUP; - if (hpte_v & HPTE_V_SECONDARY) - pteg = ~pteg; + /* valid entries have a shift value */ + if (!mmu_psize_defs[size].shift) + continue; - vpi = ((va >> 28) ^ pteg) & htab_hash_mask; + if (penc == mmu_psize_defs[size].penc) + break; + } + } - va |= vpi << PAGE_SHIFT; + /* + * FIXME, the code below works for 16M, 64K, and 4K pages as these + * fall under the p<=23 rules for calculating the virtual address. + * In the case of 16M pages, an extra bit is stolen from the AVPN + * field to achieve the requisite 24 bits. + * + * Does not work for 16G pages or 1 TB segments. + */ + shift = mmu_psize_defs[size].shift; + if (mmu_psize_defs[size].avpnm) + avpnm_bits = __ilog2_u64(mmu_psize_defs[size].avpnm) + 1; + else + avpnm_bits = 0; + if (shift - avpnm_bits <= 23) { + avpn = HPTE_V_AVPN_VAL(hpte_v) << 23; + + if (shift < 23) { + unsigned long vpi, pteg; + + pteg = slot / HPTES_PER_GROUP; + if (hpte_v & HPTE_V_SECONDARY) + pteg = ~pteg; + vpi = ((avpn >> 28) ^ pteg) & htab_hash_mask; + avpn |= (vpi << mmu_psize_defs[size].shift); + } } - return va; + *va = avpn; + *psize = size; } /* @@ -374,15 +414,14 @@ static unsigned long slot2va(unsigned long hpte_v, unsigned long slot) * * TODO: add batching support when enabled. remember, no dynamic memory here, * athough there is the control page available... - * - * XXX FIXME: 4k only for now ! */ static void native_hpte_clear(void) { unsigned long slot, slots, flags; hpte_t *hptep = htab_address; - unsigned long hpte_v; + unsigned long hpte_v, va; unsigned long pteg_count; + int psize; pteg_count = htab_hash_mask + 1; @@ -408,8 +447,9 @@ static void native_hpte_clear(void) * already hold the native_tlbie_lock. */ if (hpte_v & HPTE_V_VALID) { + hpte_decode(hptep, slot, &psize, &va); hptep->v = 0; - __tlbie(slot2va(hpte_v, slot), MMU_PAGE_4K); + __tlbie(va, psize); } } diff --git a/trunk/arch/powerpc/mm/hash_utils_64.c b/trunk/arch/powerpc/mm/hash_utils_64.c index 49618461defb..9b226fa7006f 100644 --- a/trunk/arch/powerpc/mm/hash_utils_64.c +++ b/trunk/arch/powerpc/mm/hash_utils_64.c @@ -103,7 +103,7 @@ int mmu_ci_restrictions; #ifdef CONFIG_DEBUG_PAGEALLOC static u8 *linear_map_hash_slots; static unsigned long linear_map_hash_count; -static spinlock_t linear_map_hash_lock; +static DEFINE_SPINLOCK(linear_map_hash_lock); #endif /* CONFIG_DEBUG_PAGEALLOC */ /* There are definitions of page sizes arrays to be used when none diff --git a/trunk/arch/powerpc/mm/hugetlbpage.c b/trunk/arch/powerpc/mm/hugetlbpage.c index 8508f973d9cc..fb959264c104 100644 --- a/trunk/arch/powerpc/mm/hugetlbpage.c +++ b/trunk/arch/powerpc/mm/hugetlbpage.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -566,6 +565,13 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, if (len > TASK_SIZE) return -ENOMEM; + /* handle fixed mapping: prevent overlap with huge pages */ + if (flags & MAP_FIXED) { + if (is_hugepage_only_range(mm, addr, len)) + return -EINVAL; + return addr; + } + if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); @@ -641,6 +647,13 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, if (len > TASK_SIZE) return -ENOMEM; + /* handle fixed mapping: prevent overlap with huge pages */ + if (flags & MAP_FIXED) { + if (is_hugepage_only_range(mm, addr, len)) + return -EINVAL; + return addr; + } + /* dont allow allocations above current base */ if (mm->free_area_cache > base) mm->free_area_cache = base; @@ -823,6 +836,13 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, /* Paranoia, caller should have dealt with this */ BUG_ON((addr + len) < addr); + /* Handle MAP_FIXED */ + if (flags & MAP_FIXED) { + if (prepare_hugepage_range(addr, len, pgoff)) + return -EINVAL; + return addr; + } + if (test_thread_flag(TIF_32BIT)) { curareas = current->mm->context.low_htlb_areas; @@ -1057,8 +1077,7 @@ static int __init hugetlbpage_init(void) huge_pgtable_cache = kmem_cache_create("hugepte_cache", HUGEPTE_TABLE_SIZE, HUGEPTE_TABLE_SIZE, - SLAB_HWCACHE_ALIGN | - SLAB_MUST_HWCACHE_ALIGN, + 0, zero_ctor, NULL); if (! huge_pgtable_cache) panic("hugetlbpage_init(): could not create hugepte cache\n"); diff --git a/trunk/arch/powerpc/mm/init_64.c b/trunk/arch/powerpc/mm/init_64.c index d12a87ec5ae9..fe1fe852181a 100644 --- a/trunk/arch/powerpc/mm/init_64.c +++ b/trunk/arch/powerpc/mm/init_64.c @@ -183,12 +183,8 @@ void pgtable_cache_init(void) "for size: %08x...\n", name, i, size); pgtable_cache[i] = kmem_cache_create(name, size, size, - SLAB_HWCACHE_ALIGN | - SLAB_MUST_HWCACHE_ALIGN, + SLAB_PANIC, zero_ctor, NULL); - if (! pgtable_cache[i]) - panic("pgtable_cache_init(): could not create %s!\n", - name); } } diff --git a/trunk/arch/powerpc/mm/mem.c b/trunk/arch/powerpc/mm/mem.c index c4bcd7546424..1a6e08f3298f 100644 --- a/trunk/arch/powerpc/mm/mem.c +++ b/trunk/arch/powerpc/mm/mem.c @@ -80,7 +80,6 @@ int page_is_ram(unsigned long pfn) return 0; #endif } -EXPORT_SYMBOL(page_is_ram); pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot) diff --git a/trunk/arch/powerpc/mm/mmu_decl.h b/trunk/arch/powerpc/mm/mmu_decl.h index 9c4538bb04b0..2558c34eedaa 100644 --- a/trunk/arch/powerpc/mm/mmu_decl.h +++ b/trunk/arch/powerpc/mm/mmu_decl.h @@ -40,7 +40,8 @@ extern int __map_without_bats; extern unsigned long ioremap_base; extern unsigned int rtas_data, rtas_size; -extern PTE *Hash, *Hash_end; +struct _PTE; +extern struct _PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern unsigned int num_tlbcam_entries; diff --git a/trunk/arch/powerpc/mm/pgtable_32.c b/trunk/arch/powerpc/mm/pgtable_32.c index bca560374927..d8232b7a08f7 100644 --- a/trunk/arch/powerpc/mm/pgtable_32.c +++ b/trunk/arch/powerpc/mm/pgtable_32.c @@ -261,7 +261,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags) int err = -ENOMEM; /* Use upper 10 bits of VA to index the first level map */ - pd = pmd_offset(pgd_offset_k(va), va); + pd = pmd_offset(pud_offset(pgd_offset_k(va), va), va); /* Use middle 10 bits of VA to index the second-level map */ pg = pte_alloc_kernel(pd, va); if (pg != 0) { @@ -354,23 +354,27 @@ int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp) { pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte; int retval = 0; pgd = pgd_offset(mm, addr & PAGE_MASK); if (pgd) { - pmd = pmd_offset(pgd, addr & PAGE_MASK); - if (pmd_present(*pmd)) { - pte = pte_offset_map(pmd, addr & PAGE_MASK); - if (pte) { - retval = 1; - *ptep = pte; - if (pmdp) - *pmdp = pmd; - /* XXX caller needs to do pte_unmap, yuck */ - } - } + pud = pud_offset(pgd, addr & PAGE_MASK); + if (pud && pud_present(*pud)) { + pmd = pmd_offset(pud, addr & PAGE_MASK); + if (pmd_present(*pmd)) { + pte = pte_offset_map(pmd, addr & PAGE_MASK); + if (pte) { + retval = 1; + *ptep = pte; + if (pmdp) + *pmdp = pmd; + /* XXX caller needs to do pte_unmap, yuck */ + } + } + } } return(retval); } diff --git a/trunk/arch/powerpc/mm/stab.c b/trunk/arch/powerpc/mm/stab.c index eeeacab548e6..132c6bc66ce1 100644 --- a/trunk/arch/powerpc/mm/stab.c +++ b/trunk/arch/powerpc/mm/stab.c @@ -227,7 +227,7 @@ void switch_stab(struct task_struct *tsk, struct mm_struct *mm) * the first (bolted) segment, so that do_stab_bolted won't get a * recursive segment miss on the segment table itself. */ -void stabs_alloc(void) +void __init stabs_alloc(void) { int cpu; diff --git a/trunk/arch/powerpc/platforms/44x/44x.h b/trunk/arch/powerpc/platforms/44x/44x.h new file mode 100644 index 000000000000..42eabf87fea3 --- /dev/null +++ b/trunk/arch/powerpc/platforms/44x/44x.h @@ -0,0 +1,8 @@ +#ifndef __POWERPC_PLATFORMS_44X_44X_H +#define __POWERPC_PLATFORMS_44X_44X_H + +extern u8 as1_readb(volatile u8 __iomem *addr); +extern void as1_writeb(u8 data, volatile u8 __iomem *addr); +extern void ppc44x_reset_system(char *cmd); + +#endif /* __POWERPC_PLATFORMS_44X_44X_H */ diff --git a/trunk/arch/powerpc/platforms/44x/Kconfig b/trunk/arch/powerpc/platforms/44x/Kconfig new file mode 100644 index 000000000000..8e66949e7c67 --- /dev/null +++ b/trunk/arch/powerpc/platforms/44x/Kconfig @@ -0,0 +1,56 @@ +#config BAMBOO +# bool "Bamboo" +# depends on 44x +# default n +# select 440EP +# help +# This option enables support for the IBM PPC440EP evaluation board. + +config EBONY + bool "Ebony" + depends on 44x + default y + select 440GP + help + This option enables support for the IBM PPC440GP evaluation board. + +#config LUAN +# bool "Luan" +# depends on 44x +# default n +# select 440SP +# help +# This option enables support for the IBM PPC440SP evaluation board. + +#config OCOTEA +# bool "Ocotea" +# depends on 44x +# default n +# select 440GX +# help +# This option enables support for the IBM PPC440GX evaluation board. + +# 44x specific CPU modules, selected based on the board above. +config 440EP + bool + select PPC_FPU + select IBM440EP_ERR42 + +config 440GP + bool + select IBM_NEW_EMAC_ZMII + +config 440GX + bool + +config 440SP + bool + +config 440A + bool + depends on 440GX + default y + +# 44x errata/workaround config symbols, selected by the CPU models above +config IBM440EP_ERR42 + bool diff --git a/trunk/arch/powerpc/platforms/44x/Makefile b/trunk/arch/powerpc/platforms/44x/Makefile new file mode 100644 index 000000000000..41d0a18a0e44 --- /dev/null +++ b/trunk/arch/powerpc/platforms/44x/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_44x) := misc_44x.o +obj-$(CONFIG_EBONY) += ebony.o diff --git a/trunk/arch/powerpc/platforms/44x/ebony.c b/trunk/arch/powerpc/platforms/44x/ebony.c new file mode 100644 index 000000000000..ad526eafc90b --- /dev/null +++ b/trunk/arch/powerpc/platforms/44x/ebony.c @@ -0,0 +1,73 @@ +/* + * Ebony board specific routines + * + * Matt Porter + * Copyright 2002-2005 MontaVista Software Inc. + * + * Eugene Surovegin or + * Copyright (c) 2003-2005 Zultys Technologies + * + * Rewritten and ported to the merged powerpc tree: + * Copyright 2007 David Gibson , 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "44x.h" + +static struct of_device_id ebony_of_bus[] = { + { .type = "ibm,plb", }, + { .type = "ibm,opb", }, + { .type = "ibm,ebc", }, + {}, +}; + +static int __init ebony_device_probe(void) +{ + if (!machine_is(ebony)) + return 0; + + of_platform_bus_probe(NULL, ebony_of_bus, NULL); + + return 0; +} +device_initcall(ebony_device_probe); + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init ebony_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "ibm,ebony")) + return 0; + + return 1; +} + +static void __init ebony_setup_arch(void) +{ +} + +define_machine(ebony) { + .name = "Ebony", + .probe = ebony_probe, + .setup_arch = ebony_setup_arch, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .restart = ppc44x_reset_system, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/trunk/arch/powerpc/platforms/44x/misc_44x.S b/trunk/arch/powerpc/platforms/44x/misc_44x.S new file mode 100644 index 000000000000..3bce71d5d756 --- /dev/null +++ b/trunk/arch/powerpc/platforms/44x/misc_44x.S @@ -0,0 +1,57 @@ +/* + * This file contains miscellaneous low-level functions for PPC 44x. + * Copyright 2007 David Gibson , 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; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include + + .text + +/* + * Do an IO access in AS1 + */ +_GLOBAL(as1_readb) + mfmsr r7 + ori r0,r7,MSR_DS + sync + mtmsr r0 + sync + isync + lbz r3,0(r3) + sync + mtmsr r7 + sync + isync + blr + +_GLOBAL(as1_writeb) + mfmsr r7 + ori r0,r7,MSR_DS + sync + mtmsr r0 + sync + isync + stb r3,0(r4) + sync + mtmsr r7 + sync + isync + blr + +/* + * void ppc44x_reset_system(char *cmd) + * + * At present, this routine just applies a system reset. + */ +_GLOBAL(ppc44x_reset_system) + mfspr r13,SPRN_DBCR0 + oris r13,r13,DBCR0_RST_SYSTEM@h + mtspr SPRN_DBCR0,r13 + b . /* Just in case the reset doesn't work */ diff --git a/trunk/arch/powerpc/platforms/52xx/Kconfig b/trunk/arch/powerpc/platforms/52xx/Kconfig index bc4aa4a80a12..3ffaa066c2c8 100644 --- a/trunk/arch/powerpc/platforms/52xx/Kconfig +++ b/trunk/arch/powerpc/platforms/52xx/Kconfig @@ -1,5 +1,6 @@ config PPC_MPC52xx bool + select FSL_SOC default n config PPC_MPC5200 diff --git a/trunk/arch/powerpc/platforms/52xx/Makefile b/trunk/arch/powerpc/platforms/52xx/Makefile index 07cdbcacf156..b91e39c84d46 100644 --- a/trunk/arch/powerpc/platforms/52xx/Makefile +++ b/trunk/arch/powerpc/platforms/52xx/Makefile @@ -8,3 +8,5 @@ endif obj-$(CONFIG_PPC_EFIKA) += efika.o obj-$(CONFIG_PPC_LITE5200) += lite5200.o + +obj-$(CONFIG_PM) += mpc52xx_sleep.o mpc52xx_pm.o diff --git a/trunk/arch/powerpc/platforms/52xx/efika.c b/trunk/arch/powerpc/platforms/52xx/efika.c index a6bba97314eb..f591a9fc19b9 100644 --- a/trunk/arch/powerpc/platforms/52xx/efika.c +++ b/trunk/arch/powerpc/platforms/52xx/efika.c @@ -184,6 +184,16 @@ static void efika_show_cpuinfo(struct seq_file *m) of_node_put(root); } +#ifdef CONFIG_PM +static void efika_suspend_prepare(void __iomem *mbar) +{ + u8 pin = 4; /* GPIO_WKUP_4 (GPIO_PSC6_0 - IRDA_RX) */ + u8 level = 1; /* wakeup on high level */ + /* IOW. to wake it up, short pins 1 and 3 on IRDA connector */ + mpc52xx_set_wakeup_gpio(pin, level); +} +#endif + static void __init efika_setup_arch(void) { rtas_initialize(); @@ -199,6 +209,11 @@ static void __init efika_setup_arch(void) efika_pcisetup(); +#ifdef CONFIG_PM + mpc52xx_suspend.board_suspend_prepare = efika_suspend_prepare; + mpc52xx_pm_init(); +#endif + if (ppc_md.progress) ppc_md.progress("Linux/PPC " UTS_RELEASE " running on Efika ;-)\n", 0x0); } diff --git a/trunk/arch/powerpc/platforms/52xx/lite5200.c b/trunk/arch/powerpc/platforms/52xx/lite5200.c index 8e2646ac417b..1cfc00dfb99a 100644 --- a/trunk/arch/powerpc/platforms/52xx/lite5200.c +++ b/trunk/arch/powerpc/platforms/52xx/lite5200.c @@ -85,6 +85,28 @@ lite5200_setup_cpu(void) iounmap(gpio); } +#ifdef CONFIG_PM +static u32 descr_a; +static void lite5200_suspend_prepare(void __iomem *mbar) +{ + u8 pin = 1; /* GPIO_WKUP_1 (GPIO_PSC2_4) */ + u8 level = 0; /* wakeup on low level */ + mpc52xx_set_wakeup_gpio(pin, level); + + /* + * power down usb port + * this needs to be called before of-ohci suspend code + */ + descr_a = in_be32(mbar + 0x1048); + out_be32(mbar + 0x1048, (descr_a & ~0x200) | 0x100); +} + +static void lite5200_resume_finish(void __iomem *mbar) +{ + out_be32(mbar + 0x1048, descr_a); +} +#endif + static void __init lite5200_setup_arch(void) { struct device_node *np; @@ -107,6 +129,12 @@ static void __init lite5200_setup_arch(void) mpc52xx_setup_cpu(); /* Generic */ lite5200_setup_cpu(); /* Platorm specific */ +#ifdef CONFIG_PM + mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare; + mpc52xx_suspend.board_resume_finish = lite5200_resume_finish; + mpc52xx_pm_init(); +#endif + #ifdef CONFIG_PCI np = of_find_node_by_type(NULL, "pci"); if (np) { diff --git a/trunk/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/trunk/arch/powerpc/platforms/52xx/mpc52xx_pm.c new file mode 100644 index 000000000000..fd40044d16cd --- /dev/null +++ b/trunk/arch/powerpc/platforms/52xx/mpc52xx_pm.c @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include + +#include "mpc52xx_pic.h" + + +/* these are defined in mpc52xx_sleep.S, and only used here */ +extern void mpc52xx_deep_sleep(void *sram, void *sdram_regs, + struct mpc52xx_cdm *, struct mpc52xx_intr *); +extern void mpc52xx_ds_sram(void); +extern const long mpc52xx_ds_sram_size; +extern void mpc52xx_ds_cached(void); +extern const long mpc52xx_ds_cached_size; + +static void __iomem *mbar; +static void __iomem *sdram; +static struct mpc52xx_cdm __iomem *cdm; +static struct mpc52xx_intr __iomem *intr; +static struct mpc52xx_gpio_wkup __iomem *gpiow; +static void *sram; +static int sram_size; + +struct mpc52xx_suspend mpc52xx_suspend; + +static int mpc52xx_pm_valid(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + return 1; + default: + return 0; + } +} + +int mpc52xx_set_wakeup_gpio(u8 pin, u8 level) +{ + u16 tmp; + + /* enable gpio */ + out_8(&gpiow->wkup_gpioe, in_8(&gpiow->wkup_gpioe) | (1 << pin)); + /* set as input */ + out_8(&gpiow->wkup_ddr, in_8(&gpiow->wkup_ddr) & ~(1 << pin)); + /* enable deep sleep interrupt */ + out_8(&gpiow->wkup_inten, in_8(&gpiow->wkup_inten) | (1 << pin)); + /* low/high level creates wakeup interrupt */ + tmp = in_be16(&gpiow->wkup_itype); + tmp &= ~(0x3 << (pin * 2)); + tmp |= (!level + 1) << (pin * 2); + out_be16(&gpiow->wkup_itype, tmp); + /* master enable */ + out_8(&gpiow->wkup_maste, 1); + + return 0; +} + +int mpc52xx_pm_prepare(suspend_state_t state) +{ + if (state != PM_SUSPEND_STANDBY) + return -EINVAL; + + /* map the whole register space */ + mbar = mpc52xx_find_and_map("mpc5200"); + if (!mbar) { + printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); + return -ENOSYS; + } + /* these offsets are from mpc5200 users manual */ + sdram = mbar + 0x100; + cdm = mbar + 0x200; + intr = mbar + 0x500; + gpiow = mbar + 0xc00; + sram = mbar + 0x8000; /* Those will be handled by the */ + sram_size = 0x4000; /* bestcomm driver soon */ + + /* call board suspend code, if applicable */ + if (mpc52xx_suspend.board_suspend_prepare) + mpc52xx_suspend.board_suspend_prepare(mbar); + else { + printk(KERN_ALERT "%s: %i don't know how to wake up the board\n", + __func__, __LINE__); + goto out_unmap; + } + + return 0; + + out_unmap: + iounmap(mbar); + return -ENOSYS; +} + + +char saved_sram[0x4000]; + +int mpc52xx_pm_enter(suspend_state_t state) +{ + u32 clk_enables; + u32 msr, hid0; + u32 intr_main_mask; + void __iomem * irq_0x500 = (void *)CONFIG_KERNEL_START + 0x500; + unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size; + char saved_0x500[mpc52xx_ds_cached_size]; + + /* disable all interrupts in PIC */ + intr_main_mask = in_be32(&intr->main_mask); + out_be32(&intr->main_mask, intr_main_mask | 0x1ffff); + + /* don't let DEC expire any time soon */ + mtspr(SPRN_DEC, 0x7fffffff); + + /* save SRAM */ + memcpy(saved_sram, sram, sram_size); + + /* copy low level suspend code to sram */ + memcpy(sram, mpc52xx_ds_sram, mpc52xx_ds_sram_size); + + out_8(&cdm->ccs_sleep_enable, 1); + out_8(&cdm->osc_sleep_enable, 1); + out_8(&cdm->ccs_qreq_test, 1); + + /* disable all but SDRAM and bestcomm (SRAM) clocks */ + clk_enables = in_be32(&cdm->clk_enables); + out_be32(&cdm->clk_enables, clk_enables & 0x00088000); + + /* disable power management */ + msr = mfmsr(); + mtmsr(msr & ~MSR_POW); + + /* enable sleep mode, disable others */ + hid0 = mfspr(SPRN_HID0); + mtspr(SPRN_HID0, (hid0 & ~(HID0_DOZE | HID0_NAP | HID0_DPM)) | HID0_SLEEP); + + /* save original, copy our irq handler, flush from dcache and invalidate icache */ + memcpy(saved_0x500, irq_0x500, mpc52xx_ds_cached_size); + memcpy(irq_0x500, mpc52xx_ds_cached, mpc52xx_ds_cached_size); + flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop); + + /* call low-level sleep code */ + mpc52xx_deep_sleep(sram, sdram, cdm, intr); + + /* restore original irq handler */ + memcpy(irq_0x500, saved_0x500, mpc52xx_ds_cached_size); + flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop); + + /* restore old power mode */ + mtmsr(msr & ~MSR_POW); + mtspr(SPRN_HID0, hid0); + mtmsr(msr); + + out_be32(&cdm->clk_enables, clk_enables); + out_8(&cdm->ccs_sleep_enable, 0); + out_8(&cdm->osc_sleep_enable, 0); + + /* restore SRAM */ + memcpy(sram, saved_sram, sram_size); + + /* restart jiffies */ + wakeup_decrementer(); + + /* reenable interrupts in PIC */ + out_be32(&intr->main_mask, intr_main_mask); + + return 0; +} + +int mpc52xx_pm_finish(suspend_state_t state) +{ + /* call board resume code */ + if (mpc52xx_suspend.board_resume_finish) + mpc52xx_suspend.board_resume_finish(mbar); + + iounmap(mbar); + + return 0; +} + +static struct pm_ops mpc52xx_pm_ops = { + .valid = mpc52xx_pm_valid, + .prepare = mpc52xx_pm_prepare, + .enter = mpc52xx_pm_enter, + .finish = mpc52xx_pm_finish, +}; + +int __init mpc52xx_pm_init(void) +{ + pm_set_ops(&mpc52xx_pm_ops); + return 0; +} diff --git a/trunk/arch/powerpc/platforms/52xx/mpc52xx_sleep.S b/trunk/arch/powerpc/platforms/52xx/mpc52xx_sleep.S new file mode 100644 index 000000000000..4dc170b0ae18 --- /dev/null +++ b/trunk/arch/powerpc/platforms/52xx/mpc52xx_sleep.S @@ -0,0 +1,154 @@ +#include +#include +#include + + +.text + +_GLOBAL(mpc52xx_deep_sleep) +mpc52xx_deep_sleep: /* args r3-r6: SRAM, SDRAM regs, CDM regs, INTR regs */ + + /* enable interrupts */ + mfmsr r7 + ori r7, r7, 0x8000 /* EE */ + mtmsr r7 + sync; isync; + + li r10, 0 /* flag that irq handler sets */ + + /* enable tmr7 (or any other) interrupt */ + lwz r8, 0x14(r6) /* intr->main_mask */ + ori r8, r8, 0x1 + xori r8, r8, 0x1 + stw r8, 0x14(r6) + sync + + /* emulate tmr7 interrupt */ + li r8, 0x1 + stw r8, 0x40(r6) /* intr->main_emulate */ + sync + + /* wait for it to happen */ +1: + cmpi cr0, r10, 1 + bne cr0, 1b + + /* lock icache */ + mfspr r10, SPRN_HID0 + ori r10, r10, 0x2000 + sync; isync; + mtspr SPRN_HID0, r10 + sync; isync; + + + mflr r9 /* save LR */ + + /* jump to sram */ + mtlr r3 + blrl + + mtlr r9 /* restore LR */ + + /* unlock icache */ + mfspr r10, SPRN_HID0 + ori r10, r10, 0x2000 + xori r10, r10, 0x2000 + sync; isync; + mtspr SPRN_HID0, r10 + sync; isync; + + + /* return to C code */ + blr + + +_GLOBAL(mpc52xx_ds_sram) +mpc52xx_ds_sram: + /* put SDRAM into self-refresh */ + lwz r8, 0x4(r4) /* sdram->ctrl */ + + oris r8, r8, 0x8000 /* mode_en */ + stw r8, 0x4(r4) + sync + + ori r8, r8, 0x0002 /* soft_pre */ + stw r8, 0x4(r4) + sync + xori r8, r8, 0x0002 + + xoris r8, r8, 0x8000 /* !mode_en */ + stw r8, 0x4(r4) + sync + + oris r8, r8, 0x5000 + xoris r8, r8, 0x4000 /* ref_en !cke */ + stw r8, 0x4(r4) + sync + + /* disable SDRAM clock */ + lwz r8, 0x14(r5) /* cdm->clkenable */ + ori r8, r8, 0x0008 + xori r8, r8, 0x0008 + stw r8, 0x14(r5) + sync + + + /* put mpc5200 to sleep */ + mfmsr r10 + oris r10, r10, 0x0004 /* POW = 1 */ + sync; isync; + mtmsr r10 + sync; isync; + + + /* enable clock */ + lwz r8, 0x14(r5) + ori r8, r8, 0x0008 + stw r8, 0x14(r5) + sync + + /* get ram out of self-refresh */ + lwz r8, 0x4(r4) + oris r8, r8, 0x5000 /* cke ref_en */ + stw r8, 0x4(r4) + sync + + blr +_GLOBAL(mpc52xx_ds_sram_size) +mpc52xx_ds_sram_size: + .long $-mpc52xx_ds_sram + + +/* ### interrupt handler for wakeup from deep-sleep ### */ +_GLOBAL(mpc52xx_ds_cached) +mpc52xx_ds_cached: + mtspr SPRN_SPRG0, r7 + mtspr SPRN_SPRG1, r8 + + /* disable emulated interrupt */ + mfspr r7, 311 /* MBAR */ + addi r7, r7, 0x540 /* intr->main_emul */ + li r8, 0 + stw r8, 0(r7) + sync + dcbf 0, r7 + + /* acknowledge wakeup, so CCS releases power pown */ + mfspr r7, 311 /* MBAR */ + addi r7, r7, 0x524 /* intr->enc_status */ + lwz r8, 0(r7) + ori r8, r8, 0x0400 + stw r8, 0(r7) + sync + dcbf 0, r7 + + /* flag - we handled the interrupt */ + li r10, 1 + + mfspr r8, SPRN_SPRG1 + mfspr r7, SPRN_SPRG0 + + rfi +_GLOBAL(mpc52xx_ds_cached_size) +mpc52xx_ds_cached_size: + .long $-mpc52xx_ds_cached diff --git a/trunk/arch/powerpc/platforms/83xx/mpc832x_mds.c b/trunk/arch/powerpc/platforms/83xx/mpc832x_mds.c index fff09f5d6edf..94843ed52a93 100644 --- a/trunk/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/trunk/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -111,6 +111,7 @@ static struct of_device_id mpc832x_ids[] = { { .type = "soc", }, { .compatible = "soc", }, { .type = "qe", }, + { .type = "mdio", }, {}, }; diff --git a/trunk/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/trunk/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 6b71e9ffb11a..b0b22bb29de7 100644 --- a/trunk/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/trunk/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -73,6 +73,7 @@ static struct of_device_id mpc832x_ids[] = { { .type = "soc", }, { .compatible = "soc", }, { .type = "qe", }, + { .type = "mdio", }, {}, }; diff --git a/trunk/arch/powerpc/platforms/83xx/mpc836x_mds.c b/trunk/arch/powerpc/platforms/83xx/mpc836x_mds.c index 526ed090a446..bceeff8bbfd2 100644 --- a/trunk/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/trunk/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -118,6 +118,7 @@ static struct of_device_id mpc836x_ids[] = { { .type = "soc", }, { .compatible = "soc", }, { .type = "qe", }, + { .type = "mdio", }, {}, }; diff --git a/trunk/arch/powerpc/platforms/85xx/mpc8544_ds.c b/trunk/arch/powerpc/platforms/85xx/mpc8544_ds.c index 2867f85e6325..bec84ffe708e 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc8544_ds.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc8544_ds.c @@ -84,7 +84,7 @@ void __init mpc8544_ds_pic_init(void) #ifdef CONFIG_PPC_I8259 /* Initialize the i8259 controller */ for_each_node_by_type(np, "interrupt-controller") - if (device_is_compatible(np, "chrp,iic")) { + if (of_device_is_compatible(np, "chrp,iic")) { cascade_node = np; break; } diff --git a/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 7e71636f9098..1490eb3ce0d3 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -197,7 +197,7 @@ static void __init mpc85xx_cds_pic_init(void) #ifdef CONFIG_PPC_I8259 /* Initialize the i8259 controller */ for_each_node_by_type(np, "interrupt-controller") - if (device_is_compatible(np, "chrp,iic")) { + if (of_device_is_compatible(np, "chrp,iic")) { cascade_node = np; break; } diff --git a/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 54db41689954..e3dddbfe66ff 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -147,6 +147,7 @@ static struct of_device_id mpc85xx_ids[] = { { .type = "soc", }, { .compatible = "soc", }, { .type = "qe", }, + { .type = "mdio", }, {}, }; diff --git a/trunk/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/trunk/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 3d3d98f5bd4a..90877565caa3 100644 --- a/trunk/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/trunk/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -102,7 +102,7 @@ mpc86xx_hpcn_init_irq(void) #ifdef CONFIG_PCI /* Initialize i8259 controller */ for_each_node_by_type(np, "interrupt-controller") - if (device_is_compatible(np, "chrp,iic")) { + if (of_device_is_compatible(np, "chrp,iic")) { cascade_node = np; break; } diff --git a/trunk/arch/powerpc/platforms/Kconfig b/trunk/arch/powerpc/platforms/Kconfig index 51e33347c147..361acfa2894c 100644 --- a/trunk/arch/powerpc/platforms/Kconfig +++ b/trunk/arch/powerpc/platforms/Kconfig @@ -42,6 +42,7 @@ source "arch/powerpc/platforms/83xx/Kconfig" source "arch/powerpc/platforms/85xx/Kconfig" source "arch/powerpc/platforms/86xx/Kconfig" source "arch/powerpc/platforms/embedded6xx/Kconfig" +source "arch/powerpc/platforms/44x/Kconfig" #source "arch/powerpc/platforms/4xx/Kconfig config PPC_NATIVE diff --git a/trunk/arch/powerpc/platforms/Makefile b/trunk/arch/powerpc/platforms/Makefile index 452004283f17..d6e041a46d25 100644 --- a/trunk/arch/powerpc/platforms/Makefile +++ b/trunk/arch/powerpc/platforms/Makefile @@ -6,7 +6,8 @@ obj-$(CONFIG_PPC_PMAC) += powermac/ endif endif obj-$(CONFIG_PPC_CHRP) += chrp/ -obj-$(CONFIG_4xx) += 4xx/ +#obj-$(CONFIG_4xx) += 4xx/ +obj-$(CONFIG_44x) += 44x/ obj-$(CONFIG_PPC_MPC52xx) += 52xx/ obj-$(CONFIG_PPC_8xx) += 8xx/ obj-$(CONFIG_PPC_82xx) += 82xx/ diff --git a/trunk/arch/powerpc/platforms/cell/interrupt.c b/trunk/arch/powerpc/platforms/cell/interrupt.c index 4fc4e92775d0..47264e722029 100644 --- a/trunk/arch/powerpc/platforms/cell/interrupt.c +++ b/trunk/arch/powerpc/platforms/cell/interrupt.c @@ -227,7 +227,7 @@ void iic_request_IPIs(void) static int iic_host_match(struct irq_host *h, struct device_node *node) { - return device_is_compatible(node, + return of_device_is_compatible(node, "IBM,CBEA-Internal-Interrupt-Controller"); } @@ -256,7 +256,7 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct, unsigned int node, ext, unit, class; const u32 *val; - if (!device_is_compatible(ct, + if (!of_device_is_compatible(ct, "IBM,CBEA-Internal-Interrupt-Controller")) return -ENODEV; if (intsize != 1) @@ -324,7 +324,7 @@ static int __init setup_iic(void) for (dn = NULL; (dn = of_find_node_by_name(dn,"interrupt-controller")) != NULL;) { - if (!device_is_compatible(dn, + if (!of_device_is_compatible(dn, "IBM,CBEA-Internal-Interrupt-Controller")) continue; np = of_get_property(dn, "ibm,interrupt-server-ranges", NULL); diff --git a/trunk/arch/powerpc/platforms/cell/setup.c b/trunk/arch/powerpc/platforms/cell/setup.c index 54b96183cb64..db6654272e13 100644 --- a/trunk/arch/powerpc/platforms/cell/setup.c +++ b/trunk/arch/powerpc/platforms/cell/setup.c @@ -112,7 +112,7 @@ static void __init mpic_init_IRQ(void) for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) { - if (!device_is_compatible(dn, "CBEA,platform-open-pic")) + if (!of_device_is_compatible(dn, "CBEA,platform-open-pic")) continue; /* The MPIC driver will get everything it needs from the diff --git a/trunk/arch/powerpc/platforms/cell/spider-pic.c b/trunk/arch/powerpc/platforms/cell/spider-pic.c index fb1f15797bbb..05f4b3d3d756 100644 --- a/trunk/arch/powerpc/platforms/cell/spider-pic.c +++ b/trunk/arch/powerpc/platforms/cell/spider-pic.c @@ -358,12 +358,12 @@ void __init spider_init_IRQ(void) */ for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) { - if (device_is_compatible(dn, "CBEA,platform-spider-pic")) { + if (of_device_is_compatible(dn, "CBEA,platform-spider-pic")) { if (of_address_to_resource(dn, 0, &r)) { printk(KERN_WARNING "spider-pic: Failed\n"); continue; } - } else if (device_is_compatible(dn, "sti,platform-spider-pic") + } else if (of_device_is_compatible(dn, "sti,platform-spider-pic") && (chip < 2)) { static long hard_coded_pics[] = { 0x24000008000ul, 0x34000008000ul}; diff --git a/trunk/arch/powerpc/platforms/cell/spufs/backing_ops.c b/trunk/arch/powerpc/platforms/cell/spufs/backing_ops.c index 3322528fa6eb..d32db9ffc6eb 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/backing_ops.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/backing_ops.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/powerpc/platforms/cell/spufs/hw_ops.c b/trunk/arch/powerpc/platforms/cell/spufs/hw_ops.c index 428875c5e4ec..fc4ed1ffbd4f 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/hw_ops.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/hw_ops.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/powerpc/platforms/cell/spufs/inode.c b/trunk/arch/powerpc/platforms/cell/spufs/inode.c index 13e4f70ec8c0..a93f328a7317 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/inode.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/inode.c @@ -71,8 +71,7 @@ spufs_init_once(void *p, struct kmem_cache * cachep, unsigned long flags) { struct spufs_inode_info *ei = p; - if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == - SLAB_CTOR_CONSTRUCTOR) { + if (flags & SLAB_CTOR_CONSTRUCTOR) { inode_init_once(&ei->vfs_inode); } } diff --git a/trunk/arch/powerpc/platforms/cell/spufs/sched.c b/trunk/arch/powerpc/platforms/cell/spufs/sched.c index 91030b8abdca..b6ecb30e7d58 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/sched.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/sched.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/powerpc/platforms/cell/spufs/switch.c b/trunk/arch/powerpc/platforms/cell/spufs/switch.c index 8347c4a3f894..29dc59cefc38 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/switch.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/switch.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/powerpc/platforms/chrp/pci.c b/trunk/arch/powerpc/platforms/chrp/pci.c index 1469d6478f67..d32fedc991d3 100644 --- a/trunk/arch/powerpc/platforms/chrp/pci.c +++ b/trunk/arch/powerpc/platforms/chrp/pci.c @@ -267,7 +267,7 @@ chrp_find_bridges(void) model = of_get_property(dev, "model", NULL); if (model == NULL) model = ""; - if (device_is_compatible(dev, "IBM,python")) { + if (of_device_is_compatible(dev, "IBM,python")) { setup_python(hose, dev); } else if (is_mot || strncmp(model, "Motorola, Grackle", 17) == 0) { diff --git a/trunk/arch/powerpc/platforms/chrp/setup.c b/trunk/arch/powerpc/platforms/chrp/setup.c index 1870038a8e0a..373de4c063db 100644 --- a/trunk/arch/powerpc/platforms/chrp/setup.c +++ b/trunk/arch/powerpc/platforms/chrp/setup.c @@ -448,7 +448,7 @@ static void __init chrp_find_8259(void) /* Look for cascade */ for_each_node_by_type(np, "interrupt-controller") - if (device_is_compatible(np, "chrp,iic")) { + if (of_device_is_compatible(np, "chrp,iic")) { pic = np; break; } diff --git a/trunk/arch/powerpc/platforms/chrp/smp.c b/trunk/arch/powerpc/platforms/chrp/smp.c index 1d2307e87c30..3ea0eb78568e 100644 --- a/trunk/arch/powerpc/platforms/chrp/smp.c +++ b/trunk/arch/powerpc/platforms/chrp/smp.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/powerpc/platforms/embedded6xx/Kconfig b/trunk/arch/powerpc/platforms/embedded6xx/Kconfig index 9557908ef545..8f3c2a73e165 100644 --- a/trunk/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/trunk/arch/powerpc/platforms/embedded6xx/Kconfig @@ -20,16 +20,24 @@ config MPC7448HPC2 select TSI108_BRIDGE select DEFAULT_UIMAGE select PPC_UDBG_16550 - select MPIC - select MPIC_WEIRD help Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga) platform + +config PPC_HOLLY + bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)" + select TSI108_BRIDGE + select PPC_UDBG_16550 + help + Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval + Board with TSI108/9 bridge (Hickory/Holly) endchoice config TSI108_BRIDGE bool - depends on MPC7448HPC2 + depends on MPC7448HPC2 || PPC_HOLLY + select MPIC + select MPIC_WEIRD default y config MPC10X_BRIDGE diff --git a/trunk/arch/powerpc/platforms/embedded6xx/Makefile b/trunk/arch/powerpc/platforms/embedded6xx/Makefile index d3d11a3cd656..b39fe4f470d5 100644 --- a/trunk/arch/powerpc/platforms/embedded6xx/Makefile +++ b/trunk/arch/powerpc/platforms/embedded6xx/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_MPC7448HPC2) += mpc7448_hpc2.o obj-$(CONFIG_LINKSTATION) += linkstation.o ls_uart.o +obj-$(CONFIG_PPC_HOLLY) += holly.o diff --git a/trunk/arch/powerpc/platforms/embedded6xx/holly.c b/trunk/arch/powerpc/platforms/embedded6xx/holly.c new file mode 100644 index 000000000000..3a0b4a01401c --- /dev/null +++ b/trunk/arch/powerpc/platforms/embedded6xx/holly.c @@ -0,0 +1,317 @@ +/* + * Board setup routines for the IBM 750GX/CL platform w/ TSI10x bridge + * + * Copyright 2007 IBM Corporation + * + * Stephen Winiecki + * Josh Boyer + * + * Based on code from mpc7448_hpc2.c + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +#define HOLLY_PCI_CFG_PHYS 0x7c000000 + +int holly_exclude_device(u_char bus, u_char devfn) +{ + if (bus == 0 && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} + +static void holly_remap_bridge(void) +{ + u32 lut_val, lut_addr; + int i; + + printk(KERN_INFO "Remapping PCI bridge\n"); + + /* Re-init the PCI bridge and LUT registers to have mappings that don't + * rely on PIBS + */ + lut_addr = 0x900; + for (i = 0; i < 31; i++) { + tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x00000201); + lut_addr += 4; + tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x0); + lut_addr += 4; + } + + /* Reserve the last LUT entry for PCI I/O space */ + tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x00000241); + lut_addr += 4; + tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x0); + + /* Map PCI I/O space */ + tsi108_write_reg(TSI108_PCI_PFAB_IO_UPPER, 0x0); + tsi108_write_reg(TSI108_PCI_PFAB_IO, 0x1); + + /* Map PCI CFG space */ + tsi108_write_reg(TSI108_PCI_PFAB_BAR0_UPPER, 0x0); + tsi108_write_reg(TSI108_PCI_PFAB_BAR0, 0x7c000000 | 0x01); + + /* We don't need MEM32 and PRM remapping so disable them */ + tsi108_write_reg(TSI108_PCI_PFAB_MEM32, 0x0); + tsi108_write_reg(TSI108_PCI_PFAB_PFM3, 0x0); + tsi108_write_reg(TSI108_PCI_PFAB_PFM4, 0x0); + + /* Set P2O_BAR0 */ + tsi108_write_reg(TSI108_PCI_P2O_BAR0_UPPER, 0x0); + tsi108_write_reg(TSI108_PCI_P2O_BAR0, 0xc0000000); + + /* Init the PCI LUTs to do no remapping */ + lut_addr = 0x500; + lut_val = 0x00000002; + + for (i = 0; i < 32; i++) { + tsi108_write_reg(TSI108_PCI_OFFSET + lut_addr, lut_val); + lut_addr += 4; + tsi108_write_reg(TSI108_PCI_OFFSET + lut_addr, 0x40000000); + lut_addr += 4; + lut_val += 0x02000000; + } + tsi108_write_reg(TSI108_PCI_P2O_PAGE_SIZES, 0x00007900); + + /* Set 64-bit PCI bus address for system memory */ + tsi108_write_reg(TSI108_PCI_P2O_BAR2_UPPER, 0x0); + tsi108_write_reg(TSI108_PCI_P2O_BAR2, 0x0); +} + +static void __init holly_setup_arch(void) +{ + struct device_node *cpu; + struct device_node *np; + + if (ppc_md.progress) + ppc_md.progress("holly_setup_arch():set_bridge", 0); + + cpu = of_find_node_by_type(NULL, "cpu"); + if (cpu) { + const unsigned int *fp; + + fp = of_get_property(cpu, "clock-frequency", NULL); + if (fp) + loops_per_jiffy = *fp / HZ; + else + loops_per_jiffy = 50000000 / HZ; + of_node_put(cpu); + } + tsi108_csr_vir_base = get_vir_csrbase(); + + /* setup PCI host bridge */ + holly_remap_bridge(); + + np = of_find_node_by_type(NULL, "pci"); + if (np) + tsi108_setup_pci(np, HOLLY_PCI_CFG_PHYS, 1); + + ppc_md.pci_exclude_device = holly_exclude_device; + if (ppc_md.progress) + ppc_md.progress("tsi108: resources set", 0x100); + + printk(KERN_INFO "PPC750GX/CL Platform\n"); +} + +/* + * Interrupt setup and service. Interrrupts on the holly come + * from the four external INT pins, PCI interrupts are routed via + * PCI interrupt control registers, it generates internal IRQ23 + * + * Interrupt routing on the Holly Board: + * TSI108:PB_INT[0] -> CPU0:INT# + * TSI108:PB_INT[1] -> CPU0:MCP# + * TSI108:PB_INT[2] -> N/C + * TSI108:PB_INT[3] -> N/C + */ +static void __init holly_init_IRQ(void) +{ + struct mpic *mpic; + phys_addr_t mpic_paddr = 0; + struct device_node *tsi_pic; +#ifdef CONFIG_PCI + unsigned int cascade_pci_irq; + struct device_node *tsi_pci; + struct device_node *cascade_node = NULL; +#endif + + tsi_pic = of_find_node_by_type(NULL, "open-pic"); + if (tsi_pic) { + unsigned int size; + const void *prop = of_get_property(tsi_pic, "reg", &size); + mpic_paddr = of_translate_address(tsi_pic, prop); + } + + if (mpic_paddr == 0) { + printk(KERN_ERR "%s: No tsi108 PIC found !\n", __func__); + return; + } + + pr_debug("%s: tsi108 pic phys_addr = 0x%x\n", __func__, (u32) mpic_paddr); + + mpic = mpic_alloc(tsi_pic, mpic_paddr, + MPIC_PRIMARY | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | + MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, + 24, + NR_IRQS-4, /* num_sources used */ + "Tsi108_PIC"); + + BUG_ON(mpic == NULL); + + mpic_assign_isu(mpic, 0, mpic_paddr + 0x100); + + mpic_init(mpic); + +#ifdef CONFIG_PCI + tsi_pci = of_find_node_by_type(NULL, "pci"); + if (tsi_pci == NULL) { + printk(KERN_ERR "%s: No tsi108 pci node found !\n", __func__); + return; + } + + cascade_node = of_find_node_by_type(NULL, "pic-router"); + if (cascade_node == NULL) { + printk(KERN_ERR "%s: No tsi108 pci cascade node found !\n", __func__); + return; + } + + cascade_pci_irq = irq_of_parse_and_map(tsi_pci, 0); + pr_debug("%s: tsi108 cascade_pci_irq = 0x%x\n", __func__, (u32) cascade_pci_irq); + tsi108_pci_int_init(cascade_node); + set_irq_data(cascade_pci_irq, mpic); + set_irq_chained_handler(cascade_pci_irq, tsi108_irq_cascade); +#endif + /* Configure MPIC outputs to CPU0 */ + tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0); + of_node_put(tsi_pic); +} + +void holly_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: IBM\n"); + seq_printf(m, "machine\t\t: PPC750 GX/CL\n"); +} + +void holly_restart(char *cmd) +{ + __be32 __iomem *ocn_bar1 = NULL; + unsigned long bar; + struct device_node *bridge = NULL; + const void *prop; + int size; + phys_addr_t addr = 0xc0000000; + + local_irq_disable(); + + bridge = of_find_node_by_type(NULL, "tsi-bridge"); + if (bridge) { + prop = of_get_property(bridge, "reg", &size); + addr = of_translate_address(bridge, prop); + } + addr += (TSI108_PB_OFFSET + 0x414); + + ocn_bar1 = ioremap(addr, 0x4); + + /* Turn on the BOOT bit so the addresses are correctly + * routed to the HLP interface */ + bar = ioread32be(ocn_bar1); + bar |= 2; + iowrite32be(bar, ocn_bar1); + iosync(); + + /* Set SRR0 to the reset vector and turn on MSR_IP */ + mtspr(SPRN_SRR0, 0xfff00100); + mtspr(SPRN_SRR1, MSR_IP); + + /* Do an rfi to jump back to firmware. Somewhat evil, + * but it works + */ + __asm__ __volatile__("rfi" : : : "memory"); + + /* Spin until reset happens. Shouldn't really get here */ + for (;;) ; +} + +void holly_power_off(void) +{ + local_irq_disable(); + /* No way to shut power off with software */ + for (;;) ; +} + +void holly_halt(void) +{ + holly_power_off(); +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init holly_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "ibm,holly")) + return 0; + return 1; +} + +static int ppc750_machine_check_exception(struct pt_regs *regs) +{ + const struct exception_table_entry *entry; + + /* Are we prepared to handle this fault */ + if ((entry = search_exception_tables(regs->nip)) != NULL) { + tsi108_clear_pci_cfg_error(); + regs->msr |= MSR_RI; + regs->nip = entry->fixup; + return 1; + } + return 0; +} + +define_machine(holly){ + .name = "PPC750 GX/CL TSI", + .probe = holly_probe, + .setup_arch = holly_setup_arch, + .init_IRQ = holly_init_IRQ, + .show_cpuinfo = holly_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = holly_restart, + .calibrate_decr = generic_calibrate_decr, + .machine_check_exception = ppc750_machine_check_exception, + .progress = udbg_progress, +}; diff --git a/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index c3f64ddb0be6..4542e0c837c0 100644 --- a/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -41,6 +41,7 @@ #include #include #include "mpc7448_hpc2.h" +#include #include #include @@ -51,16 +52,15 @@ #define DBG(fmt...) do { } while(0) #endif +#define MPC7448HPC2_PCI_CFG_PHYS 0xfb000000 + #ifndef CONFIG_PCI isa_io_base = MPC7448_HPC2_ISA_IO_BASE; isa_mem_base = MPC7448_HPC2_ISA_MEM_BASE; pci_dram_offset = MPC7448_HPC2_PCI_MEM_OFFSET; #endif -extern int tsi108_setup_pci(struct device_node *dev); extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); -extern void tsi108_pci_int_init(struct device_node *node); -extern void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc); int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn) { @@ -72,28 +72,16 @@ int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn) static void __init mpc7448_hpc2_setup_arch(void) { - struct device_node *cpu; struct device_node *np; if (ppc_md.progress) ppc_md.progress("mpc7448_hpc2_setup_arch():set_bridge", 0); - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu != 0) { - const unsigned int *fp; - - fp = of_get_property(cpu, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(cpu); - } tsi108_csr_vir_base = get_vir_csrbase(); /* setup PCI host bridge */ #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - tsi108_setup_pci(np); + tsi108_setup_pci(np, MPC7448HPC2_PCI_CFG_PHYS, 0); ppc_md.pci_exclude_device = mpc7448_hpc2_exclude_device; if (ppc_md.progress) @@ -222,7 +210,6 @@ static int __init mpc7448_hpc2_probe(void) static int mpc7448_machine_check_exception(struct pt_regs *regs) { - extern void tsi108_clear_pci_cfg_error(void); const struct exception_table_entry *entry; /* Are we prepared to handle this fault */ diff --git a/trunk/arch/powerpc/platforms/iseries/smp.c b/trunk/arch/powerpc/platforms/iseries/smp.c index aee5908df700..722335e32fd4 100644 --- a/trunk/arch/powerpc/platforms/iseries/smp.c +++ b/trunk/arch/powerpc/platforms/iseries/smp.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/powerpc/platforms/iseries/viopath.c b/trunk/arch/powerpc/platforms/iseries/viopath.c index 2ca2d8a9de97..354b8dd2a2c1 100644 --- a/trunk/arch/powerpc/platforms/iseries/viopath.c +++ b/trunk/arch/powerpc/platforms/iseries/viopath.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/powerpc/platforms/maple/pci.c b/trunk/arch/powerpc/platforms/maple/pci.c index b1d3b99c3f9d..7aaa5bbc9363 100644 --- a/trunk/arch/powerpc/platforms/maple/pci.c +++ b/trunk/arch/powerpc/platforms/maple/pci.c @@ -467,15 +467,15 @@ static int __init add_bridge(struct device_node *dev) hose->last_busno = bus_range ? bus_range[1] : 0xff; disp_name = NULL; - if (device_is_compatible(dev, "u3-agp")) { + if (of_device_is_compatible(dev, "u3-agp")) { setup_u3_agp(hose); disp_name = "U3-AGP"; primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { + } else if (of_device_is_compatible(dev, "u3-ht")) { setup_u3_ht(hose); disp_name = "U3-HT"; primary = 1; - } else if (device_is_compatible(dev, "u4-pcie")) { + } else if (of_device_is_compatible(dev, "u4-pcie")) { setup_u4_pcie(hose); disp_name = "U4-PCIE"; primary = 0; @@ -556,12 +556,12 @@ void __init maple_pci_init(void) continue; if (strcmp(np->type, "pci") && strcmp(np->type, "ht")) continue; - if ((device_is_compatible(np, "u4-pcie") || - device_is_compatible(np, "u3-agp")) && + if ((of_device_is_compatible(np, "u4-pcie") || + of_device_is_compatible(np, "u3-agp")) && add_bridge(np) == 0) of_node_get(np); - if (device_is_compatible(np, "u3-ht")) { + if (of_device_is_compatible(np, "u3-ht")) { of_node_get(np); ht = np; } diff --git a/trunk/arch/powerpc/platforms/maple/setup.c b/trunk/arch/powerpc/platforms/maple/setup.c index 2a30c5b2532e..354c05861629 100644 --- a/trunk/arch/powerpc/platforms/maple/setup.c +++ b/trunk/arch/powerpc/platforms/maple/setup.c @@ -231,7 +231,7 @@ static void __init maple_init_IRQ(void) */ for_each_node_by_type(np, "interrupt-controller") - if (device_is_compatible(np, "open-pic")) { + if (of_device_is_compatible(np, "open-pic")) { mpic_node = np; break; } diff --git a/trunk/arch/powerpc/platforms/pasemi/cpufreq.c b/trunk/arch/powerpc/platforms/pasemi/cpufreq.c index 2a57d6023685..3ae083851b01 100644 --- a/trunk/arch/powerpc/platforms/pasemi/cpufreq.c +++ b/trunk/arch/powerpc/platforms/pasemi/cpufreq.c @@ -31,6 +31,7 @@ #include #include #include +#include #define SDCASR_REG 0x0100 #define SDCASR_REG_STRIDE 0x1000 @@ -204,6 +205,8 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cur = pas_freqs[cur_astate].frequency; policy->cpus = cpu_online_map; + ppc_proc_freq = policy->cur * 1000ul; + cpufreq_frequency_table_get_attr(pas_freqs, policy->cpu); /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max @@ -270,6 +273,7 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy, cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); mutex_unlock(&pas_switch_mutex); + ppc_proc_freq = freqs.new * 1000ul; return 0; } diff --git a/trunk/arch/powerpc/platforms/pasemi/pci.c b/trunk/arch/powerpc/platforms/pasemi/pci.c index 056243da360b..bbc6dfcfaa91 100644 --- a/trunk/arch/powerpc/platforms/pasemi/pci.c +++ b/trunk/arch/powerpc/platforms/pasemi/pci.c @@ -173,19 +173,6 @@ static void __init pas_fixup_phb_resources(void) } -void __devinit pas_pci_irq_fixup(struct pci_dev *dev) -{ - /* DMA is special, 84 interrupts (128 -> 211), all but 128 - * need to be mapped by hand here. - */ - if (dev->vendor == 0x1959 && dev->device == 0xa007) { - int i; - for (i = 129; i < 212; i++) - irq_create_mapping(NULL, i); - } -} - - void __init pas_pci_init(void) { struct device_node *np, *root; diff --git a/trunk/arch/powerpc/platforms/pasemi/setup.c b/trunk/arch/powerpc/platforms/pasemi/setup.c index f88f0ec4c8cb..c5a3f61f8d85 100644 --- a/trunk/arch/powerpc/platforms/pasemi/setup.c +++ b/trunk/arch/powerpc/platforms/pasemi/setup.c @@ -114,7 +114,7 @@ static __init void pas_init_IRQ(void) mpic_node = NULL; for_each_node_by_type(np, "interrupt-controller") - if (device_is_compatible(np, "open-pic")) { + if (of_device_is_compatible(np, "open-pic")) { mpic_node = np; break; } @@ -211,7 +211,10 @@ static struct of_device_id pasemi_bus_ids[] = { static int __init pasemi_publish_devices(void) { - /* Publish OF platform devices for southbridge IOs */ + if (!machine_is(pasemi)) + return 0; + + /* Publish OF platform devices for SDC and other non-PCI devices */ of_platform_bus_probe(NULL, pasemi_bus_ids, NULL); return 0; @@ -248,5 +251,4 @@ define_machine(pas) { .calibrate_decr = generic_calibrate_decr, .progress = pas_progress, .machine_check_exception = pas_machine_check_handler, - .pci_irq_fixup = pas_pci_irq_fixup, }; diff --git a/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c b/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c index 567d5523b690..00f50298c342 100644 --- a/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c +++ b/trunk/arch/powerpc/platforms/powermac/cpufreq_64.c @@ -357,13 +357,13 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu) static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy) { - if (policy->cpu != 0) - return -ENODEV; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = g5_cpu_freqs[g5_query_freq()].frequency; - policy->cpus = cpu_possible_map; + /* secondary CPUs are tied to the primary one by the + * cpufreq core if in the secondary policy we tell it that + * it actually must be one policy together with all others. */ + policy->cpus = cpu_online_map; cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu); return cpufreq_frequency_table_cpuinfo(policy, diff --git a/trunk/arch/powerpc/platforms/powermac/feature.c b/trunk/arch/powerpc/platforms/powermac/feature.c index 52cfdd86c928..f29705f8047d 100644 --- a/trunk/arch/powerpc/platforms/powermac/feature.c +++ b/trunk/arch/powerpc/platforms/powermac/feature.c @@ -1418,7 +1418,7 @@ static long g5_eth_phy_reset(struct device_node *node, long param, long value) phy = of_get_next_child(node, NULL); if (!phy) return -ENODEV; - need_reset = device_is_compatible(phy, "B5221"); + need_reset = of_device_is_compatible(phy, "B5221"); of_node_put(phy); if (!need_reset) return 0; @@ -2624,7 +2624,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) { if (!compat) break; - if (device_is_compatible(node, compat)) + if (of_device_is_compatible(node, compat)) break; } if (!node) @@ -2728,7 +2728,7 @@ initial_serial_shutdown(struct device_node *np) conn = of_get_property(np, "AAPL,connector", &len); if (conn && (strcmp(conn, "infrared") == 0)) port_type = PMAC_SCC_IRDA; - else if (device_is_compatible(np, "cobalt")) + else if (of_device_is_compatible(np, "cobalt")) modem = 1; else if (slots && slots->count > 0) { if (strcmp(slots->name, "IrDA") == 0) @@ -2787,7 +2787,7 @@ set_initial_features(void) */ np = of_find_node_by_name(NULL, "ethernet"); while(np) { - if (device_is_compatible(np, "K2-GMAC")) + if (of_device_is_compatible(np, "K2-GMAC")) g5_gmac_enable(np, 0, 1); np = of_find_node_by_name(np, "ethernet"); } @@ -2799,7 +2799,7 @@ set_initial_features(void) */ np = of_find_node_by_name(NULL, "firewire"); while(np) { - if (device_is_compatible(np, "pci106b,5811")) { + if (of_device_is_compatible(np, "pci106b,5811")) { macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; g5_fw_enable(np, 0, 1); } @@ -2817,8 +2817,8 @@ set_initial_features(void) np = of_find_node_by_name(NULL, "ethernet"); while(np) { if (np->parent - && device_is_compatible(np->parent, "uni-north") - && device_is_compatible(np, "gmac")) + && of_device_is_compatible(np->parent, "uni-north") + && of_device_is_compatible(np, "gmac")) core99_gmac_enable(np, 0, 1); np = of_find_node_by_name(np, "ethernet"); } @@ -2831,10 +2831,10 @@ set_initial_features(void) np = of_find_node_by_name(NULL, "firewire"); while(np) { if (np->parent - && device_is_compatible(np->parent, "uni-north") - && (device_is_compatible(np, "pci106b,18") || - device_is_compatible(np, "pci106b,30") || - device_is_compatible(np, "pci11c1,5811"))) { + && of_device_is_compatible(np->parent, "uni-north") + && (of_device_is_compatible(np, "pci106b,18") || + of_device_is_compatible(np, "pci106b,30") || + of_device_is_compatible(np, "pci11c1,5811"))) { macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; core99_firewire_enable(np, 0, 1); } @@ -2845,8 +2845,8 @@ set_initial_features(void) np = of_find_node_by_name(NULL, "ata-6"); while(np) { if (np->parent - && device_is_compatible(np->parent, "uni-north") - && device_is_compatible(np, "kauai-ata")) { + && of_device_is_compatible(np->parent, "uni-north") + && of_device_is_compatible(np, "kauai-ata")) { core99_ata100_enable(np, 1); } np = of_find_node_by_name(np, "ata-6"); diff --git a/trunk/arch/powerpc/platforms/powermac/low_i2c.c b/trunk/arch/powerpc/platforms/powermac/low_i2c.c index 5430e146b3e9..3f507ab9c5e5 100644 --- a/trunk/arch/powerpc/platforms/powermac/low_i2c.c +++ b/trunk/arch/powerpc/platforms/powermac/low_i2c.c @@ -1207,7 +1207,7 @@ static void pmac_i2c_devscan(void (*callback)(struct device_node *dev, if (strcmp(np->name, p->name)) continue; if (p->compatible && - !device_is_compatible(np, p->compatible)) + !of_device_is_compatible(np, p->compatible)) continue; if (p->quirks & pmac_i2c_quirk_skip) break; diff --git a/trunk/arch/powerpc/platforms/powermac/nvram.c b/trunk/arch/powerpc/platforms/powermac/nvram.c index 692945c14919..c6f0f9e738e5 100644 --- a/trunk/arch/powerpc/platforms/powermac/nvram.c +++ b/trunk/arch/powerpc/platforms/powermac/nvram.c @@ -553,7 +553,7 @@ static int __init core99_nvram_setup(struct device_node *dp, unsigned long addr) * identify the chip using flash id commands and base ourselves on * a list of known chips IDs */ - if (device_is_compatible(dp, "amd-0137")) { + if (of_device_is_compatible(dp, "amd-0137")) { core99_erase_bank = amd_erase_bank; core99_write_bank = amd_write_bank; } else { @@ -588,7 +588,7 @@ int __init pmac_nvram_init(void) } } - is_core_99 = device_is_compatible(dp, "nvram,flash"); + is_core_99 = of_device_is_compatible(dp, "nvram,flash"); if (is_core_99) { err = core99_nvram_setup(dp, r1.start); goto bail; diff --git a/trunk/arch/powerpc/platforms/powermac/pci.c b/trunk/arch/powerpc/platforms/powermac/pci.c index 22c4ae4c6934..c4af9e21ac93 100644 --- a/trunk/arch/powerpc/platforms/powermac/pci.c +++ b/trunk/arch/powerpc/platforms/powermac/pci.c @@ -934,15 +934,15 @@ static int __init add_bridge(struct device_node *dev) /* 64 bits only bridges */ #ifdef CONFIG_PPC64 - if (device_is_compatible(dev, "u3-agp")) { + if (of_device_is_compatible(dev, "u3-agp")) { setup_u3_agp(hose); disp_name = "U3-AGP"; primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { + } else if (of_device_is_compatible(dev, "u3-ht")) { setup_u3_ht(hose); disp_name = "U3-HT"; primary = 1; - } else if (device_is_compatible(dev, "u4-pcie")) { + } else if (of_device_is_compatible(dev, "u4-pcie")) { setup_u4_pcie(hose); disp_name = "U4-PCIE"; primary = 0; @@ -953,7 +953,7 @@ static int __init add_bridge(struct device_node *dev) /* 32 bits only bridges */ #ifdef CONFIG_PPC32 - if (device_is_compatible(dev, "uni-north")) { + if (of_device_is_compatible(dev, "uni-north")) { primary = setup_uninorth(hose, &rsrc); disp_name = "UniNorth"; } else if (strcmp(dev->name, "pci") == 0) { @@ -1129,21 +1129,21 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) return 0; uninorth_child = node->parent && - device_is_compatible(node->parent, "uni-north"); + of_device_is_compatible(node->parent, "uni-north"); /* Firewire & GMAC were disabled after PCI probe, the driver is * claiming them, we must re-enable them now. */ if (uninorth_child && !strcmp(node->name, "firewire") && - (device_is_compatible(node, "pci106b,18") || - device_is_compatible(node, "pci106b,30") || - device_is_compatible(node, "pci11c1,5811"))) { + (of_device_is_compatible(node, "pci106b,18") || + of_device_is_compatible(node, "pci106b,30") || + of_device_is_compatible(node, "pci11c1,5811"))) { pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1); pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1); updatecfg = 1; } if (uninorth_child && !strcmp(node->name, "ethernet") && - device_is_compatible(node, "gmac")) { + of_device_is_compatible(node, "gmac")) { pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1); updatecfg = 1; } @@ -1203,18 +1203,18 @@ void __init pmac_pcibios_after_init(void) #endif /* CONFIG_BLK_DEV_IDE */ for_each_node_by_name(nd, "firewire") { - if (nd->parent && (device_is_compatible(nd, "pci106b,18") || - device_is_compatible(nd, "pci106b,30") || - device_is_compatible(nd, "pci11c1,5811")) - && device_is_compatible(nd->parent, "uni-north")) { + if (nd->parent && (of_device_is_compatible(nd, "pci106b,18") || + of_device_is_compatible(nd, "pci106b,30") || + of_device_is_compatible(nd, "pci11c1,5811")) + && of_device_is_compatible(nd->parent, "uni-north")) { pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0); pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0); } } of_node_put(nd); for_each_node_by_name(nd, "ethernet") { - if (nd->parent && device_is_compatible(nd, "gmac") - && device_is_compatible(nd->parent, "uni-north")) + if (nd->parent && of_device_is_compatible(nd, "gmac") + && of_device_is_compatible(nd->parent, "uni-north")) pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0); } of_node_put(nd); diff --git a/trunk/arch/powerpc/platforms/powermac/pic.c b/trunk/arch/powerpc/platforms/powermac/pic.c index ae5097ac0378..87cd6805171a 100644 --- a/trunk/arch/powerpc/platforms/powermac/pic.c +++ b/trunk/arch/powerpc/platforms/powermac/pic.c @@ -364,7 +364,7 @@ static void __init pmac_pic_probe_oldstyle(void) slave = of_find_node_by_name(master, "mac-io"); /* Check ordering of master & slave */ - if (device_is_compatible(master, "gatwick")) { + if (of_device_is_compatible(master, "gatwick")) { struct device_node *tmp; BUG_ON(slave == NULL); tmp = master; diff --git a/trunk/arch/powerpc/platforms/powermac/setup.c b/trunk/arch/powerpc/platforms/powermac/setup.c index b820cabac697..a410bc76a8a8 100644 --- a/trunk/arch/powerpc/platforms/powermac/setup.c +++ b/trunk/arch/powerpc/platforms/powermac/setup.c @@ -439,76 +439,14 @@ static void __init find_boot_device(void) #endif } -/* TODO: Merge the suspend-to-ram with the common code !!! - * currently, this is a stub implementation for suspend-to-disk - * only - */ - -#ifdef CONFIG_SOFTWARE_SUSPEND - -static int pmac_pm_prepare(suspend_state_t state) -{ - printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state); - - return 0; -} - -static int pmac_pm_enter(suspend_state_t state) -{ - printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state); - - /* Giveup the lazy FPU & vec so we don't have to back them - * up from the low level code - */ - enable_kernel_fp(); - -#ifdef CONFIG_ALTIVEC - if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC) - enable_kernel_altivec(); -#endif /* CONFIG_ALTIVEC */ - - return 0; -} - -static int pmac_pm_finish(suspend_state_t state) -{ - printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state); - - /* Restore userland MMU context */ - set_context(current->active_mm->context.id, current->active_mm->pgd); - - return 0; -} - -static int pmac_pm_valid(suspend_state_t state) -{ - switch (state) { - case PM_SUSPEND_DISK: - return 1; - /* can't do any other states via generic mechanism yet */ - default: - return 0; - } -} - -static struct pm_ops pmac_pm_ops = { - .pm_disk_mode = PM_DISK_SHUTDOWN, - .prepare = pmac_pm_prepare, - .enter = pmac_pm_enter, - .finish = pmac_pm_finish, - .valid = pmac_pm_valid, -}; - -#endif /* CONFIG_SOFTWARE_SUSPEND */ - static int initializing = 1; static int pmac_late_init(void) { initializing = 0; -#ifdef CONFIG_SOFTWARE_SUSPEND - pm_set_ops(&pmac_pm_ops); -#endif /* CONFIG_SOFTWARE_SUSPEND */ + /* this is udbg (which is __init) and we can later use it during + * cpu hotplug (in smp_core99_kick_cpu) */ + ppc_md.progress = NULL; return 0; } @@ -721,12 +659,57 @@ static int pmac_pci_probe_mode(struct pci_bus *bus) /* We need to use normal PCI probing for the AGP bus, * since the device for the AGP bridge isn't in the tree. */ - if (bus->self == NULL && (device_is_compatible(node, "u3-agp") || - device_is_compatible(node, "u4-pcie"))) + if (bus->self == NULL && (of_device_is_compatible(node, "u3-agp") || + of_device_is_compatible(node, "u4-pcie"))) return PCI_PROBE_NORMAL; return PCI_PROBE_DEVTREE; } -#endif + +#ifdef CONFIG_HOTPLUG_CPU +/* access per cpu vars from generic smp.c */ +DECLARE_PER_CPU(int, cpu_state); + +static void pmac_cpu_die(void) +{ + /* + * turn off as much as possible, we'll be + * kicked out as this will only be invoked + * on core99 platforms for now ... + */ + + printk(KERN_INFO "CPU#%d offline\n", smp_processor_id()); + __get_cpu_var(cpu_state) = CPU_DEAD; + smp_wmb(); + + /* + * during the path that leads here preemption is disabled, + * reenable it now so that when coming up preempt count is + * zero correctly + */ + preempt_enable(); + + /* + * hard-disable interrupts for the non-NAP case, the NAP code + * needs to re-enable interrupts (but soft-disables them) + */ + hard_irq_disable(); + + while (1) { + /* let's not take timer interrupts too often ... */ + set_dec(0x7fffffff); + + /* should always be true at this point */ + if (cpu_has_feature(CPU_FTR_CAN_NAP)) + power4_cpu_offline_powersave(); + else { + HMT_low(); + HMT_very_low(); + } + } +} +#endif /* CONFIG_HOTPLUG_CPU */ + +#endif /* CONFIG_PPC64 */ define_machine(powermac) { .name = "PowerMac", @@ -763,6 +746,6 @@ define_machine(powermac) { .phys_mem_access_prot = pci_phys_mem_access_prot, #endif #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64) - .cpu_die = generic_mach_cpu_die, + .cpu_die = pmac_cpu_die, #endif }; diff --git a/trunk/arch/powerpc/platforms/powermac/smp.c b/trunk/arch/powerpc/platforms/powermac/smp.c index 6f32c4eca6e5..686ed82bde79 100644 --- a/trunk/arch/powerpc/platforms/powermac/smp.c +++ b/trunk/arch/powerpc/platforms/powermac/smp.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -562,7 +561,7 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus) /* Look for the clock chip */ while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) { p = of_get_parent(cc); - ok = p && device_is_compatible(p, "uni-n-i2c"); + ok = p && of_device_is_compatible(p, "uni-n-i2c"); of_node_put(p); if (!ok) continue; @@ -575,11 +574,11 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus) continue; switch (*reg) { case 0xd2: - if (device_is_compatible(cc,"pulsar-legacy-slewing")) { + if (of_device_is_compatible(cc,"pulsar-legacy-slewing")) { pmac_tb_freeze = smp_core99_pulsar_tb_freeze; pmac_tb_pulsar_addr = 0xd2; name = "Pulsar"; - } else if (device_is_compatible(cc, "cy28508")) { + } else if (of_device_is_compatible(cc, "cy28508")) { pmac_tb_freeze = smp_core99_cypress_tb_freeze; name = "Cypress"; } @@ -900,7 +899,7 @@ void smp_core99_cpu_die(unsigned int cpu) cpu_dead[cpu] = 0; } -#endif +#endif /* CONFIG_HOTPLUG_CPU && CONFIG_PP32 */ /* Core99 Macs (dual G4s and G5s) */ struct smp_ops_t core99_smp_ops = { @@ -910,8 +909,16 @@ struct smp_ops_t core99_smp_ops = { .setup_cpu = smp_core99_setup_cpu, .give_timebase = smp_core99_give_timebase, .take_timebase = smp_core99_take_timebase, -#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32) +#if defined(CONFIG_HOTPLUG_CPU) +# if defined(CONFIG_PPC32) .cpu_disable = smp_core99_cpu_disable, .cpu_die = smp_core99_cpu_die, +# endif +# if defined(CONFIG_PPC64) + .cpu_disable = generic_cpu_disable, + .cpu_die = generic_cpu_die, + /* intentionally do *NOT* assign cpu_enable, + * the generic code will use kick_cpu then! */ +# endif #endif }; diff --git a/trunk/arch/powerpc/platforms/ps3/htab.c b/trunk/arch/powerpc/platforms/ps3/htab.c index ea60c451cf87..a1409e450c70 100644 --- a/trunk/arch/powerpc/platforms/ps3/htab.c +++ b/trunk/arch/powerpc/platforms/ps3/htab.c @@ -273,7 +273,8 @@ void __init ps3_map_htab(void) result = lv1_map_htab(0, &htab_addr); - htab = (hpte_t *)__ioremap(htab_addr, htab_size, PAGE_READONLY_X); + htab = (hpte_t *)__ioremap(htab_addr, htab_size, + pgprot_val(PAGE_READONLY_X)); DBG("%s:%d: lpar %016lxh, virt %016lxh\n", __func__, __LINE__, htab_addr, (unsigned long)htab); diff --git a/trunk/arch/powerpc/platforms/ps3/interrupt.c b/trunk/arch/powerpc/platforms/ps3/interrupt.c index 631c30095617..9da82c266ba9 100644 --- a/trunk/arch/powerpc/platforms/ps3/interrupt.c +++ b/trunk/arch/powerpc/platforms/ps3/interrupt.c @@ -89,7 +89,18 @@ struct ps3_private { static DEFINE_PER_CPU(struct ps3_private, ps3_private); -int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet, +/** + * ps3_virq_setup - virq related setup. + * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be + * serviced on. + * @outlet: The HV outlet from the various create outlet routines. + * @virq: The assigned Linux virq. + * + * Calls irq_create_mapping() to get a virq and sets the chip data to + * ps3_private data. + */ + +int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, unsigned int *virq) { int result; @@ -111,17 +122,6 @@ int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet, goto fail_create; } - /* Binds outlet to cpu + virq. */ - - result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0); - - if (result) { - pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", - __func__, __LINE__, ps3_result(result)); - result = -EPERM; - goto fail_connect; - } - pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__, outlet, cpu, *virq); @@ -136,94 +136,118 @@ int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet, return result; fail_set: - lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq); -fail_connect: irq_dispose_mapping(*virq); fail_create: return result; } -EXPORT_SYMBOL_GPL(ps3_alloc_irq); -int ps3_free_irq(unsigned int virq) +/** + * ps3_virq_destroy - virq related teardown. + * @virq: The assigned Linux virq. + * + * Clears chip data and calls irq_dispose_mapping() for the virq. + */ + +int ps3_virq_destroy(unsigned int virq) { - int result; const struct ps3_private *pd = get_irq_chip_data(virq); pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, pd->node, pd->cpu, virq); - result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); - - if (result) - pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", - __func__, __LINE__, ps3_result(result)); - set_irq_chip_data(virq, NULL); irq_dispose_mapping(virq); - return result; + + pr_debug("%s:%d <-\n", __func__, __LINE__); + return 0; } -EXPORT_SYMBOL_GPL(ps3_free_irq); /** - * ps3_alloc_io_irq - Assign a virq to a system bus device. + * ps3_irq_plug_setup - Generic outlet and virq related setup. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be * serviced on. - * @interrupt_id: The device interrupt id read from the system repository. + * @outlet: The HV outlet from the various create outlet routines. * @virq: The assigned Linux virq. * - * An io irq represents a non-virtualized device interrupt. interrupt_id - * coresponds to the interrupt number of the interrupt controller. + * Sets up virq and connects the irq plug. */ -int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id, +int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet, unsigned int *virq) { int result; - unsigned long outlet; + struct ps3_private *pd; - result = lv1_construct_io_irq_outlet(interrupt_id, &outlet); + result = ps3_virq_setup(cpu, outlet, virq); if (result) { - pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n", - __func__, __LINE__, ps3_result(result)); - return result; + pr_debug("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__); + goto fail_setup; } - result = ps3_alloc_irq(cpu, outlet, virq); - BUG_ON(result); + pd = get_irq_chip_data(*virq); + + /* Binds outlet to cpu + virq. */ + + result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0); + if (result) { + pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", + __func__, __LINE__, ps3_result(result)); + result = -EPERM; + goto fail_connect; + } + + return result; + +fail_connect: + ps3_virq_destroy(*virq); +fail_setup: return result; } -EXPORT_SYMBOL_GPL(ps3_alloc_io_irq); +EXPORT_SYMBOL_GPL(ps3_irq_plug_setup); + +/** + * ps3_irq_plug_destroy - Generic outlet and virq related teardown. + * @virq: The assigned Linux virq. + * + * Disconnects the irq plug and tears down virq. + * Do not call for system bus event interrupts setup with + * ps3_sb_event_receive_port_setup(). + */ -int ps3_free_io_irq(unsigned int virq) +int ps3_irq_plug_destroy(unsigned int virq) { int result; + const struct ps3_private *pd = get_irq_chip_data(virq); - result = lv1_destruct_io_irq_outlet(virq_to_hw(virq)); + pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, + pd->node, pd->cpu, virq); + + result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); if (result) - pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", - __func__, __LINE__, ps3_result(result)); + pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", + __func__, __LINE__, ps3_result(result)); - ps3_free_irq(virq); + ps3_virq_destroy(virq); return result; } -EXPORT_SYMBOL_GPL(ps3_free_io_irq); +EXPORT_SYMBOL_GPL(ps3_irq_plug_destroy); /** - * ps3_alloc_event_irq - Allocate a virq for use with a system event. + * ps3_event_receive_port_setup - Setup an event receive port. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be * serviced on. * @virq: The assigned Linux virq. * * The virq can be used with lv1_connect_interrupt_event_receive_port() to - * arrange to receive events, or with ps3_send_event_locally() to signal - * events. + * arrange to receive interrupts from system-bus devices, or with + * ps3_send_event_locally() to signal events. */ -int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq) +int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq) { int result; unsigned long outlet; @@ -237,17 +261,27 @@ int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq) return result; } - result = ps3_alloc_irq(cpu, outlet, virq); + result = ps3_irq_plug_setup(cpu, outlet, virq); BUG_ON(result); return result; } +EXPORT_SYMBOL_GPL(ps3_event_receive_port_setup); + +/** + * ps3_event_receive_port_destroy - Destroy an event receive port. + * @virq: The assigned Linux virq. + * + * Since ps3_event_receive_port_destroy destroys the receive port outlet, + * SB devices need to call disconnect_interrupt_event_receive_port() before + * this. + */ -int ps3_free_event_irq(unsigned int virq) +int ps3_event_receive_port_destroy(unsigned int virq) { int result; - pr_debug(" -> %s:%d\n", __func__, __LINE__); + pr_debug(" -> %s:%d virq: %u\n", __func__, __LINE__, virq); result = lv1_destruct_event_receive_port(virq_to_hw(virq)); @@ -255,11 +289,17 @@ int ps3_free_event_irq(unsigned int virq) pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", __func__, __LINE__, ps3_result(result)); - ps3_free_irq(virq); + /* lv1_destruct_event_receive_port() destroys the IRQ plug, + * so don't call ps3_irq_plug_destroy() here. + */ + + result = ps3_virq_destroy(virq); + BUG_ON(result); pr_debug(" <- %s:%d\n", __func__, __LINE__); return result; } +EXPORT_SYMBOL_GPL(ps3_event_receive_port_destroy); int ps3_send_event_locally(unsigned int virq) { @@ -267,7 +307,7 @@ int ps3_send_event_locally(unsigned int virq) } /** - * ps3_connect_event_irq - Assign a virq to a system bus device. + * ps3_sb_event_receive_port_setup - Setup a system bus event receive port. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be * serviced on. * @did: The HV device identifier read from the system repository. @@ -278,13 +318,15 @@ int ps3_send_event_locally(unsigned int virq) * coresponds to the software interrupt number. */ -int ps3_connect_event_irq(enum ps3_cpu_binding cpu, +int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu, const struct ps3_device_id *did, unsigned int interrupt_id, unsigned int *virq) { + /* this should go in system-bus.c */ + int result; - result = ps3_alloc_event_irq(cpu, virq); + result = ps3_event_receive_port_setup(cpu, virq); if (result) return result; @@ -296,7 +338,7 @@ int ps3_connect_event_irq(enum ps3_cpu_binding cpu, pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port" " failed: %s\n", __func__, __LINE__, ps3_result(result)); - ps3_free_event_irq(*virq); + ps3_event_receive_port_destroy(*virq); *virq = NO_IRQ; return result; } @@ -306,10 +348,13 @@ int ps3_connect_event_irq(enum ps3_cpu_binding cpu, return 0; } +EXPORT_SYMBOL(ps3_sb_event_receive_port_setup); -int ps3_disconnect_event_irq(const struct ps3_device_id *did, +int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did, unsigned int interrupt_id, unsigned int virq) { + /* this should go in system-bus.c */ + int result; pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, @@ -323,14 +368,65 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did, " failed: %s\n", __func__, __LINE__, ps3_result(result)); - ps3_free_event_irq(virq); + result = ps3_event_receive_port_destroy(virq); + BUG_ON(result); pr_debug(" <- %s:%d\n", __func__, __LINE__); return result; } +EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy); /** - * ps3_alloc_vuart_irq - Configure the system virtual uart virq. + * ps3_io_irq_setup - Setup a system bus io irq. + * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be + * serviced on. + * @interrupt_id: The device interrupt id read from the system repository. + * @virq: The assigned Linux virq. + * + * An io irq represents a non-virtualized device interrupt. interrupt_id + * coresponds to the interrupt number of the interrupt controller. + */ + +int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id, + unsigned int *virq) +{ + int result; + unsigned long outlet; + + result = lv1_construct_io_irq_outlet(interrupt_id, &outlet); + + if (result) { + pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n", + __func__, __LINE__, ps3_result(result)); + return result; + } + + result = ps3_irq_plug_setup(cpu, outlet, virq); + BUG_ON(result); + + return result; +} +EXPORT_SYMBOL_GPL(ps3_io_irq_setup); + +int ps3_io_irq_destroy(unsigned int virq) +{ + int result; + + result = lv1_destruct_io_irq_outlet(virq_to_hw(virq)); + + if (result) + pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", + __func__, __LINE__, ps3_result(result)); + + result = ps3_irq_plug_destroy(virq); + BUG_ON(result); + + return result; +} +EXPORT_SYMBOL_GPL(ps3_io_irq_destroy); + +/** + * ps3_vuart_irq_setup - Setup the system virtual uart virq. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be * serviced on. * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap. @@ -340,7 +436,7 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did, * freeing the interrupt will return a wrong state error. */ -int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp, +int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp, unsigned int *virq) { int result; @@ -359,13 +455,13 @@ int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp, return result; } - result = ps3_alloc_irq(cpu, outlet, virq); + result = ps3_irq_plug_setup(cpu, outlet, virq); BUG_ON(result); return result; } -int ps3_free_vuart_irq(unsigned int virq) +int ps3_vuart_irq_destroy(unsigned int virq) { int result; @@ -377,13 +473,14 @@ int ps3_free_vuart_irq(unsigned int virq) return result; } - ps3_free_irq(virq); + result = ps3_irq_plug_destroy(virq); + BUG_ON(result); return result; } /** - * ps3_alloc_spe_irq - Configure an spe virq. + * ps3_spe_irq_setup - Setup an spe virq. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be * serviced on. * @spe_id: The spe_id returned from lv1_construct_logical_spe(). @@ -392,7 +489,7 @@ int ps3_free_vuart_irq(unsigned int virq) * */ -int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id, +int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id, unsigned int class, unsigned int *virq) { int result; @@ -408,15 +505,16 @@ int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id, return result; } - result = ps3_alloc_irq(cpu, outlet, virq); + result = ps3_irq_plug_setup(cpu, outlet, virq); BUG_ON(result); return result; } -int ps3_free_spe_irq(unsigned int virq) +int ps3_spe_irq_destroy(unsigned int virq) { - ps3_free_irq(virq); + int result = ps3_irq_plug_destroy(virq); + BUG_ON(result); return 0; } diff --git a/trunk/arch/powerpc/platforms/ps3/mm.c b/trunk/arch/powerpc/platforms/ps3/mm.c index 2014d2b44449..f8a3e206c584 100644 --- a/trunk/arch/powerpc/platforms/ps3/mm.c +++ b/trunk/arch/powerpc/platforms/ps3/mm.c @@ -826,5 +826,4 @@ void __init ps3_mm_init(void) void ps3_mm_shutdown(void) { ps3_mm_region_destroy(&map.r1); - map.total = map.rm.size; } diff --git a/trunk/arch/powerpc/platforms/ps3/setup.c b/trunk/arch/powerpc/platforms/ps3/setup.c index ac5df9688dcb..c9894933084f 100644 --- a/trunk/arch/powerpc/platforms/ps3/setup.c +++ b/trunk/arch/powerpc/platforms/ps3/setup.c @@ -137,6 +137,12 @@ early_param("ps3fb", early_parse_ps3fb); #define prealloc_ps3fb_videomemory() do { } while (0) #endif +static int ps3_set_dabr(u64 dabr) +{ + enum {DABR_USER = 1, DABR_KERNEL = 2,}; + + return lv1_set_dabr(dabr, DABR_KERNEL | DABR_USER) ? -1 : 0; +} static void __init ps3_setup_arch(void) { @@ -234,6 +240,7 @@ define_machine(ps3) { .get_boot_time = ps3_get_boot_time, .set_rtc_time = ps3_set_rtc_time, .get_rtc_time = ps3_get_rtc_time, + .set_dabr = ps3_set_dabr, .calibrate_decr = ps3_calibrate_decr, .progress = ps3_progress, .restart = ps3_restart, diff --git a/trunk/arch/powerpc/platforms/ps3/smp.c b/trunk/arch/powerpc/platforms/ps3/smp.c index 6fb887961a6d..8729348c0608 100644 --- a/trunk/arch/powerpc/platforms/ps3/smp.c +++ b/trunk/arch/powerpc/platforms/ps3/smp.c @@ -110,7 +110,7 @@ static void __init ps3_smp_setup_cpu(int cpu) BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3); for (i = 0; i < MSG_COUNT; i++) { - result = ps3_alloc_event_irq(cpu, &virqs[i]); + result = ps3_event_receive_port_setup(cpu, &virqs[i]); if (result) continue; @@ -134,11 +134,13 @@ void ps3_smp_cleanup_cpu(int cpu) int i; DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); + for (i = 0; i < MSG_COUNT; i++) { - ps3_free_event_irq(virqs[i]); free_irq(virqs[i], (void*)(long)i); + ps3_event_receive_port_destroy(virqs[i]); virqs[i] = NO_IRQ; } + DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu); } diff --git a/trunk/arch/powerpc/platforms/ps3/spu.c b/trunk/arch/powerpc/platforms/ps3/spu.c index a397e4e17c13..651437cb2c18 100644 --- a/trunk/arch/powerpc/platforms/ps3/spu.c +++ b/trunk/arch/powerpc/platforms/ps3/spu.c @@ -184,7 +184,7 @@ static int __init setup_areas(struct spu *spu) spu_pdata(spu)->shadow = __ioremap( spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow), - PAGE_READONLY | _PAGE_NO_CACHE | _PAGE_GUARDED); + pgprot_val(PAGE_READONLY) | _PAGE_NO_CACHE | _PAGE_GUARDED); if (!spu_pdata(spu)->shadow) { pr_debug("%s:%d: ioremap shadow failed\n", __func__, __LINE__); goto fail_ioremap; @@ -230,19 +230,19 @@ static int __init setup_interrupts(struct spu *spu) { int result; - result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, + result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, 0, &spu->irqs[0]); if (result) goto fail_alloc_0; - result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, + result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, 1, &spu->irqs[1]); if (result) goto fail_alloc_1; - result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, + result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, 2, &spu->irqs[2]); if (result) @@ -251,9 +251,9 @@ static int __init setup_interrupts(struct spu *spu) return result; fail_alloc_2: - ps3_free_spe_irq(spu->irqs[1]); + ps3_spe_irq_destroy(spu->irqs[1]); fail_alloc_1: - ps3_free_spe_irq(spu->irqs[0]); + ps3_spe_irq_destroy(spu->irqs[0]); fail_alloc_0: spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ; return result; @@ -301,9 +301,9 @@ static int ps3_destroy_spu(struct spu *spu) result = lv1_disable_logical_spe(spu_pdata(spu)->spe_id, 0); BUG_ON(result); - ps3_free_spe_irq(spu->irqs[2]); - ps3_free_spe_irq(spu->irqs[1]); - ps3_free_spe_irq(spu->irqs[0]); + ps3_spe_irq_destroy(spu->irqs[2]); + ps3_spe_irq_destroy(spu->irqs[1]); + ps3_spe_irq_destroy(spu->irqs[0]); spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ; diff --git a/trunk/arch/powerpc/platforms/pseries/Makefile b/trunk/arch/powerpc/platforms/pseries/Makefile index 90235d598751..ae1fc92dc1c9 100644 --- a/trunk/arch/powerpc/platforms/pseries/Makefile +++ b/trunk/arch/powerpc/platforms/pseries/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_PCI) += pci.o pci_dlpar.o +obj-$(CONFIG_PCI_MSI) += msi.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o diff --git a/trunk/arch/powerpc/platforms/pseries/eeh.c b/trunk/arch/powerpc/platforms/pseries/eeh.c index 48fbd442e9df..63e23062e982 100644 --- a/trunk/arch/powerpc/platforms/pseries/eeh.c +++ b/trunk/arch/powerpc/platforms/pseries/eeh.c @@ -579,6 +579,36 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state) rc, state, pdn->node->full_name); } +/** + * pcibios_set_pcie_slot_reset - Set PCI-E reset state + * @dev: pci device struct + * @state: reset state to enter + * + * Return value: + * 0 if success + **/ +int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) +{ + struct device_node *dn = pci_device_to_OF_node(dev); + struct pci_dn *pdn = PCI_DN(dn); + + switch (state) { + case pcie_deassert_reset: + rtas_pci_slot_reset(pdn, 0); + break; + case pcie_hot_reset: + rtas_pci_slot_reset(pdn, 1); + break; + case pcie_warm_reset: + rtas_pci_slot_reset(pdn, 3); + break; + default: + return -EINVAL; + }; + + return 0; +} + /** * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second * @pdn: pci device node to be reset. diff --git a/trunk/arch/powerpc/platforms/pseries/iommu.c b/trunk/arch/powerpc/platforms/pseries/iommu.c index 66665c82415c..eec684a8e44e 100644 --- a/trunk/arch/powerpc/platforms/pseries/iommu.c +++ b/trunk/arch/powerpc/platforms/pseries/iommu.c @@ -504,6 +504,12 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) break; } + if (!pdn || !PCI_DN(pdn)) { + printk(KERN_WARNING "pci_dma_dev_setup_pSeriesLP: " + "no DMA window found for pci dev=%s dn=%s\n", + pci_name(dev), dn? dn->full_name : ""); + return; + } DBG(" parent is %s\n", pdn->full_name); /* Check for parent == NULL so we don't try to setup the empty EADS diff --git a/trunk/arch/powerpc/platforms/pseries/lpar.c b/trunk/arch/powerpc/platforms/pseries/lpar.c index 3a70e8ad7bc8..362dfbc260a6 100644 --- a/trunk/arch/powerpc/platforms/pseries/lpar.c +++ b/trunk/arch/powerpc/platforms/pseries/lpar.c @@ -231,13 +231,13 @@ void __init find_udbg_vterm(void) goto out; vtermno = termno[0]; - if (device_is_compatible(stdout_node, "hvterm1")) { + if (of_device_is_compatible(stdout_node, "hvterm1")) { udbg_putc = udbg_putcLP; udbg_getc = udbg_getcLP; udbg_getc_poll = udbg_getc_pollLP; if (add_console) add_preferred_console("hvc", termno[0] & 0xff, NULL); - } else if (device_is_compatible(stdout_node, "hvterm-protocol")) { + } else if (of_device_is_compatible(stdout_node, "hvterm-protocol")) { vtermno = termno[0]; udbg_putc = udbg_hvsi_putc; udbg_getc = udbg_hvsi_getc; diff --git a/trunk/arch/powerpc/platforms/pseries/msi.c b/trunk/arch/powerpc/platforms/pseries/msi.c new file mode 100644 index 000000000000..6063ea2f67ad --- /dev/null +++ b/trunk/arch/powerpc/platforms/pseries/msi.c @@ -0,0 +1,270 @@ +/* + * Copyright 2006 Jake Moilanen , IBM Corp. + * Copyright 2006-2007 Michael Ellerman, IBM 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. + * + */ + +#include +#include +#include + +#include +#include +#include + +static int query_token, change_token; + +#define RTAS_QUERY_FN 0 +#define RTAS_CHANGE_FN 1 +#define RTAS_RESET_FN 2 +#define RTAS_CHANGE_MSI_FN 3 +#define RTAS_CHANGE_MSIX_FN 4 + +static struct pci_dn *get_pdn(struct pci_dev *pdev) +{ + struct device_node *dn; + struct pci_dn *pdn; + + dn = pci_device_to_OF_node(pdev); + if (!dn) { + dev_dbg(&pdev->dev, "rtas_msi: No OF device node\n"); + return NULL; + } + + pdn = PCI_DN(dn); + if (!pdn) { + dev_dbg(&pdev->dev, "rtas_msi: No PCI DN\n"); + return NULL; + } + + return pdn; +} + +/* RTAS Helpers */ + +static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs) +{ + u32 addr, seq_num, rtas_ret[3]; + unsigned long buid; + int rc; + + addr = rtas_config_addr(pdn->busno, pdn->devfn, 0); + buid = pdn->phb->buid; + + seq_num = 1; + do { + if (func == RTAS_CHANGE_MSI_FN || func == RTAS_CHANGE_MSIX_FN) + rc = rtas_call(change_token, 6, 4, rtas_ret, addr, + BUID_HI(buid), BUID_LO(buid), + func, num_irqs, seq_num); + else + rc = rtas_call(change_token, 6, 3, rtas_ret, addr, + BUID_HI(buid), BUID_LO(buid), + func, num_irqs, seq_num); + + seq_num = rtas_ret[1]; + } while (rtas_busy_delay(rc)); + + if (rc == 0) /* Success */ + rc = rtas_ret[0]; + + pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d) = (%d)\n", + func, num_irqs, rc); + + return rc; +} + +static void rtas_disable_msi(struct pci_dev *pdev) +{ + struct pci_dn *pdn; + + pdn = get_pdn(pdev); + if (!pdn) + return; + + if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0) + pr_debug("rtas_msi: Setting MSIs to 0 failed!\n"); +} + +static int rtas_query_irq_number(struct pci_dn *pdn, int offset) +{ + u32 addr, rtas_ret[2]; + unsigned long buid; + int rc; + + addr = rtas_config_addr(pdn->busno, pdn->devfn, 0); + buid = pdn->phb->buid; + + do { + rc = rtas_call(query_token, 4, 3, rtas_ret, addr, + BUID_HI(buid), BUID_LO(buid), offset); + } while (rtas_busy_delay(rc)); + + if (rc) { + pr_debug("rtas_msi: error (%d) querying source number\n", rc); + return rc; + } + + return rtas_ret[0]; +} + +static void rtas_teardown_msi_irqs(struct pci_dev *pdev) +{ + struct msi_desc *entry; + + list_for_each_entry(entry, &pdev->msi_list, list) { + if (entry->irq == NO_IRQ) + continue; + + set_irq_msi(entry->irq, NULL); + irq_dispose_mapping(entry->irq); + } + + rtas_disable_msi(pdev); +} + +static int check_req_msi(struct pci_dev *pdev, int nvec) +{ + struct device_node *dn; + struct pci_dn *pdn; + const u32 *req_msi; + + pdn = get_pdn(pdev); + if (!pdn) + return -ENODEV; + + dn = pdn->node; + + req_msi = of_get_property(dn, "ibm,req#msi", NULL); + if (!req_msi) { + pr_debug("rtas_msi: No ibm,req#msi on %s\n", dn->full_name); + return -ENOENT; + } + + if (*req_msi < nvec) { + pr_debug("rtas_msi: ibm,req#msi requests < %d MSIs\n", nvec); + return -ENOSPC; + } + + return 0; +} + +static int rtas_msi_check_device(struct pci_dev *pdev, int nvec, int type) +{ + if (type == PCI_CAP_ID_MSIX) + pr_debug("rtas_msi: MSI-X untested, trying anyway.\n"); + + return check_req_msi(pdev, nvec); +} + +static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) +{ + struct pci_dn *pdn; + int hwirq, virq, i, rc; + struct msi_desc *entry; + + pdn = get_pdn(pdev); + if (!pdn) + return -ENODEV; + + /* + * Try the new more explicit firmware interface, if that fails fall + * back to the old interface. The old interface is known to never + * return MSI-Xs. + */ + if (type == PCI_CAP_ID_MSI) { + rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); + + if (rc != nvec) { + pr_debug("rtas_msi: trying the old firmware call.\n"); + rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec); + } + } else + rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); + + if (rc != nvec) { + pr_debug("rtas_msi: rtas_change_msi() failed\n"); + + /* + * In case of an error it's not clear whether the device is + * left with MSI enabled or not, so we explicitly disable. + */ + goto out_free; + } + + i = 0; + list_for_each_entry(entry, &pdev->msi_list, list) { + hwirq = rtas_query_irq_number(pdn, i); + if (hwirq < 0) { + rc = hwirq; + pr_debug("rtas_msi: error (%d) getting hwirq\n", rc); + goto out_free; + } + + virq = irq_create_mapping(NULL, hwirq); + + if (virq == NO_IRQ) { + pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq); + rc = -ENOSPC; + goto out_free; + } + + dev_dbg(&pdev->dev, "rtas_msi: allocated virq %d\n", virq); + set_irq_msi(virq, entry); + unmask_msi_irq(virq); + } + + return 0; + + out_free: + rtas_teardown_msi_irqs(pdev); + return rc; +} + +static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev) +{ + /* No LSI -> leave MSIs (if any) configured */ + if (pdev->irq == NO_IRQ) { + dev_dbg(&pdev->dev, "rtas_msi: no LSI, nothing to do.\n"); + return; + } + + /* No MSI -> MSIs can't have been assigned by fw, leave LSI */ + if (check_req_msi(pdev, 1)) { + dev_dbg(&pdev->dev, "rtas_msi: no req#msi, nothing to do.\n"); + return; + } + + dev_dbg(&pdev->dev, "rtas_msi: disabling existing MSI.\n"); + rtas_disable_msi(pdev); +} + +static int rtas_msi_init(void) +{ + query_token = rtas_token("ibm,query-interrupt-source-number"); + change_token = rtas_token("ibm,change-msi"); + + if ((query_token == RTAS_UNKNOWN_SERVICE) || + (change_token == RTAS_UNKNOWN_SERVICE)) { + pr_debug("rtas_msi: no RTAS tokens, no MSI support.\n"); + return -1; + } + + pr_debug("rtas_msi: Registering RTAS MSI callbacks.\n"); + + WARN_ON(ppc_md.setup_msi_irqs); + ppc_md.setup_msi_irqs = rtas_setup_msi_irqs; + ppc_md.teardown_msi_irqs = rtas_teardown_msi_irqs; + ppc_md.msi_check_device = rtas_msi_check_device; + + WARN_ON(ppc_md.pci_irq_fixup); + ppc_md.pci_irq_fixup = rtas_msi_pci_irq_fixup; + + return 0; +} +arch_initcall(rtas_msi_init); diff --git a/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c b/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c index fdc1a369f767..ffaf6c5c517b 100644 --- a/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -79,6 +79,7 @@ pcibios_remove_pci_devices(struct pci_bus *bus) pci_remove_bus_device(dev); } } +EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); /* Must be called before pci_bus_add_devices */ void diff --git a/trunk/arch/powerpc/platforms/pseries/setup.c b/trunk/arch/powerpc/platforms/pseries/setup.c index 33eec2822c66..470db6efaeb6 100644 --- a/trunk/arch/powerpc/platforms/pseries/setup.c +++ b/trunk/arch/powerpc/platforms/pseries/setup.c @@ -168,7 +168,7 @@ static void __init pseries_mpic_init_IRQ(void) /* Look for cascade */ for_each_node_by_type(np, "interrupt-controller") - if (device_is_compatible(np, "chrp,iic")) { + if (of_device_is_compatible(np, "chrp,iic")) { cascade = np; break; } diff --git a/trunk/arch/powerpc/platforms/pseries/xics.c b/trunk/arch/powerpc/platforms/pseries/xics.c index 896cbf340c42..b854e7f1001c 100644 --- a/trunk/arch/powerpc/platforms/pseries/xics.c +++ b/trunk/arch/powerpc/platforms/pseries/xics.c @@ -477,7 +477,7 @@ static int xics_host_match(struct irq_host *h, struct device_node *node) * like vdevices, events, etc... The trick we use here is to match * everything here except the legacy 8259 which is compatible "chrp,iic" */ - return !device_is_compatible(node, "chrp,iic"); + return !of_device_is_compatible(node, "chrp,iic"); } static int xics_host_map_direct(struct irq_host *h, unsigned int virq, @@ -618,7 +618,7 @@ static void __init xics_setup_8259_cascade(void) unsigned long intack = 0; for_each_node_by_type(np, "interrupt-controller") - if (device_is_compatible(np, "chrp,iic")) { + if (of_device_is_compatible(np, "chrp,iic")) { found = np; break; } diff --git a/trunk/arch/powerpc/sysdev/Makefile b/trunk/arch/powerpc/sysdev/Makefile index e96ca9618dbb..9ce775c38ab7 100644 --- a/trunk/arch/powerpc/sysdev/Makefile +++ b/trunk/arch/powerpc/sysdev/Makefile @@ -2,7 +2,9 @@ ifeq ($(CONFIG_PPC64),y) EXTRA_CFLAGS += -mno-minimal-toc endif -obj-$(CONFIG_MPIC) += mpic.o +mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o +obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) + obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o obj-$(CONFIG_PPC_MPC106) += grackle.o obj-$(CONFIG_PPC_DCR) += dcr.o @@ -26,7 +28,6 @@ endif # Temporary hack until we have migrated to asm-powerpc ifeq ($(ARCH),powerpc) -obj-$(CONFIG_MTD) += rom.o obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o obj-$(CONFIG_8xx) += mpc8xx_pic.o commproc.o obj-$(CONFIG_UCODE_PATCH) += micropatch.o diff --git a/trunk/arch/powerpc/sysdev/dart_iommu.c b/trunk/arch/powerpc/sysdev/dart_iommu.c index 336186dd7f10..a1d2042bb304 100644 --- a/trunk/arch/powerpc/sysdev/dart_iommu.c +++ b/trunk/arch/powerpc/sysdev/dart_iommu.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,9 @@ static unsigned long dart_tablesize; /* Virtual base address of the DART table */ static u32 *dart_vbase; +#ifdef CONFIG_PM +static u32 *dart_copy; +#endif /* Mapped base address for the dart */ static unsigned int __iomem *dart; @@ -346,6 +350,48 @@ void iommu_init_early_dart(void) set_pci_dma_ops(&dma_direct_ops); } +#ifdef CONFIG_PM +static void iommu_dart_save(void) +{ + memcpy(dart_copy, dart_vbase, 2*1024*1024); +} + +static void iommu_dart_restore(void) +{ + memcpy(dart_vbase, dart_copy, 2*1024*1024); + dart_tlb_invalidate_all(); +} + +static int __init iommu_init_late_dart(void) +{ + unsigned long tbasepfn; + struct page *p; + + /* if no dart table exists then we won't need to save it + * and the area has also not been reserved */ + if (!dart_tablebase) + return 0; + + tbasepfn = __pa(dart_tablebase) >> PAGE_SHIFT; + register_nosave_region_late(tbasepfn, + tbasepfn + ((1<<24) >> PAGE_SHIFT)); + + /* For suspend we need to copy the dart contents because + * it is not part of the regular mapping (see above) and + * thus not saved automatically. The memory for this copy + * must be allocated early because we need 2 MB. */ + p = alloc_pages(GFP_KERNEL, 21 - PAGE_SHIFT); + BUG_ON(!p); + dart_copy = page_address(p); + + ppc_md.iommu_save = iommu_dart_save; + ppc_md.iommu_restore = iommu_dart_restore; + + return 0; +} + +late_initcall(iommu_init_late_dart); +#endif void __init alloc_dart_table(void) { diff --git a/trunk/arch/powerpc/sysdev/mpic.c b/trunk/arch/powerpc/sysdev/mpic.c index 0b84b7c775d8..4fd2bec89916 100644 --- a/trunk/arch/powerpc/sysdev/mpic.c +++ b/trunk/arch/powerpc/sysdev/mpic.c @@ -36,6 +36,8 @@ #include #include +#include "mpic.h" + #ifdef DEBUG #define DBG(fmt...) printk(fmt) #else @@ -354,6 +356,12 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, tmp |= 0x22; writel(tmp, fixup->base + 4); spin_unlock_irqrestore(&mpic->fixup_lock, flags); + +#ifdef CONFIG_PM + /* use the lowest bit inverted to the actual HW, + * set if this fixup was enabled, clear otherwise */ + mpic->save_data[source].fixup_data = tmp | 1; +#endif } static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, @@ -375,8 +383,58 @@ static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, tmp |= 1; writel(tmp, fixup->base + 4); spin_unlock_irqrestore(&mpic->fixup_lock, flags); + +#ifdef CONFIG_PM + /* use the lowest bit inverted to the actual HW, + * set if this fixup was enabled, clear otherwise */ + mpic->save_data[source].fixup_data = tmp & ~1; +#endif } +#ifdef CONFIG_PCI_MSI +static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, + unsigned int devfn) +{ + u8 __iomem *base; + u8 pos, flags; + u64 addr = 0; + + for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; + pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { + u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); + if (id == PCI_CAP_ID_HT) { + id = readb(devbase + pos + 3); + if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_MSI_MAPPING) + break; + } + } + + if (pos == 0) + return; + + base = devbase + pos; + + flags = readb(base + HT_MSI_FLAGS); + if (!(flags & HT_MSI_FLAGS_FIXED)) { + addr = readl(base + HT_MSI_ADDR_LO) & HT_MSI_ADDR_LO_MASK; + addr = addr | ((u64)readl(base + HT_MSI_ADDR_HI) << 32); + } + + printk(KERN_DEBUG "mpic: - HT:%02x.%x %s MSI mapping found @ 0x%lx\n", + PCI_SLOT(devfn), PCI_FUNC(devfn), + flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled", addr); + + if (!(flags & HT_MSI_FLAGS_ENABLE)) + writeb(flags | HT_MSI_FLAGS_ENABLE, base + HT_MSI_FLAGS); +} +#else +static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, + unsigned int devfn) +{ + return; +} +#endif + static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, unsigned int devfn, u32 vdid) { @@ -468,6 +526,7 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) goto next; mpic_scan_ht_pic(mpic, devbase, devfn, l); + mpic_scan_ht_msi(mpic, devbase, devfn); next: /* next device, if function 0 */ @@ -559,7 +618,7 @@ static irqreturn_t mpic_ipi_action(int irq, void *dev_id) */ -static void mpic_unmask_irq(unsigned int irq) +void mpic_unmask_irq(unsigned int irq) { unsigned int loops = 100000; struct mpic *mpic = mpic_from_irq(irq); @@ -579,7 +638,7 @@ static void mpic_unmask_irq(unsigned int irq) } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK); } -static void mpic_mask_irq(unsigned int irq) +void mpic_mask_irq(unsigned int irq) { unsigned int loops = 100000; struct mpic *mpic = mpic_from_irq(irq); @@ -600,7 +659,7 @@ static void mpic_mask_irq(unsigned int irq) } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK)); } -static void mpic_end_irq(unsigned int irq) +void mpic_end_irq(unsigned int irq) { struct mpic *mpic = mpic_from_irq(irq); @@ -733,7 +792,7 @@ static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) } } -static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) +int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) { struct mpic *mpic = mpic_from_irq(virq); unsigned int src = mpic_irq_to_hw(virq); @@ -834,6 +893,8 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, if (hw >= mpic->irq_count) return -EINVAL; + mpic_msi_reserve_hwirq(mpic, hw); + /* Default chip */ chip = &mpic->hc_irq; @@ -1142,8 +1203,10 @@ void __init mpic_init(struct mpic *mpic) /* Do the HT PIC fixups on U3 broken mpic */ DBG("MPIC flags: %x\n", mpic->flags); - if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) - mpic_scan_ht_pics(mpic); + if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) { + mpic_scan_ht_pics(mpic); + mpic_u3msi_init(mpic); + } for (i = 0; i < mpic->num_sources; i++) { /* start with vector = source number, and masked */ @@ -1167,6 +1230,12 @@ void __init mpic_init(struct mpic *mpic) /* Set current processor priority to 0 */ mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); + +#ifdef CONFIG_PM + /* allocate memory to save mpic state */ + mpic->save_data = alloc_bootmem(mpic->num_sources * sizeof(struct mpic_irq_save)); + BUG_ON(mpic->save_data == NULL); +#endif } void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) @@ -1333,8 +1402,11 @@ unsigned int mpic_get_one_irq(struct mpic *mpic) #ifdef DEBUG_LOW DBG("%s: get_one_irq(): %d\n", mpic->name, src); #endif - if (unlikely(src == mpic->spurious_vec)) + if (unlikely(src == mpic->spurious_vec)) { + if (mpic->flags & MPIC_SPV_EOI) + mpic_eoi(mpic); return NO_IRQ; + } return irq_linear_revmap(mpic->irqhost, src); } @@ -1417,3 +1489,79 @@ void __devinit smp_mpic_setup_cpu(int cpu) mpic_setup_this_cpu(); } #endif /* CONFIG_SMP */ + +#ifdef CONFIG_PM +static int mpic_suspend(struct sys_device *dev, pm_message_t state) +{ + struct mpic *mpic = container_of(dev, struct mpic, sysdev); + int i; + + for (i = 0; i < mpic->num_sources; i++) { + mpic->save_data[i].vecprio = + mpic_irq_read(i, MPIC_INFO(IRQ_VECTOR_PRI)); + mpic->save_data[i].dest = + mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); + } + + return 0; +} + +static int mpic_resume(struct sys_device *dev) +{ + struct mpic *mpic = container_of(dev, struct mpic, sysdev); + int i; + + for (i = 0; i < mpic->num_sources; i++) { + mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), + mpic->save_data[i].vecprio); + mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), + mpic->save_data[i].dest); + +#ifdef CONFIG_MPIC_U3_HT_IRQS + { + struct mpic_irq_fixup *fixup = &mpic->fixups[i]; + + if (fixup->base) { + /* we use the lowest bit in an inverted meaning */ + if ((mpic->save_data[i].fixup_data & 1) == 0) + continue; + + /* Enable and configure */ + writeb(0x10 + 2 * fixup->index, fixup->base + 2); + + writel(mpic->save_data[i].fixup_data & ~1, + fixup->base + 4); + } + } +#endif + } /* end for loop */ + + return 0; +} +#endif + +static struct sysdev_class mpic_sysclass = { +#ifdef CONFIG_PM + .resume = mpic_resume, + .suspend = mpic_suspend, +#endif + set_kset_name("mpic"), +}; + +static int mpic_init_sys(void) +{ + struct mpic *mpic = mpics; + int error, id = 0; + + error = sysdev_class_register(&mpic_sysclass); + + while (mpic && !error) { + mpic->sysdev.cls = &mpic_sysclass; + mpic->sysdev.id = id++; + error = sysdev_register(&mpic->sysdev); + mpic = mpic->next; + } + return error; +} + +device_initcall(mpic_init_sys); diff --git a/trunk/arch/powerpc/sysdev/mpic.h b/trunk/arch/powerpc/sysdev/mpic.h new file mode 100644 index 000000000000..3a1c3d2c594d --- /dev/null +++ b/trunk/arch/powerpc/sysdev/mpic.h @@ -0,0 +1,38 @@ +#ifndef _POWERPC_SYSDEV_MPIC_H +#define _POWERPC_SYSDEV_MPIC_H + +/* + * Copyright 2006-2007, Michael Ellerman, 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. + * + */ + +#ifdef CONFIG_PCI_MSI +extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq); +extern int mpic_msi_init_allocator(struct mpic *mpic); +extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num); +extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num); +extern int mpic_u3msi_init(struct mpic *mpic); +#else +static inline void mpic_msi_reserve_hwirq(struct mpic *mpic, + irq_hw_number_t hwirq) +{ + return; +} + +static inline int mpic_u3msi_init(struct mpic *mpic) +{ + return -1; +} +#endif + +extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type); +extern void mpic_end_irq(unsigned int irq); +extern void mpic_mask_irq(unsigned int irq); +extern void mpic_unmask_irq(unsigned int irq); + +#endif /* _POWERPC_SYSDEV_MPIC_H */ diff --git a/trunk/arch/powerpc/sysdev/mpic_msi.c b/trunk/arch/powerpc/sysdev/mpic_msi.c new file mode 100644 index 000000000000..b076793033c2 --- /dev/null +++ b/trunk/arch/powerpc/sysdev/mpic_msi.c @@ -0,0 +1,183 @@ +/* + * Copyright 2006-2007, Michael Ellerman, 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +static void __mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) +{ + pr_debug("mpic: reserving hwirq 0x%lx\n", hwirq); + bitmap_allocate_region(mpic->hwirq_bitmap, hwirq, 0); +} + +void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) +{ + unsigned long flags; + + /* The mpic calls this even when there is no allocator setup */ + if (!mpic->hwirq_bitmap) + return; + + spin_lock_irqsave(&mpic->bitmap_lock, flags); + __mpic_msi_reserve_hwirq(mpic, hwirq); + spin_unlock_irqrestore(&mpic->bitmap_lock, flags); +} + +irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num) +{ + unsigned long flags; + int offset, order = get_count_order(num); + + spin_lock_irqsave(&mpic->bitmap_lock, flags); + /* + * This is fast, but stricter than we need. We might want to add + * a fallback routine which does a linear search with no alignment. + */ + offset = bitmap_find_free_region(mpic->hwirq_bitmap, mpic->irq_count, + order); + spin_unlock_irqrestore(&mpic->bitmap_lock, flags); + + pr_debug("mpic: allocated 0x%x (2^%d) at offset 0x%x\n", + num, order, offset); + + return offset; +} + +void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num) +{ + unsigned long flags; + int order = get_count_order(num); + + pr_debug("mpic: freeing 0x%x (2^%d) at offset 0x%x\n", + num, order, offset); + + spin_lock_irqsave(&mpic->bitmap_lock, flags); + bitmap_release_region(mpic->hwirq_bitmap, offset, order); + spin_unlock_irqrestore(&mpic->bitmap_lock, flags); +} + +#ifdef CONFIG_MPIC_U3_HT_IRQS +static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) +{ + irq_hw_number_t hwirq; + struct irq_host_ops *ops = mpic->irqhost->ops; + struct device_node *np; + int flags, index, i; + struct of_irq oirq; + + pr_debug("mpic: found U3, guessing msi allocator setup\n"); + + /* Reserve source numbers we know are reserved in the HW */ + for (i = 0; i < 8; i++) + __mpic_msi_reserve_hwirq(mpic, i); + + for (i = 42; i < 46; i++) + __mpic_msi_reserve_hwirq(mpic, i); + + for (i = 100; i < 105; i++) + __mpic_msi_reserve_hwirq(mpic, i); + + np = NULL; + while ((np = of_find_all_nodes(np))) { + pr_debug("mpic: mapping hwirqs for %s\n", np->full_name); + + index = 0; + while (of_irq_map_one(np, index++, &oirq) == 0) { + ops->xlate(mpic->irqhost, NULL, oirq.specifier, + oirq.size, &hwirq, &flags); + __mpic_msi_reserve_hwirq(mpic, hwirq); + } + } + + return 0; +} +#else +static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) +{ + return -1; +} +#endif + +static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic) +{ + int i, len; + const u32 *p; + + p = of_get_property(mpic->of_node, "msi-available-ranges", &len); + if (!p) { + pr_debug("mpic: no msi-available-ranges property found on %s\n", + mpic->of_node->full_name); + return -ENODEV; + } + + if (len % 8 != 0) { + printk(KERN_WARNING "mpic: Malformed msi-available-ranges " + "property on %s\n", mpic->of_node->full_name); + return -EINVAL; + } + + bitmap_allocate_region(mpic->hwirq_bitmap, 0, + get_count_order(mpic->irq_count)); + + /* Format is: ( )+ */ + len /= sizeof(u32); + for (i = 0; i < len / 2; i++, p += 2) + mpic_msi_free_hwirqs(mpic, *p, *(p + 1)); + + return 0; +} + +int mpic_msi_init_allocator(struct mpic *mpic) +{ + int rc, size; + + BUG_ON(mpic->hwirq_bitmap); + spin_lock_init(&mpic->bitmap_lock); + + size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long); + pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size); + + if (mem_init_done) + mpic->hwirq_bitmap = kmalloc(size, GFP_KERNEL); + else + mpic->hwirq_bitmap = alloc_bootmem(size); + + if (!mpic->hwirq_bitmap) { + pr_debug("mpic: ENOMEM allocating allocator bitmap!\n"); + return -ENOMEM; + } + + memset(mpic->hwirq_bitmap, 0, size); + + rc = mpic_msi_reserve_dt_hwirqs(mpic); + if (rc) { + if (mpic->flags & MPIC_U3_HT_IRQS) + rc = mpic_msi_reserve_u3_hwirqs(mpic); + + if (rc) + goto out_free; + } + + return 0; + + out_free: + if (mem_init_done) + kfree(mpic->hwirq_bitmap); + + mpic->hwirq_bitmap = NULL; + return rc; +} diff --git a/trunk/arch/powerpc/sysdev/mpic_u3msi.c b/trunk/arch/powerpc/sysdev/mpic_u3msi.c new file mode 100644 index 000000000000..305b864c25d9 --- /dev/null +++ b/trunk/arch/powerpc/sysdev/mpic_u3msi.c @@ -0,0 +1,186 @@ +/* + * Copyright 2006, Segher Boessenkool, IBM Corporation. + * Copyright 2006-2007, Michael Ellerman, 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mpic.h" + +/* A bit ugly, can we get this from the pci_dev somehow? */ +static struct mpic *msi_mpic; + +static void mpic_u3msi_mask_irq(unsigned int irq) +{ + mask_msi_irq(irq); + mpic_mask_irq(irq); +} + +static void mpic_u3msi_unmask_irq(unsigned int irq) +{ + mpic_unmask_irq(irq); + unmask_msi_irq(irq); +} + +static struct irq_chip mpic_u3msi_chip = { + .shutdown = mpic_u3msi_mask_irq, + .mask = mpic_u3msi_mask_irq, + .unmask = mpic_u3msi_unmask_irq, + .eoi = mpic_end_irq, + .set_type = mpic_set_irq_type, + .typename = "MPIC-U3MSI", +}; + +static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos) +{ + u8 flags; + u32 tmp; + u64 addr; + + pci_read_config_byte(pdev, pos + HT_MSI_FLAGS, &flags); + + if (flags & HT_MSI_FLAGS_FIXED) + return HT_MSI_FIXED_ADDR; + + pci_read_config_dword(pdev, pos + HT_MSI_ADDR_LO, &tmp); + addr = tmp & HT_MSI_ADDR_LO_MASK; + pci_read_config_dword(pdev, pos + HT_MSI_ADDR_HI, &tmp); + addr = addr | ((u64)tmp << 32); + + return addr; +} + +static u64 find_ht_magic_addr(struct pci_dev *pdev) +{ + struct pci_bus *bus; + unsigned int pos; + + for (bus = pdev->bus; bus; bus = bus->parent) { + pos = pci_find_ht_capability(bus->self, HT_CAPTYPE_MSI_MAPPING); + if (pos) + return read_ht_magic_addr(bus->self, pos); + } + + return 0; +} + +static int u3msi_msi_check_device(struct pci_dev *pdev, int nvec, int type) +{ + if (type == PCI_CAP_ID_MSIX) + pr_debug("u3msi: MSI-X untested, trying anyway.\n"); + + /* If we can't find a magic address then MSI ain't gonna work */ + if (find_ht_magic_addr(pdev) == 0) { + pr_debug("u3msi: no magic address found for %s\n", + pci_name(pdev)); + return -ENXIO; + } + + return 0; +} + +static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) +{ + struct msi_desc *entry; + + list_for_each_entry(entry, &pdev->msi_list, list) { + if (entry->irq == NO_IRQ) + continue; + + set_irq_msi(entry->irq, NULL); + mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), 1); + irq_dispose_mapping(entry->irq); + } + + return; +} + +static void u3msi_compose_msi_msg(struct pci_dev *pdev, int virq, + struct msi_msg *msg) +{ + u64 addr; + + addr = find_ht_magic_addr(pdev); + msg->address_lo = addr & 0xFFFFFFFF; + msg->address_hi = addr >> 32; + msg->data = virq_to_hw(virq); + + pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) at address 0x%lx\n", + virq, virq_to_hw(virq), addr); +} + +static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) +{ + irq_hw_number_t hwirq; + int rc; + unsigned int virq; + struct msi_desc *entry; + struct msi_msg msg; + + list_for_each_entry(entry, &pdev->msi_list, list) { + hwirq = mpic_msi_alloc_hwirqs(msi_mpic, 1); + if (hwirq < 0) { + rc = hwirq; + pr_debug("u3msi: failed allocating hwirq\n"); + goto out_free; + } + + virq = irq_create_mapping(msi_mpic->irqhost, hwirq); + if (virq == NO_IRQ) { + pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq); + mpic_msi_free_hwirqs(msi_mpic, hwirq, 1); + rc = -ENOSPC; + goto out_free; + } + + set_irq_msi(virq, entry); + set_irq_chip(virq, &mpic_u3msi_chip); + set_irq_type(virq, IRQ_TYPE_EDGE_RISING); + + u3msi_compose_msi_msg(pdev, virq, &msg); + write_msi_msg(virq, &msg); + + hwirq++; + } + + return 0; + + out_free: + u3msi_teardown_msi_irqs(pdev); + return rc; +} + +int mpic_u3msi_init(struct mpic *mpic) +{ + int rc; + + rc = mpic_msi_init_allocator(mpic); + if (rc) { + pr_debug("u3msi: Error allocating bitmap!\n"); + return rc; + } + + pr_debug("u3msi: Registering MPIC U3 MSI callbacks.\n"); + + BUG_ON(msi_mpic); + msi_mpic = mpic; + + WARN_ON(ppc_md.setup_msi_irqs); + ppc_md.setup_msi_irqs = u3msi_setup_msi_irqs; + ppc_md.teardown_msi_irqs = u3msi_teardown_msi_irqs; + ppc_md.msi_check_device = u3msi_msi_check_device; + + return 0; +} diff --git a/trunk/arch/powerpc/sysdev/rom.c b/trunk/arch/powerpc/sysdev/rom.c deleted file mode 100644 index c855a3b298a3..000000000000 --- a/trunk/arch/powerpc/sysdev/rom.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * ROM device registration - * - * (C) 2006 MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#include -#include -#include - -static int __init powerpc_flash_init(void) -{ - struct device_node *node = NULL; - - /* - * Register all the devices which type is "rom" - */ - while ((node = of_find_node_by_type(node, "rom")) != NULL) { - if (node->name == NULL) { - printk(KERN_WARNING "powerpc_flash_init: found 'rom' " - "device, but with no name, skipping...\n"); - continue; - } - of_platform_device_create(node, node->name, NULL); - } - return 0; -} - -arch_initcall(powerpc_flash_init); diff --git a/trunk/arch/powerpc/sysdev/tsi108_dev.c b/trunk/arch/powerpc/sysdev/tsi108_dev.c index 337039ee51e6..7d3b09b7d544 100644 --- a/trunk/arch/powerpc/sysdev/tsi108_dev.c +++ b/trunk/arch/powerpc/sysdev/tsi108_dev.c @@ -107,8 +107,9 @@ static int __init tsi108_eth_of_init(void) goto err; } - mac_addr = of_get_property(np, "address", NULL); - memcpy(tsi_eth_data.mac_addr, mac_addr, 6); + mac_addr = of_get_mac_address(np); + if (mac_addr) + memcpy(tsi_eth_data.mac_addr, mac_addr, 6); ph = of_get_property(np, "phy-handle", NULL); phy = of_find_node_by_phandle(*ph); @@ -129,6 +130,8 @@ static int __init tsi108_eth_of_init(void) tsi_eth_data.phyregs = res.start; tsi_eth_data.phy = *phy_id; tsi_eth_data.irq_num = irq_of_parse_and_map(np, 0); + if (of_device_is_compatible(phy, "bcm54xx")) + tsi_eth_data.phy_type = TSI108_PHY_BCM54XX; of_node_put(phy); ret = platform_device_add_data(tsi_eth_dev, &tsi_eth_data, diff --git a/trunk/arch/powerpc/sysdev/tsi108_pci.c b/trunk/arch/powerpc/sysdev/tsi108_pci.c index 58b9e7f8abf2..2153163fa593 100644 --- a/trunk/arch/powerpc/sysdev/tsi108_pci.c +++ b/trunk/arch/powerpc/sysdev/tsi108_pci.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,7 @@ ((((bus)<<16) | ((devfunc)<<8) | (offset & 0xfc)) + tsi108_pci_cfg_base) u32 tsi108_pci_cfg_base; +static u32 tsi108_pci_cfg_phys; u32 tsi108_csr_vir_base; static struct device_node *pci_irq_node; static struct irq_host *pci_irq_host; @@ -185,7 +187,7 @@ tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn, int offset, void tsi108_clear_pci_cfg_error(void) { - tsi108_clear_pci_error(TSI108_PCI_CFG_BASE_PHYS); + tsi108_clear_pci_error(tsi108_pci_cfg_phys); } static struct pci_ops tsi108_direct_pci_ops = { @@ -193,17 +195,17 @@ static struct pci_ops tsi108_direct_pci_ops = { tsi108_direct_write_config }; -int __init tsi108_setup_pci(struct device_node *dev) +int __init tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary) { int len; struct pci_controller *hose; struct resource rsrc; const int *bus_range; - int primary = 0, has_address = 0; + int has_address = 0; /* PCI Config mapping */ - tsi108_pci_cfg_base = (u32)ioremap(TSI108_PCI_CFG_BASE_PHYS, - TSI108_PCI_CFG_SIZE); + tsi108_pci_cfg_base = (u32)ioremap(cfg_phys, TSI108_PCI_CFG_SIZE); + tsi108_pci_cfg_phys = cfg_phys; DBG("TSI_PCI: %s tsi108_pci_cfg_base=0x%x\n", __FUNCTION__, tsi108_pci_cfg_base); diff --git a/trunk/arch/powerpc/sysdev/uic.c b/trunk/arch/powerpc/sysdev/uic.c index 968fb40af9dc..89059895a20d 100644 --- a/trunk/arch/powerpc/sysdev/uic.c +++ b/trunk/arch/powerpc/sysdev/uic.c @@ -221,7 +221,7 @@ static struct uic * __init uic_init_one(struct device_node *node) const u32 *indexp, *dcrreg; int len; - BUG_ON(! device_is_compatible(node, "ibm,uic")); + BUG_ON(! of_device_is_compatible(node, "ibm,uic")); uic = alloc_bootmem(sizeof(*uic)); if (! uic) diff --git a/trunk/arch/powerpc/xmon/xmon.c b/trunk/arch/powerpc/xmon/xmon.c index b481db1dacb4..28fdf4f50c27 100644 --- a/trunk/arch/powerpc/xmon/xmon.c +++ b/trunk/arch/powerpc/xmon/xmon.c @@ -1217,7 +1217,6 @@ static void get_function_bounds(unsigned long pc, unsigned long *startp, { unsigned long size, offset; const char *name; - char *modname; *startp = *endp = 0; if (pc == 0) @@ -1225,7 +1224,7 @@ static void get_function_bounds(unsigned long pc, unsigned long *startp, if (setjmp(bus_error_jmp) == 0) { catch_memory_errors = 1; sync(); - name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr); + name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr); if (name != NULL) { *startp = pc - offset; *endp = pc - offset + size; diff --git a/trunk/arch/ppc/kernel/ppc_htab.c b/trunk/arch/ppc/kernel/ppc_htab.c index 0a7e42d54eaf..aa07b63c0a6c 100644 --- a/trunk/arch/ppc/kernel/ppc_htab.c +++ b/trunk/arch/ppc/kernel/ppc_htab.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/ppc/kernel/smp.c b/trunk/arch/ppc/kernel/smp.c index 96a55972b986..055998575cb4 100644 --- a/trunk/arch/ppc/kernel/smp.c +++ b/trunk/arch/ppc/kernel/smp.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/ppc/syslib/ppc4xx_sgdma.c b/trunk/arch/ppc/syslib/ppc4xx_sgdma.c index 5dadca3e0d61..c4b369b50f9c 100644 --- a/trunk/arch/ppc/syslib/ppc4xx_sgdma.c +++ b/trunk/arch/ppc/syslib/ppc4xx_sgdma.c @@ -23,10 +23,10 @@ #include #include #include +#include #include #include -#include #include void diff --git a/trunk/arch/ppc/syslib/virtex_devices.h b/trunk/arch/ppc/syslib/virtex_devices.h index 4a17dd3927c1..3d4be1412f60 100644 --- a/trunk/arch/ppc/syslib/virtex_devices.h +++ b/trunk/arch/ppc/syslib/virtex_devices.h @@ -13,6 +13,13 @@ #include +/* ML300/403 reference design framebuffer driver platform data struct */ +struct xilinxfb_platform_data { + u32 rotate_screen; + u32 screen_height_mm; + u32 screen_width_mm; +}; + void __init virtex_early_serial_map(void); /* Prototype for device fixup routine. Implement this routine in the diff --git a/trunk/arch/s390/Kconfig b/trunk/arch/s390/Kconfig index e6ec418093e5..1a84719be264 100644 --- a/trunk/arch/s390/Kconfig +++ b/trunk/arch/s390/Kconfig @@ -49,6 +49,9 @@ config GENERIC_BUG config NO_IOMEM def_bool y +config NO_DMA + def_bool y + mainmenu "Linux Kernel Configuration" config S390 diff --git a/trunk/arch/s390/kernel/compat_signal.c b/trunk/arch/s390/kernel/compat_signal.c index 80a54a0149ab..a5692c460bad 100644 --- a/trunk/arch/s390/kernel/compat_signal.c +++ b/trunk/arch/s390/kernel/compat_signal.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/s390/kernel/dis.c b/trunk/arch/s390/kernel/dis.c index dabaf98943d0..a057ebf108a7 100644 --- a/trunk/arch/s390/kernel/dis.c +++ b/trunk/arch/s390/kernel/dis.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -33,7 +34,6 @@ #include #include #include -#include #ifndef CONFIG_64BIT #define ONELONG "%08lx: " diff --git a/trunk/arch/s390/kernel/kprobes.c b/trunk/arch/s390/kernel/kprobes.c index 23c61f6d965b..e39333ae0fcf 100644 --- a/trunk/arch/s390/kernel/kprobes.c +++ b/trunk/arch/s390/kernel/kprobes.c @@ -24,8 +24,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -271,23 +271,13 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, } /* Called with kretprobe_lock held */ -void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, +void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { - struct kretprobe_instance *ri; + ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14]; - if ((ri = get_free_rp_inst(rp)) != NULL) { - ri->rp = rp; - ri->task = current; - ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14]; - - /* Replace the return addr with trampoline addr */ - regs->gprs[14] = (unsigned long)&kretprobe_trampoline; - - add_rp_inst(ri); - } else { - rp->nmissed++; - } + /* Replace the return addr with trampoline addr */ + regs->gprs[14] = (unsigned long)&kretprobe_trampoline; } static int __kprobes kprobe_handler(struct pt_regs *regs) @@ -671,3 +661,10 @@ int __init arch_init_kprobes(void) { return register_kprobe(&trampoline_p); } + +int __kprobes arch_trampoline_kprobe(struct kprobe *p) +{ + if (p->addr == (kprobe_opcode_t *) & kretprobe_trampoline) + return 1; + return 0; +} diff --git a/trunk/arch/s390/kernel/process.c b/trunk/arch/s390/kernel/process.c index 11d9b0197626..eb43c3b31269 100644 --- a/trunk/arch/s390/kernel/process.c +++ b/trunk/arch/s390/kernel/process.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/s390/kernel/signal.c b/trunk/arch/s390/kernel/signal.c index 3c41907799a1..d264671c1b71 100644 --- a/trunk/arch/s390/kernel/signal.c +++ b/trunk/arch/s390/kernel/signal.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/s390/kernel/smp.c b/trunk/arch/s390/kernel/smp.c index 3754e2031b39..b7977027a28f 100644 --- a/trunk/arch/s390/kernel/smp.c +++ b/trunk/arch/s390/kernel/smp.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/s390/kernel/stacktrace.c b/trunk/arch/s390/kernel/stacktrace.c index 2e5c65a1863e..515ff9011dd7 100644 --- a/trunk/arch/s390/kernel/stacktrace.c +++ b/trunk/arch/s390/kernel/stacktrace.c @@ -59,7 +59,7 @@ static unsigned long save_context_stack(struct stack_trace *trace, } } -void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +void save_stack_trace(struct stack_trace *trace) { register unsigned long sp asm ("15"); unsigned long orig_sp, new_sp; @@ -69,20 +69,16 @@ void save_stack_trace(struct stack_trace *trace, struct task_struct *task) new_sp = save_context_stack(trace, &trace->skip, orig_sp, S390_lowcore.panic_stack - PAGE_SIZE, S390_lowcore.panic_stack); - if ((new_sp != orig_sp) && !trace->all_contexts) + if (new_sp != orig_sp) return; new_sp = save_context_stack(trace, &trace->skip, new_sp, S390_lowcore.async_stack - ASYNC_SIZE, S390_lowcore.async_stack); - if ((new_sp != orig_sp) && !trace->all_contexts) + if (new_sp != orig_sp) return; - if (task) - save_context_stack(trace, &trace->skip, new_sp, - (unsigned long) task_stack_page(task), - (unsigned long) task_stack_page(task) + THREAD_SIZE); - else - save_context_stack(trace, &trace->skip, new_sp, - S390_lowcore.thread_info, - S390_lowcore.thread_info + THREAD_SIZE); + + save_context_stack(trace, &trace->skip, new_sp, + S390_lowcore.thread_info, + S390_lowcore.thread_info + THREAD_SIZE); return; } diff --git a/trunk/arch/s390/kernel/sys_s390.c b/trunk/arch/s390/kernel/sys_s390.c index 3a77c22cda78..1c90c7e99978 100644 --- a/trunk/arch/s390/kernel/sys_s390.c +++ b/trunk/arch/s390/kernel/sys_s390.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/s390/kernel/time.c b/trunk/arch/s390/kernel/time.c index 711dae8da7ad..9c2872a7cca7 100644 --- a/trunk/arch/s390/kernel/time.c +++ b/trunk/arch/s390/kernel/time.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/s390/kernel/traps.c b/trunk/arch/s390/kernel/traps.c index 49dec830373a..cbfe73034c30 100644 --- a/trunk/arch/s390/kernel/traps.c +++ b/trunk/arch/s390/kernel/traps.c @@ -22,11 +22,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -40,7 +40,6 @@ #include #include #include -#include /* Called from entry.S only */ extern void handle_per_exception(struct pt_regs *regs); @@ -70,20 +69,6 @@ static int kstack_depth_to_print = 12; static int kstack_depth_to_print = 20; #endif /* CONFIG_64BIT */ -ATOMIC_NOTIFIER_HEAD(s390die_chain); - -int register_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&s390die_chain, nb); -} -EXPORT_SYMBOL(register_die_notifier); - -int unregister_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&s390die_chain, nb); -} -EXPORT_SYMBOL(unregister_die_notifier); - /* * For show_trace we have tree different stack to consider: * - the panic stack which is used if the kernel stack has overflown diff --git a/trunk/arch/s390/mm/fault.c b/trunk/arch/s390/mm/fault.c index 91f705adc3f9..8b924b359774 100644 --- a/trunk/arch/s390/mm/fault.c +++ b/trunk/arch/s390/mm/fault.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -30,7 +31,6 @@ #include #include -#include #include #ifndef CONFIG_64BIT diff --git a/trunk/arch/sh/Kconfig b/trunk/arch/sh/Kconfig index 4d16d8917074..d74eb120a9c6 100644 --- a/trunk/arch/sh/Kconfig +++ b/trunk/arch/sh/Kconfig @@ -22,6 +22,10 @@ config RWSEM_GENERIC_SPINLOCK config RWSEM_XCHGADD_ALGORITHM bool +config GENERIC_BUG + def_bool y + depends on BUG + config GENERIC_FIND_NEXT_BIT bool default y @@ -88,6 +92,14 @@ config SH_SOLUTION_ENGINE Select SolutionEngine if configuring for a Hitachi SH7709 or SH7750 evaluation board. +config SH_7722_SOLUTION_ENGINE + bool "SolutionEngine7722" + select SOLUTION_ENGINE + select CPU_SUBTYPE_SH7722 + help + Select 7722 SolutionEngine if configuring for a Hitachi SH772 + evaluation board. + config SH_7751_SOLUTION_ENGINE bool "SolutionEngine7751" select SOLUTION_ENGINE @@ -95,6 +107,14 @@ config SH_7751_SOLUTION_ENGINE help Select 7751 SolutionEngine if configuring for a Hitachi SH7751 evaluation board. + +config SH_7780_SOLUTION_ENGINE + bool "SolutionEngine7780" + select SOLUTION_ENGINE + select CPU_SUBTYPE_SH7780 + help + Select 7780 SolutionEngine if configuring for a Renesas SH7780 + evaluation board. config SH_7300_SOLUTION_ENGINE bool "SolutionEngine7300" @@ -193,12 +213,8 @@ config SH_RTS7751R2D Select RTS7751R2D if configuring for a Renesas Technology Sales SH-Graphics board. -config SH_R7780RP - bool "R7780RP-1" - select CPU_SUBTYPE_SH7780 - help - Select R7780RP-1 if configuring for a Renesas Solutions - HIGHLANDER board. +config SH_HIGHLANDER + bool "Highlander" config SH_EDOSK7705 bool "EDOSK7705" @@ -243,6 +259,12 @@ config SH_7619_SOLUTION_ENGINE help Select 7619 SolutionEngine if configuring for a Hitachi SH7619 evaluation board. + +config SH_LBOX_RE2 + bool "L-BOX RE2" + select CPU_SUBTYPE_SH7751R + help + Select L-BOX RE2 if configuring for the NTT COMWARE L-BOX RE2. config SH_UNKNOWN bool "BareCPU" @@ -258,6 +280,10 @@ config SH_UNKNOWN endchoice +source "arch/sh/boards/renesas/hs7751rvoip/Kconfig" +source "arch/sh/boards/renesas/rts7751r2d/Kconfig" +source "arch/sh/boards/renesas/r7780rp/Kconfig" + source "arch/sh/mm/Kconfig" config CF_ENABLER @@ -366,6 +392,16 @@ config SH_STORE_QUEUES Selecting this option will enable an in-kernel API for manipulating the store queues integrated in the SH-4 processors. +config SPECULATIVE_EXECUTION + bool "Speculative subroutine return" + depends on CPU_SUBTYPE_SH7780 && EXPERIMENTAL + help + This enables support for a speculative instruction fetch for + subroutine return. There are various pitfalls associated with + this, as outlined in the SH7780 hardware manual. + + If unsure, say N. + config CPU_HAS_INTEVT bool @@ -398,8 +434,9 @@ config CPU_HAS_PTEA endmenu -menu "Timer support" -depends on !GENERIC_TIME +menu "Timer and clock configuration" + +if !GENERIC_TIME config SH_TMU bool "TMU timer support" @@ -422,17 +459,11 @@ config SH_MTU2 help This enables the use of the MTU2 as the system timer. -endmenu - -source "arch/sh/boards/renesas/hs7751rvoip/Kconfig" - -source "arch/sh/boards/renesas/rts7751r2d/Kconfig" - -source "arch/sh/boards/renesas/r7780rp/Kconfig" +endif config SH_TIMER_IRQ int - default "28" if CPU_SUBTYPE_SH7780 + default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785 default "86" if CPU_SUBTYPE_SH7619 default "140" if CPU_SUBTYPE_SH7206 default "16" @@ -462,7 +493,8 @@ config SH_PCLK_FREQ default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \ CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \ CPU_SUBTYPE_SH7206 - default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780 + default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780 || \ + CPU_SUBTYPE_SH7785 default "60000000" if CPU_SUBTYPE_SH7751 default "66000000" if CPU_SUBTYPE_SH4_202 help @@ -477,6 +509,8 @@ config SH_CLK_MD help MD2 - MD0 pin setting. +endmenu + menu "CPU Frequency scaling" source "drivers/cpufreq/Kconfig" @@ -495,21 +529,6 @@ config SH_CPU_FREQ endmenu -source "arch/sh/drivers/dma/Kconfig" - -source "arch/sh/cchips/Kconfig" - -config HEARTBEAT - bool "Heartbeat LED" - depends on SH_MPC1211 || SH_SH03 || \ - SOLUTION_ENGINE || \ - SH_RTS7751R2D || SH_SH4202_MICRODEV || SH_LANDISK || \ - SH_R7780RP - help - Use the power-on LED on your machine as a load meter. The exact - behavior is platform-dependent, but normally the flash frequency is - a hyperbolic function of the 5-minute load average. - source "arch/sh/drivers/Kconfig" endmenu @@ -540,6 +559,20 @@ config KEXEC support. As of this writing the exact hardware interface is strongly in flux, so no good recommendation can be made. +config CRASH_DUMP + bool "kernel crash dumps (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + Generate crash dump after being started by kexec. + This should be normally only set in special crash dump kernels + which are loaded in the main kernel with kexec-tools into + a specially reserved region and then later executed after + a crash by kdump/kexec. The crash dump kernel must be compiled + to a memory address not used by the main kernel using + MEMORY_START. + + For more details see Documentation/kdump/kdump.txt + config SMP bool "Symmetric multi-processing support" ---help--- diff --git a/trunk/arch/sh/Kconfig.debug b/trunk/arch/sh/Kconfig.debug index 87902e0298e2..b56307294b67 100644 --- a/trunk/arch/sh/Kconfig.debug +++ b/trunk/arch/sh/Kconfig.debug @@ -33,6 +33,7 @@ config EARLY_SCIF_CONSOLE_PORT default "0xffe00000" if CPU_SUBTYPE_SH7780 default "0xfffe9800" if CPU_SUBTYPE_SH7206 default "0xf8420000" if CPU_SUBTYPE_SH7619 + default "0xa4400000" if CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7705 default "0xffe80000" if CPU_SH4 config EARLY_PRINTK @@ -77,16 +78,17 @@ config 4KSTACKS on the VM subsystem for higher order allocations. This option will also use IRQ stacks to compensate for the reduced stackspace. -config KGDB +config SH_KGDB bool "Include KGDB kernel debugger" select FRAME_POINTER + select DEBUG_INFO help Include in-kernel hooks for kgdb, the Linux kernel source level debugger. See for more information. Unless you are intending to debug the kernel, say N here. menu "KGDB configuration options" - depends on KGDB + depends on SH_KGDB config MORE_COMPILE_OPTIONS bool "Add any additional compile options" @@ -103,22 +105,16 @@ config KGDB_NMI bool "Enter KGDB on NMI" default n -config KGDB_THREAD - bool "Include KGDB thread support" - default y - config SH_KGDB_CONSOLE bool "Console messages through GDB" + depends on !SERIAL_SH_SCI_CONSOLE + select SERIAL_CORE_CONSOLE default n config KGDB_SYSRQ bool "Allow SysRq 'G' to enter KGDB" default y -config KGDB_KERNEL_ASSERTS - bool "Include KGDB kernel assertions" - default n - comment "Serial port setup" config KGDB_DEFPORT @@ -131,7 +127,7 @@ config KGDB_DEFBAUD choice prompt "Parity" - depends on KGDB + depends on SH_KGDB default KGDB_DEFPARITY_N config KGDB_DEFPARITY_N @@ -147,7 +143,7 @@ endchoice choice prompt "Data bits" - depends on KGDB + depends on SH_KGDB default KGDB_DEFBITS_8 config KGDB_DEFBITS_8 diff --git a/trunk/arch/sh/Makefile b/trunk/arch/sh/Makefile index bd9b1729f8b8..7b1122417050 100644 --- a/trunk/arch/sh/Makefile +++ b/trunk/arch/sh/Makefile @@ -47,7 +47,6 @@ cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) -ffreestanding cflags-$(CONFIG_SH_DSP) += -Wa,-dsp -cflags-$(CONFIG_SH_KGDB) += -g cflags-$(CONFIG_MORE_COMPILE_OPTIONS) += \ $(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g') @@ -89,7 +88,9 @@ core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/ # Boards machdir-$(CONFIG_SH_SOLUTION_ENGINE) := se/770x +machdir-$(CONFIG_SH_7722_SOLUTION_ENGINE) := se/7722 machdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) := se/7751 +machdir-$(CONFIG_SH_7780_SOLUTION_ENGINE) := se/7780 machdir-$(CONFIG_SH_7300_SOLUTION_ENGINE) := se/7300 machdir-$(CONFIG_SH_7343_SOLUTION_ENGINE) := se/7343 machdir-$(CONFIG_SH_73180_SOLUTION_ENGINE) := se/73180 @@ -103,7 +104,7 @@ machdir-$(CONFIG_SH_HS7751RVOIP) := renesas/hs7751rvoip machdir-$(CONFIG_SH_RTS7751R2D) := renesas/rts7751r2d machdir-$(CONFIG_SH_7751_SYSTEMH) := renesas/systemh machdir-$(CONFIG_SH_EDOSK7705) := renesas/edosk7705 -machdir-$(CONFIG_SH_R7780RP) := renesas/r7780rp +machdir-$(CONFIG_SH_HIGHLANDER) := renesas/r7780rp machdir-$(CONFIG_SH_7710VOIPGW) := renesas/sh7710voipgw machdir-$(CONFIG_SH_SH4202_MICRODEV) := superh/microdev machdir-$(CONFIG_SH_LANDISK) := landisk @@ -111,6 +112,7 @@ machdir-$(CONFIG_SH_TITAN) := titan machdir-$(CONFIG_SH_SHMIN) := shmin machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE) := se/7206 machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE) := se/7619 +machdir-$(CONFIG_SH_LBOX_RE2) := lboxre2 machdir-$(CONFIG_SH_UNKNOWN) := unknown incdir-y := $(notdir $(machdir-y)) diff --git a/trunk/arch/sh/boards/hp6xx/Makefile b/trunk/arch/sh/boards/hp6xx/Makefile index ff1b7f5b4e91..b3124278247c 100644 --- a/trunk/arch/sh/boards/hp6xx/Makefile +++ b/trunk/arch/sh/boards/hp6xx/Makefile @@ -2,6 +2,6 @@ # Makefile for the HP6xx specific parts of the kernel # -obj-y := setup.o +obj-y := setup.o obj-$(CONFIG_PM) += pm.o pm_wakeup.o -obj-$(CONFIG_APM) += hp6xx_apm.o +obj-$(CONFIG_APM_EMULATION) += hp6xx_apm.o diff --git a/trunk/arch/sh/boards/hp6xx/setup.c b/trunk/arch/sh/boards/hp6xx/setup.c index b5a96649ed26..6aeee85c9785 100644 --- a/trunk/arch/sh/boards/hp6xx/setup.c +++ b/trunk/arch/sh/boards/hp6xx/setup.c @@ -2,6 +2,7 @@ * linux/arch/sh/boards/hp6xx/setup.c * * Copyright (C) 2002 Andriy Skulysh + * Copyright (C) 2007 Kristoffer Ericson * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. @@ -10,6 +11,7 @@ */ #include #include +#include #include #include #include @@ -19,6 +21,40 @@ #define SCPCR 0xa4000116 #define SCPDR 0xa4000136 +/* CF Slot */ +static struct resource cf_ide_resources[] = { + [0] = { + .start = 0x15000000 + 0x1f0, + .end = 0x15000000 + 0x1f0 + 0x08 - 0x01, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0x15000000 + 0x1fe, + .end = 0x15000000 + 0x1fe + 0x01, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = 93, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device cf_ide_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(cf_ide_resources), + .resource = cf_ide_resources, +}; + +static struct platform_device *hp6xx_devices[] __initdata = { + &cf_ide_device, +}; + +static int __init hp6xx_devices_setup(void) +{ + return platform_add_devices(hp6xx_devices, ARRAY_SIZE(hp6xx_devices)); +} + static void __init hp6xx_setup(char **cmdline_p) { u8 v8; @@ -60,41 +96,12 @@ static void __init hp6xx_setup(char **cmdline_p) v |= SCPCR_TS_ENABLE; ctrl_outw(v, SCPCR); } +device_initcall(hp6xx_devices_setup); -/* - * XXX: This is stupid, we should have a generic machine vector for the cchips - * and just wrap the platform setup code in to this, as it's the only thing - * that ends up being different. - */ struct sh_machine_vector mv_hp6xx __initmv = { .mv_name = "hp6xx", .mv_setup = hp6xx_setup, .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM, - - .mv_inb = hd64461_inb, - .mv_inw = hd64461_inw, - .mv_inl = hd64461_inl, - .mv_outb = hd64461_outb, - .mv_outw = hd64461_outw, - .mv_outl = hd64461_outl, - - .mv_inb_p = hd64461_inb_p, - .mv_inw_p = hd64461_inw, - .mv_inl_p = hd64461_inl, - .mv_outb_p = hd64461_outb_p, - .mv_outw_p = hd64461_outw, - .mv_outl_p = hd64461_outl, - - .mv_insb = hd64461_insb, - .mv_insw = hd64461_insw, - .mv_insl = hd64461_insl, - .mv_outsb = hd64461_outsb, - .mv_outsw = hd64461_outsw, - .mv_outsl = hd64461_outsl, - - .mv_readw = hd64461_readw, - .mv_writew = hd64461_writew, - .mv_irq_demux = hd64461_irq_demux, }; ALIAS_MV(hp6xx) diff --git a/trunk/arch/sh/boards/landisk/Makefile b/trunk/arch/sh/boards/landisk/Makefile index 89e4beb2ad47..a696b4277fa9 100644 --- a/trunk/arch/sh/boards/landisk/Makefile +++ b/trunk/arch/sh/boards/landisk/Makefile @@ -2,4 +2,4 @@ # Makefile for I-O DATA DEVICE, INC. "LANDISK Series" # -obj-y := setup.o io.o irq.o rtc.o landisk_pwb.o +obj-y := setup.o irq.o psw.o gio.o diff --git a/trunk/arch/sh/boards/landisk/gio.c b/trunk/arch/sh/boards/landisk/gio.c new file mode 100644 index 000000000000..50d38be62f01 --- /dev/null +++ b/trunk/arch/sh/boards/landisk/gio.c @@ -0,0 +1,167 @@ +/* + * arch/sh/boards/landisk/gio.c - driver for landisk + * + * This driver will also support the I-O DATA Device, Inc. LANDISK Board. + * LANDISK and USL-5P Button, LED and GIO driver drive function. + * + * Copylight (C) 2006 kogiidena + * Copylight (C) 2002 Atom Create Engineering Co., Ltd. * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVCOUNT 4 +#define GIO_MINOR 2 /* GIO minor no. */ + +static dev_t dev; +static struct cdev *cdev_p; +static int openCnt; + +static int gio_open(struct inode *inode, struct file *filp) +{ + int minor; + + minor = MINOR(inode->i_rdev); + if (minor < DEVCOUNT) { + if (openCnt > 0) { + return -EALREADY; + } else { + openCnt++; + return 0; + } + } + return -ENOENT; +} + +static int gio_close(struct inode *inode, struct file *filp) +{ + int minor; + + minor = MINOR(inode->i_rdev); + if (minor < DEVCOUNT) { + openCnt--; + } + return 0; +} + +static int gio_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + unsigned int data; + static unsigned int addr = 0; + + if (cmd & 0x01) { /* write */ + if (copy_from_user(&data, (int *)arg, sizeof(int))) { + return -EFAULT; + } + } + + switch (cmd) { + case GIODRV_IOCSGIOSETADDR: /* addres set */ + addr = data; + break; + + case GIODRV_IOCSGIODATA1: /* write byte */ + ctrl_outb((unsigned char)(0x0ff & data), addr); + break; + + case GIODRV_IOCSGIODATA2: /* write word */ + if (addr & 0x01) { + return -EFAULT; + } + ctrl_outw((unsigned short int)(0x0ffff & data), addr); + break; + + case GIODRV_IOCSGIODATA4: /* write long */ + if (addr & 0x03) { + return -EFAULT; + } + ctrl_outl(data, addr); + break; + + case GIODRV_IOCGGIODATA1: /* read byte */ + data = ctrl_inb(addr); + break; + + case GIODRV_IOCGGIODATA2: /* read word */ + if (addr & 0x01) { + return -EFAULT; + } + data = ctrl_inw(addr); + break; + + case GIODRV_IOCGGIODATA4: /* read long */ + if (addr & 0x03) { + return -EFAULT; + } + data = ctrl_inl(addr); + break; + default: + return -EFAULT; + break; + } + + if ((cmd & 0x01) == 0) { /* read */ + if (copy_to_user((int *)arg, &data, sizeof(int))) { + return -EFAULT; + } + } + return 0; +} + +static struct file_operations gio_fops = { + .owner = THIS_MODULE, + .open = gio_open, /* open */ + .release = gio_close, /* release */ + .ioctl = gio_ioctl, /* ioctl */ +}; + +static int __init gio_init(void) +{ + int error; + + printk(KERN_INFO "gio: driver initialized\n"); + + openCnt = 0; + + if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "gio")) < 0) { + printk(KERN_ERR + "gio: Couldn't alloc_chrdev_region, error=%d\n", + error); + return 1; + } + + cdev_p = cdev_alloc(); + cdev_p->ops = &gio_fops; + error = cdev_add(cdev_p, dev, DEVCOUNT); + if (error) { + printk(KERN_ERR + "gio: Couldn't cdev_add, error=%d\n", error); + return 1; + } + + return 0; +} + +static void __exit gio_exit(void) +{ + cdev_del(cdev_p); + unregister_chrdev_region(dev, DEVCOUNT); +} + +module_init(gio_init); +module_exit(gio_exit); + +MODULE_LICENSE("GPL"); diff --git a/trunk/arch/sh/boards/landisk/io.c b/trunk/arch/sh/boards/landisk/io.c deleted file mode 100644 index 92498b4947d5..000000000000 --- a/trunk/arch/sh/boards/landisk/io.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * arch/sh/boards/landisk/io.c - * - * Copyright (C) 2001 Ian da Silva, Jeremy Siegel - * Based largely on io_se.c. - * - * I/O routine for I-O Data Device, Inc. LANDISK. - * - * Initial version only to support LAN access; some - * placeholder code from io_landisk.c left in with the - * expectation of later SuperIO and PCMCIA access. - */ -/* - * modifed by kogiidena - * 2005.03.03 - */ -#include -#include -#include -#include -#include -#include - -extern void *area5_io_base; /* Area 5 I/O Base address */ -extern void *area6_io_base; /* Area 6 I/O Base address */ - -static inline unsigned long port2adr(unsigned int port) -{ - if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) - if (port == 0x3f6) - return ((unsigned long)area5_io_base + 0x2c); - else - return ((unsigned long)area5_io_base + PA_PIDE_OFFSET + - ((port - 0x1f0) << 1)); - else if ((0x170 <= port && port < 0x178) || port == 0x376) - if (port == 0x376) - return ((unsigned long)area6_io_base + 0x2c); - else - return ((unsigned long)area6_io_base + PA_SIDE_OFFSET + - ((port - 0x170) << 1)); - else - maybebadio((unsigned long)port); - - return port; -} - -/* - * General outline: remap really low stuff [eventually] to SuperIO, - * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO) - * is mapped through the PCI IO window. Stuff with high bits (PXSEG) - * should be way beyond the window, and is used w/o translation for - * compatibility. - */ -u8 landisk_inb(unsigned long port) -{ - if (PXSEG(port)) - return ctrl_inb(port); - else if (is_pci_ioaddr(port)) - return ctrl_inb(pci_ioaddr(port)); - - return ctrl_inw(port2adr(port)) & 0xff; -} - -u8 landisk_inb_p(unsigned long port) -{ - u8 v; - - if (PXSEG(port)) - v = ctrl_inb(port); - else if (is_pci_ioaddr(port)) - v = ctrl_inb(pci_ioaddr(port)); - else - v = ctrl_inw(port2adr(port)) & 0xff; - - ctrl_delay(); - - return v; -} - -u16 landisk_inw(unsigned long port) -{ - if (PXSEG(port)) - return ctrl_inw(port); - else if (is_pci_ioaddr(port)) - return ctrl_inw(pci_ioaddr(port)); - else - maybebadio(port); - - return 0; -} - -u32 landisk_inl(unsigned long port) -{ - if (PXSEG(port)) - return ctrl_inl(port); - else if (is_pci_ioaddr(port)) - return ctrl_inl(pci_ioaddr(port)); - else - maybebadio(port); - - return 0; -} - -void landisk_outb(u8 value, unsigned long port) -{ - if (PXSEG(port)) - ctrl_outb(value, port); - else if (is_pci_ioaddr(port)) - ctrl_outb(value, pci_ioaddr(port)); - else - ctrl_outw(value, port2adr(port)); -} - -void landisk_outb_p(u8 value, unsigned long port) -{ - if (PXSEG(port)) - ctrl_outb(value, port); - else if (is_pci_ioaddr(port)) - ctrl_outb(value, pci_ioaddr(port)); - else - ctrl_outw(value, port2adr(port)); - ctrl_delay(); -} - -void landisk_outw(u16 value, unsigned long port) -{ - if (PXSEG(port)) - ctrl_outw(value, port); - else if (is_pci_ioaddr(port)) - ctrl_outw(value, pci_ioaddr(port)); - else - maybebadio(port); -} - -void landisk_outl(u32 value, unsigned long port) -{ - if (PXSEG(port)) - ctrl_outl(value, port); - else if (is_pci_ioaddr(port)) - ctrl_outl(value, pci_ioaddr(port)); - else - maybebadio(port); -} - -void landisk_insb(unsigned long port, void *dst, unsigned long count) -{ - volatile u16 *p; - u8 *buf = dst; - - if (PXSEG(port)) { - while (count--) - *buf++ = *(volatile u8 *)port; - } else if (is_pci_ioaddr(port)) { - volatile u8 *bp = (volatile u8 *)pci_ioaddr(port); - - while (count--) - *buf++ = *bp; - } else { - p = (volatile u16 *)port2adr(port); - while (count--) - *buf++ = *p & 0xff; - } -} - -void landisk_insw(unsigned long port, void *dst, unsigned long count) -{ - volatile u16 *p; - u16 *buf = dst; - - if (PXSEG(port)) - p = (volatile u16 *)port; - else if (is_pci_ioaddr(port)) - p = (volatile u16 *)pci_ioaddr(port); - else - p = (volatile u16 *)port2adr(port); - while (count--) - *buf++ = *p; -} - -void landisk_insl(unsigned long port, void *dst, unsigned long count) -{ - u32 *buf = dst; - - if (is_pci_ioaddr(port)) { - volatile u32 *p = (volatile u32 *)pci_ioaddr(port); - - while (count--) - *buf++ = *p; - } else - maybebadio(port); -} - -void landisk_outsb(unsigned long port, const void *src, unsigned long count) -{ - volatile u16 *p; - const u8 *buf = src; - - if (PXSEG(port)) - while (count--) - ctrl_outb(*buf++, port); - else if (is_pci_ioaddr(port)) { - volatile u8 *bp = (volatile u8 *)pci_ioaddr(port); - - while (count--) - *bp = *buf++; - } else { - p = (volatile u16 *)port2adr(port); - while (count--) - *p = *buf++; - } -} - -void landisk_outsw(unsigned long port, const void *src, unsigned long count) -{ - volatile u16 *p; - const u16 *buf = src; - - if (PXSEG(port)) - p = (volatile u16 *)port; - else if (is_pci_ioaddr(port)) - p = (volatile u16 *)pci_ioaddr(port); - else - p = (volatile u16 *)port2adr(port); - - while (count--) - *p = *buf++; -} - -void landisk_outsl(unsigned long port, const void *src, unsigned long count) -{ - const u32 *buf = src; - - if (is_pci_ioaddr(port)) { - volatile u32 *p = (volatile u32 *)pci_ioaddr(port); - - while (count--) - *p = *buf++; - } else - maybebadio(port); -} - -void __iomem *landisk_ioport_map(unsigned long port, unsigned int size) -{ - if (PXSEG(port)) - return (void __iomem *)port; - else if (is_pci_ioaddr(port)) - return (void __iomem *)pci_ioaddr(port); - - return (void __iomem *)port2adr(port); -} diff --git a/trunk/arch/sh/boards/landisk/irq.c b/trunk/arch/sh/boards/landisk/irq.c index 3eba6d086d7f..258649491d44 100644 --- a/trunk/arch/sh/boards/landisk/irq.c +++ b/trunk/arch/sh/boards/landisk/irq.c @@ -1,18 +1,16 @@ /* * arch/sh/boards/landisk/irq.c * + * I-O DATA Device, Inc. LANDISK Support + * + * Copyright (C) 2005-2007 kogiidena + * * Copyright (C) 2001 Ian da Silva, Jeremy Siegel * Based largely on io_se.c. * - * I/O routine for I-O Data Device, Inc. LANDISK. - * - * Initial version only to support LAN access; some - * placeholder code from io_landisk.c left in with the - * expectation of later SuperIO and PCMCIA access. - */ -/* - * modified by kogiidena - * 2005.03.03 + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. */ #include #include @@ -20,71 +18,27 @@ #include #include -static void enable_landisk_irq(unsigned int irq); -static void disable_landisk_irq(unsigned int irq); - -/* shutdown is same as "disable" */ -#define shutdown_landisk_irq disable_landisk_irq - -static void ack_landisk_irq(unsigned int irq); -static void end_landisk_irq(unsigned int irq); - -static unsigned int startup_landisk_irq(unsigned int irq) -{ - enable_landisk_irq(irq); - return 0; /* never anything pending */ -} - static void disable_landisk_irq(unsigned int irq) { - unsigned char val; unsigned char mask = 0xff ^ (0x01 << (irq - 5)); - /* Set the priority in IPR to 0 */ - val = ctrl_inb(PA_IMASK); - val &= mask; - ctrl_outb(val, PA_IMASK); + ctrl_outb(ctrl_inb(PA_IMASK) & mask, PA_IMASK); } static void enable_landisk_irq(unsigned int irq) { - unsigned char val; unsigned char value = (0x01 << (irq - 5)); - /* Set priority in IPR back to original value */ - val = ctrl_inb(PA_IMASK); - val |= value; - ctrl_outb(val, PA_IMASK); -} - -static void ack_landisk_irq(unsigned int irq) -{ - disable_landisk_irq(irq); -} - -static void end_landisk_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) - enable_landisk_irq(irq); + ctrl_outb(ctrl_inb(PA_IMASK) | value, PA_IMASK); } -static struct hw_interrupt_type landisk_irq_type = { - .typename = "LANDISK IRQ", - .startup = startup_landisk_irq, - .shutdown = shutdown_landisk_irq, - .enable = enable_landisk_irq, - .disable = disable_landisk_irq, - .ack = ack_landisk_irq, - .end = end_landisk_irq +static struct irq_chip landisk_irq_chip __read_mostly = { + .name = "LANDISK", + .mask = disable_landisk_irq, + .unmask = enable_landisk_irq, + .mask_ack = disable_landisk_irq, }; -static void make_landisk_irq(unsigned int irq) -{ - disable_irq_nosync(irq); - irq_desc[irq].chip = &landisk_irq_type; - disable_landisk_irq(irq); -} - /* * Initialize IRQ setting */ @@ -92,6 +46,11 @@ void __init init_landisk_IRQ(void) { int i; - for (i = 5; i < 14; i++) - make_landisk_irq(i); + for (i = 5; i < 14; i++) { + disable_irq_nosync(i); + set_irq_chip_and_handler_name(i, &landisk_irq_chip, + handle_level_irq, "level"); + enable_landisk_irq(i); + } + ctrl_outb(0x00, PA_PWRINT_CLR); } diff --git a/trunk/arch/sh/boards/landisk/landisk_pwb.c b/trunk/arch/sh/boards/landisk/landisk_pwb.c deleted file mode 100644 index 47a63c6617ed..000000000000 --- a/trunk/arch/sh/boards/landisk/landisk_pwb.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * arch/sh/boards/landisk/landisk_pwb.c -- driver for the Power control switch. - * - * This driver will also support the I-O DATA Device, Inc. LANDISK Board. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copylight (C) 2002 Atom Create Engineering Co., Ltd. - * - * LED control drive function added by kogiidena - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define SHUTDOWN_BTN_MINOR 1 /* Shutdown button device minor no. */ -#define LED_MINOR 21 /* LED minor no. */ -#define BTN_MINOR 22 /* BUTTON minor no. */ -#define GIO_MINOR 40 /* GIO minor no. */ - -static int openCnt; -static int openCntLED; -static int openCntGio; -static int openCntBtn; -static int landisk_btn; -static int landisk_btnctrlpid; -/* - * Functions prototypes - */ - -static int gio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); - -static int swdrv_open(struct inode *inode, struct file *filp) -{ - int minor; - - minor = MINOR(inode->i_rdev); - filp->private_data = (void *)minor; - - if (minor == SHUTDOWN_BTN_MINOR) { - if (openCnt > 0) { - return -EALREADY; - } else { - openCnt++; - return 0; - } - } else if (minor == LED_MINOR) { - if (openCntLED > 0) { - return -EALREADY; - } else { - openCntLED++; - return 0; - } - } else if (minor == BTN_MINOR) { - if (openCntBtn > 0) { - return -EALREADY; - } else { - openCntBtn++; - return 0; - } - } else if (minor == GIO_MINOR) { - if (openCntGio > 0) { - return -EALREADY; - } else { - openCntGio++; - return 0; - } - } - return -ENOENT; - -} - -static int swdrv_close(struct inode *inode, struct file *filp) -{ - int minor; - - minor = MINOR(inode->i_rdev); - if (minor == SHUTDOWN_BTN_MINOR) { - openCnt--; - } else if (minor == LED_MINOR) { - openCntLED--; - } else if (minor == BTN_MINOR) { - openCntBtn--; - } else if (minor == GIO_MINOR) { - openCntGio--; - } - return 0; -} - -static int swdrv_read(struct file *filp, char *buff, size_t count, - loff_t * ppos) -{ - int minor; - minor = (int)(filp->private_data); - - if (!access_ok(VERIFY_WRITE, (void *)buff, count)) - return -EFAULT; - - if (minor == SHUTDOWN_BTN_MINOR) { - if (landisk_btn & 0x10) { - put_user(1, buff); - return 1; - } else { - return 0; - } - } - return 0; -} - -static int swdrv_write(struct file *filp, const char *buff, size_t count, - loff_t * ppos) -{ - int minor; - minor = (int)(filp->private_data); - - if (minor == SHUTDOWN_BTN_MINOR) { - return count; - } - return count; -} - -static irqreturn_t sw_interrupt(int irq, void *dev_id) -{ - landisk_btn = (0x0ff & (~ctrl_inb(PA_STATUS))); - disable_irq(IRQ_BUTTON); - disable_irq(IRQ_POWER); - ctrl_outb(0x00, PA_PWRINT_CLR); - - if (landisk_btnctrlpid != 0) { - kill_proc(landisk_btnctrlpid, SIGUSR1, 1); - landisk_btnctrlpid = 0; - } - - return IRQ_HANDLED; -} - -static const struct file_operations swdrv_fops = { - .read = swdrv_read, /* read */ - .write = swdrv_write, /* write */ - .open = swdrv_open, /* open */ - .release = swdrv_close, /* release */ - .ioctl = gio_ioctl, /* ioctl */ - -}; - -static char banner[] __initdata = - KERN_INFO "LANDISK and USL-5P Button, LED and GIO driver initialized\n"; - -int __init swdrv_init(void) -{ - int error; - - printk("%s", banner); - - openCnt = 0; - openCntLED = 0; - openCntBtn = 0; - openCntGio = 0; - landisk_btn = 0; - landisk_btnctrlpid = 0; - - if ((error = register_chrdev(SHUTDOWN_BTN_MAJOR, "swdrv", &swdrv_fops))) { - printk(KERN_ERR - "Button, LED and GIO driver:Couldn't register driver, error=%d\n", - error); - return 1; - } - - if (request_irq(IRQ_POWER, sw_interrupt, 0, "SHUTDOWNSWITCH", NULL)) { - printk(KERN_ERR "Unable to get IRQ 11.\n"); - return 1; - } - if (request_irq(IRQ_BUTTON, sw_interrupt, 0, "USL-5P BUTTON", NULL)) { - printk(KERN_ERR "Unable to get IRQ 12.\n"); - return 1; - } - ctrl_outb(0x00, PA_PWRINT_CLR); - - return 0; -} - -module_init(swdrv_init); - -/* - * gio driver - * - */ - -#include - -static int gio_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - int minor; - unsigned int data, mask; - static unsigned int addr = 0; - - minor = (int)(filp->private_data); - - /* access control */ - if (minor == GIO_MINOR) { - ; - } else if (minor == LED_MINOR) { - if (((cmd & 0x0ff) >= 9) && ((cmd & 0x0ff) < 20)) { - ; - } else { - return -EINVAL; - } - } else if (minor == BTN_MINOR) { - if (((cmd & 0x0ff) >= 20) && ((cmd & 0x0ff) < 30)) { - ; - } else { - return -EINVAL; - } - } else { - return -EINVAL; - } - - if (cmd & 0x01) { /* write */ - if (copy_from_user(&data, (int *)arg, sizeof(int))) { - return -EFAULT; - } - } - - switch (cmd) { - case GIODRV_IOCSGIOSETADDR: /* addres set */ - addr = data; - break; - - case GIODRV_IOCSGIODATA1: /* write byte */ - ctrl_outb((unsigned char)(0x0ff & data), addr); - break; - - case GIODRV_IOCSGIODATA2: /* write word */ - if (addr & 0x01) { - return -EFAULT; - } - ctrl_outw((unsigned short int)(0x0ffff & data), addr); - break; - - case GIODRV_IOCSGIODATA4: /* write long */ - if (addr & 0x03) { - return -EFAULT; - } - ctrl_outl(data, addr); - break; - - case GIODRV_IOCGGIODATA1: /* read byte */ - data = ctrl_inb(addr); - break; - - case GIODRV_IOCGGIODATA2: /* read word */ - if (addr & 0x01) { - return -EFAULT; - } - data = ctrl_inw(addr); - break; - - case GIODRV_IOCGGIODATA4: /* read long */ - if (addr & 0x03) { - return -EFAULT; - } - data = ctrl_inl(addr); - break; - case GIODRV_IOCSGIO_LED: /* write */ - mask = ((data & 0x00ffffff) << 8) - | ((data & 0x0000ffff) << 16) - | ((data & 0x000000ff) << 24); - landisk_ledparam = data & (~mask); - if (landisk_arch == 0) { /* arch == landisk */ - landisk_ledparam &= 0x03030303; - mask = (~(landisk_ledparam >> 22)) & 0x000c; - landisk_ledparam |= mask; - } else { /* arch == usl-5p */ - mask = (landisk_ledparam >> 24) & 0x0001; - landisk_ledparam |= mask; - landisk_ledparam &= 0x007f7f7f; - } - landisk_ledparam |= 0x80; - break; - case GIODRV_IOCGGIO_LED: /* read */ - data = landisk_ledparam; - if (landisk_arch == 0) { /* arch == landisk */ - data &= 0x03030303; - } else { /* arch == usl-5p */ - ; - } - data &= (~0x080); - break; - case GIODRV_IOCSGIO_BUZZER: /* write */ - landisk_buzzerparam = data; - landisk_ledparam |= 0x80; - break; - case GIODRV_IOCGGIO_LANDISK: /* read */ - data = landisk_arch & 0x01; - break; - case GIODRV_IOCGGIO_BTN: /* read */ - data = (0x0ff & ctrl_inb(PA_PWRINT_CLR)); - data <<= 8; - data |= (0x0ff & ctrl_inb(PA_IMASK)); - data <<= 8; - data |= (0x0ff & landisk_btn); - data <<= 8; - data |= (0x0ff & (~ctrl_inb(PA_STATUS))); - break; - case GIODRV_IOCSGIO_BTNPID: /* write */ - landisk_btnctrlpid = data; - landisk_btn = 0; - if (irq_desc[IRQ_BUTTON].depth) { - enable_irq(IRQ_BUTTON); - } - if (irq_desc[IRQ_POWER].depth) { - enable_irq(IRQ_POWER); - } - break; - case GIODRV_IOCGGIO_BTNPID: /* read */ - data = landisk_btnctrlpid; - break; - default: - return -EFAULT; - break; - } - - if ((cmd & 0x01) == 0) { /* read */ - if (copy_to_user((int *)arg, &data, sizeof(int))) { - return -EFAULT; - } - } - return 0; -} diff --git a/trunk/arch/sh/boards/landisk/psw.c b/trunk/arch/sh/boards/landisk/psw.c new file mode 100644 index 000000000000..5a9b70b5decb --- /dev/null +++ b/trunk/arch/sh/boards/landisk/psw.c @@ -0,0 +1,143 @@ +/* + * arch/sh/boards/landisk/psw.c + * + * push switch support for LANDISK and USL-5P + * + * Copyright (C) 2006-2007 Paul Mundt + * Copyright (C) 2007 kogiidena + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include + +static irqreturn_t psw_irq_handler(int irq, void *arg) +{ + struct platform_device *pdev = arg; + struct push_switch *psw = platform_get_drvdata(pdev); + struct push_switch_platform_info *psw_info = pdev->dev.platform_data; + unsigned int sw_value; + int ret = 0; + + sw_value = (0x0ff & (~ctrl_inb(PA_STATUS))); + + /* Nothing to do if there's no state change */ + if (psw->state) { + ret = 1; + goto out; + } + + /* Figure out who raised it */ + if (sw_value & (1 << psw_info->bit)) { + psw->state = 1; + mod_timer(&psw->debounce, jiffies + 50); + ret = 1; + } + +out: + /* Clear the switch IRQs */ + ctrl_outb(0x00, PA_PWRINT_CLR); + + return IRQ_RETVAL(ret); +} + +static struct resource psw_power_resources[] = { + [0] = { + .start = IRQ_POWER, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource psw_usl5p_resources[] = { + [0] = { + .start = IRQ_BUTTON, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct push_switch_platform_info psw_power_platform_data = { + .name = "psw_power", + .bit = 4, + .irq_flags = IRQF_SHARED, + .irq_handler = psw_irq_handler, +}; + +static struct push_switch_platform_info psw1_platform_data = { + .name = "psw1", + .bit = 0, + .irq_flags = IRQF_SHARED, + .irq_handler = psw_irq_handler, +}; + +static struct push_switch_platform_info psw2_platform_data = { + .name = "psw2", + .bit = 2, + .irq_flags = IRQF_SHARED, + .irq_handler = psw_irq_handler, +}; + +static struct push_switch_platform_info psw3_platform_data = { + .name = "psw3", + .bit = 1, + .irq_flags = IRQF_SHARED, + .irq_handler = psw_irq_handler, +}; + +static struct platform_device psw_power_switch_device = { + .name = "push-switch", + .id = 0, + .num_resources = ARRAY_SIZE(psw_power_resources), + .resource = psw_power_resources, + .dev = { + .platform_data = &psw_power_platform_data, + }, +}; + +static struct platform_device psw1_switch_device = { + .name = "push-switch", + .id = 1, + .num_resources = ARRAY_SIZE(psw_usl5p_resources), + .resource = psw_usl5p_resources, + .dev = { + .platform_data = &psw1_platform_data, + }, +}; + +static struct platform_device psw2_switch_device = { + .name = "push-switch", + .id = 2, + .num_resources = ARRAY_SIZE(psw_usl5p_resources), + .resource = psw_usl5p_resources, + .dev = { + .platform_data = &psw2_platform_data, + }, +}; + +static struct platform_device psw3_switch_device = { + .name = "push-switch", + .id = 3, + .num_resources = ARRAY_SIZE(psw_usl5p_resources), + .resource = psw_usl5p_resources, + .dev = { + .platform_data = &psw3_platform_data, + }, +}; + +static struct platform_device *psw_devices[] = { + &psw_power_switch_device, + &psw1_switch_device, + &psw2_switch_device, + &psw3_switch_device, +}; + +static int __init psw_init(void) +{ + return platform_add_devices(psw_devices, ARRAY_SIZE(psw_devices)); +} +module_init(psw_init); diff --git a/trunk/arch/sh/boards/landisk/rtc.c b/trunk/arch/sh/boards/landisk/rtc.c deleted file mode 100644 index 0a9a2a2ad05b..000000000000 --- a/trunk/arch/sh/boards/landisk/rtc.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * arch/sh/boards/landisk/rtc.c -- RTC support - * - * Copyright (C) 2000 Philipp Rumpf - * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka - */ -/* - * modifed by kogiidena - * 2005.09.16 - */ -#include -#include -#include -#include -#include -#include -#include -#include - -extern spinlock_t rtc_lock; - -extern void -rs5c313_set_cmos_time(unsigned int BCD_yr, unsigned int BCD_mon, - unsigned int BCD_day, unsigned int BCD_hr, - unsigned int BCD_min, unsigned int BCD_sec); - -extern unsigned long -rs5c313_get_cmos_time(unsigned int *BCD_yr, unsigned int *BCD_mon, - unsigned int *BCD_day, unsigned int *BCD_hr, - unsigned int *BCD_min, unsigned int *BCD_sec); - -void landisk_rtc_gettimeofday(struct timespec *tv) -{ - unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec; - unsigned long flags; - - spin_lock_irqsave(&rtc_lock, flags); - tv->tv_sec = rs5c313_get_cmos_time - (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec); - tv->tv_nsec = 0; - spin_unlock_irqrestore(&rtc_lock, flags); -} - -int landisk_rtc_settimeofday(const time_t secs) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - unsigned long flags; - unsigned long nowtime = secs; - unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec; - - spin_lock_irqsave(&rtc_lock, flags); - - rs5c313_get_cmos_time - (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec); - cmos_minutes = BCD_min; - BCD_TO_BIN(cmos_minutes); - - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - BIN_TO_BCD(real_seconds); - BIN_TO_BCD(real_minutes); - rs5c313_set_cmos_time(BCD_yr, BCD_mon, BCD_day, BCD_hr, - real_minutes, real_seconds); - } else { - printk(KERN_WARNING - "set_rtc_time: can't update from %d to %d\n", - cmos_minutes, real_minutes); - retval = -1; - } - - spin_unlock_irqrestore(&rtc_lock, flags); - return retval; -} - -void landisk_time_init(void) -{ - rtc_sh_get_time = landisk_rtc_gettimeofday; - rtc_sh_set_time = landisk_rtc_settimeofday; -} diff --git a/trunk/arch/sh/boards/landisk/setup.c b/trunk/arch/sh/boards/landisk/setup.c index 122d69962637..a83a5d9587bb 100644 --- a/trunk/arch/sh/boards/landisk/setup.c +++ b/trunk/arch/sh/boards/landisk/setup.c @@ -1,144 +1,90 @@ /* * arch/sh/boards/landisk/setup.c * - * Copyright (C) 2000 Kazumoto Kojima - * Copyright (C) 2002 Paul Mundt - * * I-O DATA Device, Inc. LANDISK Support. * - * Modified for LANDISK by - * Atom Create Engineering Co., Ltd. 2002. - * - * modifed by kogiidena - * 2005.09.16 + * Copyright (C) 2000 Kazumoto Kojima + * Copyright (C) 2002 Paul Mundt + * Copylight (C) 2002 Atom Create Engineering Co., Ltd. + * Copyright (C) 2005-2007 kogiidena * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. */ #include +#include +#include #include #include #include -#include #include #include -void landisk_time_init(void); void init_landisk_IRQ(void); -int landisk_ledparam; -int landisk_buzzerparam; -int landisk_arch; - -/* cycle the led's in the clasic knightrider/sun pattern */ -static void heartbeat_landisk(void) -{ - static unsigned int cnt = 0, blink = 0x00, period = 25; - volatile u8 *p = (volatile u8 *)PA_LED; - char data; - - if ((landisk_ledparam & 0x080) == 0) - return; - - cnt += 1; - - if (cnt < period) - return; - - cnt = 0; - blink++; - - data = (blink & 0x01) ? (landisk_ledparam >> 16) : 0; - data |= (blink & 0x02) ? (landisk_ledparam >> 8) : 0; - data |= landisk_ledparam; - - /* buzzer */ - if (landisk_buzzerparam & 0x1) { - data |= 0x80; - } else { - data &= 0x7f; - } - *p = data; - - if (((landisk_ledparam & 0x007f7f00) == 0) && - (landisk_buzzerparam == 0)) - landisk_ledparam &= (~0x0080); - - landisk_buzzerparam >>= 1; -} - static void landisk_power_off(void) { ctrl_outb(0x01, PA_SHUTDOWN); } -static void check_usl5p(void) -{ - volatile u8 *p = (volatile u8 *)PA_LED; - u8 tmp1, tmp2; +static struct resource cf_ide_resources[3]; - tmp1 = *p; - *p = 0x40; - tmp2 = *p; - *p = tmp1; +static struct pata_platform_info pata_info = { + .ioport_shift = 1, +}; - landisk_arch = (tmp2 == 0x40); - if (landisk_arch == 1) { - /* arch == usl-5p */ - landisk_ledparam = 0x00000380; - landisk_ledparam |= (tmp1 & 0x07c); - } else { - /* arch == landisk */ - landisk_ledparam = 0x02000180; - landisk_ledparam |= 0x04; - } -} +static struct platform_device cf_ide_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(cf_ide_resources), + .resource = cf_ide_resources, + .dev = { + .platform_data = &pata_info, + }, +}; -void *area5_io_base; -void *area6_io_base; +static struct platform_device *landisk_devices[] __initdata = { + &cf_ide_device, +}; -static int __init landisk_cf_init(void) +static int __init landisk_devices_setup(void) { pgprot_t prot; - unsigned long paddrbase, psize; + unsigned long paddrbase; + void *cf_ide_base; /* open I/O area window */ paddrbase = virt_to_phys((void *)PA_AREA5_IO); - psize = PAGE_SIZE; prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16); - area5_io_base = p3_ioremap(paddrbase, psize, prot.pgprot); - if (!area5_io_base) { + cf_ide_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot); + if (!cf_ide_base) { printk("allocate_cf_area : can't open CF I/O window!\n"); return -ENOMEM; } - paddrbase = virt_to_phys((void *)PA_AREA6_IO); - psize = PAGE_SIZE; - prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16); - area6_io_base = p3_ioremap(paddrbase, psize, prot.pgprot); - if (!area6_io_base) { - printk("allocate_cf_area : can't open HDD I/O window!\n"); - return -ENOMEM; - } - - printk(KERN_INFO "Allocate Area5/6 success.\n"); - - /* XXX : do we need attribute and common-memory area also? */ - - return 0; + /* IDE cmd address : 0x1f0-0x1f7 and 0x3f6 */ + cf_ide_resources[0].start = (unsigned long)cf_ide_base + 0x40; + cf_ide_resources[0].end = (unsigned long)cf_ide_base + 0x40 + 0x0f; + cf_ide_resources[0].flags = IORESOURCE_IO; + cf_ide_resources[1].start = (unsigned long)cf_ide_base + 0x2c; + cf_ide_resources[1].end = (unsigned long)cf_ide_base + 0x2c + 0x03; + cf_ide_resources[1].flags = IORESOURCE_IO; + cf_ide_resources[2].start = IRQ_FATA; + cf_ide_resources[2].flags = IORESOURCE_IRQ; + + return platform_add_devices(landisk_devices, + ARRAY_SIZE(landisk_devices)); } +__initcall(landisk_devices_setup); + static void __init landisk_setup(char **cmdline_p) { - device_initcall(landisk_cf_init); - - landisk_buzzerparam = 0; - check_usl5p(); + /* LED ON */ + ctrl_outb(ctrl_inb(PA_LED) | 0x03, PA_LED); printk(KERN_INFO "I-O DATA DEVICE, INC. \"LANDISK Series\" support.\n"); - - board_time_init = landisk_time_init; pm_power_off = landisk_power_off; } @@ -148,29 +94,6 @@ static void __init landisk_setup(char **cmdline_p) struct sh_machine_vector mv_landisk __initmv = { .mv_name = "LANDISK", .mv_setup = landisk_setup, - .mv_nr_irqs = 72, - .mv_inb = landisk_inb, - .mv_inw = landisk_inw, - .mv_inl = landisk_inl, - .mv_outb = landisk_outb, - .mv_outw = landisk_outw, - .mv_outl = landisk_outl, - .mv_inb_p = landisk_inb_p, - .mv_inw_p = landisk_inw, - .mv_inl_p = landisk_inl, - .mv_outb_p = landisk_outb_p, - .mv_outw_p = landisk_outw, - .mv_outl_p = landisk_outl, - .mv_insb = landisk_insb, - .mv_insw = landisk_insw, - .mv_insl = landisk_insl, - .mv_outsb = landisk_outsb, - .mv_outsw = landisk_outsw, - .mv_outsl = landisk_outsl, - .mv_ioport_map = landisk_ioport_map, .mv_init_irq = init_landisk_IRQ, -#ifdef CONFIG_HEARTBEAT - .mv_heartbeat = heartbeat_landisk, -#endif }; ALIAS_MV(landisk) diff --git a/trunk/arch/sh/boards/lboxre2/Makefile b/trunk/arch/sh/boards/lboxre2/Makefile new file mode 100644 index 000000000000..e9ed140c06f6 --- /dev/null +++ b/trunk/arch/sh/boards/lboxre2/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the L-BOX RE2 specific parts of the kernel +# Copyright (c) 2007 Nobuhiro Iwamatsu + +obj-y := setup.o irq.o diff --git a/trunk/arch/sh/boards/lboxre2/irq.c b/trunk/arch/sh/boards/lboxre2/irq.c new file mode 100644 index 000000000000..5a1c3bbe7b50 --- /dev/null +++ b/trunk/arch/sh/boards/lboxre2/irq.c @@ -0,0 +1,31 @@ +/* + * linux/arch/sh/boards/lboxre2/irq.c + * + * Copyright (C) 2007 Nobuhiro Iwamatsu + * + * NTT COMWARE L-BOX RE2 Support. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ +#include +#include +#include +#include +#include +#include + +/* + * Initialize IRQ setting + */ +void __init init_lboxre2_IRQ(void) +{ + make_imask_irq(IRQ_CF1); + make_imask_irq(IRQ_CF0); + make_imask_irq(IRQ_INTD); + make_imask_irq(IRQ_ETH1); + make_imask_irq(IRQ_ETH0); + make_imask_irq(IRQ_INTA); +} diff --git a/trunk/arch/sh/boards/lboxre2/setup.c b/trunk/arch/sh/boards/lboxre2/setup.c new file mode 100644 index 000000000000..4e20f7c63bf3 --- /dev/null +++ b/trunk/arch/sh/boards/lboxre2/setup.c @@ -0,0 +1,85 @@ +/* + * linux/arch/sh/boards/lbox/setup.c + * + * Copyright (C) 2007 Nobuhiro Iwamatsu + * + * NTT COMWARE L-BOX RE2 Support + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct resource cf_ide_resources[] = { + [0] = { + .start = 0x1f0, + .end = 0x1f0 + 8 , + .flags = IORESOURCE_IO, + }, + [1] = { + .start = 0x1f0 + 0x206, + .end = 0x1f0 +8 + 0x206 + 8, + .flags = IORESOURCE_IO, + }, + [2] = { + .start = IRQ_CF0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device cf_ide_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(cf_ide_resources), + .resource = cf_ide_resources, +}; + +static struct platform_device *lboxre2_devices[] __initdata = { + &cf_ide_device, +}; + +static int __init lboxre2_devices_setup(void) +{ + u32 cf0_io_base; /* Boot CF base address */ + pgprot_t prot; + unsigned long paddrbase, psize; + + /* open I/O area window */ + paddrbase = virt_to_phys((void*)PA_AREA5_IO); + psize = PAGE_SIZE; + prot = PAGE_KERNEL_PCC( 1 , _PAGE_PCC_IO16); + cf0_io_base = (u32)p3_ioremap(paddrbase, psize, prot.pgprot); + if (!cf0_io_base) { + printk(KERN_ERR "%s : can't open CF I/O window!\n" , __func__ ); + return -ENOMEM; + } + + cf_ide_resources[0].start += cf0_io_base ; + cf_ide_resources[0].end += cf0_io_base ; + cf_ide_resources[1].start += cf0_io_base ; + cf_ide_resources[1].end += cf0_io_base ; + + return platform_add_devices(lboxre2_devices, + ARRAY_SIZE(lboxre2_devices)); + +} +device_initcall(lboxre2_devices_setup); + +/* + * The Machine Vector + */ +struct sh_machine_vector mv_lboxre2 __initmv = { + .mv_name = "L-BOX RE2", + .mv_nr_irqs = 72, + .mv_init_irq = init_lboxre2_IRQ, +}; +ALIAS_MV(lboxre2) diff --git a/trunk/arch/sh/boards/renesas/r7780rp/Kconfig b/trunk/arch/sh/boards/renesas/r7780rp/Kconfig index c26d9813d239..9fb11641fe13 100644 --- a/trunk/arch/sh/boards/renesas/r7780rp/Kconfig +++ b/trunk/arch/sh/boards/renesas/r7780rp/Kconfig @@ -1,14 +1,24 @@ -if SH_R7780RP +if SH_HIGHLANDER -menu "R7780RP options" +choice + prompt "Highlander options" + default SH_R7780MP + +config SH_R7780RP + bool "R7780RP-1 board support" + select CPU_SUBTYPE_SH7780 config SH_R7780MP bool "R7780MP board support" - default y + select CPU_SUBTYPE_SH7780 help Selecting this option will enable support for the mass-production version of the R7780RP. If in doubt, say Y. -endmenu +config SH_R7785RP + bool "R7785RP board support" + select CPU_SUBTYPE_SH7785 + +endchoice endif diff --git a/trunk/arch/sh/boards/renesas/r7780rp/Makefile b/trunk/arch/sh/boards/renesas/r7780rp/Makefile index ed5f5a9a3b3e..609e5d50dde8 100644 --- a/trunk/arch/sh/boards/renesas/r7780rp/Makefile +++ b/trunk/arch/sh/boards/renesas/r7780rp/Makefile @@ -1,7 +1,7 @@ # # Makefile for the R7780RP-1 specific parts of the kernel # - -obj-y := setup.o irq.o - +irqinit-y := irq-r7780rp.o +irqinit-$(CONFIG_SH_R7785RP) := irq-r7785rp.o obj-$(CONFIG_PUSH_SWITCH) += psw.o +obj-y := setup.o irq.o $(irqinit-y) diff --git a/trunk/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c b/trunk/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c new file mode 100644 index 000000000000..f5f358746c9e --- /dev/null +++ b/trunk/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c @@ -0,0 +1,21 @@ +/* + * Renesas Solutions Highlander R7780RP-1 Support. + * + * Copyright (C) 2002 Atom Create Engineering Co., Ltd. + * Copyright (C) 2006 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include + +void __init highlander_init_irq(void) +{ + int i; + + for (i = 0; i < 15; i++) + make_r7780rp_irq(i); +} diff --git a/trunk/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c b/trunk/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c new file mode 100644 index 000000000000..dd6ec4ce44dc --- /dev/null +++ b/trunk/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c @@ -0,0 +1,29 @@ +/* + * Renesas Solutions Highlander R7780RP-1 Support. + * + * Copyright (C) 2002 Atom Create Engineering Co., Ltd. + * Copyright (C) 2006 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include + +void __init highlander_init_irq(void) +{ + ctrl_outw(0x0000, PA_IRLSSR1); /* FPGA IRLSSR1(CF_CD clear) */ + + /* Setup the FPGA IRL */ + ctrl_outw(0x0000, PA_IRLPRA); /* FPGA IRLA */ + ctrl_outw(0xe598, PA_IRLPRB); /* FPGA IRLB */ + ctrl_outw(0x7060, PA_IRLPRC); /* FPGA IRLC */ + ctrl_outw(0x0000, PA_IRLPRD); /* FPGA IRLD */ + ctrl_outw(0x4321, PA_IRLPRE); /* FPGA IRLE */ + ctrl_outw(0x0000, PA_IRLPRF); /* FPGA IRLF */ + + make_r7780rp_irq(1); /* CF card */ + make_r7780rp_irq(10); /* On-board ethernet */ +} diff --git a/trunk/arch/sh/boards/renesas/r7780rp/irq.c b/trunk/arch/sh/boards/renesas/r7780rp/irq.c index cc381e197783..e0b8eb52f376 100644 --- a/trunk/arch/sh/boards/renesas/r7780rp/irq.c +++ b/trunk/arch/sh/boards/renesas/r7780rp/irq.c @@ -14,10 +14,12 @@ #include #include -#ifdef CONFIG_SH_R7780MP -static int mask_pos[] = {12, 11, 9, 14, 15, 8, 13, 6, 5, 4, 3, 2, 0, 0, 1, 0}; -#else +#ifdef CONFIG_SH_R7780RP static int mask_pos[] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 5, 6, 4, 0, 1, 2, 0}; +#elif defined(CONFIG_SH_R7780MP) +static int mask_pos[] = {12, 11, 9, 14, 15, 8, 13, 6, 5, 4, 3, 2, 0, 0, 1, 0}; +#elif defined(CONFIG_SH_R7785RP) +static int mask_pos[] = {2, 11, 2, 2, 2, 2, 9, 8, 7, 5, 10, 2, 2, 2, 2, 2}; #endif static void enable_r7780rp_irq(unsigned int irq) @@ -40,17 +42,10 @@ static struct irq_chip r7780rp_irq_chip __read_mostly = { .mask_ack = disable_r7780rp_irq, }; -/* - * Initialize IRQ setting - */ -void __init init_r7780rp_IRQ(void) +void make_r7780rp_irq(unsigned int irq) { - int i; - - for (i = 0; i < 15; i++) { - disable_irq_nosync(i); - set_irq_chip_and_handler_name(i, &r7780rp_irq_chip, - handle_level_irq, "level"); - enable_r7780rp_irq(i); - } + disable_irq_nosync(irq); + set_irq_chip_and_handler_name(irq, &r7780rp_irq_chip, + handle_level_irq, "level"); + enable_r7780rp_irq(irq); } diff --git a/trunk/arch/sh/boards/renesas/r7780rp/setup.c b/trunk/arch/sh/boards/renesas/r7780rp/setup.c index 2faba6679e64..0727ef92f2b3 100644 --- a/trunk/arch/sh/boards/renesas/r7780rp/setup.c +++ b/trunk/arch/sh/boards/renesas/r7780rp/setup.c @@ -1,10 +1,13 @@ /* * arch/sh/boards/renesas/r7780rp/setup.c * + * Renesas Solutions Highlander Support. + * * Copyright (C) 2002 Atom Create Engineering Co., Ltd. * Copyright (C) 2005 - 2007 Paul Mundt * - * Renesas Solutions Highlander R7780RP-1 Support. + * This contains support for the R7780RP-1, R7780MP, and R7785RP + * Highlander modules. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -18,32 +21,6 @@ #include #include -extern void init_r7780rp_IRQ(void); - -static struct resource m66596_usb_host_resources[] = { - [0] = { - .start = 0xa4800000, - .end = 0xa4ffffff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 6, /* irq number */ - .end = 6, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device m66596_usb_host_device = { - .name = "m66596-hcd", - .id = 0, - .dev = { - .dma_mask = NULL, /* don't use dma */ - .coherent_dma_mask = 0xffffffff, - }, - .num_resources = ARRAY_SIZE(m66596_usb_host_resources), - .resource = m66596_usb_host_resources, -}; - static struct resource cf_ide_resources[] = { [0] = { .start = PA_AREA5_IO + 0x1000, @@ -56,10 +33,10 @@ static struct resource cf_ide_resources[] = { .flags = IORESOURCE_MEM, }, [2] = { -#ifdef CONFIG_SH_R7780MP - .start = 1, -#else +#ifdef CONFIG_SH_R7780RP .start = 4, +#else + .start = 1, #endif .flags = IORESOURCE_IRQ, }, @@ -92,15 +69,18 @@ static struct resource heartbeat_resources[] = { static struct platform_device heartbeat_device = { .name = "heartbeat", .id = -1, + + /* R7785RP has a slightly more sensible FPGA.. */ +#ifndef CONFIG_SH_R7785RP .dev = { .platform_data = heartbeat_bit_pos, }, +#endif .num_resources = ARRAY_SIZE(heartbeat_resources), .resource = heartbeat_resources, }; static struct platform_device *r7780rp_devices[] __initdata = { - &m66596_usb_host_device, &cf_ide_device, &heartbeat_device, }; @@ -110,18 +90,19 @@ static int __init r7780rp_devices_setup(void) return platform_add_devices(r7780rp_devices, ARRAY_SIZE(r7780rp_devices)); } +device_initcall(r7780rp_devices_setup); /* * Platform specific clocks */ static void ivdr_clk_enable(struct clk *clk) { - ctrl_outw(ctrl_inw(PA_IVDRCTL) | (1 << 8), PA_IVDRCTL); + ctrl_outw(ctrl_inw(PA_IVDRCTL) | (1 << IVDR_CK_ON), PA_IVDRCTL); } static void ivdr_clk_disable(struct clk *clk) { - ctrl_outw(ctrl_inw(PA_IVDRCTL) & ~(1 << 8), PA_IVDRCTL); + ctrl_outw(ctrl_inw(PA_IVDRCTL) & ~(1 << IVDR_CK_ON), PA_IVDRCTL); } static struct clk_ops ivdr_clk_ops = { @@ -140,22 +121,22 @@ static struct clk *r7780rp_clocks[] = { static void r7780rp_power_off(void) { -#ifdef CONFIG_SH_R7780MP - ctrl_outw(0x0001, PA_POFF); -#endif + if (mach_is_r7780mp() || mach_is_r7785rp()) + ctrl_outw(0x0001, PA_POFF); } /* * Initialize the board */ -static void __init r7780rp_setup(char **cmdline_p) +static void __init highlander_setup(char **cmdline_p) { u16 ver = ctrl_inw(PA_VERREG); int i; - device_initcall(r7780rp_devices_setup); - - printk(KERN_INFO "Renesas Solutions Highlander R7780RP-1 support.\n"); + printk(KERN_INFO "Renesas Solutions Highlander %s support.\n", + mach_is_r7780rp() ? "R7780RP-1" : + mach_is_r7780mp() ? "R7780MP" : + "R7785RP"); printk(KERN_INFO "Board version: %d (revision %d), " "FPGA version: %d (revision %d)\n", @@ -173,9 +154,10 @@ static void __init r7780rp_setup(char **cmdline_p) } ctrl_outw(0x0000, PA_OBLED); /* Clear LED. */ -#ifndef CONFIG_SH_R7780MP - ctrl_outw(0x0001, PA_SDPOW); /* SD Power ON */ -#endif + + if (mach_is_r7780rp()) + ctrl_outw(0x0001, PA_SDPOW); /* SD Power ON */ + ctrl_outw(ctrl_inw(PA_IVDRCTL) | 0x01, PA_IVDRCTL); /* Si13112 */ pm_power_off = r7780rp_power_off; @@ -184,10 +166,10 @@ static void __init r7780rp_setup(char **cmdline_p) /* * The Machine Vector */ -struct sh_machine_vector mv_r7780rp __initmv = { - .mv_name = "Highlander R7780RP-1", - .mv_setup = r7780rp_setup, +struct sh_machine_vector mv_highlander __initmv = { + .mv_name = "Highlander", .mv_nr_irqs = 109, - .mv_init_irq = init_r7780rp_IRQ, + .mv_setup = highlander_setup, + .mv_init_irq = highlander_init_irq, }; -ALIAS_MV(r7780rp) +ALIAS_MV(highlander) diff --git a/trunk/arch/sh/boards/se/770x/io.c b/trunk/arch/sh/boards/se/770x/io.c index 9941949331ab..c4550473d4c3 100644 --- a/trunk/arch/sh/boards/se/770x/io.c +++ b/trunk/arch/sh/boards/se/770x/io.c @@ -27,6 +27,8 @@ int sh_pcic_io_dummy; static inline volatile __u16 * port2adr(unsigned int port) { + if (port & 0xff000000) + return ( volatile __u16 *) port; if (port >= 0x2000) return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000)); else if (port >= 0x1000) diff --git a/trunk/arch/sh/boards/se/770x/irq.c b/trunk/arch/sh/boards/se/770x/irq.c index 307ca5da6232..c8eccff77a04 100644 --- a/trunk/arch/sh/boards/se/770x/irq.c +++ b/trunk/arch/sh/boards/se/770x/irq.c @@ -55,23 +55,34 @@ void make_se770x_irq(struct ipr_data *table, unsigned int nr_irqs) } static struct ipr_data se770x_ipr_map[] = { + /* + * Super I/O (Just mimic PC): + * 1: keyboard + * 3: serial 0 + * 4: serial 1 + * 5: printer + * 6: floppy + * 8: rtc + * 12: mouse + * 14: ide0 + */ #if defined(CONFIG_CPU_SUBTYPE_SH7705) /* This is default value */ - { 0xf-0x2, 0, 8, 0x2 , BCR_ILCRA}, - { 0xf-0xa, 0, 4, 0xa , BCR_ILCRA}, - { 0xf-0x5, 0, 0, 0x5 , BCR_ILCRB}, - { 0xf-0x8, 0, 4, 0x8 , BCR_ILCRC}, - { 0xf-0xc, 0, 0, 0xc , BCR_ILCRC}, - { 0xf-0xe, 0, 12, 0xe , BCR_ILCRD}, - { 0xf-0x3, 0, 4, 0x3 , BCR_ILCRD}, /* LAN */ - { 0xf-0xd, 0, 8, 0xd , BCR_ILCRE}, - { 0xf-0x9, 0, 4, 0x9 , BCR_ILCRE}, - { 0xf-0x1, 0, 0, 0x1 , BCR_ILCRE}, - { 0xf-0xf, 0, 12, 0xf , BCR_ILCRF}, - { 0xf-0xb, 0, 4, 0xb , BCR_ILCRF}, - { 0xf-0x7, 0, 12, 0x7 , BCR_ILCRG}, - { 0xf-0x6, 0, 8, 0x6 , BCR_ILCRG}, - { 0xf-0x4, 0, 4, 0x4 , BCR_ILCRG}, + { 13, 0, 8, 0x0f-13 ,BCR_ILCRA}, + { 5 , 0, 4, 0x0f- 5 ,BCR_ILCRA}, + { 10, 0, 0, 0x0f-10, BCR_ILCRB}, + { 7 , 0, 4, 0x0f- 7, BCR_ILCRC}, + { 3 , 0, 0, 0x0f- 3, BCR_ILCRC}, + { 1 , 0, 12, 0x0f- 1, BCR_ILCRD}, + { 12, 0, 4, 0x0f-12, BCR_ILCRD}, /* LAN */ + { 2 , 0, 8, 0x0f- 2, BCR_ILCRE}, /* PCIRQ2 */ + { 6 , 0, 4, 0x0f- 6, BCR_ILCRE}, /* PCIRQ1 */ + { 14, 0, 0, 0x0f-14, BCR_ILCRE}, /* PCIRQ0 */ + { 0 , 0, 12, 0x0f , BCR_ILCRF}, + { 4 , 0, 4, 0x0f- 4, BCR_ILCRF}, + { 8 , 0, 12, 0x0f- 8, BCR_ILCRG}, + { 9 , 0, 8, 0x0f- 9, BCR_ILCRG}, + { 11, 0, 4, 0x0f-11, BCR_ILCRG}, #else { 14, 0, 8, 0x0f-14 ,BCR_ILCRA}, { 12, 0, 4, 0x0f-12 ,BCR_ILCRA}, @@ -81,8 +92,10 @@ static struct ipr_data se770x_ipr_map[] = { { 4, 0, 4, 0x0f- 4 ,BCR_ILCRC}, { 3, 0, 0, 0x0f- 3 ,BCR_ILCRC}, { 1, 0, 12, 0x0f- 1 ,BCR_ILCRD}, +#if defined(CONFIG_STNIC) /* ST NIC */ { 10, 0, 4, 0x0f-10 ,BCR_ILCRD}, /* LAN */ +#endif /* MRSHPC IRQs setting */ { 0, 0, 12, 0x0f- 0 ,BCR_ILCRE}, /* PCIRQ3 */ { 11, 0, 8, 0x0f-11 ,BCR_ILCRE}, /* PCIRQ2 */ @@ -100,18 +113,6 @@ static struct ipr_data se770x_ipr_map[] = { */ void __init init_se_IRQ(void) { - /* - * Super I/O (Just mimic PC): - * 1: keyboard - * 3: serial 0 - * 4: serial 1 - * 5: printer - * 6: floppy - * 8: rtc - * 12: mouse - * 14: ide0 - */ -#if defined(CONFIG_CPU_SUBTYPE_SH7705) /* Disable all interrupts */ ctrl_outw(0, BCR_ILCRA); ctrl_outw(0, BCR_ILCRB); @@ -120,6 +121,6 @@ void __init init_se_IRQ(void) ctrl_outw(0, BCR_ILCRE); ctrl_outw(0, BCR_ILCRF); ctrl_outw(0, BCR_ILCRG); -#endif + make_se770x_irq(se770x_ipr_map, ARRAY_SIZE(se770x_ipr_map)); } diff --git a/trunk/arch/sh/boards/se/770x/setup.c b/trunk/arch/sh/boards/se/770x/setup.c index 45cbc36b9fb7..17a2631de3ba 100644 --- a/trunk/arch/sh/boards/se/770x/setup.c +++ b/trunk/arch/sh/boards/se/770x/setup.c @@ -63,6 +63,31 @@ static void __init smsc_setup(char **cmdline_p) outb_p(CONFIG_EXIT, CONFIG_PORT); } + +static struct resource cf_ide_resources[] = { + [0] = { + .start = PA_MRSHPC_IO + 0x1f0, + .end = PA_MRSHPC_IO + 0x1f0 + 8, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = PA_MRSHPC_IO + 0x1f0 + 0x206, + .end = PA_MRSHPC_IO + 0x1f0 +8 + 0x206 + 8, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = IRQ_CFCARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device cf_ide_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(cf_ide_resources), + .resource = cf_ide_resources, +}; + static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; static struct resource heartbeat_resources[] = { @@ -85,13 +110,14 @@ static struct platform_device heartbeat_device = { static struct platform_device *se_devices[] __initdata = { &heartbeat_device, + &cf_ide_device, }; static int __init se_devices_setup(void) { return platform_add_devices(se_devices, ARRAY_SIZE(se_devices)); } -__initcall(se_devices_setup); +device_initcall(se_devices_setup); /* * The Machine Vector @@ -107,6 +133,8 @@ struct sh_machine_vector mv_se __initmv = { .mv_nr_irqs = 61, #elif defined(CONFIG_CPU_SUBTYPE_SH7705) .mv_nr_irqs = 86, +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) + .mv_nr_irqs = 104, #endif .mv_inb = se_inb, diff --git a/trunk/arch/sh/boards/se/7722/Makefile b/trunk/arch/sh/boards/se/7722/Makefile new file mode 100644 index 000000000000..8694373389e5 --- /dev/null +++ b/trunk/arch/sh/boards/se/7722/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the HITACHI UL SolutionEngine 7722 specific parts of the kernel +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# + +obj-y := setup.o irq.o diff --git a/trunk/arch/sh/boards/se/7722/irq.c b/trunk/arch/sh/boards/se/7722/irq.c new file mode 100644 index 000000000000..099e5deb77f8 --- /dev/null +++ b/trunk/arch/sh/boards/se/7722/irq.c @@ -0,0 +1,101 @@ +/* + * linux/arch/sh/boards/se/7722/irq.c + * + * Copyright (C) 2007 Nobuhiro Iwamatsu + * + * Hitachi UL SolutionEngine 7722 Support. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include + +#define INTC_INTMSK0 0xFFD00044 +#define INTC_INTMSKCLR0 0xFFD00064 + +static void disable_se7722_irq(unsigned int irq) +{ + struct ipr_data *p = get_irq_chip_data(irq); + ctrl_outw( ctrl_inw( p->addr ) | p->priority , p->addr ); +} + +static void enable_se7722_irq(unsigned int irq) +{ + struct ipr_data *p = get_irq_chip_data(irq); + ctrl_outw( ctrl_inw( p->addr ) & ~p->priority , p->addr ); +} + +static struct irq_chip se7722_irq_chip __read_mostly = { + .name = "SE7722", + .mask = disable_se7722_irq, + .unmask = enable_se7722_irq, + .mask_ack = disable_se7722_irq, +}; + +static struct ipr_data ipr_irq_table[] = { + /* irq ,idx,sft, priority , addr */ + { MRSHPC_IRQ0 , 0 , 0 , MRSHPC_BIT0 , IRQ01_MASK } , + { MRSHPC_IRQ1 , 0 , 0 , MRSHPC_BIT1 , IRQ01_MASK } , + { MRSHPC_IRQ2 , 0 , 0 , MRSHPC_BIT2 , IRQ01_MASK } , + { MRSHPC_IRQ3 , 0 , 0 , MRSHPC_BIT3 , IRQ01_MASK } , + { SMC_IRQ , 0 , 0 , SMC_BIT , IRQ01_MASK } , + { EXT_IRQ , 0 , 0 , EXT_BIT , IRQ01_MASK } , +}; + +int se7722_irq_demux(int irq) +{ + + if ((irq == IRQ0_IRQ)||(irq == IRQ1_IRQ)) { + volatile unsigned short intv = + *(volatile unsigned short *)IRQ01_STS; + if (irq == IRQ0_IRQ){ + if(intv & SMC_BIT ) { + return SMC_IRQ; + } else if(intv & USB_BIT) { + return USB_IRQ; + } else { + printk("intv =%04x\n", intv); + return SMC_IRQ; + } + } else if(irq == IRQ1_IRQ){ + if(intv & MRSHPC_BIT0) { + return MRSHPC_IRQ0; + } else if(intv & MRSHPC_BIT1) { + return MRSHPC_IRQ1; + } else if(intv & MRSHPC_BIT2) { + return MRSHPC_IRQ2; + } else if(intv & MRSHPC_BIT3) { + return MRSHPC_IRQ3; + } else { + printk("BIT_EXTENTION =%04x\n", intv); + return EXT_IRQ; + } + } + } + return irq; + +} +/* + * Initialize IRQ setting + */ +void __init init_se7722_IRQ(void) +{ + int i = 0; + ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */ + ctrl_outl((3 << ((7 - 0) * 4))|(3 << ((7 - 1) * 4)), INTC_INTPRI0); /* irq0 pri=3,irq1,pri=3 */ + ctrl_outw((2 << ((7 - 0) * 2))|(2 << ((7 - 1) * 2)), INTC_ICR1); /* irq0,1 low-level irq */ + + for (i = 0; i < ARRAY_SIZE(ipr_irq_table); i++) { + disable_irq_nosync(ipr_irq_table[i].irq); + set_irq_chip_and_handler_name( ipr_irq_table[i].irq, &se7722_irq_chip, + handle_level_irq, "level"); + set_irq_chip_data( ipr_irq_table[i].irq, &ipr_irq_table[i] ); + disable_se7722_irq(ipr_irq_table[i].irq); + } +} diff --git a/trunk/arch/sh/boards/se/7722/setup.c b/trunk/arch/sh/boards/se/7722/setup.c new file mode 100644 index 000000000000..636ca6c987e0 --- /dev/null +++ b/trunk/arch/sh/boards/se/7722/setup.c @@ -0,0 +1,148 @@ +/* + * linux/arch/sh/boards/se/7722/setup.c + * + * Copyright (C) 2007 Nobuhiro Iwamatsu + * + * Hitachi UL SolutionEngine 7722 Support. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + */ +#include +#include +#include +#include +#include +#include + +/* Heartbeat */ +static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_LED, + .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .dev = { + .platform_data = heartbeat_bit_pos, + }, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +/* SMC91x */ +static struct resource smc91x_eth_resources[] = { + [0] = { + .name = "smc91x-regs" , + .start = PA_LAN + 0x300, + .end = PA_LAN + 0x300 + 0x10 , + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = SMC_IRQ, + .end = SMC_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_eth_device = { + .name = "smc91x", + .id = 0, + .dev = { + .dma_mask = NULL, /* don't use dma */ + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(smc91x_eth_resources), + .resource = smc91x_eth_resources, +}; + +static struct resource cf_ide_resources[] = { + [0] = { + .start = PA_MRSHPC_IO + 0x1f0, + .end = PA_MRSHPC_IO + 0x1f0 + 8 , + .flags = IORESOURCE_IO, + }, + [1] = { + .start = PA_MRSHPC_IO + 0x1f0 + 0x206, + .end = PA_MRSHPC_IO + 0x1f0 +8 + 0x206 + 8, + .flags = IORESOURCE_IO, + }, + [2] = { + .start = MRSHPC_IRQ0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device cf_ide_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(cf_ide_resources), + .resource = cf_ide_resources, +}; + +static struct platform_device *se7722_devices[] __initdata = { + &heartbeat_device, + &smc91x_eth_device, + &cf_ide_device, +}; + +static int __init se7722_devices_setup(void) +{ + return platform_add_devices(se7722_devices, + ARRAY_SIZE(se7722_devices)); +} +device_initcall(se7722_devices_setup); + +static void __init se7722_setup(char **cmdline_p) +{ + ctrl_outw(0x010D, FPGA_OUT); /* FPGA */ + + ctrl_outl(0x00051001, MSTPCR0); + ctrl_outl(0x00000000, MSTPCR1); + /* KEYSC, VOU, BEU, CEU, VEU, VPU, LCDC */ + ctrl_outl(0xffffbfC0, MSTPCR2); + + ctrl_outw(0x0000, PORT_PECR); /* PORT E 1 = IRQ5 ,E 0 = BS */ + ctrl_outw(0x1000, PORT_PJCR); /* PORT J 1 = IRQ1,J 0 =IRQ0 */ + + /* LCDC I/O */ + ctrl_outw(0x0020, PORT_PSELD); + + /* SIOF1*/ + ctrl_outw(0x0003, PORT_PSELB); + ctrl_outw(0xe000, PORT_PSELC); + ctrl_outw(0x0000, PORT_PKCR); + + /* LCDC */ + ctrl_outw(0x4020, PORT_PHCR); + ctrl_outw(0x0000, PORT_PLCR); + ctrl_outw(0x0000, PORT_PMCR); + ctrl_outw(0x0002, PORT_PRCR); + ctrl_outw(0x0000, PORT_PXCR); /* LCDC,CS6A */ + + /* KEYSC */ + ctrl_outw(0x0A10, PORT_PSELA); /* BS,SHHID2 */ + ctrl_outw(0x0000, PORT_PYCR); + ctrl_outw(0x0000, PORT_PZCR); +} + +/* + * The Machine Vector + */ +struct sh_machine_vector mv_se7722 __initmv = { + .mv_name = "Solution Engine 7722" , + .mv_setup = se7722_setup , + .mv_nr_irqs = 109 , + .mv_init_irq = init_se7722_IRQ, + .mv_irq_demux = se7722_irq_demux, + +}; +ALIAS_MV(se7722) diff --git a/trunk/arch/sh/boards/se/7751/setup.c b/trunk/arch/sh/boards/se/7751/setup.c index e3feae6ec0bf..770defed9c4a 100644 --- a/trunk/arch/sh/boards/se/7751/setup.c +++ b/trunk/arch/sh/boards/se/7751/setup.c @@ -14,153 +14,6 @@ #include #include -void init_7751se_IRQ(void); - -#ifdef CONFIG_SH_KGDB -#include -static int kgdb_uart_setup(void); -static struct kgdb_sermap kgdb_uart_sermap = -{ "ttyS", 0, kgdb_uart_setup, NULL }; -#endif - -/* - * Initialize the board - */ -static void __init sh7751se_setup(char **cmdline_p) -{ - /* Call init_smsc() replacement to set up SuperIO. */ - /* XXX: RTC setting comes here */ -#ifdef CONFIG_SH_KGDB - kgdb_register_sermap(&kgdb_uart_sermap); -#endif -} - -/********************************************************************* - * Currently a hack (e.g. does not interact well w/serial.c, lots of * - * hardcoded stuff) but may be useful if SCI/F needs debugging. * - * Mostly copied from x86 code (see files asm-i386/kgdb_local.h and * - * arch/i386/lib/kgdb_serial.c). * - *********************************************************************/ - -#ifdef CONFIG_SH_KGDB -#include -#include -#include -#include - -#define COM1_PORT 0x3f8 /* Base I/O address */ -#define COM1_IRQ 4 /* IRQ not used yet */ -#define COM2_PORT 0x2f8 /* Base I/O address */ -#define COM2_IRQ 3 /* IRQ not used yet */ - -#define SB_CLOCK 1843200 /* Serial baud clock */ -#define SB_BASE (SB_CLOCK/16) -#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS - -struct uart_port { - int base; -}; -#define UART_NPORTS 2 -struct uart_port uart_ports[] = { - { COM1_PORT }, - { COM2_PORT }, -}; -struct uart_port *kgdb_uart_port; - -#define UART_IN(reg) inb_p(kgdb_uart_port->base + reg) -#define UART_OUT(reg,v) outb_p((v), kgdb_uart_port->base + reg) - -/* Basic read/write functions for the UART */ -#define UART_LSR_RXCERR (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE) -static int kgdb_uart_getchar(void) -{ - int lsr; - int c = -1; - - while (c == -1) { - lsr = UART_IN(UART_LSR); - if (lsr & UART_LSR_DR) - c = UART_IN(UART_RX); - if ((lsr & UART_LSR_RXCERR)) - c = -1; - } - return c; -} - -static void kgdb_uart_putchar(int c) -{ - while ((UART_IN(UART_LSR) & UART_LSR_THRE) == 0) - ; - UART_OUT(UART_TX, c); -} - -/* - * Initialize UART to configured/requested values. - * (But we don't interrupts yet, or interact w/serial.c) - */ -static int kgdb_uart_setup(void) -{ - int port; - int lcr = 0; - int bdiv = 0; - - if (kgdb_portnum >= UART_NPORTS) { - KGDB_PRINTK("uart port %d invalid.\n", kgdb_portnum); - return -1; - } - - kgdb_uart_port = &uart_ports[kgdb_portnum]; - - /* Init sequence from gdb_hook_interrupt */ - UART_IN(UART_RX); - UART_OUT(UART_IER, 0); - - UART_IN(UART_RX); /* Serial driver comments say */ - UART_IN(UART_IIR); /* this clears interrupt regs */ - UART_IN(UART_MSR); - - /* Figure basic LCR values */ - switch (kgdb_bits) { - case '7': - lcr |= UART_LCR_WLEN7; - break; - default: case '8': - lcr |= UART_LCR_WLEN8; - break; - } - switch (kgdb_parity) { - case 'O': - lcr |= UART_LCR_PARITY; - break; - case 'E': - lcr |= (UART_LCR_PARITY | UART_LCR_EPAR); - break; - default: break; - } - - /* Figure the baud rate divisor */ - bdiv = (SB_BASE/kgdb_baud); - - /* Set the baud rate and LCR values */ - UART_OUT(UART_LCR, (lcr | UART_LCR_DLAB)); - UART_OUT(UART_DLL, (bdiv & 0xff)); - UART_OUT(UART_DLM, ((bdiv >> 8) & 0xff)); - UART_OUT(UART_LCR, lcr); - - /* Set the MCR */ - UART_OUT(UART_MCR, SB_MCR); - - /* Turn off FIFOs for now */ - UART_OUT(UART_FCR, 0); - - /* Setup complete: initialize function pointers */ - kgdb_getchar = kgdb_uart_getchar; - kgdb_putchar = kgdb_uart_putchar; - - return 0; -} -#endif /* CONFIG_SH_KGDB */ - static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 }; static struct resource heartbeat_resources[] = { @@ -197,7 +50,6 @@ __initcall(se7751_devices_setup); */ struct sh_machine_vector mv_7751se __initmv = { .mv_name = "7751 SolutionEngine", - .mv_setup = sh7751se_setup, .mv_nr_irqs = 72, .mv_inb = sh7751se_inb, diff --git a/trunk/arch/sh/boards/se/7780/Makefile b/trunk/arch/sh/boards/se/7780/Makefile new file mode 100644 index 000000000000..6b88adae3ecc --- /dev/null +++ b/trunk/arch/sh/boards/se/7780/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the HITACHI UL SolutionEngine 7780 specific parts of the kernel +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# + +obj-y := setup.o irq.o diff --git a/trunk/arch/sh/boards/se/7780/irq.c b/trunk/arch/sh/boards/se/7780/irq.c new file mode 100644 index 000000000000..3d0625c2d07b --- /dev/null +++ b/trunk/arch/sh/boards/se/7780/irq.c @@ -0,0 +1,89 @@ +/* + * linux/arch/sh/boards/se/7780/irq.c + * + * Copyright (C) 2006,2007 Nobuhiro Iwamatsu + * + * Hitachi UL SolutionEngine 7780 Support. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include + +#define INTC_INTMSK0 0xFFD00044 +#define INTC_INTMSKCLR0 0xFFD00064 + +static void disable_se7780_irq(unsigned int irq) +{ + struct intc2_data *p = get_irq_chip_data(irq); + ctrl_outl(1 << p->msk_shift, INTC_INTMSK0 + p->msk_offset); +} + +static void enable_se7780_irq(unsigned int irq) +{ + struct intc2_data *p = get_irq_chip_data(irq); + ctrl_outl(1 << p->msk_shift, INTC_INTMSKCLR0 + p->msk_offset); +} + +static struct irq_chip se7780_irq_chip __read_mostly = { + .name = "SE7780", + .mask = disable_se7780_irq, + .unmask = enable_se7780_irq, + .mask_ack = disable_se7780_irq, +}; + +static struct intc2_data intc2_irq_table[] = { + { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT1 */ + { 4, 0, 30, 0, 30, 3 }, /* daughter board EXTINT2 */ + { 6, 0, 29, 0, 29, 3 }, /* daughter board EXTINT3 */ + { 8, 0, 28, 0, 28, 3 }, /* SMC 91C111 (LAN) */ + { 10, 0, 27, 0, 27, 3 }, /* daughter board EXTINT4 */ + { 4, 0, 30, 0, 30, 3 }, /* daughter board EXTINT5 */ + { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT6 */ + { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT7 */ + { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT8 */ + { 0 , 0, 24, 0, 24, 3 }, /* SM501 */ +}; + +/* + * Initialize IRQ setting + */ +void __init init_se7780_IRQ(void) +{ + int i ; + + /* enable all interrupt at FPGA */ + ctrl_outw(0, FPGA_INTMSK1); + /* mask SM501 interrupt */ + ctrl_outw((ctrl_inw(FPGA_INTMSK1) | 0x0002), FPGA_INTMSK1); + /* enable all interrupt at FPGA */ + ctrl_outw(0, FPGA_INTMSK2); + + /* set FPGA INTSEL register */ + /* FPGA + 0x06 */ + ctrl_outw( ((IRQPIN_SM501 << IRQPOS_SM501) | + (IRQPIN_SMC91CX << IRQPOS_SMC91CX)), FPGA_INTSEL1); + + /* FPGA + 0x08 */ + ctrl_outw(((IRQPIN_EXTINT4 << IRQPOS_EXTINT4) | + (IRQPIN_EXTINT3 << IRQPOS_EXTINT3) | + (IRQPIN_EXTINT2 << IRQPOS_EXTINT2) | + (IRQPIN_EXTINT1 << IRQPOS_EXTINT1)), FPGA_INTSEL2); + + /* FPGA + 0x0A */ + ctrl_outw((IRQPIN_PCCPW << IRQPOS_PCCPW), FPGA_INTSEL3); + + for (i = 0; i < ARRAY_SIZE(intc2_irq_table); i++) { + disable_irq_nosync(intc2_irq_table[i].irq); + set_irq_chip_and_handler_name( intc2_irq_table[i].irq, &se7780_irq_chip, + handle_level_irq, "level"); + set_irq_chip_data( intc2_irq_table[i].irq, &intc2_irq_table[i] ); + disable_se7780_irq(intc2_irq_table[i].irq); + } +} diff --git a/trunk/arch/sh/boards/se/7780/setup.c b/trunk/arch/sh/boards/se/7780/setup.c new file mode 100644 index 000000000000..df7d08a24c9f --- /dev/null +++ b/trunk/arch/sh/boards/se/7780/setup.c @@ -0,0 +1,122 @@ +/* + * linux/arch/sh/boards/se/7780/setup.c + * + * Copyright (C) 2006,2007 Nobuhiro Iwamatsu + * + * Hitachi UL SolutionEngine 7780 Support. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include + +/* Heartbeat */ +static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_LED, + .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .dev = { + .platform_data = heartbeat_bit_pos, + }, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +/* SMC91x */ +static struct resource smc91x_eth_resources[] = { + [0] = { + .name = "smc91x-regs" , + .start = PA_LAN + 0x300, + .end = PA_LAN + 0x300 + 0x10 , + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = SMC_IRQ, + .end = SMC_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_eth_device = { + .name = "smc91x", + .id = 0, + .dev = { + .dma_mask = NULL, /* don't use dma */ + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(smc91x_eth_resources), + .resource = smc91x_eth_resources, +}; + +static struct platform_device *se7780_devices[] __initdata = { + &heartbeat_device, + &smc91x_eth_device, +}; + +static int __init se7780_devices_setup(void) +{ + return platform_add_devices(se7780_devices, + ARRAY_SIZE(se7780_devices)); +} +device_initcall(se7780_devices_setup); + +#define GPIO_PHCR 0xFFEA000E +#define GPIO_PMSELR 0xFFEA0080 +#define GPIO_PECR 0xFFEA0008 + +static void __init se7780_setup(char **cmdline_p) +{ + /* "SH-Linux" on LED Display */ + ctrl_outw( 'S' , PA_LED_DISP + (DISP_SEL0_ADDR << 1) ); + ctrl_outw( 'H' , PA_LED_DISP + (DISP_SEL1_ADDR << 1) ); + ctrl_outw( '-' , PA_LED_DISP + (DISP_SEL2_ADDR << 1) ); + ctrl_outw( 'L' , PA_LED_DISP + (DISP_SEL3_ADDR << 1) ); + ctrl_outw( 'i' , PA_LED_DISP + (DISP_SEL4_ADDR << 1) ); + ctrl_outw( 'n' , PA_LED_DISP + (DISP_SEL5_ADDR << 1) ); + ctrl_outw( 'u' , PA_LED_DISP + (DISP_SEL6_ADDR << 1) ); + ctrl_outw( 'x' , PA_LED_DISP + (DISP_SEL7_ADDR << 1) ); + + printk(KERN_INFO "Hitachi UL Solutions Engine 7780SE03 support.\n"); + + /* + * PCI REQ/GNT setting + * REQ0/GNT0 -> USB + * REQ1/GNT1 -> PC Card + * REQ2/GNT2 -> Serial ATA + * REQ3/GNT3 -> PCI slot + */ + ctrl_outw(0x0213, FPGA_REQSEL); + + /* GPIO setting */ + ctrl_outw(0x0000, GPIO_PECR); + ctrl_outw(ctrl_inw(GPIO_PHCR)&0xfff3, GPIO_PHCR); + ctrl_outw(0x0c00, GPIO_PMSELR); + + /* iVDR Power ON */ + ctrl_outw(0x0001, FPGA_IVDRPW); +} + +/* + * The Machine Vector + */ +struct sh_machine_vector mv_se7780 __initmv = { + .mv_name = "Solution Engine 7780" , + .mv_setup = se7780_setup , + .mv_nr_irqs = 111 , + .mv_init_irq = init_se7780_IRQ, +}; +ALIAS_MV(se7780) diff --git a/trunk/arch/sh/configs/lboxre2_defconfig b/trunk/arch/sh/configs/lboxre2_defconfig new file mode 100644 index 000000000000..be86414dcc87 --- /dev/null +++ b/trunk/arch/sh/configs/lboxre2_defconfig @@ -0,0 +1,1271 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.21-rc4 +# Sat Mar 24 22:04:27 2007 +# +CONFIG_SUPERH=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +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_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_EXTRA_PASS=y +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=y +# 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=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# System type +# +# CONFIG_SH_SOLUTION_ENGINE is not set +# CONFIG_SH_7751_SOLUTION_ENGINE is not set +# CONFIG_SH_7300_SOLUTION_ENGINE is not set +# CONFIG_SH_7343_SOLUTION_ENGINE is not set +# CONFIG_SH_73180_SOLUTION_ENGINE is not set +# CONFIG_SH_7751_SYSTEMH is not set +# CONFIG_SH_HP6XX is not set +# CONFIG_SH_SATURN is not set +# CONFIG_SH_DREAMCAST is not set +# CONFIG_SH_MPC1211 is not set +# CONFIG_SH_SH03 is not set +# CONFIG_SH_SECUREEDGE5410 is not set +# CONFIG_SH_HS7751RVOIP is not set +# CONFIG_SH_7710VOIPGW is not set +# CONFIG_SH_RTS7751R2D is not set +# CONFIG_SH_HIGHLANDER is not set +# CONFIG_SH_EDOSK7705 is not set +# CONFIG_SH_SH4202_MICRODEV is not set +# CONFIG_SH_LANDISK is not set +# CONFIG_SH_TITAN is not set +# CONFIG_SH_SHMIN is not set +# CONFIG_SH_7206_SOLUTION_ENGINE is not set +# CONFIG_SH_7619_SOLUTION_ENGINE is not set +CONFIG_SH_LBOX_RE2=y +# CONFIG_SH_UNKNOWN is not set + +# +# Processor selection +# +CONFIG_CPU_SH4=y + +# +# SH-2 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7604 is not set +# CONFIG_CPU_SUBTYPE_SH7619 is not set + +# +# SH-2A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7206 is not set + +# +# SH-3 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7300 is not set +# CONFIG_CPU_SUBTYPE_SH7705 is not set +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set + +# +# SH-4 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +CONFIG_CPU_SUBTYPE_SH7751=y +CONFIG_CPU_SUBTYPE_SH7751R=y +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set + +# +# ST40 Processor Support +# +# CONFIG_CPU_SUBTYPE_ST40STB1 is not set +# CONFIG_CPU_SUBTYPE_ST40GX1 is not set + +# +# SH-4A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7770 is not set +# CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set + +# +# SH4AL-DSP Processor Support +# +# CONFIG_CPU_SUBTYPE_SH73180 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set + +# +# Memory management options +# +CONFIG_MMU=y +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_MEMORY_START=0x0c000000 +CONFIG_MEMORY_SIZE=0x04000000 +CONFIG_VSYSCALL=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 + +# +# Cache configuration +# +# CONFIG_SH_DIRECT_MAPPED is not set +# CONFIG_SH_WRITETHROUGH is not set +# CONFIG_SH_OCRAM is not set + +# +# Processor features +# +CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_SH_FPU=y +# CONFIG_SH_DSP is not set +# CONFIG_SH_STORE_QUEUES is not set +CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_IPR_IRQ=y +CONFIG_CPU_HAS_SR_RB=y +CONFIG_CPU_HAS_PTEA=y + +# +# Timer and clock configuration +# +CONFIG_SH_TMU=y +CONFIG_SH_TIMER_IRQ=16 +# CONFIG_NO_IDLE_HZ is not set +CONFIG_SH_PCLK_FREQ=40000000 + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# DMA support +# +# CONFIG_SH_DMA is not set + +# +# Companion Chips +# +# CONFIG_HD6446X_SERIES is not set + +# +# Additional SuperH Device Drivers +# +# CONFIG_HEARTBEAT is not set +# CONFIG_PUSH_SWITCH is not set + +# +# Kernel features +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_KEXEC=y +# CONFIG_SMP is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00001000 +CONFIG_BOOT_LINK_OFFSET=0x00800000 +# CONFIG_UBC_WAKEUP is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttySC1,115200 root=/dev/sda1" + +# +# Bus options +# +CONFIG_ISA=y +CONFIG_PCI=y +CONFIG_SH_PCIDMA_NONCOHERENT=y +CONFIG_PCI_AUTO=y +CONFIG_PCI_AUTO_UPDATE_RESOURCES=y + +# +# PCCARD (PCMCIA/CardBus) support +# +CONFIG_PCCARD=y +CONFIG_PCMCIA_DEBUG=y +CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y +CONFIG_CARDBUS=y + +# +# PC-card bridges +# +CONFIG_YENTA=y +CONFIG_YENTA_O2=y +# CONFIG_YENTA_RICOH is not set +# CONFIG_YENTA_TI is not set +# CONFIG_YENTA_TOSHIBA is not set +# CONFIG_PD6729 is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +CONFIG_PCMCIA_PROBE=y +CONFIG_PCCARD_NONSTATIC=y + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options (EXPERIMENTAL) +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS 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=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NF_CONNTRACK_ENABLED is not set +# CONFIG_NETFILTER_XTABLES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES 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=y +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set +# CONFIG_PNPACPI is not set + +# +# Block devices +# +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# 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_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE 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 is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_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_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_LEGACY is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_QDI is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_WINBOND_VLB is not set +CONFIG_PATA_PLATFORM=y + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# 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 + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_STNIC is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_SMC91X is not set +# CONFIG_NET_VENDOR_RACAL is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_CS89x0 is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +CONFIG_NE2K_PCI=y +# CONFIG_8139CP is not set +CONFIG_8139TOO=y +CONFIG_8139TOO_PIO=y +CONFIG_8139TOO_TUNE_TWISTER=y +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_SC92031 is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_AXNET is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD 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 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=2 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# 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=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# HID Devices +# +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set + +# +# RTC drivers +# +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_SH is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Auxiliary Display support +# + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# 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 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 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 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_SH_STANDARD_BIOS=y +# CONFIG_EARLY_SCIF_CONSOLE is not set +# CONFIG_EARLY_PRINTK is not set +# CONFIG_SH_KGDB is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# 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_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/trunk/arch/sh/configs/r7780rp_defconfig b/trunk/arch/sh/configs/r7780rp_defconfig index 2b75b4896ba5..48c6a2194c98 100644 --- a/trunk/arch/sh/configs/r7780rp_defconfig +++ b/trunk/arch/sh/configs/r7780rp_defconfig @@ -1,10 +1,11 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.19 -# Wed Dec 6 11:59:38 2006 +# Linux kernel version: 2.6.21-rc7 +# Tue May 1 12:28:39 2007 # CONFIG_SUPERH=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y @@ -13,6 +14,8 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y # CONFIG_GENERIC_TIME is not set CONFIG_STACKTRACE_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -31,6 +34,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=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set @@ -41,7 +45,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_SYSFS_DEPRECATED is not set # CONFIG_RELAY is not set -CONFIG_INITRAMFS_SOURCE="" +# CONFIG_BLK_DEV_INITRD is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y CONFIG_EMBEDDED=y @@ -99,23 +103,23 @@ CONFIG_DEFAULT_IOSCHED="noop" # System type # # CONFIG_SH_SOLUTION_ENGINE is not set +# CONFIG_SH_7722_SOLUTION_ENGINE is not set # CONFIG_SH_7751_SOLUTION_ENGINE is not set +# CONFIG_SH_7780_SOLUTION_ENGINE is not set # CONFIG_SH_7300_SOLUTION_ENGINE is not set # CONFIG_SH_7343_SOLUTION_ENGINE is not set # CONFIG_SH_73180_SOLUTION_ENGINE is not set # CONFIG_SH_7751_SYSTEMH is not set # CONFIG_SH_HP6XX is not set -# CONFIG_SH_EC3104 is not set # CONFIG_SH_SATURN is not set # CONFIG_SH_DREAMCAST is not set -# CONFIG_SH_BIGSUR is not set # CONFIG_SH_MPC1211 is not set # CONFIG_SH_SH03 is not set # CONFIG_SH_SECUREEDGE5410 is not set # CONFIG_SH_HS7751RVOIP is not set # CONFIG_SH_7710VOIPGW is not set # CONFIG_SH_RTS7751R2D is not set -CONFIG_SH_R7780RP=y +CONFIG_SH_HIGHLANDER=y # CONFIG_SH_EDOSK7705 is not set # CONFIG_SH_SH4202_MICRODEV is not set # CONFIG_SH_LANDISK is not set @@ -123,7 +127,11 @@ CONFIG_SH_R7780RP=y # CONFIG_SH_SHMIN is not set # CONFIG_SH_7206_SOLUTION_ENGINE is not set # CONFIG_SH_7619_SOLUTION_ENGINE is not set +# CONFIG_SH_LBOX_RE2 is not set # CONFIG_SH_UNKNOWN is not set +CONFIG_SH_R7780RP=y +# CONFIG_SH_R7780MP is not set +# CONFIG_SH_R7785RP is not set # # Processor selection @@ -152,6 +160,7 @@ CONFIG_CPU_SH4A=y # CONFIG_CPU_SUBTYPE_SH7708 is not set # CONFIG_CPU_SUBTYPE_SH7709 is not set # CONFIG_CPU_SUBTYPE_SH7710 is not set +# CONFIG_CPU_SUBTYPE_SH7712 is not set # # SH-4 Processor Support @@ -183,6 +192,7 @@ CONFIG_CPU_SUBTYPE_SH7780=y # # CONFIG_CPU_SUBTYPE_SH73180 is not set # CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set # # Memory management options @@ -193,6 +203,8 @@ CONFIG_MEMORY_START=0x08000000 CONFIG_MEMORY_SIZE=0x08000000 # CONFIG_32BIT is not set CONFIG_VSYSCALL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_PAGE_SIZE_4KB=y # CONFIG_PAGE_SIZE_8KB is not set # CONFIG_PAGE_SIZE_64KB is not set @@ -210,6 +222,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=0 # # Cache configuration @@ -226,20 +239,15 @@ CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_SH_FPU=y # CONFIG_SH_DSP is not set CONFIG_SH_STORE_QUEUES=y +CONFIG_SPECULATIVE_EXECUTION=y CONFIG_CPU_HAS_INTEVT=y CONFIG_CPU_HAS_INTC2_IRQ=y CONFIG_CPU_HAS_SR_RB=y -CONFIG_CPU_HAS_PTEA=y # -# Timer support +# Timer and clock configuration # CONFIG_SH_TMU=y - -# -# R7780RP options -# -CONFIG_SH_R7780MP=y CONFIG_SH_TIMER_IRQ=28 CONFIG_NO_IDLE_HZ=y CONFIG_SH_PCLK_FREQ=32000000 @@ -262,6 +270,7 @@ CONFIG_SH_PCLK_FREQ=32000000 # # Additional SuperH Device Drivers # +# CONFIG_HEARTBEAT is not set CONFIG_PUSH_SWITCH=y # @@ -269,9 +278,11 @@ CONFIG_PUSH_SWITCH=y # # CONFIG_HZ_100 is not set CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=250 CONFIG_KEXEC=y +# CONFIG_CRASH_DUMP is not set # CONFIG_SMP is not set # CONFIG_PREEMPT_NONE is not set # CONFIG_PREEMPT_VOLUNTARY is not set @@ -294,7 +305,6 @@ CONFIG_PCI=y CONFIG_SH_PCIDMA_NONCOHERENT=y CONFIG_PCI_AUTO=y CONFIG_PCI_AUTO_UPDATE_RESOURCES=y -# CONFIG_PCI_MULTITHREAD_PROBE is not set # CONFIG_PCI_DEBUG is not set # @@ -334,6 +344,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 is not set @@ -425,6 +436,7 @@ CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=m # CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set # @@ -445,6 +457,7 @@ CONFIG_FW_LOADER=m # # Plug and Play support # +# CONFIG_PNPACPI is not set # # Block devices @@ -461,7 +474,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -# CONFIG_BLK_DEV_INITRD is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -481,6 +493,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # 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 @@ -500,6 +513,7 @@ CONFIG_CHR_DEV_SG=m # CONFIG_SCSI_MULTI_LUN is not set # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set # # SCSI Transports @@ -544,11 +558,13 @@ CONFIG_CHR_DEV_SG=m # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set # # Serial ATA (prod) and Parallel ATA (experimental) drivers # CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set # CONFIG_SATA_AHCI is not set # CONFIG_SATA_SVW is not set # CONFIG_ATA_PIIX is not set @@ -564,6 +580,7 @@ CONFIG_SATA_SIL=y # CONFIG_SATA_ULI is not set # CONFIG_SATA_VIA is not set # CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set # CONFIG_PATA_ALI is not set # CONFIG_PATA_AMD is not set # CONFIG_PATA_ARTOP is not set @@ -579,6 +596,7 @@ CONFIG_SATA_SIL=y # CONFIG_PATA_HPT3X2N is not set # CONFIG_PATA_HPT3X3 is not set # CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set # CONFIG_PATA_JMICRON is not set # CONFIG_PATA_TRIFLEX is not set # CONFIG_PATA_MARVELL is not set @@ -685,6 +703,7 @@ CONFIG_8139TOO_8129=y CONFIG_VIA_RHINE=m CONFIG_VIA_RHINE_MMIO=y # CONFIG_VIA_RHINE_NAPI is not set +# CONFIG_SC92031 is not set # # Ethernet (1000 Mbit) @@ -707,11 +726,13 @@ CONFIG_R8169=y # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set # CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set # # 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 @@ -889,9 +910,15 @@ CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set # CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_VT1211 is not set # CONFIG_HWMON_DEBUG_CHIP is not set +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + # # Multimedia devices # @@ -905,9 +932,8 @@ CONFIG_HWMON=y # # Graphics support # -CONFIG_FIRMWARE_EDID=y -# CONFIG_FB is not set # CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_FB is not set # # Sound @@ -923,15 +949,20 @@ CONFIG_SOUND=m # Open Sound System # CONFIG_SOUND_PRIME=m -# CONFIG_OSS_OBSOLETE_DRIVER is not set +# CONFIG_OBSOLETE_OSS is not set # CONFIG_SOUND_BT878 is not set -# CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ICH is not set # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_VIA82CXXX is not set +# +# HID Devices +# +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set + # # USB support # @@ -1016,6 +1047,14 @@ CONFIG_RTC_DRV_SH=y # DMA Devices # +# +# Auxiliary Display support +# + +# +# Virtualization +# + # # File systems # @@ -1174,6 +1213,11 @@ CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + # # Profiling support # @@ -1184,19 +1228,22 @@ CONFIG_OPROFILE=m # Kernel hacking # CONFIG_TRACE_IRQFLAGS_SUPPORT=y -CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_TIME is not set CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# 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 +# CONFIG_TIMER_STATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_PREEMPT is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_RWSEMS is not set # CONFIG_DEBUG_LOCK_ALLOC is not set # CONFIG_PROVE_LOCKING is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set @@ -1204,19 +1251,19 @@ CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_FS=y # CONFIG_DEBUG_VM is not set # CONFIG_DEBUG_LIST is not set -CONFIG_FRAME_POINTER=y +# CONFIG_FRAME_POINTER is not set CONFIG_FORCED_INLINING=y -# CONFIG_HEADERS_CHECK is not set # CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_SH_STANDARD_BIOS is not set +# CONFIG_FAULT_INJECTION is not set +CONFIG_SH_STANDARD_BIOS=y # CONFIG_EARLY_SCIF_CONSOLE is not set +CONFIG_EARLY_PRINTK=y CONFIG_DEBUG_STACKOVERFLOW=y # CONFIG_DEBUG_STACK_USAGE is not set # CONFIG_4KSTACKS is not set -# CONFIG_KGDB is not set +# CONFIG_SH_KGDB is not set # # Security options @@ -1233,6 +1280,7 @@ CONFIG_CRYPTO_BLKCIPHER=y CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_MD4 is not set CONFIG_CRYPTO_MD5=y @@ -1241,9 +1289,13 @@ CONFIG_CRYPTO_MD5=y # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set CONFIG_CRYPTO_ECB=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 @@ -1257,6 +1309,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 # @@ -1266,7 +1319,10 @@ CONFIG_CRYPTO_DES=y # # 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_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/trunk/arch/sh/configs/r7785rp_defconfig b/trunk/arch/sh/configs/r7785rp_defconfig new file mode 100644 index 000000000000..0f5ec649daf8 --- /dev/null +++ b/trunk/arch/sh/configs/r7785rp_defconfig @@ -0,0 +1,1334 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.21-rc3 +# Mon Mar 12 14:26:33 2007 +# +CONFIG_SUPERH=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +CONFIG_SHMEM=y +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=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 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_SH_SOLUTION_ENGINE is not set +# CONFIG_SH_7751_SOLUTION_ENGINE is not set +# CONFIG_SH_7300_SOLUTION_ENGINE is not set +# CONFIG_SH_7343_SOLUTION_ENGINE is not set +# CONFIG_SH_73180_SOLUTION_ENGINE is not set +# CONFIG_SH_7751_SYSTEMH is not set +# CONFIG_SH_HP6XX is not set +# CONFIG_SH_SATURN is not set +# CONFIG_SH_DREAMCAST is not set +# CONFIG_SH_MPC1211 is not set +# CONFIG_SH_SH03 is not set +# CONFIG_SH_SECUREEDGE5410 is not set +# CONFIG_SH_HS7751RVOIP is not set +# CONFIG_SH_7710VOIPGW is not set +# CONFIG_SH_RTS7751R2D is not set +CONFIG_SH_HIGHLANDER=y +# CONFIG_SH_EDOSK7705 is not set +# CONFIG_SH_SH4202_MICRODEV is not set +# CONFIG_SH_LANDISK is not set +# CONFIG_SH_TITAN is not set +# CONFIG_SH_SHMIN is not set +# CONFIG_SH_7206_SOLUTION_ENGINE is not set +# CONFIG_SH_7619_SOLUTION_ENGINE is not set +# CONFIG_SH_UNKNOWN is not set +# CONFIG_SH_R7780RP is not set +# CONFIG_SH_R7780MP is not set +CONFIG_SH_R7785RP=y + +# +# Processor selection +# +CONFIG_CPU_SH4=y +CONFIG_CPU_SH4A=y +CONFIG_CPU_SHX2=y + +# +# SH-2 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7604 is not set +# CONFIG_CPU_SUBTYPE_SH7619 is not set + +# +# SH-2A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7206 is not set + +# +# SH-3 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7300 is not set +# CONFIG_CPU_SUBTYPE_SH7705 is not set +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set + +# +# SH-4 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +# CONFIG_CPU_SUBTYPE_SH7751 is not set +# CONFIG_CPU_SUBTYPE_SH7751R is not set +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set + +# +# ST40 Processor Support +# +# CONFIG_CPU_SUBTYPE_ST40STB1 is not set +# CONFIG_CPU_SUBTYPE_ST40GX1 is not set + +# +# SH-4A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7770 is not set +# CONFIG_CPU_SUBTYPE_SH7780 is not set +CONFIG_CPU_SUBTYPE_SH7785=y + +# +# SH4AL-DSP Processor Support +# +# CONFIG_CPU_SUBTYPE_SH73180 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set + +# +# Memory management options +# +CONFIG_MMU=y +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x08000000 +CONFIG_32BIT=y +# CONFIG_X2TLB is not set +CONFIG_VSYSCALL=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_HUGETLB_PAGE_SIZE_64K is not set +# CONFIG_HUGETLB_PAGE_SIZE_256K is not set +CONFIG_HUGETLB_PAGE_SIZE_1MB=y +# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 + +# +# Cache configuration +# +# CONFIG_SH_DIRECT_MAPPED is not set +# CONFIG_SH_WRITETHROUGH is not set +# CONFIG_SH_OCRAM is not set + +# +# Processor features +# +CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_SH_FPU=y +# CONFIG_SH_DSP is not set +CONFIG_SH_STORE_QUEUES=y +CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_INTC2_IRQ=y +CONFIG_CPU_HAS_SR_RB=y +CONFIG_CPU_HAS_PTEA=y + +# +# Timer and clock configuration +# +CONFIG_SH_TMU=y +CONFIG_SH_TIMER_IRQ=28 +CONFIG_NO_IDLE_HZ=y +CONFIG_SH_PCLK_FREQ=50000000 + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# DMA support +# +# CONFIG_SH_DMA is not set + +# +# Companion Chips +# +# CONFIG_HD6446X_SERIES is not set + +# +# Additional SuperH Device Drivers +# +CONFIG_HEARTBEAT=y +CONFIG_PUSH_SWITCH=y + +# +# Kernel features +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_KEXEC=y +# CONFIG_SMP is not set +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_BKL=y + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00001000 +CONFIG_BOOT_LINK_OFFSET=0x00800000 +# CONFIG_UBC_WAKEUP is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/sda1" + +# +# Bus options +# +CONFIG_PCI=y +CONFIG_SH_PCIDMA_NONCOHERENT=y +CONFIG_PCI_AUTO=y +CONFIG_PCI_AUTO_UPDATE_RESOURCES=y +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options (EXPERIMENTAL) +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# 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=m +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# 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 +CONFIG_WIRELESS_EXT=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=m +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNPACPI is not set + +# +# Block devices +# +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE 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=m +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_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_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +CONFIG_SATA_SIL=y +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +CONFIG_PATA_PLATFORM=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# 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 + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_STNIC is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_SMC91X is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +CONFIG_R8169=y +# CONFIG_R8169_NAPI is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_NET_WIRELESS_RTNETLINK is not set + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +# CONFIG_IPW2100 is not set +# CONFIG_IPW2200 is not set +# CONFIG_HERMES is not set +# CONFIG_ATMEL is not set + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +# CONFIG_PRISM54 is not set +# CONFIG_HOSTAP is not set +CONFIG_NET_WIRELESS=y + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=6 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_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=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frambuffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_EPSON1355 is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +# CONFIG_SND is not set + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=m +# CONFIG_OBSOLETE_OSS is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set + +# +# HID Devices +# +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set + +# +# RTC drivers +# +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set +CONFIG_RTC_DRV_SH=y +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Auxiliary Display support +# + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_MINIX_FS=y +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=m + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=y +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y +CONFIG_CONFIGFS_FS=m + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# 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 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_CODEPAGE_932=y +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=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=y +CONFIG_OPROFILE=m + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DETECT_SOFTLOCKUP is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_LOCK_ALLOC=y +# CONFIG_PROVE_LOCKING is not set +CONFIG_LOCKDEP=y +# CONFIG_DEBUG_LOCKDEP is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +CONFIG_DEBUG_LOCKING_API_SELFTESTS=y +CONFIG_STACKTRACE=y +# 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_FAULT_INJECTION is not set +CONFIG_SH_STANDARD_BIOS=y +# CONFIG_EARLY_SCIF_CONSOLE is not set +CONFIG_EARLY_PRINTK=y +CONFIG_DEBUG_STACKOVERFLOW=y +CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_4KSTACKS is not set +# CONFIG_SH_KGDB is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=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 +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# + +# +# 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_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/trunk/arch/sh/configs/se7705_defconfig b/trunk/arch/sh/configs/se7705_defconfig index 06ebd6ec0cdb..87ae5c1f8629 100644 --- a/trunk/arch/sh/configs/se7705_defconfig +++ b/trunk/arch/sh/configs/se7705_defconfig @@ -1,15 +1,21 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18 -# Tue Oct 3 12:03:04 2006 +# Linux kernel version: 2.6.21-rc5 +# Thu Apr 26 09:16:31 2007 # CONFIG_SUPERH=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -33,7 +39,9 @@ CONFIG_LOCALVERSION_AUTO=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_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y @@ -91,27 +99,30 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" CONFIG_SOLUTION_ENGINE=y CONFIG_SH_SOLUTION_ENGINE=y # CONFIG_SH_7751_SOLUTION_ENGINE is not set +# CONFIG_SH_7780_SOLUTION_ENGINE is not set # CONFIG_SH_7300_SOLUTION_ENGINE is not set # CONFIG_SH_7343_SOLUTION_ENGINE is not set # CONFIG_SH_73180_SOLUTION_ENGINE is not set +# CONFIG_SH_7722_SOLUTION_ENGINE is not set # CONFIG_SH_7751_SYSTEMH is not set # CONFIG_SH_HP6XX is not set -# CONFIG_SH_EC3104 is not set # CONFIG_SH_SATURN is not set # CONFIG_SH_DREAMCAST is not set -# CONFIG_SH_BIGSUR is not set # CONFIG_SH_MPC1211 is not set # CONFIG_SH_SH03 is not set # CONFIG_SH_SECUREEDGE5410 is not set # CONFIG_SH_HS7751RVOIP is not set # CONFIG_SH_7710VOIPGW is not set # CONFIG_SH_RTS7751R2D is not set -# CONFIG_SH_R7780RP is not set +# CONFIG_SH_HIGHLANDER is not set # CONFIG_SH_EDOSK7705 is not set # CONFIG_SH_SH4202_MICRODEV is not set # CONFIG_SH_LANDISK is not set # CONFIG_SH_TITAN is not set # CONFIG_SH_SHMIN is not set +# CONFIG_SH_7206_SOLUTION_ENGINE is not set +# CONFIG_SH_7619_SOLUTION_ENGINE is not set +# CONFIG_SH_LBOX_RE2 is not set # CONFIG_SH_UNKNOWN is not set # @@ -123,6 +134,12 @@ CONFIG_CPU_SH3=y # SH-2 Processor Support # # CONFIG_CPU_SUBTYPE_SH7604 is not set +# CONFIG_CPU_SUBTYPE_SH7619 is not set + +# +# SH-2A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7206 is not set # # SH-3 Processor Support @@ -134,6 +151,7 @@ CONFIG_CPU_SUBTYPE_SH7705=y # CONFIG_CPU_SUBTYPE_SH7708 is not set # CONFIG_CPU_SUBTYPE_SH7709 is not set # CONFIG_CPU_SUBTYPE_SH7710 is not set +# CONFIG_CPU_SUBTYPE_SH7712 is not set # # SH-4 Processor Support @@ -158,12 +176,14 @@ CONFIG_CPU_SUBTYPE_SH7705=y # # CONFIG_CPU_SUBTYPE_SH7770 is not set # CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set # # SH4AL-DSP Processor Support # # CONFIG_CPU_SUBTYPE_SH73180 is not set # CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set # # Memory management options @@ -173,6 +193,11 @@ CONFIG_PAGE_OFFSET=0x80000000 CONFIG_MEMORY_START=0x0c000000 CONFIG_MEMORY_SIZE=0x02000000 CONFIG_VSYSCALL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y # CONFIG_DISCONTIGMEM_MANUAL is not set @@ -182,6 +207,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=0 # # Cache configuration @@ -190,23 +216,31 @@ CONFIG_SH7705_CACHE_32KB=y # CONFIG_SH_DIRECT_MAPPED is not set # CONFIG_SH_WRITETHROUGH is not set # CONFIG_SH_OCRAM is not set -# CONFIG_CF_ENABLER is not set +CONFIG_CF_ENABLER=y +# CONFIG_CF_AREA5 is not set +CONFIG_CF_AREA6=y +# CONFIG_CF_AREA4 is not set +CONFIG_CF_BASE_ADDR=0xb8000000 # # Processor features # CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set # CONFIG_SH_FPU_EMU is not set # CONFIG_SH_DSP is not set # CONFIG_SH_ADC is not set CONFIG_CPU_HAS_INTEVT=y CONFIG_CPU_HAS_PINT_IRQ=y +CONFIG_CPU_HAS_IPR_IRQ=y CONFIG_CPU_HAS_SR_RB=y # -# Timer support +# Timer and clock configuration # CONFIG_SH_TMU=y +CONFIG_SH_TIMER_IRQ=16 +# CONFIG_NO_IDLE_HZ is not set CONFIG_SH_PCLK_FREQ=33333333 # @@ -223,13 +257,19 @@ CONFIG_SH_PCLK_FREQ=33333333 # Companion Chips # # CONFIG_HD6446X_SERIES is not set + +# +# Additional SuperH Device Drivers +# CONFIG_HEARTBEAT=y +# CONFIG_PUSH_SWITCH is not set # # Kernel features # # CONFIG_HZ_100 is not set CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=250 # CONFIG_KEXEC is not set @@ -287,6 +327,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 is not set @@ -307,11 +348,13 @@ CONFIG_IP_PNP_RARP=y # CONFIG_INET_TUNNEL is not set CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set # CONFIG_IPV6 is not set # CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set @@ -388,6 +431,7 @@ CONFIG_MTD_PARTITIONS=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 @@ -461,6 +505,7 @@ CONFIG_MTD_CFI_UTIL=y # # Plug and Play support # +# CONFIG_PNPACPI is not set # # Block devices @@ -472,10 +517,13 @@ 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 +# +# Misc devices +# + # # ATA/ATAPI/MFM/RLL support # @@ -649,17 +697,12 @@ CONFIG_HW_RANDOM=y # CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set - -# -# Ftape, the floppy tape device driver -# # CONFIG_RAW_DRIVER is not set # # TPM devices # # CONFIG_TCG_TPM is not set -# CONFIG_TELCLOCK is not set # # I2C support @@ -675,6 +718,7 @@ CONFIG_HW_RANDOM=y # # Dallas's 1-wire bus # +# CONFIG_W1 is not set # # Hardware Monitoring support @@ -683,18 +727,19 @@ CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set # CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_VT1211 is not set # CONFIG_HWMON_DEBUG_CHIP is not set # -# Misc devices +# Multifunction device drivers # +# CONFIG_MFD_SM501 is not set # # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices @@ -704,7 +749,7 @@ CONFIG_VIDEO_V4L2=y # # Graphics support # -CONFIG_FIRMWARE_EDID=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # CONFIG_FB is not set # @@ -712,6 +757,12 @@ CONFIG_FIRMWARE_EDID=y # # CONFIG_SOUND is not set +# +# HID Devices +# +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set + # # USB support # @@ -772,6 +823,14 @@ CONFIG_FIRMWARE_EDID=y # DMA Devices # +# +# Auxiliary Display support +# + +# +# Virtualization +# + # # File systems # @@ -779,10 +838,12 @@ 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 @@ -828,7 +889,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 is not set CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 CONFIG_JFFS2_FS_WRITEBUFFER=y @@ -877,6 +937,10 @@ CONFIG_MSDOS_PARTITION=y # # CONFIG_NLS is not set +# +# Distributed Lock Manager +# + # # Profiling support # @@ -885,15 +949,18 @@ CONFIG_MSDOS_PARTITION=y # # Kernel hacking # +CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_SH_STANDARD_BIOS is not set -# CONFIG_KGDB is not set +# CONFIG_EARLY_SCIF_CONSOLE is not set +# CONFIG_SH_KGDB is not set # # Security options @@ -908,6 +975,7 @@ CONFIG_LOG_BUF_SHIFT=14 # # Library routines # +CONFIG_BITREVERSE=y CONFIG_CRC_CCITT=y # CONFIG_CRC16 is not set CONFIG_CRC32=y @@ -915,3 +983,5 @@ CONFIG_CRC32=y CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/trunk/arch/sh/configs/se7712_defconfig b/trunk/arch/sh/configs/se7712_defconfig new file mode 100644 index 000000000000..a5e37dbc5353 --- /dev/null +++ b/trunk/arch/sh/configs/se7712_defconfig @@ -0,0 +1,1088 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.21-rc4 +# Wed Mar 28 10:19:02 2007 +# +CONFIG_SUPERH=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +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_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +# CONFIG_BUG is not set +CONFIG_ELF_CORE=y +# CONFIG_BASE_FULL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +# CONFIG_SHMEM is not set +CONFIG_SLAB=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_RT_MUTEXES=y +CONFIG_TINY_SHMEM=y +CONFIG_BASE_SMALL=1 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set + +# +# Block layer +# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set + +# +# 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_SOLUTION_ENGINE=y +CONFIG_SH_SOLUTION_ENGINE=y +# CONFIG_SH_7751_SOLUTION_ENGINE is not set +# CONFIG_SH_7300_SOLUTION_ENGINE is not set +# CONFIG_SH_7343_SOLUTION_ENGINE is not set +# CONFIG_SH_73180_SOLUTION_ENGINE is not set +# CONFIG_SH_7751_SYSTEMH is not set +# CONFIG_SH_HP6XX is not set +# CONFIG_SH_SATURN is not set +# CONFIG_SH_DREAMCAST is not set +# CONFIG_SH_MPC1211 is not set +# CONFIG_SH_SH03 is not set +# CONFIG_SH_SECUREEDGE5410 is not set +# CONFIG_SH_HS7751RVOIP is not set +# CONFIG_SH_7710VOIPGW is not set +# CONFIG_SH_RTS7751R2D is not set +# CONFIG_SH_HIGHLANDER is not set +# CONFIG_SH_EDOSK7705 is not set +# CONFIG_SH_SH4202_MICRODEV is not set +# CONFIG_SH_LANDISK is not set +# CONFIG_SH_TITAN is not set +# CONFIG_SH_SHMIN is not set +# CONFIG_SH_7206_SOLUTION_ENGINE is not set +# CONFIG_SH_7619_SOLUTION_ENGINE is not set +# CONFIG_SH_LBOX_RE2 is not set +# CONFIG_SH_UNKNOWN is not set + +# +# Processor selection +# +CONFIG_CPU_SH3=y + +# +# SH-2 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7604 is not set +# CONFIG_CPU_SUBTYPE_SH7619 is not set + +# +# SH-2A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7206 is not set + +# +# SH-3 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7300 is not set +# CONFIG_CPU_SUBTYPE_SH7705 is not set +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set +CONFIG_CPU_SUBTYPE_SH7712=y + +# +# SH-4 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +# CONFIG_CPU_SUBTYPE_SH7751 is not set +# CONFIG_CPU_SUBTYPE_SH7751R is not set +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set + +# +# ST40 Processor Support +# +# CONFIG_CPU_SUBTYPE_ST40STB1 is not set +# CONFIG_CPU_SUBTYPE_ST40GX1 is not set + +# +# SH-4A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7770 is not set +# CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set + +# +# SH4AL-DSP Processor Support +# +# CONFIG_CPU_SUBTYPE_SH73180 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set + +# +# Memory management options +# +CONFIG_MMU=y +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_MEMORY_START=0x0c000000 +CONFIG_MEMORY_SIZE=0x02000000 +CONFIG_VSYSCALL=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 + +# +# Cache configuration +# +# CONFIG_SH_DIRECT_MAPPED is not set +# CONFIG_SH_WRITETHROUGH is not set +# CONFIG_SH_OCRAM is not set +CONFIG_CF_ENABLER=y +# CONFIG_CF_AREA5 is not set +CONFIG_CF_AREA6=y +CONFIG_CF_BASE_ADDR=0xb8000000 + +# +# Processor features +# +CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_SH_FPU_EMU is not set +# CONFIG_SH_DSP is not set +# CONFIG_SH_ADC is not set +CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_IPR_IRQ=y +CONFIG_CPU_HAS_SR_RB=y + +# +# Timer and clock configuration +# +CONFIG_SH_TMU=y +CONFIG_SH_TIMER_IRQ=16 +# CONFIG_NO_IDLE_HZ is not set +CONFIG_SH_PCLK_FREQ=33333333 + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# DMA support +# +# CONFIG_SH_DMA is not set + +# +# Companion Chips +# +# CONFIG_HD6446X_SERIES is not set + +# +# Additional SuperH Device Drivers +# +CONFIG_HEARTBEAT=y +# CONFIG_PUSH_SWITCH is not set + +# +# Kernel features +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_KEXEC is not set +# CONFIG_SMP is not set +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_PREEMPT is not set + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00001000 +CONFIG_BOOT_LINK_OFFSET=0x00800000 +# CONFIG_UBC_WAKEUP is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/sda1" + +# +# Bus options +# +# CONFIG_PCI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options (EXPERIMENTAL) +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +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=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# 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=y +CONFIG_NET_SCH_FIFO=y +CONFIG_NET_SCH_CLK_JIFFIES=y +# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set +# CONFIG_NET_SCH_CLK_CPU is not set + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_HFSC=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_RED=y +CONFIG_NET_SCH_SFQ=y +CONFIG_NET_SCH_TEQL=y +CONFIG_NET_SCH_TBF=y +CONFIG_NET_SCH_GRED=y +CONFIG_NET_SCH_DSMARK=y +CONFIG_NET_SCH_NETEM=y +CONFIG_NET_SCH_INGRESS=y + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +CONFIG_NET_CLS_TCINDEX=y +CONFIG_NET_CLS_ROUTE4=y +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=y +# CONFIG_NET_CLS_U32 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_CLS_IND=y +CONFIG_NET_ESTIMATOR=y + +# +# 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 +CONFIG_FIB_RULES=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_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=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND 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 +# +# CONFIG_PNPACPI is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE 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 is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_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=y +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_PATA_PLATFORM=y + +# +# 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 +# + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET 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 + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=2 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=m +# CONFIG_GEN_RTC 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 + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set + +# +# InfiniBand support +# + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Auxiliary Display support +# + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=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 is not set +# CONFIG_NFSD is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DETECT_SOFTLOCKUP is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +CONFIG_FRAME_POINTER=y +# CONFIG_FORCED_INLINING is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SH_STANDARD_BIOS is not set +# CONFIG_EARLY_SCIF_CONSOLE is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_4KSTACKS is not set +# CONFIG_SH_KGDB is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +CONFIG_CRYPTO_ECB=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 +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_DEFLATE=y +# 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 + +# +# Hardware crypto devices +# + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=y +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/trunk/arch/sh/configs/se7722_defconfig b/trunk/arch/sh/configs/se7722_defconfig new file mode 100644 index 000000000000..ca4c663dfa37 --- /dev/null +++ b/trunk/arch/sh/configs/se7722_defconfig @@ -0,0 +1,980 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.21-rc7 +# Fri Apr 27 16:30:30 2007 +# +CONFIG_SUPERH=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_UTS_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_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 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_SOLUTION_ENGINE=y +# CONFIG_SH_SOLUTION_ENGINE is not set +CONFIG_SH_7722_SOLUTION_ENGINE=y +# CONFIG_SH_7751_SOLUTION_ENGINE is not set +# CONFIG_SH_7780_SOLUTION_ENGINE is not set +# CONFIG_SH_7300_SOLUTION_ENGINE is not set +# CONFIG_SH_7343_SOLUTION_ENGINE is not set +# CONFIG_SH_73180_SOLUTION_ENGINE is not set +# CONFIG_SH_7751_SYSTEMH is not set +# CONFIG_SH_HP6XX is not set +# CONFIG_SH_SATURN is not set +# CONFIG_SH_DREAMCAST is not set +# CONFIG_SH_MPC1211 is not set +# CONFIG_SH_SH03 is not set +# CONFIG_SH_SECUREEDGE5410 is not set +# CONFIG_SH_HS7751RVOIP is not set +# CONFIG_SH_7710VOIPGW is not set +# CONFIG_SH_RTS7751R2D is not set +# CONFIG_SH_HIGHLANDER is not set +# CONFIG_SH_EDOSK7705 is not set +# CONFIG_SH_SH4202_MICRODEV is not set +# CONFIG_SH_LANDISK is not set +# CONFIG_SH_TITAN is not set +# CONFIG_SH_SHMIN is not set +# CONFIG_SH_7206_SOLUTION_ENGINE is not set +# CONFIG_SH_7619_SOLUTION_ENGINE is not set +# CONFIG_SH_LBOX_RE2 is not set +# CONFIG_SH_UNKNOWN is not set + +# +# Processor selection +# +CONFIG_CPU_SH4=y +CONFIG_CPU_SH4A=y +CONFIG_CPU_SH4AL_DSP=y +CONFIG_CPU_SHX2=y + +# +# SH-2 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7604 is not set +# CONFIG_CPU_SUBTYPE_SH7619 is not set + +# +# SH-2A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7206 is not set + +# +# SH-3 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7300 is not set +# CONFIG_CPU_SUBTYPE_SH7705 is not set +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set +# CONFIG_CPU_SUBTYPE_SH7712 is not set + +# +# SH-4 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +# CONFIG_CPU_SUBTYPE_SH7751 is not set +# CONFIG_CPU_SUBTYPE_SH7751R is not set +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set + +# +# ST40 Processor Support +# +# CONFIG_CPU_SUBTYPE_ST40STB1 is not set +# CONFIG_CPU_SUBTYPE_ST40GX1 is not set + +# +# SH-4A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7770 is not set +# CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set + +# +# SH4AL-DSP Processor Support +# +# CONFIG_CPU_SUBTYPE_SH73180 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set +CONFIG_CPU_SUBTYPE_SH7722=y + +# +# Memory management options +# +CONFIG_MMU=y +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_MEMORY_START=0x0c000000 +CONFIG_MEMORY_SIZE=0x04000000 +# CONFIG_32BIT is not set +# CONFIG_X2TLB is not set +CONFIG_VSYSCALL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_HUGETLB_PAGE_SIZE_64K=y +# CONFIG_HUGETLB_PAGE_SIZE_256K is not set +# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 + +# +# Cache configuration +# +# CONFIG_SH_DIRECT_MAPPED is not set +# CONFIG_SH_WRITETHROUGH is not set +# CONFIG_SH_OCRAM is not set +CONFIG_CF_ENABLER=y +# CONFIG_CF_AREA5 is not set +CONFIG_CF_AREA6=y +CONFIG_CF_BASE_ADDR=0xb8000000 + +# +# Processor features +# +CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_SH_FPU is not set +# CONFIG_SH_FPU_EMU is not set +CONFIG_SH_DSP=y +CONFIG_SH_STORE_QUEUES=y +CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_IPR_IRQ=y +CONFIG_CPU_HAS_SR_RB=y +CONFIG_CPU_HAS_PTEA=y + +# +# Timer and clock configuration +# +CONFIG_SH_TMU=y +CONFIG_SH_TIMER_IRQ=16 +CONFIG_NO_IDLE_HZ=y +CONFIG_SH_PCLK_FREQ=33333333 + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# DMA support +# +# CONFIG_SH_DMA is not set + +# +# Companion Chips +# +# CONFIG_HD6446X_SERIES is not set + +# +# Additional SuperH Device Drivers +# +CONFIG_HEARTBEAT=y +# CONFIG_PUSH_SWITCH is not set + +# +# Kernel features +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_KEXEC=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_SMP is not set +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_BKL=y + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00001000 +CONFIG_BOOT_LINK_OFFSET=0x00800000 +# CONFIG_UBC_WAKEUP is not set +# CONFIG_CMDLINE_BOOL is not set + +# +# Bus options +# +# CONFIG_PCI is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options (EXPERIMENTAL) +# +# CONFIG_PM is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set + +# +# 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_SYS_HYPERVISOR is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNPACPI is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE 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 is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_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=y +# CONFIG_ATA_NONSTANDARD is not set +CONFIG_PATA_PLATFORM=y + +# +# 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_STNIC is not set +CONFIG_SMC91X=y + +# +# 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 + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=2 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_HW_RANDOM=y +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_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=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# HID Devices +# +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set + +# +# RTC drivers +# +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set +CONFIG_RTC_DRV_SH=y +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Auxiliary Display support +# + +# +# Virtualization +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS 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_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# 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 is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_SH_STANDARD_BIOS is not set +# CONFIG_EARLY_SCIF_CONSOLE is not set +# CONFIG_SH_KGDB is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# 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_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/trunk/arch/sh/configs/se7780_defconfig b/trunk/arch/sh/configs/se7780_defconfig new file mode 100644 index 000000000000..538661e98793 --- /dev/null +++ b/trunk/arch/sh/configs/se7780_defconfig @@ -0,0 +1,1309 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.21-rc3 +# Thu Mar 15 14:06:20 2007 +# +CONFIG_SUPERH=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_TIME is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +# CONFIG_IPC_NS is not set +CONFIG_SYSVIPC_SYSCTL=y +# 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=y +CONFIG_IKCONFIG_PROC=y +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_KALLSYMS is not set +# CONFIG_HOTPLUG is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +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_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_LSF is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_AS is not set +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_DEFAULT_AS is not set +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" + +# +# System type +# +CONFIG_SOLUTION_ENGINE=y +# CONFIG_SH_SOLUTION_ENGINE is not set +# CONFIG_SH_7751_SOLUTION_ENGINE is not set +CONFIG_SH_7780_SOLUTION_ENGINE=y +# CONFIG_SH_7300_SOLUTION_ENGINE is not set +# CONFIG_SH_7343_SOLUTION_ENGINE is not set +# CONFIG_SH_73180_SOLUTION_ENGINE is not set +# CONFIG_SH_7751_SYSTEMH is not set +# CONFIG_SH_HP6XX is not set +# CONFIG_SH_SATURN is not set +# CONFIG_SH_DREAMCAST is not set +# CONFIG_SH_MPC1211 is not set +# CONFIG_SH_SH03 is not set +# CONFIG_SH_SECUREEDGE5410 is not set +# CONFIG_SH_HS7751RVOIP is not set +# CONFIG_SH_7710VOIPGW is not set +# CONFIG_SH_RTS7751R2D is not set +# CONFIG_SH_HIGHLANDER is not set +# CONFIG_SH_EDOSK7705 is not set +# CONFIG_SH_SH4202_MICRODEV is not set +# CONFIG_SH_LANDISK is not set +# CONFIG_SH_TITAN is not set +# CONFIG_SH_SHMIN is not set +# CONFIG_SH_7206_SOLUTION_ENGINE is not set +# CONFIG_SH_7619_SOLUTION_ENGINE is not set +# CONFIG_SH_UNKNOWN is not set + +# +# Processor selection +# +CONFIG_CPU_SH4=y +CONFIG_CPU_SH4A=y + +# +# SH-2 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7604 is not set +# CONFIG_CPU_SUBTYPE_SH7619 is not set + +# +# SH-2A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7206 is not set + +# +# SH-3 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7300 is not set +# CONFIG_CPU_SUBTYPE_SH7705 is not set +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set + +# +# SH-4 Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +# CONFIG_CPU_SUBTYPE_SH7751 is not set +# CONFIG_CPU_SUBTYPE_SH7751R is not set +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set + +# +# ST40 Processor Support +# +# CONFIG_CPU_SUBTYPE_ST40STB1 is not set +# CONFIG_CPU_SUBTYPE_ST40GX1 is not set + +# +# SH-4A Processor Support +# +# CONFIG_CPU_SUBTYPE_SH7770 is not set +CONFIG_CPU_SUBTYPE_SH7780=y +# CONFIG_CPU_SUBTYPE_SH7785 is not set + +# +# SH4AL-DSP Processor Support +# +# CONFIG_CPU_SUBTYPE_SH73180 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set +# CONFIG_CPU_SUBTYPE_SH7722 is not set + +# +# Memory management options +# +CONFIG_MMU=y +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_MEMORY_START=0x08000000 +CONFIG_MEMORY_SIZE=0x08000000 +CONFIG_32BIT=y +CONFIG_VSYSCALL=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 + +# +# Cache configuration +# +# CONFIG_SH_DIRECT_MAPPED is not set +# CONFIG_SH_WRITETHROUGH is not set +# CONFIG_SH_OCRAM is not set + +# +# Processor features +# +CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_SH_FPU=y +# CONFIG_SH_DSP is not set +# CONFIG_SH_STORE_QUEUES is not set +CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_INTC2_IRQ=y +CONFIG_CPU_HAS_SR_RB=y + +# +# Timer and clock configuration +# +CONFIG_SH_TMU=y +CONFIG_SH_TIMER_IRQ=28 +# CONFIG_NO_IDLE_HZ is not set +CONFIG_SH_PCLK_FREQ=33333333 + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# DMA support +# +# CONFIG_SH_DMA is not set + +# +# Companion Chips +# +# CONFIG_HD6446X_SERIES is not set + +# +# Additional SuperH Device Drivers +# +CONFIG_HEARTBEAT=y +# CONFIG_PUSH_SWITCH is not set + +# +# Kernel features +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_SMP is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00001000 +CONFIG_BOOT_LINK_OFFSET=0x00810000 +# CONFIG_UBC_WAKEUP is not set +# CONFIG_CMDLINE_BOOL is not set + +# +# Bus options +# +CONFIG_PCI=y +CONFIG_SH_PCIDMA_NONCOHERENT=y +CONFIG_PCI_AUTO=y +CONFIG_PCI_AUTO_UPDATE_RESOURCES=y + +# +# PCCARD (PCMCIA/CardBus) support +# + +# +# PCI Hotplug Support +# + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC 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_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_IPV6=y +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER 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 + +# +# 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 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 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=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set +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 is not set +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +CONFIG_MTD_ROM=y +# 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_PHYSMAP is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 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 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 +# +# CONFIG_PNPACPI is not set + +# +# Block devices +# +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_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_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# Misc devices +# +# CONFIG_SGI_IOC4 is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +# 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=y +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_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_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_SRP is not set + +# +# Serial ATA (prod) and Parallel ATA (experimental) drivers +# +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +CONFIG_SATA_SIL=y +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_PLATFORM is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# 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 + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +CONFIG_SMSC_PHY=y +# CONFIG_BROADCOM_PHY is not set +# CONFIG_FIXED_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_STNIC is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +CONFIG_SMC91X=y + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_QLA3XXX is not set + +# +# 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 +# CONFIG_NETXEN_NIC is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD 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 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=2 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +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_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# + +# +# 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=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set +# CONFIG_USB_DABUSB is not set + +# +# Graphics support +# +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +# CONFIG_FB_DDC is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frambuffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_EPSON1355 is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_LOGO_SUPERH_MONO is not set +# CONFIG_LOGO_SUPERH_VGA16 is not set +CONFIG_LOGO_SUPERH_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +# CONFIG_SND is not set + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=y +# CONFIG_OBSOLETE_OSS is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set + +# +# HID Devices +# +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_UHCI_HCD is not set +# 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_FREECOM is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_USB_HIDDEV 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_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set +# CONFIG_USB_APPLETOUCH is not set +# CONFIG_USB_GTCO is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MICROTEK is not set + +# +# USB Network Adapters +# +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS 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_LCD is not set +# CONFIG_USB_BERRY_CHARGE 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_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# + +# +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# +# Auxiliary Display support +# + +# +# Virtualization +# + +# +# 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_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_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_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +# CONFIG_SYSFS is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_HFSPLUS_FS is not set +# CONFIG_JFFS2_FS 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=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 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 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_SH_STANDARD_BIOS is not set +# CONFIG_EARLY_SCIF_CONSOLE is not set +# CONFIG_SH_KGDB is not set + +# +# Security options +# +# CONFIG_KEYS 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_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y diff --git a/trunk/arch/sh/drivers/Kconfig b/trunk/arch/sh/drivers/Kconfig index c54c758e6243..420c6b2f33a5 100644 --- a/trunk/arch/sh/drivers/Kconfig +++ b/trunk/arch/sh/drivers/Kconfig @@ -1,5 +1,15 @@ +source "arch/sh/drivers/dma/Kconfig" +source "arch/sh/cchips/Kconfig" + menu "Additional SuperH Device Drivers" +config HEARTBEAT + bool "Heartbeat LED" + help + Use the power-on LED on your machine as a load meter. The exact + behavior is platform-dependent, but normally the flash frequency is + a hyperbolic function of the 5-minute load average. + config PUSH_SWITCH tristate "Push switch support" help diff --git a/trunk/arch/sh/drivers/heartbeat.c b/trunk/arch/sh/drivers/heartbeat.c index bc59cb6cd78b..23dd6080422f 100644 --- a/trunk/arch/sh/drivers/heartbeat.c +++ b/trunk/arch/sh/drivers/heartbeat.c @@ -40,16 +40,9 @@ static void heartbeat_timer(unsigned long data) static unsigned bit = 0, up = 1; ctrl_outw(1 << hd->bit_pos[bit], (unsigned long)hd->base); - if (up) - if (bit == (ARRAY_SIZE(hd->bit_pos) - 1)) { - bit--; - up = 0; - } else - bit++; - else if (bit == 0) - up = 1; - else - bit--; + bit += up; + if ((bit == 0) || (bit == ARRAY_SIZE(hd->bit_pos)-1)) + up = -up; mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) / ((avenrun[0] / 5) + (3 << FSHIFT))))); diff --git a/trunk/arch/sh/drivers/pci/Makefile b/trunk/arch/sh/drivers/pci/Makefile index cc8d0d0b1427..0e9b532b9fbc 100644 --- a/trunk/arch/sh/drivers/pci/Makefile +++ b/trunk/arch/sh/drivers/pci/Makefile @@ -8,12 +8,15 @@ obj-$(CONFIG_PCI_AUTO) += pci-auto.o obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) += pci-st40.o obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o ops-sh4.o obj-$(CONFIG_CPU_SUBTYPE_SH7780) += pci-sh7780.o ops-sh4.o +obj-$(CONFIG_CPU_SUBTYPE_SH7785) += pci-sh7780.o ops-sh4.o obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \ dma-dreamcast.o obj-$(CONFIG_SH_SECUREEDGE5410) += ops-snapgear.o obj-$(CONFIG_SH_RTS7751R2D) += ops-rts7751r2d.o fixups-rts7751r2d.o obj-$(CONFIG_SH_SH03) += ops-sh03.o fixups-sh03.o -obj-$(CONFIG_SH_R7780RP) += ops-r7780rp.o fixups-r7780rp.o +obj-$(CONFIG_SH_HIGHLANDER) += ops-r7780rp.o fixups-r7780rp.o obj-$(CONFIG_SH_TITAN) += ops-titan.o obj-$(CONFIG_SH_LANDISK) += ops-landisk.o +obj-$(CONFIG_SH_LBOX_RE2) += ops-lboxre2.o fixups-lboxre2.o +obj-$(CONFIG_SH_7780_SOLUTION_ENGINE) += ops-se7780.o fixups-se7780.o diff --git a/trunk/arch/sh/drivers/pci/fixups-lboxre2.c b/trunk/arch/sh/drivers/pci/fixups-lboxre2.c new file mode 100644 index 000000000000..40b19bdfb891 --- /dev/null +++ b/trunk/arch/sh/drivers/pci/fixups-lboxre2.c @@ -0,0 +1,41 @@ +/* + * arch/sh/drivers/pci/fixups-lboxre2.c + * + * L-BOX RE2 PCI fixups + * + * Copyright (C) 2007 Nobuhiro Iwamatsu + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include "pci-sh4.h" + +#define PCIMCR_MRSET_OFF 0xBFFFFFFF +#define PCIMCR_RFSH_OFF 0xFFFFFFFB + +int pci_fixup_pcic(void) +{ + unsigned long bcr1, mcr; + + bcr1 = inl(SH7751_BCR1); + bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ + pci_write_reg(bcr1, SH4_PCIBCR1); + + /* Enable all interrupts, so we known what to fix */ + pci_write_reg(0x0000c3ff, SH4_PCIINTM); + pci_write_reg(0x0000380f, SH4_PCIAINTM); + pci_write_reg(0xfb900047, SH7751_PCICONF1); + pci_write_reg(0xab000001, SH7751_PCICONF4); + + mcr = inl(SH7751_MCR); + mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; + pci_write_reg(mcr, SH4_PCIMCR); + + pci_write_reg(0x0c000000, SH7751_PCICONF5); + pci_write_reg(0xd0000000, SH7751_PCICONF6); + pci_write_reg(0x0c000000, SH4_PCILAR0); + pci_write_reg(0x00000000, SH4_PCILAR1); + + return 0; +} diff --git a/trunk/arch/sh/drivers/pci/fixups-se7780.c b/trunk/arch/sh/drivers/pci/fixups-se7780.c new file mode 100644 index 000000000000..880cea1c0d89 --- /dev/null +++ b/trunk/arch/sh/drivers/pci/fixups-se7780.c @@ -0,0 +1,60 @@ +/* + * arch/sh/drivers/pci/fixups-se7780.c + * + * HITACHI UL Solution Engine 7780 PCI fixups + * + * Copyright (C) 2003 Lineo uSolutions, Inc. + * Copyright (C) 2004 - 2006 Paul Mundt + * Copyright (C) 2006 Nobuhiro Iwamatsu + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include "pci-sh4.h" +#include + +int pci_fixup_pcic(void) +{ + ctrl_outl(0x00000001, SH7780_PCI_VCR2); + + /* Enable all interrupts, so we know what to fix */ + pci_write_reg(0x0000C3FF, SH7780_PCIIMR); + pci_write_reg(0x0000380F, SH7780_PCIAINTM); + + /* Set up standard PCI config registers */ + ctrl_outw(0xFB00, PCI_REG(SH7780_PCISTATUS)); + ctrl_outw(0x0047, PCI_REG(SH7780_PCICMD)); + ctrl_outb( 0x00, PCI_REG(SH7780_PCIPIF)); + ctrl_outb( 0x00, PCI_REG(SH7780_PCISUB)); + ctrl_outb( 0x06, PCI_REG(SH7780_PCIBCC)); + ctrl_outw(0x1912, PCI_REG(SH7780_PCISVID)); + ctrl_outw(0x0001, PCI_REG(SH7780_PCISID)); + + pci_write_reg(0x08000000, SH7780_PCIMBAR0); /* PCI */ + pci_write_reg(0x08000000, SH7780_PCILAR0); /* SHwy */ + pci_write_reg(0x07F00001, SH7780_PCILSR); /* size 128M w/ MBAR */ + + pci_write_reg(0x00000000, SH7780_PCIMBAR1); + pci_write_reg(0x00000000, SH7780_PCILAR1); + pci_write_reg(0x00000000, SH7780_PCILSR1); + + pci_write_reg(0xAB000801, SH7780_PCIIBAR); + + /* + * Set the MBR so PCI address is one-to-one with window, + * meaning all calls go straight through... use ifdef to + * catch erroneous assumption. + */ + pci_write_reg(0xFD000000 , SH7780_PCIMBR0); + pci_write_reg(0x00FC0000 , SH7780_PCIMBMR0); /* 16M */ + + /* Set IOBR for window containing area specified in pci.h */ + pci_write_reg(PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE-1), SH7780_PCIIOBR); + pci_write_reg((SH7780_PCI_IO_SIZE-1) & (7 << 18), SH7780_PCIIOBMR); + + pci_write_reg(0xA5000C01, SH7780_PCICR); + + return 0; +} diff --git a/trunk/arch/sh/drivers/pci/ops-landisk.c b/trunk/arch/sh/drivers/pci/ops-landisk.c index d06030815a96..bff09ecf3419 100644 --- a/trunk/arch/sh/drivers/pci/ops-landisk.c +++ b/trunk/arch/sh/drivers/pci/ops-landisk.c @@ -17,8 +17,8 @@ static struct resource sh7751_io_resource = { .name = "SH7751 IO", - .start = 0x4000, - .end = 0x4000 + SH7751_PCI_IO_SIZE - 1, + .start = SH7751_PCI_IO_BASE, + .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1, .flags = IORESOURCE_IO }; diff --git a/trunk/arch/sh/drivers/pci/ops-lboxre2.c b/trunk/arch/sh/drivers/pci/ops-lboxre2.c new file mode 100644 index 000000000000..a13cb764b0b9 --- /dev/null +++ b/trunk/arch/sh/drivers/pci/ops-lboxre2.c @@ -0,0 +1,63 @@ +/* + * linux/arch/sh/drivers/pci/ops-lboxre2.c + * + * Copyright (C) 2007 Nobuhiro Iwamatsu + * + * PCI initialization for the NTT COMWARE L-BOX RE2 + */ +#include +#include +#include +#include +#include +#include +#include "pci-sh4.h" + +static char lboxre2_irq_tab[] __initdata = { + IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD, +}; + +int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) +{ + return lboxre2_irq_tab[slot]; +} + +static struct resource sh7751_io_resource = { + .name = "SH7751_IO", + .start = SH7751_PCI_IO_BASE , + .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO +}; + +static struct resource sh7751_mem_resource = { + .name = "SH7751_mem", + .start = SH7751_PCI_MEMORY_BASE, + .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM +}; + +extern struct pci_ops sh7751_pci_ops; + +struct pci_channel board_pci_channels[] = { + { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, + { NULL, NULL, NULL, 0, 0 }, +}; + +EXPORT_SYMBOL(board_pci_channels); + +static struct sh4_pci_address_map sh7751_pci_map = { + .window0 = { + .base = SH7751_CS3_BASE_ADDR, + .size = 0x04000000, + }, + .window1 = { + .base = 0x00000000, /* Unused */ + .size = 0x00000000, /* Unused */ + }, + .flags = SH4_PCIC_NO_RESET, +}; + +int __init pcibios_init_platform(void) +{ + return sh7751_pcic_init(&sh7751_pci_map); +} diff --git a/trunk/arch/sh/drivers/pci/ops-r7780rp.c b/trunk/arch/sh/drivers/pci/ops-r7780rp.c index eeea1577e112..f2216081ab85 100644 --- a/trunk/arch/sh/drivers/pci/ops-r7780rp.c +++ b/trunk/arch/sh/drivers/pci/ops-r7780rp.c @@ -17,18 +17,25 @@ #include #include "pci-sh4.h" +static char r7780rp_irq_tab[] __initdata = { + 0, 1, 2, 3, +}; + +static char r7780mp_irq_tab[] __initdata = { + 65, 66, 67, 68, +}; + int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) { - switch (slot) { - case 0: return IRQ_PCISLOT1; /* PCI Interrupt #1 */ - case 1: return IRQ_PCISLOT2; /* PCI Interrupt #2 */ - case 2: return IRQ_PCISLOT3; /* PCI Interrupt #3 */ - case 3: return IRQ_PCISLOT4; /* PCI Interrupt E4 */ - default: - printk(KERN_ERR "PCI: Bad IRQ mapping " - "request for slot %d, func %d\n", slot, pin-1); - return -1; - } + if (mach_is_r7780rp()) + return r7780rp_irq_tab[slot]; + if (mach_is_r7780mp() || mach_is_r7785rp()) + return r7780mp_irq_tab[slot]; + + printk(KERN_ERR "PCI: Bad IRQ mapping " + "request for slot %d, func %d\n", slot, pin-1); + + return -1; } static struct resource sh7780_io_resource = { diff --git a/trunk/arch/sh/drivers/pci/ops-se7780.c b/trunk/arch/sh/drivers/pci/ops-se7780.c new file mode 100644 index 000000000000..212674df5e13 --- /dev/null +++ b/trunk/arch/sh/drivers/pci/ops-se7780.c @@ -0,0 +1,96 @@ +/* + * linux/arch/sh/drivers/pci/ops-se7780.c + * + * Copyright (C) 2006 Nobuhiro Iwamatsu + * + * PCI initialization for the Hitachi UL Solution Engine 7780SE03 + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + */ +#include +#include +#include +#include +#include +#include +#include +#include "pci-sh4.h" + +/* + * IDSEL = AD16 PCI slot + * IDSEL = AD17 PCI slot + * IDSEL = AD18 Serial ATA Controller (Silicon Image SiL3512A) + * IDSEL = AD19 USB Host Controller (NEC uPD7210100A) + */ + +/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */ +static char se7780_irq_tab[4][16] __initdata = { + /* INTA */ + { 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + /* INTB */ + { 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + /* INTC */ + { 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + /* INTD */ + { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +}; + +int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) +{ + return se7780_irq_tab[pin-1][slot]; +} + +static struct resource se7780_io_resource = { + .name = "SH7780_IO", + .start = 0x2000, + .end = 0x2000 + SH7780_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO +}; + +static struct resource se7780_mem_resource = { + .name = "SH7780_mem", + .start = SH7780_PCI_MEMORY_BASE, + .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM +}; + +extern struct pci_ops se7780_pci_ops; + +struct pci_channel board_pci_channels[] = { + { &sh4_pci_ops, &se7780_io_resource, &se7780_mem_resource, 0, 0xff }, + { NULL, NULL, NULL, 0, 0 }, +}; +EXPORT_SYMBOL(board_pci_channels); + +static struct sh4_pci_address_map se7780_pci_map = { + .window0 = { + .base = SH7780_CS2_BASE_ADDR, + .size = 0x04000000, + }, + .flags = SH4_PCIC_NO_RESET, +}; + +int __init pcibios_init_platform(void) +{ + printk("SH7780 PCI: Finished initialization of the PCI controller\n"); + + /* + * FPGA PCISEL register initialize + * + * CPU || SLOT1 | SLOT2 | S-ATA | USB + * ------------------------------------- + * INTA || INTA | INTD | -- | INTB + * ------------------------------------- + * INTB || INTB | INTA | -- | INTC + * ------------------------------------- + * INTC || INTC | INTB | INTA | -- + * ------------------------------------- + * INTD || INTD | INTC | -- | INTA + * ------------------------------------- + */ + ctrl_outw(0x0013, FPGA_PCI_INTSEL1); + ctrl_outw(0xE402, FPGA_PCI_INTSEL2); + + return sh7780_pcic_init(&se7780_pci_map); +} diff --git a/trunk/arch/sh/drivers/pci/ops-sh4.c b/trunk/arch/sh/drivers/pci/ops-sh4.c index 2d4371009a5e..54232f13e406 100644 --- a/trunk/arch/sh/drivers/pci/ops-sh4.c +++ b/trunk/arch/sh/drivers/pci/ops-sh4.c @@ -162,3 +162,9 @@ char * __init pcibios_setup(char *str) return str; } + +int __attribute__((weak)) pci_fixup_pcic(void) +{ + /* Nothing to do. */ + return 0; +} diff --git a/trunk/arch/sh/drivers/pci/pci-sh4.h b/trunk/arch/sh/drivers/pci/pci-sh4.h index 5a61d6041f2c..1901c33cde6a 100644 --- a/trunk/arch/sh/drivers/pci/pci-sh4.h +++ b/trunk/arch/sh/drivers/pci/pci-sh4.h @@ -1,7 +1,7 @@ #ifndef __PCI_SH4_H #define __PCI_SH4_H -#ifdef CONFIG_CPU_SUBTYPE_SH7780 +#if defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785) #include "pci-sh7780.h" #else #include "pci-sh7751.h" diff --git a/trunk/arch/sh/drivers/pci/pci-sh7751.c b/trunk/arch/sh/drivers/pci/pci-sh7751.c index 9ddff760d3c6..1aca7fe5783b 100644 --- a/trunk/arch/sh/drivers/pci/pci-sh7751.c +++ b/trunk/arch/sh/drivers/pci/pci-sh7751.c @@ -12,7 +12,6 @@ * License. See linux/COPYING for more information. * */ - #undef DEBUG #include @@ -28,7 +27,7 @@ * Initialization. Try all known PCI access methods. Note that we support * using both PCI BIOS and direct access: in such cases, we use I/O ports * to access config space. - * + * * Note that the platform specific initialization (BSC registers, and memory * space mapping) will be called via the platform defined function * pcibios_init_platform(). @@ -115,7 +114,7 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map) * Wait Cycle Control + Parity Enable + Bus Master + * Mem space enable */ - word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER | + word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER | SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES; pci_write_reg(word, SH7751_PCICONF1); @@ -123,10 +122,10 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map) word = PCI_BASE_CLASS_BRIDGE << 24; pci_write_reg(word, SH7751_PCICONF2); - /* Set IO and Mem windows to local address - * Make PCI and local address the same for easy 1 to 1 mapping + /* Set IO and Mem windows to local address + * Make PCI and local address the same for easy 1 to 1 mapping * Window0 = map->window0.size @ non-cached area base = SDRAM - * Window1 = map->window1.size @ cached area base = SDRAM + * Window1 = map->window1.size @ cached area base = SDRAM */ word = map->window0.size - 1; pci_write_reg(word, SH4_PCILSR0); @@ -175,7 +174,7 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map) case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(5); break; case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(6); break; } - + if (!word) return 0; @@ -194,9 +193,7 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map) * DMA interrupts... */ -#ifdef CONFIG_SH_RTS7751R2D pci_fixup_pcic(); -#endif /* SH7751 init done, set central function init complete */ /* use round robin mode to stop a device starving/overruning */ diff --git a/trunk/arch/sh/drivers/pci/pci-sh7780.c b/trunk/arch/sh/drivers/pci/pci-sh7780.c index 602b644c35ad..5508e45d4838 100644 --- a/trunk/arch/sh/drivers/pci/pci-sh7780.c +++ b/trunk/arch/sh/drivers/pci/pci-sh7780.c @@ -48,7 +48,7 @@ static int __init sh7780_pci_init(void) { unsigned int id; - int ret; + int ret, match = 0; pr_debug("PCI: Starting intialization.\n"); @@ -56,19 +56,43 @@ static int __init sh7780_pci_init(void) /* check for SH7780/SH7780R hardware */ id = pci_read_reg(SH7780_PCIVID); - if ((id != ((SH7780_DEVICE_ID << 16) | SH7780_VENDOR_ID)) && - (id != ((SH7781_DEVICE_ID << 16) | SH7780_VENDOR_ID))) { + if ((id & 0xffff) == SH7780_VENDOR_ID) { + switch ((id >> 16) & 0xffff) { + case SH7780_DEVICE_ID: + case SH7781_DEVICE_ID: + case SH7785_DEVICE_ID: + match = 1; + break; + } + } + + if (unlikely(!match)) { printk(KERN_ERR "PCI: This is not an SH7780 (%x)\n", id); return -ENODEV; } /* Setup the INTC */ - ctrl_outl(0x00200000, INTC_ICR0); /* INTC SH-4 Mode */ - ctrl_outl(0x00078000, INTC_INT2MSKCR); /* enable PCIINTA - PCIINTD */ - ctrl_outl(0x40000000, INTC_INTMSK1); /* disable IRL4-7 Interrupt */ - ctrl_outl(0x0000fffe, INTC_INTMSK2); /* disable IRL4-7 Interrupt */ - ctrl_outl(0x80000000, INTC_INTMSKCLR1); /* enable IRL0-3 Interrupt */ - ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); /* enable IRL0-3 Interrupt */ + if (mach_is_7780se()) { + /* ICR0: IRL=use separately */ + ctrl_outl(0x00C00020, INTC_ICR0); + /* ICR1: detect low level(for 2ndcut) */ + ctrl_outl(0xAAAA0000, INTC_ICR1); + /* INTPRI: priority=3(all) */ + ctrl_outl(0x33333333, INTC_INTPRI); + } else { + /* INTC SH-4 Mode */ + ctrl_outl(0x00200000, INTC_ICR0); + /* enable PCIINTA - PCIINTD */ + ctrl_outl(0x00078000, INTC_INT2MSKCR); + /* disable IRL4-7 Interrupt */ + ctrl_outl(0x40000000, INTC_INTMSK1); + /* disable IRL4-7 Interrupt */ + ctrl_outl(0x0000fffe, INTC_INTMSK2); + /* enable IRL0-3 Interrupt */ + ctrl_outl(0x80000000, INTC_INTMSKCLR1); + /* enable IRL0-3 Interrupt */ + ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); + } if ((ret = sh4_pci_check_direct()) != 0) return ret; @@ -138,9 +162,8 @@ int __init sh7780_pcic_init(struct sh4_pci_address_map *map) * DMA interrupts... */ -#ifdef CONFIG_SH_R7780RP + /* Apply any last-minute PCIC fixups */ pci_fixup_pcic(); -#endif /* SH7780 init done, set central function init complete */ /* use round robin mode to stop a device starving/overruning */ diff --git a/trunk/arch/sh/drivers/pci/pci-sh7780.h b/trunk/arch/sh/drivers/pci/pci-sh7780.h index f02d2180a4bc..00d12d0f8c1f 100644 --- a/trunk/arch/sh/drivers/pci/pci-sh7780.h +++ b/trunk/arch/sh/drivers/pci/pci-sh7780.h @@ -14,8 +14,9 @@ /* Platform Specific Values */ #define SH7780_VENDOR_ID 0x1912 -#define SH7780_DEVICE_ID 0x0002 #define SH7781_DEVICE_ID 0x0001 +#define SH7780_DEVICE_ID 0x0002 +#define SH7785_DEVICE_ID 0x0007 /* SH7780 Control Registers */ #define SH7780_PCI_VCR0 0xFE000000 @@ -65,6 +66,22 @@ #define SH7780_PCIPMCSR_BSE 0x046 #define SH7780_PCICDD 0x047 +#define SH7780_PCICR 0x100 /* PCI Control Register */ +#define SH7780_PCILSR 0x104 /* PCI Local Space Register0 */ +#define SH7780_PCILSR1 0x108 /* PCI Local Space Register1 */ +#define SH7780_PCILAR0 0x10C /* PCI Local Address Register1 */ +#define SH7780_PCILAR1 0x110 /* PCI Local Address Register1 */ +#define SH7780_PCIIR 0x114 /* PCI Interrupt Register */ +#define SH7780_PCIIMR 0x118 /* PCI Interrupt Mask Register */ +#define SH7780_PCIAIR 0x11C /* Error Address Register */ +#define SH7780_PCICIR 0x120 /* Error Command/Data Register */ +#define SH7780_PCIAINT 0x130 /* Arbiter Interrupt Register */ +#define SH7780_PCIAINTM 0x134 /* Arbiter Int. Mask Register */ +#define SH7780_PCIBMIR 0x138 /* Error Bus Master Register */ +#define SH7780_PCIPAR 0x1C0 /* PIO Address Register */ +#define SH7780_PCIPINT 0x1CC /* Power Mgmnt Int. Register */ +#define SH7780_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */ + #define SH7780_PCIMBR0 0x1E0 #define SH7780_PCIMBMR0 0x1E4 #define SH7780_PCIMBR2 0x1F0 diff --git a/trunk/arch/sh/drivers/pci/pci-st40.c b/trunk/arch/sh/drivers/pci/pci-st40.c index efecb3d5995c..d67656a44b15 100644 --- a/trunk/arch/sh/drivers/pci/pci-st40.c +++ b/trunk/arch/sh/drivers/pci/pci-st40.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/trunk/arch/sh/kernel/Makefile b/trunk/arch/sh/kernel/Makefile index ff30d7f58043..9104b6257644 100644 --- a/trunk/arch/sh/kernel/Makefile +++ b/trunk/arch/sh/kernel/Makefile @@ -20,5 +20,6 @@ obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o +obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/trunk/arch/sh/kernel/cf-enabler.c b/trunk/arch/sh/kernel/cf-enabler.c index 3e5fa1e24df0..0758d48147a0 100644 --- a/trunk/arch/sh/kernel/cf-enabler.c +++ b/trunk/arch/sh/kernel/cf-enabler.c @@ -29,7 +29,7 @@ * 0xB8001000 : Common Memory * 0xBA000000 : I/O */ -#if defined(CONFIG_IDE) && defined(CONFIG_CPU_SH4) +#if defined(CONFIG_CPU_SH4) /* SH4 can't access PCMCIA interface through P2 area. * we must remap it with appropreate attribute bit of the page set. * this part is based on Greg Banks' hd64465_ss.c implementation - Masahiro Abe */ @@ -71,7 +71,7 @@ static int __init cf_init_default(void) /* You must have enabled the card, and set the level interrupt * before reaching this point. Possibly in boot ROM or boot loader. */ -#if defined(CONFIG_IDE) && defined(CONFIG_CPU_SH4) +#if defined(CONFIG_CPU_SH4) allocate_cf_area(); #endif #if defined(CONFIG_SH_UNKNOWN) @@ -84,15 +84,25 @@ static int __init cf_init_default(void) #if defined(CONFIG_SH_SOLUTION_ENGINE) #include +#elif defined(CONFIG_SH_7722_SOLUTION_ENGINE) +#include +#endif /* - * SolutionEngine + * SolutionEngine Seriese * + * about MS770xSE * 0xB8400000 : Common Memory * 0xB8500000 : Attribute * 0xB8600000 : I/O + * + * about MS7722SE + * 0xB0400000 : Common Memory + * 0xB0500000 : Attribute + * 0xB0600000 : I/O */ +#if defined(CONFIG_SH_SOLUTION_ENGINE) || defined(CONFIG_SH_7722_SOLUTION_ENGINE) static int __init cf_init_se(void) { if ((ctrl_inw(MRSHPC_CSR) & 0x000c) != 0) @@ -109,7 +119,7 @@ static int __init cf_init_se(void) * flag == COMMON/ATTRIBUTE/IO */ /* common window open */ - ctrl_outw(0x8a84, MRSHPC_MW0CR1);/* window 0xb8400000 */ + ctrl_outw(0x8a84, MRSHPC_MW0CR1); if((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0) /* common mode & bus width 16bit SWAP = 1*/ ctrl_outw(0x0b00, MRSHPC_MW0CR2); @@ -118,7 +128,7 @@ static int __init cf_init_se(void) ctrl_outw(0x0300, MRSHPC_MW0CR2); /* attribute window open */ - ctrl_outw(0x8a85, MRSHPC_MW1CR1);/* window 0xb8500000 */ + ctrl_outw(0x8a85, MRSHPC_MW1CR1); if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0) /* attribute mode & bus width 16bit SWAP = 1*/ ctrl_outw(0x0a00, MRSHPC_MW1CR2); @@ -127,7 +137,7 @@ static int __init cf_init_se(void) ctrl_outw(0x0200, MRSHPC_MW1CR2); /* I/O window open */ - ctrl_outw(0x8a86, MRSHPC_IOWCR1);/* I/O window 0xb8600000 */ + ctrl_outw(0x8a86, MRSHPC_IOWCR1); ctrl_outw(0x0008, MRSHPC_CDCR); /* I/O card mode */ if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0) ctrl_outw(0x0a00, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 1*/ @@ -143,10 +153,10 @@ static int __init cf_init_se(void) int __init cf_init(void) { -#if defined(CONFIG_SH_SOLUTION_ENGINE) - if (MACH_SE) + if( mach_is_se() || mach_is_7722se() ){ return cf_init_se(); -#endif + } + return cf_init_default(); } diff --git a/trunk/arch/sh/kernel/cpu/clock.c b/trunk/arch/sh/kernel/cpu/clock.c index abb586b12565..014f318f5a05 100644 --- a/trunk/arch/sh/kernel/cpu/clock.c +++ b/trunk/arch/sh/kernel/cpu/clock.c @@ -1,7 +1,7 @@ /* * arch/sh/kernel/cpu/clock.c - SuperH clock framework * - * Copyright (C) 2005, 2006 Paul Mundt + * Copyright (C) 2005, 2006, 2007 Paul Mundt * * This clock framework is derived from the OMAP version by: * @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -98,15 +99,17 @@ int __clk_enable(struct clk *clk) if (clk->ops && clk->ops->init) clk->ops->init(clk); + kref_get(&clk->kref); + if (clk->flags & CLK_ALWAYS_ENABLED) return 0; if (likely(clk->ops && clk->ops->enable)) clk->ops->enable(clk); - kref_get(&clk->kref); return 0; } +EXPORT_SYMBOL_GPL(__clk_enable); int clk_enable(struct clk *clk) { @@ -119,6 +122,7 @@ int clk_enable(struct clk *clk) return ret; } +EXPORT_SYMBOL_GPL(clk_enable); static void clk_kref_release(struct kref *kref) { @@ -127,11 +131,17 @@ static void clk_kref_release(struct kref *kref) void __clk_disable(struct clk *clk) { + int count = kref_put(&clk->kref, clk_kref_release); + if (clk->flags & CLK_ALWAYS_ENABLED) return; - kref_put(&clk->kref, clk_kref_release); + if (!count) { /* count reaches zero, disable the clock */ + if (likely(clk->ops && clk->ops->disable)) + clk->ops->disable(clk); + } } +EXPORT_SYMBOL_GPL(__clk_disable); void clk_disable(struct clk *clk) { @@ -141,6 +151,7 @@ void clk_disable(struct clk *clk) __clk_disable(clk); spin_unlock_irqrestore(&clock_lock, flags); } +EXPORT_SYMBOL_GPL(clk_disable); int clk_register(struct clk *clk) { @@ -151,8 +162,18 @@ int clk_register(struct clk *clk) mutex_unlock(&clock_list_sem); + if (clk->flags & CLK_ALWAYS_ENABLED) { + pr_debug( "Clock '%s' is ALWAYS_ENABLED\n", clk->name); + if (clk->ops && clk->ops->init) + clk->ops->init(clk); + if (clk->ops && clk->ops->enable) + clk->ops->enable(clk); + pr_debug( "Enabled."); + } + return 0; } +EXPORT_SYMBOL_GPL(clk_register); void clk_unregister(struct clk *clk) { @@ -160,13 +181,21 @@ void clk_unregister(struct clk *clk) list_del(&clk->node); mutex_unlock(&clock_list_sem); } +EXPORT_SYMBOL_GPL(clk_unregister); -inline unsigned long clk_get_rate(struct clk *clk) +unsigned long clk_get_rate(struct clk *clk) { return clk->rate; } +EXPORT_SYMBOL_GPL(clk_get_rate); int clk_set_rate(struct clk *clk, unsigned long rate) +{ + return clk_set_rate_ex(clk, rate, 0); +} +EXPORT_SYMBOL_GPL(clk_set_rate); + +int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id) { int ret = -EOPNOTSUPP; @@ -174,7 +203,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate) unsigned long flags; spin_lock_irqsave(&clock_lock, flags); - ret = clk->ops->set_rate(clk, rate); + ret = clk->ops->set_rate(clk, rate, algo_id); spin_unlock_irqrestore(&clock_lock, flags); } @@ -183,6 +212,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate) return ret; } +EXPORT_SYMBOL_GPL(clk_set_rate_ex); void clk_recalc_rate(struct clk *clk) { @@ -197,6 +227,7 @@ void clk_recalc_rate(struct clk *clk) if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) propagate_rate(clk); } +EXPORT_SYMBOL_GPL(clk_recalc_rate); /* * Returns a clock. Note that we first try to use device id on the bus @@ -233,18 +264,43 @@ struct clk *clk_get(struct device *dev, const char *id) return clk; } +EXPORT_SYMBOL_GPL(clk_get); void clk_put(struct clk *clk) { if (clk && !IS_ERR(clk)) module_put(clk->owner); } +EXPORT_SYMBOL_GPL(clk_put); void __init __attribute__ ((weak)) arch_init_clk_ops(struct clk_ops **ops, int type) { } +static int show_clocks(char *buf, char **start, off_t off, + int len, int *eof, void *data) +{ + struct clk *clk; + char *p = buf; + + list_for_each_entry_reverse(clk, &clock_list, node) { + unsigned long rate = clk_get_rate(clk); + + /* + * Don't bother listing dummy clocks with no ancestry + * that only support enable and disable ops. + */ + if (unlikely(!rate && !clk->parent)) + continue; + + p += sprintf(p, "%-12s\t: %ld.%02ldMHz\n", clk->name, + rate / 1000000, (rate % 1000000) / 10000); + } + + return p - buf; +} + int __init clk_init(void) { int i, ret = 0; @@ -256,7 +312,6 @@ int __init clk_init(void) arch_init_clk_ops(&clk->ops, i); ret |= clk_register(clk); - clk_enable(clk); } /* Kick the child clocks.. */ @@ -266,35 +321,14 @@ int __init clk_init(void) return ret; } -int show_clocks(struct seq_file *m) +static int __init clk_proc_init(void) { - struct clk *clk; - - list_for_each_entry_reverse(clk, &clock_list, node) { - unsigned long rate = clk_get_rate(clk); - - /* - * Don't bother listing dummy clocks with no ancestry - * that only support enable and disable ops. - */ - if (unlikely(!rate && !clk->parent)) - continue; - - seq_printf(m, "%-12s\t: %ld.%02ldMHz\n", clk->name, - rate / 1000000, (rate % 1000000) / 10000); - } + struct proc_dir_entry *p; + p = create_proc_read_entry("clocks", S_IRUSR, NULL, + show_clocks, NULL); + if (unlikely(!p)) + return -EINVAL; return 0; } - -EXPORT_SYMBOL_GPL(clk_register); -EXPORT_SYMBOL_GPL(clk_unregister); -EXPORT_SYMBOL_GPL(clk_get); -EXPORT_SYMBOL_GPL(clk_put); -EXPORT_SYMBOL_GPL(clk_enable); -EXPORT_SYMBOL_GPL(clk_disable); -EXPORT_SYMBOL_GPL(__clk_enable); -EXPORT_SYMBOL_GPL(__clk_disable); -EXPORT_SYMBOL_GPL(clk_get_rate); -EXPORT_SYMBOL_GPL(clk_set_rate); -EXPORT_SYMBOL_GPL(clk_recalc_rate); +subsys_initcall(clk_proc_init); diff --git a/trunk/arch/sh/kernel/cpu/init.c b/trunk/arch/sh/kernel/cpu/init.c index 726acfcb9b77..6451ad630174 100644 --- a/trunk/arch/sh/kernel/cpu/init.c +++ b/trunk/arch/sh/kernel/cpu/init.c @@ -41,6 +41,23 @@ __setup("no" __stringify(x), x##_setup); onchip_setup(fpu); onchip_setup(dsp); +#ifdef CONFIG_SPECULATIVE_EXECUTION +#define CPUOPM 0xff2f0000 +#define CPUOPM_RABD (1 << 5) + +static void __init speculative_execution_init(void) +{ + /* Clear RABD */ + ctrl_outl(ctrl_inl(CPUOPM) & ~CPUOPM_RABD, CPUOPM); + + /* Flush the update */ + (void)ctrl_inl(CPUOPM); + ctrl_barrier(); +} +#else +#define speculative_execution_init() do { } while (0) +#endif + /* * Generic first-level cache init */ @@ -261,4 +278,6 @@ asmlinkage void __init sh_cpu_init(void) */ ubc_wakeup(); #endif + + speculative_execution_init(); } diff --git a/trunk/arch/sh/kernel/cpu/irq/Makefile b/trunk/arch/sh/kernel/cpu/irq/Makefile index 0049d217561a..1c23308cfc25 100644 --- a/trunk/arch/sh/kernel/cpu/irq/Makefile +++ b/trunk/arch/sh/kernel/cpu/irq/Makefile @@ -4,6 +4,6 @@ obj-y += imask.o obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o -obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o +obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o diff --git a/trunk/arch/sh/kernel/cpu/irq/intc2.c b/trunk/arch/sh/kernel/cpu/irq/intc2.c index 74defe76a058..d8e22f4ff0f0 100644 --- a/trunk/arch/sh/kernel/cpu/irq/intc2.c +++ b/trunk/arch/sh/kernel/cpu/irq/intc2.c @@ -18,7 +18,8 @@ #define INTC2_BASE 0xfe080000 #define INTC2_INTMSK (INTC2_BASE + 0x40) #define INTC2_INTMSKCLR (INTC2_BASE + 0x60) -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) +#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) #define INTC2_BASE 0xffd40000 #define INTC2_INTMSK (INTC2_BASE + 0x38) #define INTC2_INTMSKCLR (INTC2_BASE + 0x3c) diff --git a/trunk/arch/sh/kernel/cpu/irq/pint.c b/trunk/arch/sh/kernel/cpu/irq/pint.c index f60007783a21..67602685df1a 100644 --- a/trunk/arch/sh/kernel/cpu/irq/pint.c +++ b/trunk/arch/sh/kernel/cpu/irq/pint.c @@ -18,6 +18,58 @@ #include #include +#if defined(CONFIG_CPU_SUBTYPE_SH7705) +#define INTC_INTER 0xA4000014UL +#define INTC_IPRD 0xA4000018UL +#define INTC_ICR2 0xA4000012UL + +/* PFC */ +#define PORT_PACR 0xA4000100UL +#define PORT_PBCR 0xA4000102UL +#define PORT_PCCR 0xA4000104UL +#define PORT_PDCR 0xA4000106UL +#define PORT_PECR 0xA4000108UL +#define PORT_PFCR 0xA400010AUL +#define PORT_PGCR 0xA400010CUL +#define PORT_PHCR 0xA400010EUL +#define PORT_PJCR 0xA4000110UL +#define PORT_PKCR 0xA4000112UL +#define PORT_PLCR 0xA4000114UL +#define PORT_PMCR 0xA4000118UL +#define PORT_PNCR 0xA400011AUL +#define PORT_PECR2 0xA4050148UL +#define PORT_PFCR2 0xA405014AUL +#define PORT_PNCR2 0xA405015AUL + +/* I/O port */ +#define PORT_PADR 0xA4000120UL +#define PORT_PBDR 0xA4000122UL +#define PORT_PCDR 0xA4000124UL +#define PORT_PDDR 0xA4000126UL +#define PORT_PEDR 0xA4000128UL +#define PORT_PFDR 0xA400012AUL +#define PORT_PGDR 0xA400012CUL +#define PORT_PHDR 0xA400012EUL +#define PORT_PJDR 0xA4000130UL +#define PORT_PKDR 0xA4000132UL +#define PORT_PLDR 0xA4000134UL +#define PORT_PMDR 0xA4000138UL +#define PORT_PNDR 0xA400013AUL + +#define PINT0_IRQ 40 +#define PINT8_IRQ 41 +#define PINT_IRQ_BASE 86 + +#define PINT0_IPR_ADDR INTC_IPRD +#define PINT0_IPR_POS 3 +#define PINT0_PRIORITY 2 + +#define PINT8_IPR_ADDR INTC_IPRD +#define PINT8_IPR_POS 2 +#define PINT8_PRIORITY 2 + +#endif /* CONFIG_CPU_SUBTYPE_SH7705 */ + static unsigned char pint_map[256]; static unsigned long portcr_mask; @@ -126,7 +178,7 @@ int ipr_irq_demux(int irq) unsigned long creg, dreg, d, sav; if (irq == PINT0_IRQ) { -#if defined(CONFIG_CPU_SUBTYPE_SH7707) +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7707) creg = PORT_PACR; dreg = PORT_PADR; #else @@ -144,7 +196,7 @@ int ipr_irq_demux(int irq) return PINT_IRQ_BASE + pint_map[d]; } else if (irq == PINT8_IRQ) { -#if defined(CONFIG_CPU_SUBTYPE_SH7707) +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7707) creg = PORT_PBCR; dreg = PORT_PBDR; #else diff --git a/trunk/arch/sh/kernel/cpu/sh3/Makefile b/trunk/arch/sh/kernel/cpu/sh3/Makefile index 83905e4e4387..09faa056cd43 100644 --- a/trunk/arch/sh/kernel/cpu/sh3/Makefile +++ b/trunk/arch/sh/kernel/cpu/sh3/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o obj-$(CONFIG_CPU_SUBTYPE_SH7300) += setup-sh7300.o obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o +obj-$(CONFIG_CPU_SUBTYPE_SH7712) += setup-sh7710.o # Primary on-chip clocks (common) clock-$(CONFIG_CPU_SH3) := clock-sh3.o diff --git a/trunk/arch/sh/kernel/cpu/sh3/probe.c b/trunk/arch/sh/kernel/cpu/sh3/probe.c index 821b0ab7b528..647623b22edc 100644 --- a/trunk/arch/sh/kernel/cpu/sh3/probe.c +++ b/trunk/arch/sh/kernel/cpu/sh3/probe.c @@ -78,6 +78,9 @@ int __init detect_cpu_and_cache_system(void) #if defined(CONFIG_CPU_SUBTYPE_SH7710) current_cpu_data.type = CPU_SH7710; #endif +#if defined(CONFIG_CPU_SUBTYPE_SH7712) + current_cpu_data.type = CPU_SH7712; +#endif #if defined(CONFIG_CPU_SUBTYPE_SH7705) current_cpu_data.type = CPU_SH7705; diff --git a/trunk/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/trunk/arch/sh/kernel/cpu/sh3/setup-sh7705.c index a8e41c5241fa..1983fb7ad6ea 100644 --- a/trunk/arch/sh/kernel/cpu/sh3/setup-sh7705.c +++ b/trunk/arch/sh/kernel/cpu/sh3/setup-sh7705.c @@ -2,6 +2,7 @@ * SH7705 Setup * * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2007 Nobuhiro Iwamatsu * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -14,15 +15,15 @@ static struct plat_sci_port sci_platform_data[] = { { - .mapbase = 0xa4400000, + .mapbase = 0xa4410000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 52, 53, 55, 54 }, + .irqs = { 56, 57, 59 }, }, { - .mapbase = 0xa4410000, + .mapbase = 0xa4400000, .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCIF, - .irqs = { 56, 57, 59, 58 }, + .irqs = { 52, 53, 55 }, }, { .flags = 0, } @@ -46,3 +47,48 @@ static int __init sh7705_devices_setup(void) ARRAY_SIZE(sh7705_devices)); } __initcall(sh7705_devices_setup); + +static struct ipr_data sh7705_ipr_map[] = { + /* IRQ, IPR-idx, shift, priority */ + { 16, 0, 12, 2 }, /* TMU0 TUNI*/ + { 17, 0, 8, 2 }, /* TMU1 TUNI */ + { 18, 0, 4, 2 }, /* TMU2 TUNI */ + { 27, 1, 12, 2 }, /* WDT ITI */ + { 20, 0, 0, 2 }, /* RTC ATI (alarm) */ + { 21, 0, 0, 2 }, /* RTC PRI (period) */ + { 22, 0, 0, 2 }, /* RTC CUI (carry) */ + { 48, 4, 12, 7 }, /* DMAC DMTE0 */ + { 49, 4, 12, 7 }, /* DMAC DMTE1 */ + { 50, 4, 12, 7 }, /* DMAC DMTE2 */ + { 51, 4, 12, 7 }, /* DMAC DMTE3 */ + { 52, 4, 8, 3 }, /* SCIF0 ERI */ + { 53, 4, 8, 3 }, /* SCIF0 RXI */ + { 55, 4, 8, 3 }, /* SCIF0 TXI */ + { 56, 4, 4, 3 }, /* SCIF1 ERI */ + { 57, 4, 4, 3 }, /* SCIF1 RXI */ + { 59, 4, 4, 3 }, /* SCIF1 TXI */ +}; + +static unsigned long ipr_offsets[] = { + 0xFFFFFEE2 /* 0: IPRA */ +, 0xFFFFFEE4 /* 1: IPRB */ +, 0xA4000016 /* 2: IPRC */ +, 0xA4000018 /* 3: IPRD */ +, 0xA400001A /* 4: IPRE */ +, 0xA4080000 /* 5: IPRF */ +, 0xA4080002 /* 6: IPRG */ +, 0xA4080004 /* 7: IPRH */ +}; + +/* given the IPR index return the address of the IPR register */ +unsigned int map_ipridx_to_addr(int idx) +{ + if (idx >= ARRAY_SIZE(ipr_offsets)) + return 0; + return ipr_offsets[idx]; +} + +void __init init_IRQ_ipr() +{ + make_ipr_irq(sh7705_ipr_map, ARRAY_SIZE(sh7705_ipr_map)); +} diff --git a/trunk/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/trunk/arch/sh/kernel/cpu/sh3/setup-sh7709.c index dc9b211cf87f..c7d7c35fc834 100644 --- a/trunk/arch/sh/kernel/cpu/sh3/setup-sh7709.c +++ b/trunk/arch/sh/kernel/cpu/sh3/setup-sh7709.c @@ -48,24 +48,33 @@ static struct platform_device *sh7709_devices[] __initdata = { static int __init sh7709_devices_setup(void) { return platform_add_devices(sh7709_devices, - ARRAY_SIZE(sh7709_devices)); + ARRAY_SIZE(sh7709_devices)); } __initcall(sh7709_devices_setup); -#define IPRx(A,N) .addr=A, .shift=0*N*-1 +#define IPRx(A,N) .addr=A, .shift=N #define IPRA(N) IPRx(0xfffffee2UL,N) #define IPRB(N) IPRx(0xfffffee4UL,N) +#define IPRC(N) IPRx(0xa4000016UL,N) +#define IPRD(N) IPRx(0xa4000018UL,N) #define IPRE(N) IPRx(0xa400001aUL,N) static struct ipr_data sh7709_ipr_map[] = { - [16] = { IPRA(15-12), 2 }, /* TMU TUNI0 */ - [17] = { IPRA(11-8), 4 }, /* TMU TUNI1 */ - [22] = { IPRA(3-0), 2 }, /* RTC CUI */ - [23 ... 26] = { IPRB(7-4), 3 }, /* SCI */ - [27] = { IPRB(15-12), 2 }, /* WDT ITI */ - [48 ... 51] = { IPRE(15-12), 7 }, /* DMA */ - [52 ... 55] = { IPRE(11-8), 3 }, /* IRDA */ - [56 ... 59] = { IPRE(7-4), 3 }, /* SCIF */ + [16] = { IPRA(12), 2 }, /* TMU TUNI0 */ + [17] = { IPRA(8), 4 }, /* TMU TUNI1 */ + [18 ... 19] = { IPRA(4), 1 }, /* TMU TUNI1 */ + [20 ... 22] = { IPRA(0), 2 }, /* RTC CUI */ + [23 ... 26] = { IPRB(4), 3 }, /* SCI */ + [27] = { IPRB(12), 2 }, /* WDT ITI */ + [32] = { IPRC(0), 1 }, /* IRQ 0 */ + [33] = { IPRC(4), 1 }, /* IRQ 1 */ + [34] = { IPRC(8), 1 }, /* IRQ 2 APM */ + [35] = { IPRC(12), 1 }, /* IRQ 3 TOUCHSCREEN */ + [36] = { IPRD(0), 1 }, /* IRQ 4 */ + [37] = { IPRD(4), 1 }, /* IRQ 5 */ + [48 ... 51] = { IPRE(12), 7 }, /* DMA */ + [52 ... 55] = { IPRE(8), 3 }, /* IRDA */ + [56 ... 59] = { IPRE(4), 3 }, /* SCIF */ }; void __init init_IRQ_ipr() diff --git a/trunk/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/trunk/arch/sh/kernel/cpu/sh3/setup-sh7710.c index 895f99ee6a95..51760a7e7f1c 100644 --- a/trunk/arch/sh/kernel/cpu/sh3/setup-sh7710.c +++ b/trunk/arch/sh/kernel/cpu/sh3/setup-sh7710.c @@ -2,6 +2,7 @@ * SH7710 Setup * * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2007 Nobuhiro Iwamatsu * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -19,6 +20,12 @@ static struct plat_sci_port sci_platform_data[] = { .type = PORT_SCIF, .irqs = { 52, 53, 55, 54 }, }, { + .mapbase = 0xa4420000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 56, 57, 59, 58 }, + }, { + .flags = 0, } }; @@ -41,3 +48,56 @@ static int __init sh7710_devices_setup(void) ARRAY_SIZE(sh7710_devices)); } __initcall(sh7710_devices_setup); + +static struct ipr_data sh7710_ipr_map[] = { + /* IRQ, IPR-idx, shift, priority */ + { 16, 0, 12, 2 }, /* TMU0 TUNI*/ + { 17, 0, 8, 2 }, /* TMU1 TUNI */ + { 18, 0, 4, 2 }, /* TMU2 TUNI */ + { 27, 1, 12, 2 }, /* WDT ITI */ + { 20, 0, 0, 2 }, /* RTC ATI (alarm) */ + { 21, 0, 0, 2 }, /* RTC PRI (period) */ + { 22, 0, 0, 2 }, /* RTC CUI (carry) */ + { 48, 4, 12, 7 }, /* DMAC DMTE0 */ + { 49, 4, 12, 7 }, /* DMAC DMTE1 */ + { 50, 4, 12, 7 }, /* DMAC DMTE2 */ + { 51, 4, 12, 7 }, /* DMAC DMTE3 */ + { 52, 4, 8, 3 }, /* SCIF0 ERI */ + { 53, 4, 8, 3 }, /* SCIF0 RXI */ + { 54, 4, 8, 3 }, /* SCIF0 BRI */ + { 55, 4, 8, 3 }, /* SCIF0 TXI */ + { 56, 4, 4, 3 }, /* SCIF1 ERI */ + { 57, 4, 4, 3 }, /* SCIF1 RXI */ + { 58, 4, 4, 3 }, /* SCIF1 BRI */ + { 59, 4, 4, 3 }, /* SCIF1 TXI */ + { 76, 5, 8, 7 }, /* DMAC DMTE4 */ + { 77, 5, 8, 7 }, /* DMAC DMTE5 */ + { 80, 6, 12, 5 }, /* EDMAC EINT0 */ + { 81, 6, 8, 5 }, /* EDMAC EINT1 */ + { 82, 6, 4, 5 }, /* EDMAC EINT2 */ +}; + +static unsigned long ipr_offsets[] = { + 0xA414FEE2 /* 0: IPRA */ +, 0xA414FEE4 /* 1: IPRB */ +, 0xA4140016 /* 2: IPRC */ +, 0xA4140018 /* 3: IPRD */ +, 0xA414001A /* 4: IPRE */ +, 0xA4080000 /* 5: IPRF */ +, 0xA4080002 /* 6: IPRG */ +, 0xA4080004 /* 7: IPRH */ +, 0xA4080006 /* 8: IPRI */ +}; + +/* given the IPR index return the address of the IPR register */ +unsigned int map_ipridx_to_addr(int idx) +{ + if (idx >= ARRAY_SIZE(ipr_offsets)) + return 0; + return ipr_offsets[idx]; +} + +void __init init_IRQ_ipr() +{ + make_ipr_irq(sh7710_ipr_map, ARRAY_SIZE(sh7710_ipr_map)); +} diff --git a/trunk/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/trunk/arch/sh/kernel/cpu/sh4/clock-sh4-202.c index fa2019aabd74..fcb2c41bc34e 100644 --- a/trunk/arch/sh/kernel/cpu/sh4/clock-sh4-202.c +++ b/trunk/arch/sh/kernel/cpu/sh4/clock-sh4-202.c @@ -82,7 +82,8 @@ static void shoc_clk_init(struct clk *clk) for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) { int divisor = frqcr3_divisors[i]; - if (clk->ops->set_rate(clk, clk->parent->rate / divisor) == 0) + if (clk->ops->set_rate(clk, clk->parent->rate / + divisor, 0) == 0) break; } diff --git a/trunk/arch/sh/kernel/cpu/sh4/probe.c b/trunk/arch/sh/kernel/cpu/sh4/probe.c index 58950de2696d..8cd04904c77a 100644 --- a/trunk/arch/sh/kernel/cpu/sh4/probe.c +++ b/trunk/arch/sh/kernel/cpu/sh4/probe.c @@ -124,6 +124,14 @@ int __init detect_cpu_and_cache_system(void) current_cpu_data.dcache.ways = 4; current_cpu_data.flags |= CPU_HAS_LLSC; break; + case 0x3004: + case 0x3007: + current_cpu_data.type = CPU_SH7785; + current_cpu_data.icache.ways = 4; + current_cpu_data.dcache.ways = 4; + current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER | + CPU_HAS_LLSC; + break; case 0x3008: if (prr == 0xa0) { current_cpu_data.type = CPU_SH7722; diff --git a/trunk/arch/sh/kernel/cpu/sh4a/Makefile b/trunk/arch/sh/kernel/cpu/sh4a/Makefile index a8f493f2f21f..ab7422f8f820 100644 --- a/trunk/arch/sh/kernel/cpu/sh4a/Makefile +++ b/trunk/arch/sh/kernel/cpu/sh4a/Makefile @@ -5,6 +5,7 @@ # CPU subtype setup obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o +obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o @@ -13,7 +14,8 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o +clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o -clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7343.o +clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o obj-y += $(clock-y) diff --git a/trunk/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/trunk/arch/sh/kernel/cpu/sh4a/clock-sh7722.c new file mode 100644 index 000000000000..29090035bc5b --- /dev/null +++ b/trunk/arch/sh/kernel/cpu/sh4a/clock-sh7722.c @@ -0,0 +1,600 @@ +/* + * arch/sh/kernel/cpu/sh4a/clock-sh7722.c + * + * SH7722 support for the clock framework + * + * Copyright (c) 2006-2007 Nomad Global Solutions Inc + * Based on code for sh7343 by Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include + +#define SH7722_PLL_FREQ (32000000/8) +#define N (-1) +#define NM (-2) +#define ROUND_NEAREST 0 +#define ROUND_DOWN -1 +#define ROUND_UP +1 + +static int adjust_algos[][3] = { + {}, /* NO_CHANGE */ + { NM, N, 1 }, /* N:1, N:1 */ + { 3, 2, 2 }, /* 3:2:2 */ + { 5, 2, 2 }, /* 5:2:2 */ + { N, 1, 1 }, /* N:1:1 */ + + { N, 1 }, /* N:1 */ + + { N, 1 }, /* N:1 */ + { 3, 2 }, + { 4, 3 }, + { 5, 4 }, + + { N, 1 } +}; + +static unsigned long adjust_pair_of_clocks(unsigned long r1, unsigned long r2, + int m1, int m2, int round_flag) +{ + unsigned long rem, div; + int the_one = 0; + + pr_debug( "Actual values: r1 = %ld\n", r1); + pr_debug( "...............r2 = %ld\n", r2); + + if (m1 == m2) { + r2 = r1; + pr_debug( "setting equal rates: r2 now %ld\n", r2); + } else if ((m2 == N && m1 == 1) || + (m2 == NM && m1 == N)) { /* N:1 or NM:N */ + pr_debug( "Setting rates as 1:N (N:N*M)\n"); + rem = r2 % r1; + pr_debug( "...remainder = %ld\n", rem); + if (rem) { + div = r2 / r1; + pr_debug( "...div = %ld\n", div); + switch (round_flag) { + case ROUND_NEAREST: + the_one = rem >= r1/2 ? 1 : 0; break; + case ROUND_UP: + the_one = 1; break; + case ROUND_DOWN: + the_one = 0; break; + } + + r2 = r1 * (div + the_one); + pr_debug( "...setting r2 to %ld\n", r2); + } + } else if ((m2 == 1 && m1 == N) || + (m2 == N && m1 == NM)) { /* 1:N or N:NM */ + pr_debug( "Setting rates as N:1 (N*M:N)\n"); + rem = r1 % r2; + pr_debug( "...remainder = %ld\n", rem); + if (rem) { + div = r1 / r2; + pr_debug( "...div = %ld\n", div); + switch (round_flag) { + case ROUND_NEAREST: + the_one = rem > r2/2 ? 1 : 0; break; + case ROUND_UP: + the_one = 0; break; + case ROUND_DOWN: + the_one = 1; break; + } + + r2 = r1 / (div + the_one); + pr_debug( "...setting r2 to %ld\n", r2); + } + } else { /* value:value */ + pr_debug( "Setting rates as %d:%d\n", m1, m2); + div = r1 / m1; + r2 = div * m2; + pr_debug( "...div = %ld\n", div); + pr_debug( "...setting r2 to %ld\n", r2); + } + + return r2; +} + +static void adjust_clocks(int originate, int *l, unsigned long v[], + int n_in_line) +{ + int x; + + pr_debug( "Go down from %d...\n", originate); + /* go up recalculation clocks */ + for (x = originate; x>0; x -- ) + v[x-1] = adjust_pair_of_clocks(v[x], v[x-1], + l[x], l[x-1], + ROUND_UP); + + pr_debug( "Go up from %d...\n", originate); + /* go down recalculation clocks */ + for (x = originate; xrate = CONFIG_SH_PCLK_FREQ * (1 + (frqcr >> 24 & 0xF)); +} + +static int master_clk_setrate(struct clk *clk, unsigned long rate, int id) +{ + int div = rate / SH7722_PLL_FREQ; + int master_divs[] = { 2, 3, 4, 6, 8, 16 }; + int index; + unsigned long frqcr; + + if (rate < SH7722_PLL_FREQ * 2) + return -EINVAL; + + for (index = 1; index < ARRAY_SIZE(master_divs); index++) + if (div >= master_divs[index - 1] && div < master_divs[index]) + break; + + if (index >= ARRAY_SIZE(master_divs)) + index = ARRAY_SIZE(master_divs); + div = master_divs[index - 1]; + + frqcr = ctrl_inl(FRQCR); + frqcr &= ~(0xF << 24); + frqcr |= ( (div-1) << 24); + ctrl_outl(frqcr, FRQCR); + + return 0; +} + +static struct clk_ops sh7722_master_clk_ops = { + .init = master_clk_init, + .recalc = master_clk_recalc, + .set_rate = master_clk_setrate, +}; + +struct frqcr_context { + unsigned mask; + unsigned shift; +}; + +struct frqcr_context sh7722_get_clk_context(const char *name) +{ + struct frqcr_context ctx = { 0, }; + + if (!strcmp(name, "peripheral_clk")) { + ctx.shift = 0; + ctx.mask = 0xF; + } else if (!strcmp(name, "sdram_clk")) { + ctx.shift = 4; + ctx.mask = 0xF; + } else if (!strcmp(name, "bus_clk")) { + ctx.shift = 8; + ctx.mask = 0xF; + } else if (!strcmp(name, "sh_clk")) { + ctx.shift = 12; + ctx.mask = 0xF; + } else if (!strcmp(name, "umem_clk")) { + ctx.shift = 16; + ctx.mask = 0xF; + } else if (!strcmp(name, "cpu_clk")) { + ctx.shift = 20; + ctx.mask = 7; + } + return ctx; +} + +/** + * sh7722_find_divisors - find divisor for setting rate + * + * All sh7722 clocks use the same set of multipliers/divisors. This function + * chooses correct divisor to set the rate of clock with parent clock that + * generates frequency of 'parent_rate' + * + * @parent_rate: rate of parent clock + * @rate: requested rate to be set + */ +static int sh7722_find_divisors(unsigned long parent_rate, unsigned rate) +{ + unsigned div2 = parent_rate * 2 / rate; + int index; + + if (rate > parent_rate) + return -EINVAL; + + for (index = 1; index < ARRAY_SIZE(divisors2); index++) { + if (div2 > divisors2[index] && div2 <= divisors2[index]) + break; + } + if (index >= ARRAY_SIZE(divisors2)) + index = ARRAY_SIZE(divisors2) - 1; + return divisors2[index]; +} + +static void sh7722_frqcr_recalc(struct clk *clk) +{ + struct frqcr_context ctx = sh7722_get_clk_context(clk->name); + unsigned long frqcr = ctrl_inl(FRQCR); + int index; + + index = (frqcr >> ctx.shift) & ctx.mask; + clk->rate = clk->parent->rate * 2 / divisors2[index]; +} + +static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate, + int algo_id) +{ + struct frqcr_context ctx = sh7722_get_clk_context(clk->name); + unsigned long parent_rate = clk->parent->rate; + int div; + unsigned long frqcr; + int err = 0; + + /* pretty invalid */ + if (parent_rate < rate) + return -EINVAL; + + /* look for multiplier/divisor pair */ + div = sh7722_find_divisors(parent_rate, rate); + if (div<0) + return div; + + /* calculate new value of clock rate */ + clk->rate = parent_rate * 2 / div; + frqcr = ctrl_inl(FRQCR); + + /* FIXME: adjust as algo_id specifies */ + if (algo_id != NO_CHANGE) { + int originator; + char *algo_group_1[] = { "cpu_clk", "umem_clk", "sh_clk" }; + char *algo_group_2[] = { "sh_clk", "bus_clk" }; + char *algo_group_3[] = { "sh_clk", "sdram_clk" }; + char *algo_group_4[] = { "bus_clk", "peripheral_clk" }; + char *algo_group_5[] = { "cpu_clk", "peripheral_clk" }; + char **algo_current = NULL; + /* 3 is the maximum number of clocks in relation */ + struct clk *ck[3]; + unsigned long values[3]; /* the same comment as above */ + int part_length = -1; + int i; + + /* + * all the steps below only required if adjustion was + * requested + */ + if (algo_id == IUS_N1_N1 || + algo_id == IUS_322 || + algo_id == IUS_522 || + algo_id == IUS_N11) { + algo_current = algo_group_1; + part_length = 3; + } + if (algo_id == SB_N1) { + algo_current = algo_group_2; + part_length = 2; + } + if (algo_id == SB3_N1 || + algo_id == SB3_32 || + algo_id == SB3_43 || + algo_id == SB3_54) { + algo_current = algo_group_3; + part_length = 2; + } + if (algo_id == BP_N1) { + algo_current = algo_group_4; + part_length = 2; + } + if (algo_id == IP_N1) { + algo_current = algo_group_5; + part_length = 2; + } + if (!algo_current) + goto incorrect_algo_id; + + originator = -1; + for (i = 0; i < part_length; i ++ ) { + if (originator >= 0 && !strcmp(clk->name, + algo_current[i])) + originator = i; + ck[i] = clk_get(NULL, algo_current[i]); + values[i] = clk_get_rate(ck[i]); + } + + if (originator >= 0) + adjust_clocks(originator, adjust_algos[algo_id], + values, part_length); + + for (i = 0; i < part_length; i ++ ) { + struct frqcr_context part_ctx; + int part_div; + + if (likely(!err)) { + part_div = sh7722_find_divisors(parent_rate, + rate); + if (part_div > 0) { + part_ctx = sh7722_get_clk_context( + ck[i]->name); + frqcr &= ~(part_ctx.mask << + part_ctx.shift); + frqcr |= part_div << part_ctx.shift; + } else + err = part_div; + } + + ck[i]->ops->recalc(ck[i]); + clk_put(ck[i]); + } + } + + /* was there any error during recalculation ? If so, bail out.. */ + if (unlikely(err!=0)) + goto out_err; + + /* clear FRQCR bits */ + frqcr &= ~(ctx.mask << ctx.shift); + frqcr |= div << ctx.shift; + + /* ...and perform actual change */ + ctrl_outl(frqcr, FRQCR); + return 0; + +incorrect_algo_id: + return -EINVAL; +out_err: + return err; +} + +static struct clk_ops sh7722_frqcr_clk_ops = { + .recalc = sh7722_frqcr_recalc, + .set_rate = sh7722_frqcr_set_rate, +}; + +/* + * clock ops methods for SIU A/B and IrDA clock + * + */ +static int sh7722_siu_which(struct clk *clk) +{ + if (!strcmp(clk->name, "siu_a_clk")) + return 0; + if (!strcmp(clk->name, "siu_b_clk")) + return 1; + if (!strcmp(clk->name, "irda_clk")) + return 2; + return -EINVAL; +} + +static unsigned long sh7722_siu_regs[] = { + [0] = SCLKACR, + [1] = SCLKBCR, + [2] = IrDACLKCR, +}; + +static int sh7722_siu_start_stop(struct clk *clk, int enable) +{ + int siu = sh7722_siu_which(clk); + unsigned long r; + + if (siu < 0) + return siu; + BUG_ON(siu > 2); + r = ctrl_inl(sh7722_siu_regs[siu]); + if (enable) + ctrl_outl(r & ~(1 << 8), sh7722_siu_regs[siu]); + else + ctrl_outl(r | (1 << 8), sh7722_siu_regs[siu]); + return 0; +} + +static void sh7722_siu_enable(struct clk *clk) +{ + sh7722_siu_start_stop(clk, 1); +} + +static void sh7722_siu_disable(struct clk *clk) +{ + sh7722_siu_start_stop(clk, 0); +} + +static void sh7722_video_enable(struct clk *clk) +{ + unsigned long r; + + r = ctrl_inl(VCLKCR); + ctrl_outl( r & ~(1<<8), VCLKCR); +} + +static void sh7722_video_disable(struct clk *clk) +{ + unsigned long r; + + r = ctrl_inl(VCLKCR); + ctrl_outl( r | (1<<8), VCLKCR); +} + +static int sh7722_video_set_rate(struct clk *clk, unsigned long rate, + int algo_id) +{ + unsigned long r; + + r = ctrl_inl(VCLKCR); + r &= ~0x3F; + r |= ((clk->parent->rate / rate - 1) & 0x3F); + ctrl_outl(r, VCLKCR); + return 0; +} + +static void sh7722_video_recalc(struct clk *clk) +{ + unsigned long r; + + r = ctrl_inl(VCLKCR); + clk->rate = clk->parent->rate / ((r & 0x3F) + 1); +} + +static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id) +{ + int siu = sh7722_siu_which(clk); + unsigned long r; + int div; + + if (siu < 0) + return siu; + BUG_ON(siu > 2); + r = ctrl_inl(sh7722_siu_regs[siu]); + div = sh7722_find_divisors(clk->parent->rate, rate); + if (div < 0) + return div; + r = (r & ~0xF) | div; + ctrl_outl(r, sh7722_siu_regs[siu]); + return 0; +} + +static void sh7722_siu_recalc(struct clk *clk) +{ + int siu = sh7722_siu_which(clk); + unsigned long r; + + if (siu < 0) + return /* siu */ ; + BUG_ON(siu > 1); + r = ctrl_inl(sh7722_siu_regs[siu]); + clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF]; +} + +static struct clk_ops sh7722_siu_clk_ops = { + .recalc = sh7722_siu_recalc, + .set_rate = sh7722_siu_set_rate, + .enable = sh7722_siu_enable, + .disable = sh7722_siu_disable, +}; + +static struct clk_ops sh7722_video_clk_ops = { + .recalc = sh7722_video_recalc, + .set_rate = sh7722_video_set_rate, + .enable = sh7722_video_enable, + .disable = sh7722_video_disable, +}; +/* + * and at last, clock definitions themselves + */ +static struct clk sh7722_umem_clock = { + .name = "umem_clk", + .ops = &sh7722_frqcr_clk_ops, +}; + +static struct clk sh7722_sh_clock = { + .name = "sh_clk", + .ops = &sh7722_frqcr_clk_ops, +}; + +static struct clk sh7722_peripheral_clock = { + .name = "peripheral_clk", + .ops = &sh7722_frqcr_clk_ops, +}; + +static struct clk sh7722_sdram_clock = { + .name = "sdram_clk", + .ops = &sh7722_frqcr_clk_ops, +}; + +/* + * these three clocks - SIU A, SIU B, IrDA - share the same clk_ops + * methods of clk_ops determine which register they should access by + * examining clk->name field + */ +static struct clk sh7722_siu_a_clock = { + .name = "siu_a_clk", + .ops = &sh7722_siu_clk_ops, +}; + +static struct clk sh7722_siu_b_clock = { + .name = "siu_b_clk", + .ops = &sh7722_siu_clk_ops, +}; + +static struct clk sh7722_irda_clock = { + .name = "irda_clk", + .ops = &sh7722_siu_clk_ops, +}; + +static struct clk sh7722_video_clock = { + .name = "video_clk", + .ops = &sh7722_video_clk_ops, +}; + +static struct clk *sh7722_clocks[] = { + &sh7722_umem_clock, + &sh7722_sh_clock, + &sh7722_peripheral_clock, + &sh7722_sdram_clock, + &sh7722_siu_a_clock, + &sh7722_siu_b_clock, + &sh7722_irda_clock, + &sh7722_video_clock, +}; + +/* + * init in order: master, module, bus, cpu + */ +struct clk_ops *onchip_ops[] = { + &sh7722_master_clk_ops, + &sh7722_frqcr_clk_ops, + &sh7722_frqcr_clk_ops, + &sh7722_frqcr_clk_ops, +}; + +void __init +arch_init_clk_ops(struct clk_ops **ops, int type) +{ + BUG_ON(type < 0 || type > ARRAY_SIZE(onchip_ops)); + *ops = onchip_ops[type]; +} + +int __init sh7722_clock_init(void) +{ + struct clk *master; + int i; + + master = clk_get(NULL, "master_clk"); + for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) { + pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name); + sh7722_clocks[i]->parent = master; + clk_register(sh7722_clocks[i]); + } + clk_put(master); + return 0; +} +arch_initcall(sh7722_clock_init); diff --git a/trunk/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/trunk/arch/sh/kernel/cpu/sh4a/clock-sh7785.c new file mode 100644 index 000000000000..805535aa505e --- /dev/null +++ b/trunk/arch/sh/kernel/cpu/sh4a/clock-sh7785.c @@ -0,0 +1,162 @@ +/* + * arch/sh/kernel/cpu/sh4a/clock-sh7785.c + * + * SH7785 support for the clock framework + * + * Copyright (C) 2007 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include + +static int ifc_divisors[] = { 1, 2, 4, 6 }; +static int ufc_divisors[] = { 1, 1, 4, 6 }; +static int sfc_divisors[] = { 1, 1, 4, 6 }; +static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18, + 24, 32, 36, 48, 1, 1, 1, 1 }; +static int mfc_divisors[] = { 1, 1, 4, 6 }; +static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18, + 24, 32, 36, 48, 1, 1, 1, 1 }; + +static void master_clk_init(struct clk *clk) +{ + clk->rate *= 36; +} + +static struct clk_ops sh7785_master_clk_ops = { + .init = master_clk_init, +}; + +static void module_clk_recalc(struct clk *clk) +{ + int idx = (ctrl_inl(FRQMR1) & 0x000f); + clk->rate = clk->parent->rate / pfc_divisors[idx]; +} + +static struct clk_ops sh7785_module_clk_ops = { + .recalc = module_clk_recalc, +}; + +static void bus_clk_recalc(struct clk *clk) +{ + int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f); + clk->rate = clk->parent->rate / bfc_divisors[idx]; +} + +static struct clk_ops sh7785_bus_clk_ops = { + .recalc = bus_clk_recalc, +}; + +static void cpu_clk_recalc(struct clk *clk) +{ + int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003); + clk->rate = clk->parent->rate / ifc_divisors[idx]; +} + +static struct clk_ops sh7785_cpu_clk_ops = { + .recalc = cpu_clk_recalc, +}; + +static struct clk_ops *sh7785_clk_ops[] = { + &sh7785_master_clk_ops, + &sh7785_module_clk_ops, + &sh7785_bus_clk_ops, + &sh7785_cpu_clk_ops, +}; + +void __init arch_init_clk_ops(struct clk_ops **ops, int idx) +{ + if (idx < ARRAY_SIZE(sh7785_clk_ops)) + *ops = sh7785_clk_ops[idx]; +} + +static void shyway_clk_recalc(struct clk *clk) +{ + int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003); + clk->rate = clk->parent->rate / sfc_divisors[idx]; +} + +static struct clk_ops sh7785_shyway_clk_ops = { + .recalc = shyway_clk_recalc, +}; + +static struct clk sh7785_shyway_clk = { + .name = "shyway_clk", + .flags = CLK_ALWAYS_ENABLED, + .ops = &sh7785_shyway_clk_ops, +}; + +static void ddr_clk_recalc(struct clk *clk) +{ + int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003); + clk->rate = clk->parent->rate / mfc_divisors[idx]; +} + +static struct clk_ops sh7785_ddr_clk_ops = { + .recalc = ddr_clk_recalc, +}; + +static struct clk sh7785_ddr_clk = { + .name = "ddr_clk", + .flags = CLK_ALWAYS_ENABLED, + .ops = &sh7785_ddr_clk_ops, +}; + +static void ram_clk_recalc(struct clk *clk) +{ + int idx = ((ctrl_inl(FRQMR1) >> 24) & 0x0003); + clk->rate = clk->parent->rate / ufc_divisors[idx]; +} + +static struct clk_ops sh7785_ram_clk_ops = { + .recalc = ram_clk_recalc, +}; + +static struct clk sh7785_ram_clk = { + .name = "ram_clk", + .flags = CLK_ALWAYS_ENABLED, + .ops = &sh7785_ram_clk_ops, +}; + +/* + * Additional SH7785-specific on-chip clocks that aren't already part of the + * clock framework + */ +static struct clk *sh7785_onchip_clocks[] = { + &sh7785_shyway_clk, + &sh7785_ddr_clk, + &sh7785_ram_clk, +}; + +static int __init sh7785_clk_init(void) +{ + struct clk *clk = clk_get(NULL, "master_clk"); + int i; + + for (i = 0; i < ARRAY_SIZE(sh7785_onchip_clocks); i++) { + struct clk *clkp = sh7785_onchip_clocks[i]; + + clkp->parent = clk; + clk_register(clkp); + clk_enable(clkp); + } + + /* + * Now that we have the rest of the clocks registered, we need to + * force the parent clock to propagate so that these clocks will + * automatically figure out their rate. We cheat by handing the + * parent clock its current rate and forcing child propagation. + */ + clk_set_rate(clk, clk_get_rate(clk)); + + clk_put(clk); + + return 0; +} +arch_initcall(sh7785_clk_init); diff --git a/trunk/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/trunk/arch/sh/kernel/cpu/sh4a/setup-sh7785.c new file mode 100644 index 000000000000..07b0de82cfe6 --- /dev/null +++ b/trunk/arch/sh/kernel/cpu/sh4a/setup-sh7785.c @@ -0,0 +1,103 @@ +/* + * SH7785 Setup + * + * Copyright (C) 2007 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include + +static struct plat_sci_port sci_platform_data[] = { + { + .mapbase = 0xffea0000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 40, 41, 43, 42 }, + }, { + .mapbase = 0xffeb0000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 44, 45, 47, 46 }, + }, + + /* + * The rest of these all have multiplexed IRQs + */ + { + .mapbase = 0xffec0000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 60, 60, 60, 60 }, + }, { + .mapbase = 0xffed0000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 61, 61, 61, 61 }, + }, { + .mapbase = 0xffee0000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 62, 62, 62, 62 }, + }, { + .mapbase = 0xffef0000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 63, 63, 63, 63 }, + }, { + .flags = 0, + } +}; + +static struct platform_device sci_device = { + .name = "sh-sci", + .id = -1, + .dev = { + .platform_data = sci_platform_data, + }, +}; + +static struct platform_device *sh7785_devices[] __initdata = { + &sci_device, +}; + +static int __init sh7785_devices_setup(void) +{ + return platform_add_devices(sh7785_devices, + ARRAY_SIZE(sh7785_devices)); +} +__initcall(sh7785_devices_setup); + +static struct intc2_data intc2_irq_table[] = { + { 28, 0, 24, 0, 0, 2 }, /* TMU0 */ + + { 40, 8, 24, 0, 2, 3 }, /* SCIF0 ERI */ + { 41, 8, 24, 0, 2, 3 }, /* SCIF0 RXI */ + { 42, 8, 24, 0, 2, 3 }, /* SCIF0 BRI */ + { 43, 8, 24, 0, 2, 3 }, /* SCIF0 TXI */ + + { 44, 8, 16, 0, 3, 3 }, /* SCIF1 ERI */ + { 45, 8, 16, 0, 3, 3 }, /* SCIF1 RXI */ + { 46, 8, 16, 0, 3, 3 }, /* SCIF1 BRI */ + { 47, 8, 16, 0, 3, 3 }, /* SCIF1 TXI */ + + { 64, 0x14, 8, 0, 14, 2 }, /* PCIC0 */ + { 65, 0x14, 0, 0, 15, 2 }, /* PCIC1 */ + { 66, 0x18, 24, 0, 16, 2 }, /* PCIC2 */ + { 67, 0x18, 16, 0, 17, 2 }, /* PCIC3 */ + { 68, 0x18, 8, 0, 18, 2 }, /* PCIC4 */ + + { 60, 8, 8, 0, 4, 3 }, /* SCIF2 ERI, RXI, BRI, TXI */ + { 60, 8, 0, 0, 5, 3 }, /* SCIF3 ERI, RXI, BRI, TXI */ + { 60, 12, 24, 0, 6, 3 }, /* SCIF4 ERI, RXI, BRI, TXI */ + { 60, 12, 16, 0, 7, 3 }, /* SCIF5 ERI, RXI, BRI, TXI */ +}; + +void __init init_IRQ_intc2(void) +{ + make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table)); +} diff --git a/trunk/arch/sh/kernel/crash_dump.c b/trunk/arch/sh/kernel/crash_dump.c new file mode 100644 index 000000000000..4a2ecbe27d8e --- /dev/null +++ b/trunk/arch/sh/kernel/crash_dump.c @@ -0,0 +1,46 @@ +/* + * crash_dump.c - Memory preserving reboot related code. + * + * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) + * Copyright (C) IBM Corporation, 2004. All rights reserved + */ + +#include +#include +#include +#include + +/** + * copy_oldmem_page - copy one page from "oldmem" + * @pfn: page frame number to be copied + * @buf: target memory address for the copy; this can be in kernel address + * space or user address space (see @userbuf) + * @csize: number of bytes to copy + * @offset: offset in bytes into the page (based on pfn) to begin the copy + * @userbuf: if set, @buf is in user address space, use copy_to_user(), + * otherwise @buf is in kernel address space, use memcpy(). + * + * Copy a page from "oldmem". For this page, there is no pte mapped + * in the current kernel. We stitch up a pte, similar to kmap_atomic. + */ +ssize_t copy_oldmem_page(unsigned long pfn, char *buf, + size_t csize, unsigned long offset, int userbuf) +{ + void *vaddr; + + if (!csize) + return 0; + + vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE); + + if (userbuf) { + if (copy_to_user(buf, (vaddr + offset), csize)) { + iounmap(vaddr); + return -EFAULT; + } + } else + memcpy(buf, (vaddr + offset), csize); + + iounmap(vaddr); + return csize; +} diff --git a/trunk/arch/sh/kernel/early_printk.c b/trunk/arch/sh/kernel/early_printk.c index 9048c0326d87..9833493d8867 100644 --- a/trunk/arch/sh/kernel/early_printk.c +++ b/trunk/arch/sh/kernel/early_printk.c @@ -192,20 +192,14 @@ int __init setup_early_printk(char *buf) } #endif - if (likely(early_console)) + if (likely(early_console)) { + if (keep_early) + early_console->flags &= ~CON_BOOT; + else + early_console->flags |= CON_BOOT; register_console(early_console); + } return 0; } early_param("earlyprintk", setup_early_printk); - -void __init disable_early_printk(void) -{ - if (!early_console_initialized || !early_console) - return; - if (!keep_early) { - printk("disabling early console\n"); - unregister_console(early_console); - } else - printk("keeping early console\n"); -} diff --git a/trunk/arch/sh/kernel/irq.c b/trunk/arch/sh/kernel/irq.c index 9bdd8a00cd4a..27b923c45b3d 100644 --- a/trunk/arch/sh/kernel/irq.c +++ b/trunk/arch/sh/kernel/irq.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,7 @@ int show_interrupts(struct seq_file *p, void *v) seq_putc(p, '\n'); } - if (i < NR_IRQS) { + if (i < sh_mv.mv_nr_irqs) { spin_lock_irqsave(&irq_desc[i].lock, flags); action = irq_desc[i].action; if (!action) @@ -61,7 +62,7 @@ int show_interrupts(struct seq_file *p, void *v) seq_putc(p, '\n'); unlock: spin_unlock_irqrestore(&irq_desc[i].lock, flags); - } else if (i == NR_IRQS) + } else if (i == sh_mv.mv_nr_irqs) seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count)); return 0; diff --git a/trunk/arch/sh/kernel/kgdb_stub.c b/trunk/arch/sh/kernel/kgdb_stub.c index d8927d85492e..a5323364cbca 100644 --- a/trunk/arch/sh/kernel/kgdb_stub.c +++ b/trunk/arch/sh/kernel/kgdb_stub.c @@ -6,11 +6,11 @@ * David Grothe , Tigran Aivazian , * Amit S. Kale , William Gatliff , * Ben Lee, Steve Chamberlain and Benoit Miller . - * + * * This version by Henry Bell * Minor modifications by Jeremy Siegel - * - * Contains low-level support for remote debug using GDB. + * + * Contains low-level support for remote debug using GDB. * * To enable debugger support, two things need to happen. A call to * set_debug_traps() is necessary in order to allow any breakpoints @@ -48,7 +48,7 @@ * k kill (Detach GDB) * * d Toggle debug flag - * D Detach GDB + * D Detach GDB * * Hct Set thread t for operations, OK or ENN * c = 'c' (step, cont), c = 'g' (other @@ -58,7 +58,7 @@ * qfThreadInfo Get list of current threads (first) m * qsThreadInfo " " " " " (subsequent) * qOffsets Get section offsets Text=x;Data=y;Bss=z - * + * * TXX Find if thread XX is alive OK or ENN * ? What was the last sigval ? SNN (signal NN) * O Output to GDB console @@ -74,7 +74,7 @@ * '$' or '#'. If starts with two characters followed by * ':', then the existing stubs interpret this as a sequence number. * - * CSUM1 and CSUM2 are ascii hex representation of an 8-bit + * CSUM1 and CSUM2 are ascii hex representation of an 8-bit * checksum of , the most significant nibble is sent first. * the hex digits 0-9,a-f are used. * @@ -86,8 +86,8 @@ * Responses can be run-length encoded to save space. A '*' means that * the next character is an ASCII encoding giving a repeat count which * stands for that many repititions of the character preceding the '*'. - * The encoding is n+29, yielding a printable character where n >=3 - * (which is where RLE starts to win). Don't use an n > 126. + * The encoding is n+29, yielding a printable character where n >=3 + * (which is where RLE starts to win). Don't use an n > 126. * * So "0* " means the same as "0000". */ @@ -100,12 +100,10 @@ #include #include #include - -#ifdef CONFIG_SH_KGDB_CONSOLE #include -#endif - +#include #include +#include #include #include #include @@ -153,7 +151,6 @@ char kgdb_in_gdb_mode; char in_nmi; /* Set during NMI to prevent reentry */ int kgdb_nofault; /* Boolean to ignore bus errs (i.e. in GDB) */ int kgdb_enabled = 1; /* Default to enabled, cmdline can disable */ -int kgdb_halt; /* Exposed for user access */ struct task_struct *kgdb_current; @@ -246,14 +243,6 @@ static char out_buffer[OUTBUFMAX]; static void kgdb_to_gdb(const char *s); -#ifdef CONFIG_KGDB_THREAD -static struct task_struct *trapped_thread; -static struct task_struct *current_thread; -typedef unsigned char threadref[8]; -#define BUF_THREAD_ID_SIZE 16 -#endif - - /* Convert ch to hex */ static int hex(const char ch) { @@ -328,7 +317,7 @@ static int hex_to_int(char **ptr, int *int_value) } /* Copy the binary array pointed to by buf into mem. Fix $, #, - and 0x7d escaped with 0x7d. Return a pointer to the character + and 0x7d escaped with 0x7d. Return a pointer to the character after the last byte written. */ static char *ebin_to_mem(const char *buf, char *mem, int count) { @@ -349,66 +338,6 @@ static char *pack_hex_byte(char *pkt, int byte) return pkt; } -#ifdef CONFIG_KGDB_THREAD - -/* Pack a thread ID */ -static char *pack_threadid(char *pkt, threadref * id) -{ - char *limit; - unsigned char *altid; - - altid = (unsigned char *) id; - - limit = pkt + BUF_THREAD_ID_SIZE; - while (pkt < limit) - pkt = pack_hex_byte(pkt, *altid++); - return pkt; -} - -/* Convert an integer into our threadref */ -static void int_to_threadref(threadref * id, const int value) -{ - unsigned char *scan = (unsigned char *) id; - int i = 4; - - while (i--) - *scan++ = 0; - - *scan++ = (value >> 24) & 0xff; - *scan++ = (value >> 16) & 0xff; - *scan++ = (value >> 8) & 0xff; - *scan++ = (value & 0xff); -} - -/* Return a task structure ptr for a particular pid */ -static struct task_struct *get_thread(int pid) -{ - struct task_struct *thread; - - /* Use PID_MAX w/gdb for pid 0 */ - if (pid == PID_MAX) pid = 0; - - /* First check via PID */ - thread = find_task_by_pid(pid); - - if (thread) - return thread; - - /* Start at the start */ - thread = init_tasks[0]; - - /* Walk along the linked list of tasks */ - do { - if (thread->pid == pid) - return thread; - thread = thread->next_task; - } while (thread != init_tasks[0]); - - return NULL; -} - -#endif /* CONFIG_KGDB_THREAD */ - /* Scan for the start char '$', read the packet and check the checksum */ static void get_packet(char *buffer, int buflen) { @@ -452,7 +381,7 @@ static void get_packet(char *buffer, int buflen) /* Ack successful transfer */ put_debug_char('+'); - /* If a sequence char is present, reply + /* If a sequence char is present, reply the sequence ID */ if (buffer[2] == ':') { put_debug_char(buffer[0]); @@ -611,74 +540,6 @@ static void gdb_regs_to_kgdb_regs(const int *gdb_regs, regs->vbr = gdb_regs[VBR]; } -#ifdef CONFIG_KGDB_THREAD -/* Make a local copy of registers from the specified thread */ -asmlinkage void ret_from_fork(void); -static void thread_regs_to_gdb_regs(const struct task_struct *thread, - int *gdb_regs) -{ - int regno; - int *tregs; - - /* Initialize to zero */ - for (regno = 0; regno < MAXREG; regno++) - gdb_regs[regno] = 0; - - /* Just making sure... */ - if (thread == NULL) - return; - - /* A new fork has pt_regs on the stack from a fork() call */ - if (thread->thread.pc == (unsigned long)ret_from_fork) { - - int vbr_val; - struct pt_regs *kregs; - kregs = (struct pt_regs*)thread->thread.sp; - - gdb_regs[R0] = kregs->regs[R0]; - gdb_regs[R1] = kregs->regs[R1]; - gdb_regs[R2] = kregs->regs[R2]; - gdb_regs[R3] = kregs->regs[R3]; - gdb_regs[R4] = kregs->regs[R4]; - gdb_regs[R5] = kregs->regs[R5]; - gdb_regs[R6] = kregs->regs[R6]; - gdb_regs[R7] = kregs->regs[R7]; - gdb_regs[R8] = kregs->regs[R8]; - gdb_regs[R9] = kregs->regs[R9]; - gdb_regs[R10] = kregs->regs[R10]; - gdb_regs[R11] = kregs->regs[R11]; - gdb_regs[R12] = kregs->regs[R12]; - gdb_regs[R13] = kregs->regs[R13]; - gdb_regs[R14] = kregs->regs[R14]; - gdb_regs[R15] = kregs->regs[R15]; - gdb_regs[PC] = kregs->pc; - gdb_regs[PR] = kregs->pr; - gdb_regs[GBR] = kregs->gbr; - gdb_regs[MACH] = kregs->mach; - gdb_regs[MACL] = kregs->macl; - gdb_regs[SR] = kregs->sr; - - asm("stc vbr, %0":"=r"(vbr_val)); - gdb_regs[VBR] = vbr_val; - return; - } - - /* Otherwise, we have only some registers from switch_to() */ - tregs = (int *)thread->thread.sp; - gdb_regs[R15] = (int)tregs; - gdb_regs[R14] = *tregs++; - gdb_regs[R13] = *tregs++; - gdb_regs[R12] = *tregs++; - gdb_regs[R11] = *tregs++; - gdb_regs[R10] = *tregs++; - gdb_regs[R9] = *tregs++; - gdb_regs[R8] = *tregs++; - gdb_regs[PR] = *tregs++; - gdb_regs[GBR] = *tregs++; - gdb_regs[PC] = thread->thread.pc; -} -#endif /* CONFIG_KGDB_THREAD */ - /* Calculate the new address for after a step */ static short *get_step_address(void) { @@ -759,7 +620,7 @@ static short *get_step_address(void) return (short *) addr; } -/* Set up a single-step. Replace the instruction immediately after the +/* Set up a single-step. Replace the instruction immediately after the current instruction (i.e. next in the expected flow of control) with a trap instruction, so that returning will cause only a single instruction to be executed. Note that this model is slightly broken for instructions @@ -797,37 +658,11 @@ static void undo_single_step(void) /* Send a signal message */ static void send_signal_msg(const int signum) { -#ifndef CONFIG_KGDB_THREAD out_buffer[0] = 'S'; out_buffer[1] = highhex(signum); out_buffer[2] = lowhex(signum); out_buffer[3] = 0; put_packet(out_buffer); -#else /* CONFIG_KGDB_THREAD */ - int threadid; - threadref thref; - char *out = out_buffer; - const char *tstring = "thread"; - - *out++ = 'T'; - *out++ = highhex(signum); - *out++ = lowhex(signum); - - while (*tstring) { - *out++ = *tstring++; - } - *out++ = ':'; - - threadid = trapped_thread->pid; - if (threadid == 0) threadid = PID_MAX; - int_to_threadref(&thref, threadid); - pack_threadid(out, &thref); - out += BUF_THREAD_ID_SIZE; - *out++ = ';'; - - *out = 0; - put_packet(out_buffer); -#endif /* CONFIG_KGDB_THREAD */ } /* Reply that all was well */ @@ -962,15 +797,7 @@ static void step_with_sig_msg(void) /* Send register contents */ static void send_regs_msg(void) { -#ifdef CONFIG_KGDB_THREAD - if (!current_thread) - kgdb_regs_to_gdb_regs(&trap_registers, registers); - else - thread_regs_to_gdb_regs(current_thread, registers); -#else kgdb_regs_to_gdb_regs(&trap_registers, registers); -#endif - mem_to_hex((char *) registers, out_buffer, NUMREGBYTES); put_packet(out_buffer); } @@ -978,201 +805,13 @@ static void send_regs_msg(void) /* Set register contents - currently can't set other thread's registers */ static void set_regs_msg(void) { -#ifdef CONFIG_KGDB_THREAD - if (!current_thread) { -#endif - kgdb_regs_to_gdb_regs(&trap_registers, registers); - hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES); - gdb_regs_to_kgdb_regs(registers, &trap_registers); - send_ok_msg(); -#ifdef CONFIG_KGDB_THREAD - } else - send_err_msg(); -#endif -} - - -#ifdef CONFIG_KGDB_THREAD - -/* Set the status for a thread */ -void set_thread_msg(void) -{ - int threadid; - struct task_struct *thread = NULL; - char *ptr; - - switch (in_buffer[1]) { - - /* To select which thread for gG etc messages, i.e. supported */ - case 'g': - - ptr = &in_buffer[2]; - hex_to_int(&ptr, &threadid); - thread = get_thread(threadid); - - /* If we haven't found it */ - if (!thread) { - send_err_msg(); - break; - } - - /* Set current_thread (or not) */ - if (thread == trapped_thread) - current_thread = NULL; - else - current_thread = thread; - send_ok_msg(); - break; - - /* To select which thread for cCsS messages, i.e. unsupported */ - case 'c': - send_ok_msg(); - break; - - default: - send_empty_msg(); - break; - } -} - -/* Is a thread alive? */ -static void thread_status_msg(void) -{ - char *ptr; - int threadid; - struct task_struct *thread = NULL; - - ptr = &in_buffer[1]; - hex_to_int(&ptr, &threadid); - thread = get_thread(threadid); - if (thread) - send_ok_msg(); - else - send_err_msg(); -} -/* Send the current thread ID */ -static void thread_id_msg(void) -{ - int threadid; - threadref thref; - - out_buffer[0] = 'Q'; - out_buffer[1] = 'C'; - - if (current_thread) - threadid = current_thread->pid; - else if (trapped_thread) - threadid = trapped_thread->pid; - else /* Impossible, but just in case! */ - { - send_err_msg(); - return; - } - - /* Translate pid 0 to PID_MAX for gdb */ - if (threadid == 0) threadid = PID_MAX; - - int_to_threadref(&thref, threadid); - pack_threadid(out_buffer + 2, &thref); - out_buffer[2 + BUF_THREAD_ID_SIZE] = '\0'; - put_packet(out_buffer); -} - -/* Send thread info */ -static void thread_info_msg(void) -{ - struct task_struct *thread = NULL; - int threadid; - char *pos; - threadref thref; - - /* Start with 'm' */ - out_buffer[0] = 'm'; - pos = &out_buffer[1]; - - /* For all possible thread IDs - this will overrun if > 44 threads! */ - /* Start at 1 and include PID_MAX (since GDB won't use pid 0...) */ - for (threadid = 1; threadid <= PID_MAX; threadid++) { - - read_lock(&tasklist_lock); - thread = get_thread(threadid); - read_unlock(&tasklist_lock); - - /* If it's a valid thread */ - if (thread) { - int_to_threadref(&thref, threadid); - pack_threadid(pos, &thref); - pos += BUF_THREAD_ID_SIZE; - *pos++ = ','; - } - } - *--pos = 0; /* Lose final comma */ - put_packet(out_buffer); - -} - -/* Return printable info for gdb's 'info threads' command */ -static void thread_extra_info_msg(void) -{ - int threadid; - struct task_struct *thread = NULL; - char buffer[20], *ptr; - int i; - - /* Extract thread ID */ - ptr = &in_buffer[17]; - hex_to_int(&ptr, &threadid); - thread = get_thread(threadid); - - /* If we don't recognise it, say so */ - if (thread == NULL) - strcpy(buffer, "(unknown)"); - else - strcpy(buffer, thread->comm); - - /* Construct packet */ - for (i = 0, ptr = out_buffer; buffer[i]; i++) - ptr = pack_hex_byte(ptr, buffer[i]); - - if (thread->thread.pc == (unsigned long)ret_from_fork) { - strcpy(buffer, ""); - for (i = 0; buffer[i]; i++) - ptr = pack_hex_byte(ptr, buffer[i]); - } - - *ptr = '\0'; - put_packet(out_buffer); -} - -/* Handle all qFooBarBaz messages - have to use an if statement as - opposed to a switch because q messages can have > 1 char id. */ -static void query_msg(void) -{ - const char *q_start = &in_buffer[1]; - - /* qC = return current thread ID */ - if (strncmp(q_start, "C", 1) == 0) - thread_id_msg(); - - /* qfThreadInfo = query all threads (first) */ - else if (strncmp(q_start, "fThreadInfo", 11) == 0) - thread_info_msg(); - - /* qsThreadInfo = query all threads (subsequent). We know we have sent - them all after the qfThreadInfo message, so there are no to send */ - else if (strncmp(q_start, "sThreadInfo", 11) == 0) - put_packet("l"); /* el = last */ - - /* qThreadExtraInfo = supply printable information per thread */ - else if (strncmp(q_start, "ThreadExtraInfo", 15) == 0) - thread_extra_info_msg(); - - /* Unsupported - empty message as per spec */ - else - send_empty_msg(); + kgdb_regs_to_gdb_regs(&trap_registers, registers); + hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES); + gdb_regs_to_kgdb_regs(registers, &trap_registers); + send_ok_msg(); } -#endif /* CONFIG_KGDB_THREAD */ +#ifdef CONFIG_SH_KGDB_CONSOLE /* * Bring up the ports.. */ @@ -1185,6 +824,9 @@ static int kgdb_serial_setup(void) return 0; } +#else +#define kgdb_serial_setup() 0 +#endif /* The command loop, read and act on requests */ static void kgdb_command_loop(const int excep_code, const int trapa_value) @@ -1193,7 +835,7 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) if (excep_code == NMI_VEC) { #ifndef CONFIG_KGDB_NMI - KGDB_PRINTK("Ignoring unexpected NMI?\n"); + printk(KERN_NOTICE "KGDB: Ignoring unexpected NMI?\n"); return; #else /* CONFIG_KGDB_NMI */ if (!kgdb_enabled) { @@ -1207,19 +849,10 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) if (!kgdb_enabled) return; -#ifdef CONFIG_KGDB_THREAD - /* Until GDB specifies a thread */ - current_thread = NULL; - trapped_thread = current; -#endif - /* Enter GDB mode (e.g. after detach) */ if (!kgdb_in_gdb_mode) { /* Do serial setup, notify user, issue preemptive ack */ - kgdb_serial_setup(); - KGDB_PRINTK("Waiting for GDB (on %s%d at %d baud)\n", - (kgdb_porttype ? kgdb_porttype->name : ""), - kgdb_portnum, kgdb_baud); + printk(KERN_NOTICE "KGDB: Waiting for GDB\n"); kgdb_in_gdb_mode = 1; put_debug_char('+'); } @@ -1233,21 +866,18 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) will later be replaced by its original one. Do NOT do this for trap 0xff, since that indicates a compiled-in breakpoint which will not be replaced (and we would retake the trap forever) */ - if ((excep_code == TRAP_VEC) && (trapa_value != (0xff << 2))) { + if ((excep_code == TRAP_VEC) && (trapa_value != (0x3c << 2))) trap_registers.pc -= 2; - } /* Undo any stepping we may have done */ undo_single_step(); while (1) { - out_buffer[0] = 0; get_packet(in_buffer, BUFMAX); /* Examine first char of buffer to see what we need to do */ switch (in_buffer[0]) { - case '?': /* Send which signal we've received */ send_signal_msg(sigval); break; @@ -1291,21 +921,6 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) step_msg(); return; -#ifdef CONFIG_KGDB_THREAD - - case 'H': /* Task related */ - set_thread_msg(); - break; - - case 'T': /* Query thread status */ - thread_status_msg(); - break; - - case 'q': /* Handle query - currently thread-related */ - query_msg(); - break; -#endif - case 'k': /* 'Kill the program' with a kernel ? */ break; @@ -1323,11 +938,8 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value) } /* There has been an exception, most likely a breakpoint. */ -asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs __regs) +static void handle_exception(struct pt_regs *regs) { - struct pt_regs *regs = RELOC_HIDE(&__regs, 0); int excep_code, vbr_val; int count; int trapa_value = ctrl_inl(TRA); @@ -1355,7 +967,7 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, kgdb_trapa_val = trapa_value; /* Act on the exception */ - kgdb_command_loop(excep_code >> 5, trapa_value); + kgdb_command_loop(excep_code, trapa_value); kgdb_current = NULL; @@ -1373,14 +985,12 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, asm("ldc %0, vbr": :"r"(vbr_val)); } -/* Trigger a breakpoint by function */ -void breakpoint(void) +asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs __regs) { - if (!kgdb_enabled) { - kgdb_enabled = 1; - kgdb_init(); - } - BREAKPOINT(); + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); + handle_exception(regs); } /* Initialise the KGDB data structures and serial configuration */ @@ -1395,24 +1005,16 @@ int kgdb_init(void) kgdb_in_gdb_mode = 0; if (kgdb_serial_setup() != 0) { - KGDB_PRINTK("serial setup error\n"); + printk(KERN_NOTICE "KGDB: serial setup error\n"); return -1; } /* Init ptr to exception handler */ - kgdb_debug_hook = kgdb_handle_exception; + kgdb_debug_hook = handle_exception; kgdb_bus_err_hook = kgdb_handle_bus_error; /* Enter kgdb now if requested, or just report init done */ - if (kgdb_halt) { - kgdb_in_gdb_mode = 1; - put_debug_char('+'); - breakpoint(); - } - else - { - KGDB_PRINTK("stub is initialized.\n"); - } + printk(KERN_NOTICE "KGDB: stub is initialized.\n"); return 0; } @@ -1437,7 +1039,7 @@ static void kgdb_msg_write(const char *s, unsigned count) /* Calculate how many this time */ wcount = (count > MAXOUT) ? MAXOUT : count; - + /* Pack in hex chars */ for (i = 0; i < wcount; i++) bufptr = pack_hex_byte(bufptr, s[i]); @@ -1467,3 +1069,25 @@ void kgdb_console_write(struct console *co, const char *s, unsigned count) kgdb_msg_write(s, count); } #endif + +#ifdef CONFIG_KGDB_SYSRQ +static void sysrq_handle_gdb(int key, struct tty_struct *tty) +{ + printk("Entering GDB stub\n"); + breakpoint(); +} + +static struct sysrq_key_op sysrq_gdb_op = { + .handler = sysrq_handle_gdb, + .help_msg = "Gdb", + .action_msg = "GDB", +}; + +static int gdb_register_sysrq(void) +{ + printk("Registering GDB sysrq handler\n"); + register_sysrq_key('g', &sysrq_gdb_op); + return 0; +} +module_init(gdb_register_sysrq); +#endif diff --git a/trunk/arch/sh/kernel/machine_kexec.c b/trunk/arch/sh/kernel/machine_kexec.c index 08587cdb64d6..790ed69b8666 100644 --- a/trunk/arch/sh/kernel/machine_kexec.c +++ b/trunk/arch/sh/kernel/machine_kexec.c @@ -59,13 +59,13 @@ static void kexec_info(struct kimage *image) printk(" segment[%d]: 0x%08x - 0x%08x (0x%08x)\n", i, (unsigned int)image->segment[i].mem, - (unsigned int)image->segment[i].mem + image->segment[i].memsz, + (unsigned int)image->segment[i].mem + + image->segment[i].memsz, (unsigned int)image->segment[i].memsz); - } + } printk(" start : 0x%08x\n\n", (unsigned int)image->start); } - /* * Do not allocate memory (or fail in any way) in machine_kexec(). * We are past the point of no return, committed to rebooting now. @@ -101,6 +101,27 @@ NORET_TYPE void machine_kexec(struct kimage *image) /* now call it */ rnk = (relocate_new_kernel_t) reboot_code_buffer; - (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg); + (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg); } +/* crashkernel=size@addr specifies the location to reserve for + * a crash kernel. By reserving this memory we guarantee + * that linux never sets it up as a DMA target. + * Useful for holding code to do something appropriate + * after a kernel panic. + */ +static int __init parse_crashkernel(char *arg) +{ + unsigned long size, base; + size = memparse(arg, &arg); + if (*arg == '@') { + base = memparse(arg+1, &arg); + /* FIXME: Do I want a sanity check + * to validate the memory range? + */ + crashk_res.start = base; + crashk_res.end = base + size - 1; + } + return 0; +} +early_param("crashkernel", parse_crashkernel); diff --git a/trunk/arch/sh/kernel/process.c b/trunk/arch/sh/kernel/process.c index e7607366ac4e..329b3f3051de 100644 --- a/trunk/arch/sh/kernel/process.c +++ b/trunk/arch/sh/kernel/process.c @@ -7,7 +7,7 @@ * * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC - * Copyright (C) 2002 - 2006 Paul Mundt + * Copyright (C) 2002 - 2007 Paul Mundt */ #include #include @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -299,7 +300,8 @@ static void ubc_set_tracing(int asid, unsigned long pc) ctrl_outl(0, UBC_BAMRA); if (current_cpu_data.type == CPU_SH7729 || - current_cpu_data.type == CPU_SH7710) { + current_cpu_data.type == CPU_SH7710 || + current_cpu_data.type == CPU_SH7712) { ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA); ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR); } else { @@ -495,6 +497,10 @@ asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5, /* Rewind */ regs->pc -= 2; + if (notify_die(DIE_TRAP, regs, regs->tra & 0xff, + SIGTRAP) == NOTIFY_STOP) + return; + force_sig(SIGTRAP, current); } @@ -510,6 +516,10 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5, /* Rewind */ regs->pc -= 2; + if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff, + SIGTRAP) == NOTIFY_STOP) + return; + #ifdef CONFIG_BUG if (__kernel_text_address(instruction_pointer(regs))) { u16 insn = *(u16 *)instruction_pointer(regs); diff --git a/trunk/arch/sh/kernel/ptrace.c b/trunk/arch/sh/kernel/ptrace.c index 855f7246cfff..3fb5fc0b550d 100644 --- a/trunk/arch/sh/kernel/ptrace.c +++ b/trunk/arch/sh/kernel/ptrace.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sh/kernel/setup.c b/trunk/arch/sh/kernel/setup.c index 98802ab28211..477d2a854fc4 100644 --- a/trunk/arch/sh/kernel/setup.c +++ b/trunk/arch/sh/kernel/setup.c @@ -4,7 +4,7 @@ * This file handles the architecture-dependent parts of initialization * * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2002 - 2006 Paul Mundt + * Copyright (C) 2002 - 2007 Paul Mundt */ #include #include @@ -15,21 +15,22 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include #include #include #include +#include -#ifdef CONFIG_SH_KGDB -#include -static int kgdb_parse_options(char *options); -#endif extern void * __rd_start, * __rd_end; + /* * Machine setup.. */ @@ -205,53 +206,33 @@ static int __init sh_mv_setup(char **cmdline_p) return 0; } -void __init setup_arch(char **cmdline_p) +/* + * Register fully available low RAM pages with the bootmem allocator. + */ +static void __init register_bootmem_low_pages(void) { - unsigned long bootmap_size; - unsigned long start_pfn, max_pfn, max_low_pfn; - -#ifdef CONFIG_CMDLINE_BOOL - strcpy(COMMAND_LINE, CONFIG_CMDLINE); -#endif - - ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); - -#ifdef CONFIG_BLK_DEV_RAM - rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; - rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); - rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); -#endif - - if (!MOUNT_ROOT_RDONLY) - root_mountflags &= ~MS_RDONLY; - init_mm.start_code = (unsigned long) _text; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) _end; - - code_resource.start = (unsigned long)virt_to_phys(_text); - code_resource.end = (unsigned long)virt_to_phys(_etext)-1; - data_resource.start = (unsigned long)virt_to_phys(_etext); - data_resource.end = (unsigned long)virt_to_phys(_edata)-1; - - sh_mv_setup(cmdline_p); - + unsigned long curr_pfn, last_pfn, pages; /* - * Find the highest page frame number we have available + * We are rounding up the start address of usable memory: */ - max_pfn = PFN_DOWN(__pa(memory_end)); + curr_pfn = PFN_UP(__MEMORY_START); /* - * Determine low and high memory ranges: + * ... and at the end of the usable range downwards: */ - max_low_pfn = max_pfn; + last_pfn = PFN_DOWN(__pa(memory_end)); - /* - * Partially used pages are not usable - thus - * we are rounding upwards: - */ - start_pfn = PFN_UP(__pa(_end)); + if (last_pfn > max_low_pfn) + last_pfn = max_low_pfn; + + pages = last_pfn - curr_pfn; + free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages)); +} + +void __init setup_bootmem_allocator(unsigned long start_pfn) +{ + unsigned long bootmap_size; /* * Find a proper area for the bootmem bitmap. After this @@ -259,31 +240,11 @@ void __init setup_arch(char **cmdline_p) * is intact) must be done via bootmem_alloc(). */ bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn, - __MEMORY_START>>PAGE_SHIFT, - max_low_pfn); - /* - * Register fully available low RAM pages with the bootmem allocator. - */ - { - unsigned long curr_pfn, last_pfn, pages; - - /* - * We are rounding up the start address of usable memory: - */ - curr_pfn = PFN_UP(__MEMORY_START); - /* - * ... and at the end of the usable range downwards: - */ - last_pfn = PFN_DOWN(__pa(memory_end)); + min_low_pfn, max_low_pfn); - if (last_pfn > max_low_pfn) - last_pfn = max_low_pfn; - - pages = last_pfn - curr_pfn; - free_bootmem_node(NODE_DATA(0), PFN_PHYS(curr_pfn), - PFN_PHYS(pages)); - } + register_bootmem_low_pages(); + node_set_online(0); /* * Reserve the kernel text and @@ -292,14 +253,14 @@ void __init setup_arch(char **cmdline_p) * case of us accidentally initializing the bootmem allocator with * an invalid RAM area. */ - reserve_bootmem_node(NODE_DATA(0), __MEMORY_START+PAGE_SIZE, + reserve_bootmem(__MEMORY_START+PAGE_SIZE, (PFN_PHYS(start_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START); /* * reserve physical page 0 - it's a special BIOS page on many boxes, * enabling clean reboots, SMP operation, laptop functions. */ - reserve_bootmem_node(NODE_DATA(0), __MEMORY_START, PAGE_SIZE); + reserve_bootmem(__MEMORY_START, PAGE_SIZE); #ifdef CONFIG_BLK_DEV_INITRD ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); @@ -313,8 +274,8 @@ void __init setup_arch(char **cmdline_p) if (LOADER_TYPE && INITRD_START) { if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { - reserve_bootmem_node(NODE_DATA(0), INITRD_START + - __MEMORY_START, INITRD_SIZE); + reserve_bootmem(INITRD_START + __MEMORY_START, + INITRD_SIZE); initrd_start = INITRD_START + PAGE_OFFSET + __MEMORY_START; initrd_end = initrd_start + INITRD_SIZE; @@ -327,6 +288,76 @@ void __init setup_arch(char **cmdline_p) } } #endif +#ifdef CONFIG_KEXEC + if (crashk_res.start != crashk_res.end) + reserve_bootmem(crashk_res.start, + crashk_res.end - crashk_res.start + 1); +#endif +} + +#ifndef CONFIG_NEED_MULTIPLE_NODES +static void __init setup_memory(void) +{ + unsigned long start_pfn; + + /* + * Partially used pages are not usable - thus + * we are rounding upwards: + */ + start_pfn = PFN_UP(__pa(_end)); + setup_bootmem_allocator(start_pfn); +} +#else +extern void __init setup_memory(void); +#endif + +void __init setup_arch(char **cmdline_p) +{ + enable_mmu(); + +#ifdef CONFIG_CMDLINE_BOOL + strcpy(COMMAND_LINE, CONFIG_CMDLINE); +#endif + + ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); + +#ifdef CONFIG_BLK_DEV_RAM + rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; + rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); + rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); +#endif + + if (!MOUNT_ROOT_RDONLY) + root_mountflags &= ~MS_RDONLY; + init_mm.start_code = (unsigned long) _text; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) _end; + + code_resource.start = virt_to_phys(_text); + code_resource.end = virt_to_phys(_etext)-1; + data_resource.start = virt_to_phys(_etext); + data_resource.end = virt_to_phys(_edata)-1; + + parse_early_param(); + + sh_mv_setup(cmdline_p); + + /* + * Find the highest page frame number we have available + */ + max_pfn = PFN_DOWN(__pa(memory_end)); + + /* + * Determine low and high memory ranges: + */ + max_low_pfn = max_pfn; + min_low_pfn = __MEMORY_START >> PAGE_SHIFT; + + nodes_clear(node_online_map); + setup_memory(); + paging_init(); + sparse_init(); #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; @@ -335,8 +366,6 @@ void __init setup_arch(char **cmdline_p) /* Perform the machine specific initialisation */ if (likely(sh_mv.mv_setup)) sh_mv.mv_setup(cmdline_p); - - paging_init(); } struct sh_machine_vector* __init get_mv_byname(const char* name) @@ -380,6 +409,7 @@ static const char *cpu_name[] = { [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706", [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708", [CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710", + [CPU_SH7712] = "SH7712", [CPU_SH7729] = "SH7729", [CPU_SH7750] = "SH7750", [CPU_SH7750S] = "SH7750S", [CPU_SH7750R] = "SH7750R", [CPU_SH7751] = "SH7751", [CPU_SH7751R] = "SH7751R", @@ -477,7 +507,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) c->loops_per_jiffy/(500000/HZ), (c->loops_per_jiffy/(5000/HZ)) % 100); - return show_clocks(m); + return 0; } static void *c_start(struct seq_file *m, loff_t *pos) @@ -499,92 +529,3 @@ struct seq_operations cpuinfo_op = { .show = show_cpuinfo, }; #endif /* CONFIG_PROC_FS */ - -#ifdef CONFIG_SH_KGDB -/* - * Parse command-line kgdb options. By default KGDB is enabled, - * entered on error (or other action) using default serial info. - * The command-line option can include a serial port specification - * and an action to override default or configured behavior. - */ -struct kgdb_sermap kgdb_sci_sermap = -{ "ttySC", 5, kgdb_sci_setup, NULL }; - -struct kgdb_sermap *kgdb_serlist = &kgdb_sci_sermap; -struct kgdb_sermap *kgdb_porttype = &kgdb_sci_sermap; - -void kgdb_register_sermap(struct kgdb_sermap *map) -{ - struct kgdb_sermap *last; - - for (last = kgdb_serlist; last->next; last = last->next) - ; - last->next = map; - if (!map->namelen) { - map->namelen = strlen(map->name); - } -} - -static int __init kgdb_parse_options(char *options) -{ - char c; - int baud; - - /* Check for port spec (or use default) */ - - /* Determine port type and instance */ - if (!memcmp(options, "tty", 3)) { - struct kgdb_sermap *map = kgdb_serlist; - - while (map && memcmp(options, map->name, map->namelen)) - map = map->next; - - if (!map) { - KGDB_PRINTK("unknown port spec in %s\n", options); - return -1; - } - - kgdb_porttype = map; - kgdb_serial_setup = map->setup_fn; - kgdb_portnum = options[map->namelen] - '0'; - options += map->namelen + 1; - - options = (*options == ',') ? options+1 : options; - - /* Read optional parameters (baud/parity/bits) */ - baud = simple_strtoul(options, &options, 10); - if (baud != 0) { - kgdb_baud = baud; - - c = toupper(*options); - if (c == 'E' || c == 'O' || c == 'N') { - kgdb_parity = c; - options++; - } - - c = *options; - if (c == '7' || c == '8') { - kgdb_bits = c; - options++; - } - options = (*options == ',') ? options+1 : options; - } - } - - /* Check for action specification */ - if (!memcmp(options, "halt", 4)) { - kgdb_halt = 1; - options += 4; - } else if (!memcmp(options, "disabled", 8)) { - kgdb_enabled = 0; - options += 8; - } - - if (*options) { - KGDB_PRINTK("ignored unknown options: %s\n", options); - return 0; - } - return 1; -} -__setup("kgdb=", kgdb_parse_options); -#endif /* CONFIG_SH_KGDB */ diff --git a/trunk/arch/sh/kernel/sh_ksyms.c b/trunk/arch/sh/kernel/sh_ksyms.c index 6e0d10fac4a8..fa91641c1f62 100644 --- a/trunk/arch/sh/kernel/sh_ksyms.c +++ b/trunk/arch/sh/kernel/sh_ksyms.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -65,7 +64,6 @@ EXPORT_SYMBOL(__div64_32); /* These symbols are generated by the compiler itself */ DECLARE_EXPORT(__udivsi3); -DECLARE_EXPORT(__udivdi3); DECLARE_EXPORT(__sdivsi3); DECLARE_EXPORT(__ashrdi3); DECLARE_EXPORT(__ashldi3); diff --git a/trunk/arch/sh/kernel/signal.c b/trunk/arch/sh/kernel/signal.c index 9f39ef1f73da..eb0191c374b6 100644 --- a/trunk/arch/sh/kernel/signal.c +++ b/trunk/arch/sh/kernel/signal.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sh/kernel/stacktrace.c b/trunk/arch/sh/kernel/stacktrace.c index 0d5268afe80f..4bdd2f83535d 100644 --- a/trunk/arch/sh/kernel/stacktrace.c +++ b/trunk/arch/sh/kernel/stacktrace.c @@ -19,14 +19,7 @@ */ void save_stack_trace(struct stack_trace *trace, struct task_struct *task) { - unsigned long *sp; - - if (!task) - task = current; - if (task == current) - sp = (unsigned long *)current_stack_pointer; - else - sp = (unsigned long *)task->thread.sp; + unsigned long *sp = (unsigned long *)current_stack_pointer; while (!kstack_end(sp)) { unsigned long addr = *sp++; diff --git a/trunk/arch/sh/kernel/sys_sh.c b/trunk/arch/sh/kernel/sys_sh.c index e18f183e1035..76b1bc7f7029 100644 --- a/trunk/arch/sh/kernel/sys_sh.c +++ b/trunk/arch/sh/kernel/sys_sh.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sh/kernel/timers/timer-cmt.c b/trunk/arch/sh/kernel/timers/timer-cmt.c index a574b93a4e7b..82de6895ade5 100644 --- a/trunk/arch/sh/kernel/timers/timer-cmt.c +++ b/trunk/arch/sh/kernel/timers/timer-cmt.c @@ -115,7 +115,7 @@ static irqreturn_t cmt_timer_interrupt(int irq, void *dev_id) static struct irqaction cmt_irq = { .name = "timer", .handler = cmt_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .mask = CPU_MASK_NONE, }; diff --git a/trunk/arch/sh/kernel/timers/timer-mtu2.c b/trunk/arch/sh/kernel/timers/timer-mtu2.c index fffcd1c09873..b7499a2a9188 100644 --- a/trunk/arch/sh/kernel/timers/timer-mtu2.c +++ b/trunk/arch/sh/kernel/timers/timer-mtu2.c @@ -110,7 +110,7 @@ static irqreturn_t mtu2_timer_interrupt(int irq, void *dev_id) static struct irqaction mtu2_irq = { .name = "timer", .handler = mtu2_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .mask = CPU_MASK_NONE, }; diff --git a/trunk/arch/sh/kernel/timers/timer-tmu.c b/trunk/arch/sh/kernel/timers/timer-tmu.c index e060e71d0785..d9e3151c891e 100644 --- a/trunk/arch/sh/kernel/timers/timer-tmu.c +++ b/trunk/arch/sh/kernel/timers/timer-tmu.c @@ -99,7 +99,7 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy) static struct irqaction tmu_irq = { .name = "timer", .handler = tmu_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .mask = CPU_MASK_NONE, }; @@ -148,7 +148,9 @@ static int tmu_timer_init(void) /* Start TMU0 */ tmu_timer_stop(); -#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760) +#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \ + !defined(CONFIG_CPU_SUBTYPE_SH7760) && \ + !defined(CONFIG_CPU_SUBTYPE_SH7785) ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); #endif diff --git a/trunk/arch/sh/kernel/traps.c b/trunk/arch/sh/kernel/traps.c index e9f168f60f95..7b40f0ff3dfc 100644 --- a/trunk/arch/sh/kernel/traps.c +++ b/trunk/arch/sh/kernel/traps.c @@ -5,7 +5,7 @@ * SuperH version: Copyright (C) 1999 Niibe Yutaka * Copyright (C) 2000 Philipp Rumpf * Copyright (C) 2000 David Howells - * Copyright (C) 2002 - 2006 Paul Mundt + * Copyright (C) 2002 - 2007 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -18,10 +18,12 @@ #include #include #include +#include #include #include #include #include +#include #ifdef CONFIG_SH_KGDB #include @@ -74,7 +76,21 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top) } } -DEFINE_SPINLOCK(die_lock); +ATOMIC_NOTIFIER_HEAD(shdie_chain); + +int register_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&shdie_chain, nb); +} +EXPORT_SYMBOL(register_die_notifier); + +int unregister_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&shdie_chain, nb); +} +EXPORT_SYMBOL(unregister_die_notifier); + +static DEFINE_SPINLOCK(die_lock); void die(const char * str, struct pt_regs * regs, long err) { @@ -130,40 +146,6 @@ static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err) return -EFAULT; } -#ifdef CONFIG_BUG -#ifdef CONFIG_DEBUG_BUGVERBOSE -static inline void do_bug_verbose(struct pt_regs *regs) -{ - struct bug_frame f; - long len; - - if (__copy_from_user(&f, (const void __user *)regs->pc, - sizeof(struct bug_frame))) - return; - - len = __strnlen_user(f.file, PATH_MAX) - 1; - if (unlikely(len < 0 || len >= PATH_MAX)) - f.file = ""; - len = __strnlen_user(f.func, PATH_MAX) - 1; - if (unlikely(len < 0 || len >= PATH_MAX)) - f.func = ""; - - printk(KERN_ALERT "kernel BUG in %s() at %s:%d!\n", - f.func, f.file, f.line); -} -#else -static inline void do_bug_verbose(struct pt_regs *regs) -{ -} -#endif /* CONFIG_DEBUG_BUGVERBOSE */ - -void handle_BUG(struct pt_regs *regs) -{ - do_bug_verbose(regs); - die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff); -} -#endif /* CONFIG_BUG */ - /* * handle an instruction that does an unaligned memory access by emulating the * desired behaviour @@ -888,6 +870,25 @@ void __init trap_init(void) per_cpu_trap_init(); } +#ifdef CONFIG_BUG +void handle_BUG(struct pt_regs *regs) +{ + enum bug_trap_type tt; + tt = report_bug(regs->pc); + if (tt == BUG_TRAP_TYPE_WARN) { + regs->pc += 2; + return; + } + + die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff); +} + +int is_valid_bugaddr(unsigned long addr) +{ + return addr >= PAGE_OFFSET; +} +#endif + void show_trace(struct task_struct *tsk, unsigned long *sp, struct pt_regs *regs) { diff --git a/trunk/arch/sh/kernel/vmlinux.lds.S b/trunk/arch/sh/kernel/vmlinux.lds.S index 2f606d0ce1f6..d83143cc5ca9 100644 --- a/trunk/arch/sh/kernel/vmlinux.lds.S +++ b/trunk/arch/sh/kernel/vmlinux.lds.S @@ -34,9 +34,11 @@ SECTIONS __ex_table : { *(__ex_table) } __stop___ex_table = .; + _etext = .; /* End of text section */ + RODATA - _etext = .; /* End of text section */ + BUG_TABLE .data : { /* Data */ *(.data) @@ -53,6 +55,10 @@ SECTIONS . = ALIGN(PAGE_SIZE); .data.page_aligned : { *(.data.page_aligned) } + __nosave_begin = .; + .data_nosave : { *(.data.nosave) } + . = ALIGN(PAGE_SIZE); + __nosave_end = .; . = ALIGN(PAGE_SIZE); __per_cpu_start = .; @@ -110,43 +116,10 @@ SECTIONS * it's a module. */ /DISCARD/ : { - *(.exit.text) - *(.exit.data) *(.exitcall.exit) } - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging section are relative to the beginning - of the section so we begin .debug at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /* These must appear regardless of . */ + STABS_DEBUG + + DWARF_DEBUG } diff --git a/trunk/arch/sh/lib/Makefile b/trunk/arch/sh/lib/Makefile index 0b9cca5c7cb4..e23dd1a3fccd 100644 --- a/trunk/arch/sh/lib/Makefile +++ b/trunk/arch/sh/lib/Makefile @@ -3,11 +3,9 @@ # lib-y = delay.o memset.o memmove.o memchr.o \ - checksum.o strlen.o div64.o udivdi3.o \ - div64-generic.o + checksum.o strlen.o div64.o div64-generic.o memcpy-y := memcpy.o memcpy-$(CONFIG_CPU_SH4) := memcpy-sh4.o lib-y += $(memcpy-y) - diff --git a/trunk/arch/sh/lib/udivdi3.c b/trunk/arch/sh/lib/udivdi3.c deleted file mode 100644 index 68f038bf3c50..000000000000 --- a/trunk/arch/sh/lib/udivdi3.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Simple __udivdi3 function which doesn't use FPU. - */ - -#include - -extern u64 __xdiv64_32(u64 n, u32 d); -extern void panic(const char * fmt, ...); - -u64 __udivdi3(u64 n, u64 d) -{ - if (d & ~0xffffffff) - panic("Need true 64-bit/64-bit division"); - return __xdiv64_32(n, (u32)d); -} - diff --git a/trunk/arch/sh/mm/Kconfig b/trunk/arch/sh/mm/Kconfig index 6b0d28ac9241..12f3d394dc28 100644 --- a/trunk/arch/sh/mm/Kconfig +++ b/trunk/arch/sh/mm/Kconfig @@ -67,6 +67,7 @@ config CPU_SUBTYPE_SH7300 config CPU_SUBTYPE_SH7705 bool "Support SH7705 processor" select CPU_SH3 + select CPU_HAS_IPR_IRQ select CPU_HAS_PINT_IRQ config CPU_SUBTYPE_SH7706 @@ -101,9 +102,17 @@ config CPU_SUBTYPE_SH7709 config CPU_SUBTYPE_SH7710 bool "Support SH7710 processor" select CPU_SH3 + select CPU_HAS_IPR_IRQ help Select SH7710 if you have a SH3-DSP SH7710 CPU. +config CPU_SUBTYPE_SH7712 + bool "Support SH7712 processor" + select CPU_SH3 + select CPU_HAS_IPR_IRQ + help + Select SH7712 if you have a SH3-DSP SH7712 CPU. + comment "SH-4 Processor Support" config CPU_SUBTYPE_SH7750 @@ -283,6 +292,17 @@ config VSYSCALL For systems with an MMU that can afford to give up a page, (the default value) say Y. +config NODES_SHIFT + int + default "1" + depends on NEED_MULTIPLE_NODES + +config ARCH_FLATMEM_ENABLE + def_bool y + +config ARCH_POPULATES_NODE_MAP + def_bool y + choice prompt "Kernel page size" default PAGE_SIZE_4KB diff --git a/trunk/arch/sh/mm/fault-nommu.c b/trunk/arch/sh/mm/fault-nommu.c index 34d4e0c68fbb..923cb456819b 100644 --- a/trunk/arch/sh/mm/fault-nommu.c +++ b/trunk/arch/sh/mm/fault-nommu.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/sh/mm/fault.c b/trunk/arch/sh/mm/fault.c index fa5d7f0b9f18..0ecc117cade4 100644 --- a/trunk/arch/sh/mm/fault.c +++ b/trunk/arch/sh/mm/fault.c @@ -2,7 +2,7 @@ * Page fault handler for SH with an MMU. * * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2003 - 2007 Paul Mundt * * Based on linux/arch/i386/mm/fault.c: * Copyright (C) 1995 Linus Torvalds @@ -15,12 +15,42 @@ #include #include #include +#include #include #include #include #include -extern void die(const char *,struct pt_regs *,long); +#ifdef CONFIG_KPROBES +ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); + +/* Hook to register for page fault notifications */ +int register_page_fault_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); +} + +int unregister_page_fault_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); +} + +static inline int notify_page_fault(enum die_val val, struct pt_regs *regs, + int trap, int sig) +{ + struct die_args args = { + .regs = regs, + .trapnr = trap, + }; + return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); +} +#else +static inline int notify_page_fault(enum die_val val, struct pt_regs *regs, + int trap, int sig) +{ + return NOTIFY_DONE; +} +#endif /* * This routine handles page faults. It determines the address, @@ -39,6 +69,11 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, siginfo_t info; trace_hardirqs_on(); + + if (notify_page_fault(DIE_PAGE_FAULT, regs, + writeaccess, SIGSEGV) == NOTIFY_STOP) + return; + local_irq_enable(); #ifdef CONFIG_SH_KGDB diff --git a/trunk/arch/sh/mm/hugetlbpage.c b/trunk/arch/sh/mm/hugetlbpage.c index cf2c2ee35a37..ae8c321d6e2a 100644 --- a/trunk/arch/sh/mm/hugetlbpage.c +++ b/trunk/arch/sh/mm/hugetlbpage.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/sh/mm/init.c b/trunk/arch/sh/mm/init.c index ae957a932375..4d030988b368 100644 --- a/trunk/arch/sh/mm/init.c +++ b/trunk/arch/sh/mm/init.c @@ -1,37 +1,20 @@ -/* $Id: init.c,v 1.19 2004/02/21 04:42:16 kkojima Exp $ - * - * linux/arch/sh/mm/init.c +/* + * linux/arch/sh/mm/init.c * * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2002, 2004 Paul Mundt + * Copyright (C) 2002 - 2007 Paul Mundt * * Based on linux/arch/i386/mm/init.c: * Copyright (C) 1995 Linus Torvalds */ - -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include -#include #include -#include #include -#include -#include -#include -#include -#include +#include +#include #include -#include #include #include #include @@ -39,37 +22,51 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); pgd_t swapper_pg_dir[PTRS_PER_PGD]; -#ifdef CONFIG_MMU -/* It'd be good if these lines were in the standard header file. */ -#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT) -#define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn) -#endif - void (*copy_page)(void *from, void *to); void (*clear_page)(void *to); void show_mem(void) { - int i, total = 0, reserved = 0; - int shared = 0, cached = 0; + int total = 0, reserved = 0, free = 0; + int shared = 0, cached = 0, slab = 0; + pg_data_t *pgdat; printk("Mem-info:\n"); show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - i = max_mapnr; - while (i-- > 0) { - total++; - if (PageReserved(mem_map+i)) - reserved++; - else if (PageSwapCache(mem_map+i)) - cached++; - else if (page_count(mem_map+i)) - shared += page_count(mem_map+i) - 1; + + for_each_online_pgdat(pgdat) { + struct page *page, *end; + unsigned long flags; + + pgdat_resize_lock(pgdat, &flags); + page = pgdat->node_mem_map; + end = page + pgdat->node_spanned_pages; + + do { + total++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (PageSlab(page)) + slab++; + else if (!page_count(page)) + free++; + else + shared += page_count(page) - 1; + page++; + } while (page < end); + + pgdat_resize_unlock(pgdat, &flags); } - printk("%d pages of RAM\n",total); - printk("%d reserved pages\n",reserved); - printk("%d pages shared\n",shared); - printk("%d pages swap cached\n",cached); + + printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + printk("%d pages of RAM\n", total); + printk("%d free pages\n", free); + printk("%d reserved pages\n", reserved); + printk("%d slab pages\n", slab); + printk("%d pages shared\n", shared); + printk("%d pages swap cached\n", cached); } #ifdef CONFIG_MMU @@ -147,52 +144,38 @@ extern char __init_begin, __init_end; */ void __init paging_init(void) { - unsigned long zones_size[MAX_NR_ZONES] = { 0, }; + int nid; - /* - * Setup some defaults for the zone sizes.. these should be safe - * regardless of distcontiguous memory or MMU settings. - */ - zones_size[ZONE_NORMAL] = __MEMORY_SIZE >> PAGE_SHIFT; -#ifdef CONFIG_HIGHMEM - zones_size[ZONE_HIGHMEM] = 0 >> PAGE_SHIFT; -#endif - -#ifdef CONFIG_MMU - /* - * If we have an MMU, and want to be using it .. we need to adjust - * the zone sizes accordingly, in addition to turning it on. - */ - { - /* We don't need to map the kernel through the TLB, as - * it is permanatly mapped using P1. So clear the - * entire pgd. */ - memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir)); - - /* Turn on the MMU */ - enable_mmu(); - zones_size[ZONE_NORMAL] = MAX_LOW_PFN - START_PFN; - } + /* We don't need to map the kernel through the TLB, as + * it is permanatly mapped using P1. So clear the + * entire pgd. */ + memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir)); /* Set an initial value for the MMU.TTB so we don't have to * check for a null value. */ set_TTB(swapper_pg_dir); -#elif defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4) - /* - * If we don't have CONFIG_MMU set and the processor in question - * still has an MMU, care needs to be taken to make sure it doesn't - * stay on.. Since the boot loader could have potentially already - * turned it on, and we clearly don't want it, we simply turn it off. - * - * We don't need to do anything special for the zone sizes, since the - * default values that were already configured up above should be - * satisfactory. - */ - disable_mmu(); -#endif - NODE_DATA(0)->node_mem_map = NULL; - free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0); + for_each_online_node(nid) { + pg_data_t *pgdat = NODE_DATA(nid); + unsigned long max_zone_pfns[MAX_NR_ZONES]; + unsigned long low, start_pfn; + + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); + + start_pfn = pgdat->bdata->node_boot_start >> PAGE_SHIFT; + low = pgdat->bdata->node_low_pfn; + + max_zone_pfns[ZONE_NORMAL] = low; + add_active_range(nid, start_pfn, low); + + printk("Node %u: start_pfn = 0x%lx, low = 0x%lx\n", + nid, start_pfn, low); + + free_area_init_nodes(max_zone_pfns); + + printk("Node %u: mem_map starts at %p\n", + pgdat->node_id, pgdat->node_mem_map); + } } static struct kcore_list kcore_mem, kcore_vmalloc; @@ -200,18 +183,33 @@ static struct kcore_list kcore_mem, kcore_vmalloc; void __init mem_init(void) { int codesize, reservedpages, datasize, initsize; - int tmp; - extern unsigned long memory_start; + int nid; -#ifdef CONFIG_MMU - high_memory = (void *)__va(MAX_LOW_PFN * PAGE_SIZE); -#else - extern unsigned long memory_end; + reservedpages = 0; - high_memory = (void *)(memory_end & PAGE_MASK); -#endif + for_each_online_node(nid) { + pg_data_t *pgdat = NODE_DATA(nid); + unsigned long node_pages = 0; + void *node_high_memory; + int i; + + num_physpages += pgdat->node_present_pages; + + if (pgdat->node_spanned_pages) + node_pages = free_all_bootmem_node(pgdat); + + totalram_pages += node_pages; - max_mapnr = num_physpages = MAP_NR(high_memory) - MAP_NR(memory_start); + for (i = 0; i < node_pages; i++) + if (PageReserved(pgdat->node_mem_map + i)) + reservedpages++; + + node_high_memory = (void *)((pgdat->node_start_pfn + + pgdat->node_spanned_pages) << + PAGE_SHIFT); + if (node_high_memory > high_memory) + high_memory = node_high_memory; + } /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); @@ -229,16 +227,6 @@ void __init mem_init(void) clear_page = clear_page_nommu; #endif - /* this will put all low memory onto the freelists */ - totalram_pages += free_all_bootmem_node(NODE_DATA(0)); - reservedpages = 0; - for (tmp = 0; tmp < num_physpages; tmp++) - /* - * Only count reserved RAM pages - */ - if (PageReserved(mem_map+tmp)) - reservedpages++; - codesize = (unsigned long) &_etext - (unsigned long) &_text; datasize = (unsigned long) &_edata - (unsigned long) &_etext; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; @@ -250,7 +238,7 @@ void __init mem_init(void) printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, " "%dk reserved, %dk data, %dk init)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), - max_mapnr << (PAGE_SHIFT-10), + totalram_pages << (PAGE_SHIFT-10), codesize >> 10, reservedpages << (PAGE_SHIFT-10), datasize >> 10, @@ -289,4 +277,3 @@ void free_initrd_mem(unsigned long start, unsigned long end) printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); } #endif - diff --git a/trunk/arch/sh/mm/pmb.c b/trunk/arch/sh/mm/pmb.c index d0d45e2e0ab3..02aae06527dc 100644 --- a/trunk/arch/sh/mm/pmb.c +++ b/trunk/arch/sh/mm/pmb.c @@ -311,9 +311,9 @@ static int __init pmb_init(void) BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES)); - pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), - 0, 0, pmb_cache_ctor, pmb_cache_dtor); - BUG_ON(!pmb_cache); + pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0, + SLAB_PANIC, pmb_cache_ctor, + pmb_cache_dtor); jump_to_P2(); diff --git a/trunk/arch/sh/tools/mach-types b/trunk/arch/sh/tools/mach-types index 4fe0f94cbf42..554f801db67b 100644 --- a/trunk/arch/sh/tools/mach-types +++ b/trunk/arch/sh/tools/mach-types @@ -9,6 +9,7 @@ SE SH_SOLUTION_ENGINE 7751SE SH_7751_SOLUTION_ENGINE 7300SE SH_7300_SOLUTION_ENGINE 7343SE SH_7343_SOLUTION_ENGINE +7780SE SH_7780_SOLUTION_ENGINE 73180SE SH_73180_SOLUTION_ENGINE 7751SYSTEMH SH_7751_SYSTEMH HP6XX SH_HP6XX @@ -26,6 +27,7 @@ SH03 SH_SH03 LANDISK SH_LANDISK R7780RP SH_R7780RP R7780MP SH_R7780MP +R7785RP SH_R7785RP TITAN SH_TITAN SHMIN SH_SHMIN 7710VOIPGW SH_7710VOIPGW diff --git a/trunk/arch/sh64/kernel/early_printk.c b/trunk/arch/sh64/kernel/early_printk.c index 8c8a76e180aa..4f9131123672 100644 --- a/trunk/arch/sh64/kernel/early_printk.c +++ b/trunk/arch/sh64/kernel/early_printk.c @@ -79,7 +79,7 @@ static struct console sh_console = { .name = "scifcon", .write = sh_console_write, .setup = sh_console_setup, - .flags = CON_PRINTBUFFER, + .flags = CON_PRINTBUFFER | CON_BOOT, .index = -1, }; @@ -97,9 +97,3 @@ void __init enable_early_printk(void) register_console(&sh_console); } - -void disable_early_printk(void) -{ - unregister_console(&sh_console); -} - diff --git a/trunk/arch/sh64/kernel/irq.c b/trunk/arch/sh64/kernel/irq.c index e7e07f8749c9..f68b4f6c9b31 100644 --- a/trunk/arch/sh64/kernel/irq.c +++ b/trunk/arch/sh64/kernel/irq.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sh64/kernel/pci_sh5.c b/trunk/arch/sh64/kernel/pci_sh5.c index 9dae689b6a9b..49862e165c06 100644 --- a/trunk/arch/sh64/kernel/pci_sh5.c +++ b/trunk/arch/sh64/kernel/pci_sh5.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sh64/kernel/sh_ksyms.c b/trunk/arch/sh64/kernel/sh_ksyms.c index 7aa4b4f7bc5e..461ea3de316f 100644 --- a/trunk/arch/sh64/kernel/sh_ksyms.c +++ b/trunk/arch/sh64/kernel/sh_ksyms.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/sh64/kernel/signal.c b/trunk/arch/sh64/kernel/signal.c index 1666d3efb52e..b76bdfa473d6 100644 --- a/trunk/arch/sh64/kernel/signal.c +++ b/trunk/arch/sh64/kernel/signal.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sh64/kernel/sys_sh64.c b/trunk/arch/sh64/kernel/sys_sh64.c index ad0fa4e003e7..19126daf9f4c 100644 --- a/trunk/arch/sh64/kernel/sys_sh64.c +++ b/trunk/arch/sh64/kernel/sys_sh64.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sh64/kernel/traps.c b/trunk/arch/sh64/kernel/traps.c index c346d7ef9280..9d0d58fb29fa 100644 --- a/trunk/arch/sh64/kernel/traps.c +++ b/trunk/arch/sh64/kernel/traps.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sh64/kernel/unwind.c b/trunk/arch/sh64/kernel/unwind.c index f934f97f9f9c..1214c78e3584 100644 --- a/trunk/arch/sh64/kernel/unwind.c +++ b/trunk/arch/sh64/kernel/unwind.c @@ -46,15 +46,15 @@ static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc, struct pt_regs *regs) { const char *sym; - char *modname, namebuf[128]; - unsigned long offset, size; + char namebuf[128]; + unsigned long offset; unsigned long prologue = 0; unsigned long fp_displacement = 0; unsigned long fp_prev = 0; unsigned long offset_r14 = 0, offset_r18 = 0; int i, found_prologue_end = 0; - sym = kallsyms_lookup(pc, &size, &offset, &modname, namebuf); + sym = kallsyms_lookup(pc, NULL, &offset, NULL, namebuf); if (!sym) return -EINVAL; diff --git a/trunk/arch/sh64/mm/fault.c b/trunk/arch/sh64/mm/fault.c index 4f72ab33bb2b..4dd8ee8f01ce 100644 --- a/trunk/arch/sh64/mm/fault.c +++ b/trunk/arch/sh64/mm/fault.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/sh64/mm/hugetlbpage.c b/trunk/arch/sh64/mm/hugetlbpage.c index 4b455f611146..fa66daa2dfa9 100644 --- a/trunk/arch/sh64/mm/hugetlbpage.c +++ b/trunk/arch/sh64/mm/hugetlbpage.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/sh64/mm/tlbmiss.c b/trunk/arch/sh64/mm/tlbmiss.c index c8615954aaa9..d4c5334186d0 100644 --- a/trunk/arch/sh64/mm/tlbmiss.c +++ b/trunk/arch/sh64/mm/tlbmiss.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/sparc/kernel/head.S b/trunk/arch/sparc/kernel/head.S index 9a219e8b5ddb..97da13c52563 100644 --- a/trunk/arch/sparc/kernel/head.S +++ b/trunk/arch/sparc/kernel/head.S @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include /* TI_UWINMASK */ #include diff --git a/trunk/arch/sparc/kernel/irq.c b/trunk/arch/sparc/kernel/irq.c index 5b4841d067c1..bdbefa8a9742 100644 --- a/trunk/arch/sparc/kernel/irq.c +++ b/trunk/arch/sparc/kernel/irq.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc/kernel/process.c b/trunk/arch/sparc/kernel/process.c index fc874e63a499..2940d2c1a778 100644 --- a/trunk/arch/sparc/kernel/process.c +++ b/trunk/arch/sparc/kernel/process.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc/kernel/setup.c b/trunk/arch/sparc/kernel/setup.c index eccd8e87f529..64c0ed98820a 100644 --- a/trunk/arch/sparc/kernel/setup.c +++ b/trunk/arch/sparc/kernel/setup.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -40,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc/kernel/signal.c b/trunk/arch/sparc/kernel/signal.c index c9301b9143ca..9994cac95078 100644 --- a/trunk/arch/sparc/kernel/signal.c +++ b/trunk/arch/sparc/kernel/signal.c @@ -17,7 +17,6 @@ #include #include #include -#include #include /* do_coredum */ #include diff --git a/trunk/arch/sparc/kernel/smp.c b/trunk/arch/sparc/kernel/smp.c index 6b5f26b0fb75..4d9ad59031bb 100644 --- a/trunk/arch/sparc/kernel/smp.c +++ b/trunk/arch/sparc/kernel/smp.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc/kernel/sun4d_irq.c b/trunk/arch/sparc/kernel/sun4d_irq.c index 0e27e226e0e2..116d6a241ca2 100644 --- a/trunk/arch/sparc/kernel/sun4d_irq.c +++ b/trunk/arch/sparc/kernel/sun4d_irq.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/sparc/kernel/sun4d_smp.c b/trunk/arch/sparc/kernel/sun4d_smp.c index c69de5d4863d..098c94f1a322 100644 --- a/trunk/arch/sparc/kernel/sun4d_smp.c +++ b/trunk/arch/sparc/kernel/sun4d_smp.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc/kernel/sun4m_smp.c b/trunk/arch/sparc/kernel/sun4m_smp.c index e2d9c018bd56..63ed19bfd028 100644 --- a/trunk/arch/sparc/kernel/sun4m_smp.c +++ b/trunk/arch/sparc/kernel/sun4m_smp.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -405,7 +404,7 @@ void __init smp4m_blackbox_current(unsigned *addr) addr[0] = 0x81580000 | rd; /* rd %tbr, reg */ addr[2] = 0x8130200a | rd | rs1; /* srl reg, 0xa, reg */ - addr[4] = 0x8008200c | rd | rs1; /* and reg, 3, reg */ + addr[4] = 0x8008200c | rd | rs1; /* and reg, 0xc, reg */ } void __init sun4m_init_smp(void) diff --git a/trunk/arch/sparc/kernel/sunos_ioctl.c b/trunk/arch/sparc/kernel/sunos_ioctl.c index 32e8274e4357..e613cc6a10ba 100644 --- a/trunk/arch/sparc/kernel/sunos_ioctl.c +++ b/trunk/arch/sparc/kernel/sunos_ioctl.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/sparc/kernel/sys_solaris.c b/trunk/arch/sparc/kernel/sys_solaris.c index 01b07bb440f0..2226a5992484 100644 --- a/trunk/arch/sparc/kernel/sys_solaris.c +++ b/trunk/arch/sparc/kernel/sys_solaris.c @@ -12,7 +12,6 @@ #include #include #include -#include #include asmlinkage int diff --git a/trunk/arch/sparc/kernel/traps.c b/trunk/arch/sparc/kernel/traps.c index 527687afc1c4..dc9ffea2a4f7 100644 --- a/trunk/arch/sparc/kernel/traps.c +++ b/trunk/arch/sparc/kernel/traps.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -22,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/sparc/lib/bitext.c b/trunk/arch/sparc/lib/bitext.c index 2e168d16547f..764b3eb7b604 100644 --- a/trunk/arch/sparc/lib/bitext.c +++ b/trunk/arch/sparc/lib/bitext.c @@ -9,7 +9,6 @@ * fragmentation. */ -#include #include #include diff --git a/trunk/arch/sparc/mm/fault.c b/trunk/arch/sparc/mm/fault.c index 9eeed3347df3..c3483365db4b 100644 --- a/trunk/arch/sparc/mm/fault.c +++ b/trunk/arch/sparc/mm/fault.c @@ -18,9 +18,9 @@ #include #include #include -#include #include #include +#include #include #include @@ -30,7 +30,6 @@ #include #include #include -#include #include extern int prom_node_root; diff --git a/trunk/arch/sparc/mm/srmmu.c b/trunk/arch/sparc/mm/srmmu.c index 0df7121cef07..e5eaa8072ae0 100644 --- a/trunk/arch/sparc/mm/srmmu.c +++ b/trunk/arch/sparc/mm/srmmu.c @@ -18,13 +18,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc64/Kconfig b/trunk/arch/sparc64/Kconfig index be9e10b94ef8..ad8d6b256a70 100644 --- a/trunk/arch/sparc64/Kconfig +++ b/trunk/arch/sparc64/Kconfig @@ -34,6 +34,10 @@ config MMU bool default y +config QUICKLIST + bool + default y + config STACKTRACE_SUPPORT bool default y diff --git a/trunk/arch/sparc64/defconfig b/trunk/arch/sparc64/defconfig index 120c9c33b7a6..37c2d3695658 100644 --- a/trunk/arch/sparc64/defconfig +++ b/trunk/arch/sparc64/defconfig @@ -1,15 +1,16 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.21-rc4 -# Sat Mar 17 14:18:44 2007 +# Linux kernel version: 2.6.21 +# Sun May 6 22:46:54 2007 # CONFIG_SPARC=y CONFIG_SPARC64=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_64BIT=y CONFIG_MMU=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y -CONFIG_TIME_INTERPOLATION=y CONFIG_ARCH_MAY_HAVE_PC_FDC=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set @@ -108,6 +109,9 @@ CONFIG_GENERIC_HARDIRQS=y # # General machine setup # +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y # CONFIG_SMP is not set CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_TABLE=m @@ -140,8 +144,7 @@ CONFIG_SELECT_MEMORY_MODEL=y CONFIG_SPARSEMEM_MANUAL=y CONFIG_SPARSEMEM=y CONFIG_HAVE_MEMORY_PRESENT=y -# CONFIG_SPARSEMEM_STATIC is not set -CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_STATIC=y CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_RESOURCES_64BIT=y CONFIG_ZONE_DMA_FLAG=0 @@ -151,6 +154,7 @@ CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +CONFIG_ARCH_SUPPORTS_MSI=y CONFIG_PCI_MSI=y # CONFIG_PCI_DEBUG is not set CONFIG_SUN_OPENPROMFS=m @@ -178,7 +182,6 @@ CONFIG_NET=y # # Networking options # -# CONFIG_NETDEBUG is not set CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y @@ -219,6 +222,7 @@ CONFIG_IPV6=m CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m @@ -292,6 +296,14 @@ CONFIG_NET_TCPPROBE=m # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set # @@ -312,10 +324,6 @@ CONFIG_FW_LOADER=y # Connector - unified userspace <-> kernelspace linker # CONFIG_CONNECTOR=m - -# -# Memory Technology Devices (MTD) -# # CONFIG_MTD is not set # @@ -383,7 +391,6 @@ CONFIG_BLK_DEV_IDEPCI=y # CONFIG_BLK_DEV_OPTI621 is not set CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set -CONFIG_IDEDMA_PCI_AUTO=y CONFIG_IDEDMA_ONLYDISK=y # CONFIG_BLK_DEV_AEC62XX is not set CONFIG_BLK_DEV_ALI15X3=y @@ -413,7 +420,6 @@ CONFIG_BLK_DEV_ALI15X3=y # CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set -CONFIG_IDEDMA_AUTO=y # CONFIG_BLK_DEV_HD is not set # @@ -443,6 +449,7 @@ CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set # CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m # # SCSI Transports @@ -485,6 +492,7 @@ CONFIG_ISCSI_TCP=m # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_ESP_CORE is not set # CONFIG_SCSI_SUNESP is not set # CONFIG_SCSI_SRP is not set @@ -628,9 +636,10 @@ CONFIG_BNX2=m # CONFIG_TR is not set # -# Wireless LAN (non-hamradio) +# Wireless LAN # -# CONFIG_NET_RADIO is not set +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set # # Wan interfaces @@ -695,6 +704,12 @@ CONFIG_KEYBOARD_LKKBD=m # CONFIG_KEYBOARD_STOWAWAY is not set CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set CONFIG_MOUSE_SERIAL=y # CONFIG_MOUSE_VSXXXAA is not set # CONFIG_INPUT_JOYSTICK is not set @@ -702,6 +717,7 @@ CONFIG_MOUSE_SERIAL=y CONFIG_INPUT_MISC=y CONFIG_INPUT_SPARCSPKR=y # CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_POLLDEV is not set # # Hardware I/O ports @@ -763,11 +779,8 @@ CONFIG_RTC=y # TPM devices # # CONFIG_TCG_TPM is not set - -# -# I2C support -# CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y # CONFIG_I2C_CHARDEV is not set # @@ -791,17 +804,17 @@ CONFIG_I2C_ALGOBIT=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_SIMTEC is not set # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set # CONFIG_I2C_SIS96X is not set # CONFIG_I2C_STUB is not set +# CONFIG_I2C_TINY_USB is not set # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set -# CONFIG_I2C_PCA_ISA is not set # # Miscellaneous I2C Chip support @@ -912,7 +925,7 @@ CONFIG_FB_MODE_HELPERS=y CONFIG_FB_TILEBLITTING=y # -# Frambuffer hardware drivers +# Frame buffer hardware drivers # # CONFIG_FB_CIRRUS is not set # CONFIG_FB_PM2 is not set @@ -937,6 +950,8 @@ CONFIG_FB_RADEON_I2C=y # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set # CONFIG_FB_TRIDENT is not set +# CONFIG_FB_XVR500 is not set +# CONFIG_FB_XVR2500 is not set # CONFIG_FB_PCI is not set # CONFIG_FB_VIRTUAL is not set @@ -1093,6 +1108,14 @@ CONFIG_AC97_BUS=m CONFIG_HID=y # CONFIG_HID_DEBUG is not set +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y + # # USB support # @@ -1106,6 +1129,7 @@ CONFIG_USB=y # Miscellaneous USB options # CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set # CONFIG_USB_DYNAMIC_MINORS is not set # CONFIG_USB_OTG is not set @@ -1156,10 +1180,6 @@ CONFIG_USB_STORAGE=m # # USB Input Devices # -CONFIG_USB_HID=y -# CONFIG_USB_HIDINPUT_POWERBOOK is not set -# CONFIG_HID_FF is not set -CONFIG_USB_HIDDEV=y # CONFIG_USB_AIPTEK is not set # CONFIG_USB_WACOM is not set # CONFIG_USB_ACECAD is not set @@ -1524,6 +1544,7 @@ CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_LRW=m +# CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_BLOWFISH=m diff --git a/trunk/arch/sparc64/kernel/Makefile b/trunk/arch/sparc64/kernel/Makefile index eff0c01d3579..6bf6fb65bc20 100644 --- a/trunk/arch/sparc64/kernel/Makefile +++ b/trunk/arch/sparc64/kernel/Makefile @@ -17,7 +17,7 @@ obj-y := process.o setup.o cpu.o idprom.o \ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ pci_psycho.o pci_sabre.o pci_schizo.o \ - pci_sun4v.o pci_sun4v_asm.o + pci_sun4v.o pci_sun4v_asm.o pci_fire.o obj-$(CONFIG_SMP) += smp.o trampoline.o obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o diff --git a/trunk/arch/sparc64/kernel/central.c b/trunk/arch/sparc64/kernel/central.c index c65b2f9c98d8..8230099f0d8a 100644 --- a/trunk/arch/sparc64/kernel/central.c +++ b/trunk/arch/sparc64/kernel/central.c @@ -98,7 +98,7 @@ void apply_central_ranges(struct linux_central *central, central->num_central_ranges); } -void * __init central_alloc_bootmem(unsigned long size) +static void * __init central_alloc_bootmem(unsigned long size) { void *ret; @@ -116,7 +116,7 @@ static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r) return ret | (unsigned long) r->phys_addr; } -static void probe_other_fhcs(void) +static void __init probe_other_fhcs(void) { struct device_node *dp; const struct linux_prom64_registers *fpregs; @@ -298,7 +298,7 @@ static void init_all_fhc_hw(void) } -void central_probe(void) +void __init central_probe(void) { struct linux_prom_registers fpregs[6]; const struct linux_prom_registers *pr; diff --git a/trunk/arch/sparc64/kernel/irq.c b/trunk/arch/sparc64/kernel/irq.c index 6241e3dbbd57..3edc18e1b818 100644 --- a/trunk/arch/sparc64/kernel/irq.c +++ b/trunk/arch/sparc64/kernel/irq.c @@ -279,7 +279,7 @@ static void sun4u_irq_enable(unsigned int virt_irq) struct irq_handler_data *data = get_irq_chip_data(virt_irq); if (likely(data)) { - unsigned long cpuid, imap; + unsigned long cpuid, imap, val; unsigned int tid; cpuid = irq_choose_cpu(virt_irq); @@ -287,7 +287,11 @@ static void sun4u_irq_enable(unsigned int virt_irq) tid = sun4u_compute_tid(imap, cpuid); - upa_writel(tid | IMAP_VALID, imap); + val = upa_readq(imap); + val &= ~(IMAP_TID_UPA | IMAP_TID_JBUS | + IMAP_AID_SAFARI | IMAP_NID_SAFARI); + val |= tid | IMAP_VALID; + upa_writeq(val, imap); } } @@ -297,10 +301,10 @@ static void sun4u_irq_disable(unsigned int virt_irq) if (likely(data)) { unsigned long imap = data->imap; - u32 tmp = upa_readl(imap); + u32 tmp = upa_readq(imap); tmp &= ~IMAP_VALID; - upa_writel(tmp, imap); + upa_writeq(tmp, imap); } } @@ -309,7 +313,7 @@ static void sun4u_irq_end(unsigned int virt_irq) struct irq_handler_data *data = get_irq_chip_data(virt_irq); if (likely(data)) - upa_writel(ICLR_IDLE, data->iclr); + upa_writeq(ICLR_IDLE, data->iclr); } static void sun4v_irq_enable(unsigned int virt_irq) @@ -465,7 +469,7 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) BUG_ON(tlb_type == hypervisor); - ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; + ino = (upa_readq(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; bucket = &ivector_table[ino]; if (!bucket->virt_irq) { bucket->virt_irq = virt_irq_alloc(__irq(bucket)); diff --git a/trunk/arch/sparc64/kernel/kprobes.c b/trunk/arch/sparc64/kernel/kprobes.c index ae221f0d4a6f..a44fe47a3c2b 100644 --- a/trunk/arch/sparc64/kernel/kprobes.c +++ b/trunk/arch/sparc64/kernel/kprobes.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/trunk/arch/sparc64/kernel/pci.c b/trunk/arch/sparc64/kernel/pci.c index 9a549547cb2b..966861b212be 100644 --- a/trunk/arch/sparc64/kernel/pci.c +++ b/trunk/arch/sparc64/kernel/pci.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -190,6 +189,7 @@ extern void schizo_init(struct device_node *, const char *); extern void schizo_plus_init(struct device_node *, const char *); extern void tomatillo_init(struct device_node *, const char *); extern void sun4v_pci_init(struct device_node *, const char *); +extern void fire_pci_init(struct device_node *, const char *); static struct { char *model_name; @@ -207,6 +207,7 @@ static struct { { "SUNW,tomatillo", tomatillo_init }, { "pci108e,a801", tomatillo_init }, { "SUNW,sun4v-pci", sun4v_pci_init }, + { "pciex108e,80f0", fire_pci_init }, }; #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \ sizeof(pci_controller_table[0])) @@ -436,6 +437,13 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, printk(" class: 0x%x device name: %s\n", dev->class, pci_name(dev)); + /* I have seen IDE devices which will not respond to + * the bmdma simplex check reads if bus mastering is + * disabled. + */ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) + pci_set_master(dev); + dev->current_state = 4; /* unknown power state */ dev->error_state = pci_channel_io_normal; @@ -468,7 +476,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, return dev; } -static void __init apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p) +static void __devinit apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p) { u32 idx, first, last; @@ -497,9 +505,9 @@ static void __init pci_resource_adjust(struct resource *res, /* Cook up fake bus resources for SUNW,simba PCI bridges which lack * a proper 'ranges' property. */ -static void __init apb_fake_ranges(struct pci_dev *dev, - struct pci_bus *bus, - struct pci_pbm_info *pbm) +static void __devinit apb_fake_ranges(struct pci_dev *dev, + struct pci_bus *bus, + struct pci_pbm_info *pbm) { struct resource *res; u32 first, last; @@ -522,15 +530,15 @@ static void __init apb_fake_ranges(struct pci_dev *dev, pci_resource_adjust(res, &pbm->mem_space); } -static void __init pci_of_scan_bus(struct pci_pbm_info *pbm, - struct device_node *node, - struct pci_bus *bus); +static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm, + struct device_node *node, + struct pci_bus *bus); #define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1]) -void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, - struct device_node *node, - struct pci_dev *dev) +static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, + struct device_node *node, + struct pci_dev *dev) { struct pci_bus *bus; const u32 *busrange, *ranges; @@ -629,9 +637,9 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, pci_of_scan_bus(pbm, node, bus); } -static void __init pci_of_scan_bus(struct pci_pbm_info *pbm, - struct device_node *node, - struct pci_bus *bus) +static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm, + struct device_node *node, + struct pci_bus *bus) { struct device_node *child; const u32 *reg; @@ -733,7 +741,7 @@ int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev, return PCIBIOS_SUCCESSFUL; } -struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm) +struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm) { struct pci_controller_info *p = pbm->parent; struct device_node *node = pbm->prom_node; diff --git a/trunk/arch/sparc64/kernel/pci_fire.c b/trunk/arch/sparc64/kernel/pci_fire.c new file mode 100644 index 000000000000..0fe626631e12 --- /dev/null +++ b/trunk/arch/sparc64/kernel/pci_fire.c @@ -0,0 +1,418 @@ +/* pci_fire.c: Sun4u platform PCI-E controller support. + * + * Copyright (C) 2007 David S. Miller (davem@davemloft.net) + */ +#include +#include +#include +#include + +#include +#include +#include + +#include "pci_impl.h" + +#define fire_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define fire_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory") + +/* Fire config space address format is nearly identical to + * that of SCHIZO and PSYCHO, except that in order to accomodate + * PCI-E extended config space the encoding can handle 12 bits + * of register address: + * + * 32 28 27 20 19 15 14 12 11 2 1 0 + * ------------------------------------------------- + * |0 0 0 0 0| bus | device | function | reg | 0 0 | + * ------------------------------------------------- + */ +#define FIRE_CONFIG_BASE(PBM) ((PBM)->config_space) +#define FIRE_CONFIG_ENCODE(BUS, DEVFN, REG) \ + (((unsigned long)(BUS) << 20) | \ + ((unsigned long)(DEVFN) << 12) | \ + ((unsigned long)(REG))) + +static void *fire_pci_config_mkaddr(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned int devfn, + int where) +{ + if (!pbm) + return NULL; + return (void *) + (FIRE_CONFIG_BASE(pbm) | + FIRE_CONFIG_ENCODE(bus, devfn, where)); +} + +/* FIRE PCI configuration space accessors. */ + +static int fire_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, + int where, int size, u32 *value) +{ + struct pci_pbm_info *pbm = bus_dev->sysdata; + unsigned char bus = bus_dev->number; + u32 *addr; + u16 tmp16; + u8 tmp8; + + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, + size, value); + switch (size) { + case 1: + *value = 0xff; + break; + case 2: + *value = 0xffff; + break; + case 4: + *value = 0xffffffff; + break; + } + + addr = fire_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + switch (size) { + case 1: + pci_config_read8((u8 *)addr, &tmp8); + *value = tmp8; + break; + + case 2: + if (where & 0x01) { + printk("pci_read_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_read16((u16 *)addr, &tmp16); + *value = tmp16; + break; + + case 4: + if (where & 0x03) { + printk("pci_read_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + + pci_config_read32(addr, value); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int fire_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, + int where, int size, u32 value) +{ + struct pci_pbm_info *pbm = bus_dev->sysdata; + unsigned char bus = bus_dev->number; + u32 *addr; + + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, + size, value); + addr = fire_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + switch (size) { + case 1: + pci_config_write8((u8 *)addr, value); + break; + + case 2: + if (where & 0x01) { + printk("pci_write_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_write16((u16 *)addr, value); + break; + + case 4: + if (where & 0x03) { + printk("pci_write_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + + pci_config_write32(addr, value); + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pci_fire_ops = { + .read = fire_read_pci_cfg, + .write = fire_write_pci_cfg, +}; + +static void pbm_scan_bus(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + pbm->pci_bus = pci_scan_one_pbm(pbm); +} + +static void pci_fire_scan_bus(struct pci_controller_info *p) +{ + struct device_node *dp; + + if ((dp = p->pbm_A.prom_node) != NULL) + pbm_scan_bus(p, &p->pbm_A); + + if ((dp = p->pbm_B.prom_node) != NULL) + pbm_scan_bus(p, &p->pbm_B); + + /* XXX register error interrupt handlers XXX */ +} + +#define FIRE_IOMMU_CONTROL 0x40000UL +#define FIRE_IOMMU_TSBBASE 0x40008UL +#define FIRE_IOMMU_FLUSH 0x40100UL +#define FIRE_IOMMU_FLUSHINV 0x40100UL + +static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm) +{ + struct iommu *iommu = pbm->iommu; + u32 vdma[2], dma_mask; + u64 control; + int tsbsize; + + /* No virtual-dma property on these guys, use largest size. */ + vdma[0] = 0xc0000000; /* base */ + vdma[1] = 0x40000000; /* size */ + dma_mask = 0xffffffff; + tsbsize = 128; + + /* Register addresses. */ + iommu->iommu_control = pbm->pbm_regs + FIRE_IOMMU_CONTROL; + iommu->iommu_tsbbase = pbm->pbm_regs + FIRE_IOMMU_TSBBASE; + iommu->iommu_flush = pbm->pbm_regs + FIRE_IOMMU_FLUSH; + iommu->iommu_flushinv = pbm->pbm_regs + FIRE_IOMMU_FLUSHINV; + + /* We use the main control/status register of FIRE as the write + * completion register. + */ + iommu->write_complete_reg = pbm->controller_regs + 0x410000UL; + + /* + * Invalidate TLB Entries. + */ + fire_write(iommu->iommu_flushinv, ~(u64)0); + + pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask); + + fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL); + + control = fire_read(iommu->iommu_control); + control |= (0x00000400 /* TSB cache snoop enable */ | + 0x00000300 /* Cache mode */ | + 0x00000002 /* Bypass enable */ | + 0x00000001 /* Translation enable */); + fire_write(iommu->iommu_control, control); +} + +/* Based at pbm->controller_regs */ +#define FIRE_PARITY_CONTROL 0x470010UL +#define FIRE_PARITY_ENAB 0x8000000000000000UL +#define FIRE_FATAL_RESET_CTL 0x471028UL +#define FIRE_FATAL_RESET_SPARE 0x0000000004000000UL +#define FIRE_FATAL_RESET_MB 0x0000000002000000UL +#define FIRE_FATAL_RESET_CPE 0x0000000000008000UL +#define FIRE_FATAL_RESET_APE 0x0000000000004000UL +#define FIRE_FATAL_RESET_PIO 0x0000000000000040UL +#define FIRE_FATAL_RESET_JW 0x0000000000000004UL +#define FIRE_FATAL_RESET_JI 0x0000000000000002UL +#define FIRE_FATAL_RESET_JR 0x0000000000000001UL +#define FIRE_CORE_INTR_ENABLE 0x471800UL + +/* Based at pbm->pbm_regs */ +#define FIRE_TLU_CTRL 0x80000UL +#define FIRE_TLU_CTRL_TIM 0x00000000da000000UL +#define FIRE_TLU_CTRL_QDET 0x0000000000000100UL +#define FIRE_TLU_CTRL_CFG 0x0000000000000001UL +#define FIRE_TLU_DEV_CTRL 0x90008UL +#define FIRE_TLU_LINK_CTRL 0x90020UL +#define FIRE_TLU_LINK_CTRL_CLK 0x0000000000000040UL +#define FIRE_LPU_RESET 0xe2008UL +#define FIRE_LPU_LLCFG 0xe2200UL +#define FIRE_LPU_LLCFG_VC0 0x0000000000000100UL +#define FIRE_LPU_FCTRL_UCTRL 0xe2240UL +#define FIRE_LPU_FCTRL_UCTRL_N 0x0000000000000002UL +#define FIRE_LPU_FCTRL_UCTRL_P 0x0000000000000001UL +#define FIRE_LPU_TXL_FIFOP 0xe2430UL +#define FIRE_LPU_LTSSM_CFG2 0xe2788UL +#define FIRE_LPU_LTSSM_CFG3 0xe2790UL +#define FIRE_LPU_LTSSM_CFG4 0xe2798UL +#define FIRE_LPU_LTSSM_CFG5 0xe27a0UL +#define FIRE_DMC_IENAB 0x31800UL +#define FIRE_DMC_DBG_SEL_A 0x53000UL +#define FIRE_DMC_DBG_SEL_B 0x53008UL +#define FIRE_PEC_IENAB 0x51800UL + +static void pci_fire_hw_init(struct pci_pbm_info *pbm) +{ + u64 val; + + fire_write(pbm->controller_regs + FIRE_PARITY_CONTROL, + FIRE_PARITY_ENAB); + + fire_write(pbm->controller_regs + FIRE_FATAL_RESET_CTL, + (FIRE_FATAL_RESET_SPARE | + FIRE_FATAL_RESET_MB | + FIRE_FATAL_RESET_CPE | + FIRE_FATAL_RESET_APE | + FIRE_FATAL_RESET_PIO | + FIRE_FATAL_RESET_JW | + FIRE_FATAL_RESET_JI | + FIRE_FATAL_RESET_JR)); + + fire_write(pbm->controller_regs + FIRE_CORE_INTR_ENABLE, ~(u64)0); + + val = fire_read(pbm->pbm_regs + FIRE_TLU_CTRL); + val |= (FIRE_TLU_CTRL_TIM | + FIRE_TLU_CTRL_QDET | + FIRE_TLU_CTRL_CFG); + fire_write(pbm->pbm_regs + FIRE_TLU_CTRL, val); + fire_write(pbm->pbm_regs + FIRE_TLU_DEV_CTRL, 0); + fire_write(pbm->pbm_regs + FIRE_TLU_LINK_CTRL, + FIRE_TLU_LINK_CTRL_CLK); + + fire_write(pbm->pbm_regs + FIRE_LPU_RESET, 0); + fire_write(pbm->pbm_regs + FIRE_LPU_LLCFG, + FIRE_LPU_LLCFG_VC0); + fire_write(pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL, + (FIRE_LPU_FCTRL_UCTRL_N | + FIRE_LPU_FCTRL_UCTRL_P)); + fire_write(pbm->pbm_regs + FIRE_LPU_TXL_FIFOP, + ((0xffff << 16) | (0x0000 << 0))); + fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2, 3000000); + fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3, 500000); + fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4, + (2 << 16) | (140 << 8)); + fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5, 0); + + fire_write(pbm->pbm_regs + FIRE_DMC_IENAB, ~(u64)0); + fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_A, 0); + fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_B, 0); + + fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0); +} + +static void pci_fire_pbm_init(struct pci_controller_info *p, + struct device_node *dp, u32 portid) +{ + const struct linux_prom64_registers *regs; + struct pci_pbm_info *pbm; + const u32 *ino_bitmap; + const unsigned int *busrange; + + if ((portid & 1) == 0) + pbm = &p->pbm_A; + else + pbm = &p->pbm_B; + + pbm->portid = portid; + pbm->parent = p; + pbm->prom_node = dp; + pbm->name = dp->full_name; + + regs = of_get_property(dp, "reg", NULL); + pbm->pbm_regs = regs[0].phys_addr; + pbm->controller_regs = regs[1].phys_addr - 0x410000UL; + + printk("%s: SUN4U PCIE Bus Module\n", pbm->name); + + pci_determine_mem_io_space(pbm); + + ino_bitmap = of_get_property(dp, "ino-bitmap", NULL); + pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) | + ((u64)ino_bitmap[0] << 0UL)); + + busrange = of_get_property(dp, "bus-range", NULL); + pbm->pci_first_busno = busrange[0]; + pbm->pci_last_busno = busrange[1]; + + pci_fire_hw_init(pbm); + pci_fire_pbm_iommu_init(pbm); +} + +static inline int portid_compare(u32 x, u32 y) +{ + if (x == (y ^ 1)) + return 1; + return 0; +} + +void fire_pci_init(struct device_node *dp, const char *model_name) +{ + struct pci_controller_info *p; + u32 portid = of_getintprop_default(dp, "portid", 0xff); + struct iommu *iommu; + + for (p = pci_controller_root; p; p = p->next) { + struct pci_pbm_info *pbm; + + if (p->pbm_A.prom_node && p->pbm_B.prom_node) + continue; + + pbm = (p->pbm_A.prom_node ? + &p->pbm_A : + &p->pbm_B); + + if (portid_compare(pbm->portid, portid)) { + pci_fire_pbm_init(p, dp, portid); + return; + } + } + + p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); + if (!p) + goto fatal_memory_error; + + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + if (!iommu) + goto fatal_memory_error; + + p->pbm_A.iommu = iommu; + + iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); + if (!iommu) + goto fatal_memory_error; + + p->pbm_B.iommu = iommu; + + p->next = pci_controller_root; + pci_controller_root = p; + + p->index = pci_num_controllers++; + + p->scan_bus = pci_fire_scan_bus; + /* XXX MSI support XXX */ + p->pci_ops = &pci_fire_ops; + + /* Like PSYCHO and SCHIZO we have a 2GB aligned area + * for memory space. + */ + pci_memspace_mask = 0x7fffffffUL; + + pci_fire_pbm_init(p, dp, portid); + return; + +fatal_memory_error: + prom_printf("PCI_FIRE: Fatal memory allocation error.\n"); + prom_halt(); +} diff --git a/trunk/arch/sparc64/kernel/pci_iommu.c b/trunk/arch/sparc64/kernel/pci_iommu.c index 66712772f494..9e405cbbcb0d 100644 --- a/trunk/arch/sparc64/kernel/pci_iommu.c +++ b/trunk/arch/sparc64/kernel/pci_iommu.c @@ -37,17 +37,21 @@ /* Must be invoked under the IOMMU lock. */ static void __iommu_flushall(struct iommu *iommu) { - unsigned long tag; - int entry; + if (iommu->iommu_flushinv) { + pci_iommu_write(iommu->iommu_flushinv, ~(u64)0); + } else { + unsigned long tag; + int entry; - tag = iommu->iommu_flush + (0xa580UL - 0x0210UL); - for (entry = 0; entry < 16; entry++) { - pci_iommu_write(tag, 0); - tag += 8; - } + tag = iommu->iommu_flush + (0xa580UL - 0x0210UL); + for (entry = 0; entry < 16; entry++) { + pci_iommu_write(tag, 0); + tag += 8; + } - /* Ensure completion of previous PIO writes. */ - (void) pci_iommu_read(iommu->write_complete_reg); + /* Ensure completion of previous PIO writes. */ + (void) pci_iommu_read(iommu->write_complete_reg); + } } #define IOPTE_CONSISTENT(CTX) \ diff --git a/trunk/arch/sparc64/kernel/process.c b/trunk/arch/sparc64/kernel/process.c index a114151f9fbe..8e3c6e435110 100644 --- a/trunk/arch/sparc64/kernel/process.c +++ b/trunk/arch/sparc64/kernel/process.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc64/kernel/prom.c b/trunk/arch/sparc64/kernel/prom.c index 5e1fcd05160d..c54d4d8af014 100644 --- a/trunk/arch/sparc64/kernel/prom.c +++ b/trunk/arch/sparc64/kernel/prom.c @@ -386,11 +386,9 @@ static unsigned int psycho_irq_build(struct device_node *dp, /* Now build the IRQ bucket. */ imap = controller_regs + imap_off; - imap += 4; iclr_off = psycho_iclr_offset(ino); iclr = controller_regs + iclr_off; - iclr += 4; if ((ino & 0x20) == 0) inofixup = ino & 0x03; @@ -398,7 +396,7 @@ static unsigned int psycho_irq_build(struct device_node *dp, return build_irq(inofixup, iclr, imap); } -static void psycho_irq_trans_init(struct device_node *dp) +static void __init psycho_irq_trans_init(struct device_node *dp) { const struct linux_prom64_registers *regs; @@ -613,11 +611,9 @@ static unsigned int sabre_irq_build(struct device_node *dp, /* Now build the IRQ bucket. */ imap = controller_regs + imap_off; - imap += 4; iclr_off = sabre_iclr_offset(ino); iclr = controller_regs + iclr_off; - iclr += 4; if ((ino & 0x20) == 0) inofixup = ino & 0x03; @@ -640,7 +636,7 @@ static unsigned int sabre_irq_build(struct device_node *dp, return virt_irq; } -static void sabre_irq_trans_init(struct device_node *dp) +static void __init sabre_irq_trans_init(struct device_node *dp) { const struct linux_prom64_registers *regs; struct sabre_irq_data *irq_data; @@ -679,13 +675,14 @@ static unsigned long schizo_iclr_offset(unsigned long ino) static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs, unsigned int ino) { - return pbm_regs + schizo_iclr_offset(ino) + 4; + + return pbm_regs + schizo_iclr_offset(ino); } static unsigned long schizo_ino_to_imap(unsigned long pbm_regs, unsigned int ino) { - return pbm_regs + schizo_imap_offset(ino) + 4; + return pbm_regs + schizo_imap_offset(ino); } #define schizo_read(__reg) \ @@ -796,7 +793,8 @@ static unsigned int schizo_irq_build(struct device_node *dp, return virt_irq; } -static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo) +static void __init __schizo_irq_trans_init(struct device_node *dp, + int is_tomatillo) { const struct linux_prom64_registers *regs; struct schizo_irq_data *irq_data; @@ -818,12 +816,12 @@ static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo) irq_data->chip_version = of_getintprop_default(dp, "version#", 0); } -static void schizo_irq_trans_init(struct device_node *dp) +static void __init schizo_irq_trans_init(struct device_node *dp) { __schizo_irq_trans_init(dp, 0); } -static void tomatillo_irq_trans_init(struct device_node *dp) +static void __init tomatillo_irq_trans_init(struct device_node *dp) { __schizo_irq_trans_init(dp, 1); } @@ -837,7 +835,7 @@ static unsigned int pci_sun4v_irq_build(struct device_node *dp, return sun4v_build_irq(devhandle, devino); } -static void pci_sun4v_irq_trans_init(struct device_node *dp) +static void __init pci_sun4v_irq_trans_init(struct device_node *dp) { const struct linux_prom64_registers *regs; @@ -848,6 +846,85 @@ static void pci_sun4v_irq_trans_init(struct device_node *dp) dp->irq_trans->data = (void *) (unsigned long) ((regs->phys_addr >> 32UL) & 0x0fffffff); } + +struct fire_irq_data { + unsigned long pbm_regs; + u32 portid; +}; + +#define FIRE_IMAP_BASE 0x001000 +#define FIRE_ICLR_BASE 0x001400 + +static unsigned long fire_imap_offset(unsigned long ino) +{ + return FIRE_IMAP_BASE + (ino * 8UL); +} + +static unsigned long fire_iclr_offset(unsigned long ino) +{ + return FIRE_ICLR_BASE + (ino * 8UL); +} + +static unsigned long fire_ino_to_iclr(unsigned long pbm_regs, + unsigned int ino) +{ + return pbm_regs + fire_iclr_offset(ino); +} + +static unsigned long fire_ino_to_imap(unsigned long pbm_regs, + unsigned int ino) +{ + return pbm_regs + fire_imap_offset(ino); +} + +static unsigned int fire_irq_build(struct device_node *dp, + unsigned int ino, + void *_data) +{ + struct fire_irq_data *irq_data = _data; + unsigned long pbm_regs = irq_data->pbm_regs; + unsigned long imap, iclr; + unsigned long int_ctrlr; + + ino &= 0x3f; + + /* Now build the IRQ bucket. */ + imap = fire_ino_to_imap(pbm_regs, ino); + iclr = fire_ino_to_iclr(pbm_regs, ino); + + /* Set the interrupt controller number. */ + int_ctrlr = 1 << 6; + upa_writeq(int_ctrlr, imap); + + /* The interrupt map registers do not have an INO field + * like other chips do. They return zero in the INO + * field, and the interrupt controller number is controlled + * in bits 6 thru 9. So in order for build_irq() to get + * the INO right we pass it in as part of the fixup + * which will get added to the map register zero value + * read by build_irq(). + */ + ino |= (irq_data->portid << 6); + ino -= int_ctrlr; + return build_irq(ino, iclr, imap); +} + +static void __init fire_irq_trans_init(struct device_node *dp) +{ + const struct linux_prom64_registers *regs; + struct fire_irq_data *irq_data; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = fire_irq_build; + + irq_data = prom_early_alloc(sizeof(struct fire_irq_data)); + + regs = of_get_property(dp, "reg", NULL); + dp->irq_trans->data = irq_data; + + irq_data->pbm_regs = regs[0].phys_addr; + irq_data->portid = of_getintprop_default(dp, "portid", 0); +} #endif /* CONFIG_PCI */ #ifdef CONFIG_SBUS @@ -995,7 +1072,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp, return build_irq(sbus_level, iclr, imap); } -static void sbus_irq_trans_init(struct device_node *dp) +static void __init sbus_irq_trans_init(struct device_node *dp) { const struct linux_prom64_registers *regs; @@ -1042,7 +1119,7 @@ static unsigned int central_build_irq(struct device_node *dp, return build_irq(0, iclr, imap); } -static void central_irq_trans_init(struct device_node *dp) +static void __init central_irq_trans_init(struct device_node *dp) { dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); dp->irq_trans->irq_build = central_build_irq; @@ -1056,7 +1133,7 @@ struct irq_trans { }; #ifdef CONFIG_PCI -static struct irq_trans pci_irq_trans_table[] = { +static struct irq_trans __initdata pci_irq_trans_table[] = { { "SUNW,sabre", sabre_irq_trans_init }, { "pci108e,a000", sabre_irq_trans_init }, { "pci108e,a001", sabre_irq_trans_init }, @@ -1069,6 +1146,7 @@ static struct irq_trans pci_irq_trans_table[] = { { "SUNW,tomatillo", tomatillo_irq_trans_init }, { "pci108e,a801", tomatillo_irq_trans_init }, { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init }, + { "pciex108e,80f0", fire_irq_trans_init }, }; #endif @@ -1081,7 +1159,7 @@ static unsigned int sun4v_vdev_irq_build(struct device_node *dp, return sun4v_build_irq(devhandle, devino); } -static void sun4v_vdev_irq_trans_init(struct device_node *dp) +static void __init sun4v_vdev_irq_trans_init(struct device_node *dp) { const struct linux_prom64_registers *regs; @@ -1093,7 +1171,7 @@ static void sun4v_vdev_irq_trans_init(struct device_node *dp) ((regs->phys_addr >> 32UL) & 0x0fffffff); } -static void irq_trans_init(struct device_node *dp) +static void __init irq_trans_init(struct device_node *dp) { #ifdef CONFIG_PCI const char *model; diff --git a/trunk/arch/sparc64/kernel/signal.c b/trunk/arch/sparc64/kernel/signal.c index 96d56a8410ad..203e87301005 100644 --- a/trunk/arch/sparc64/kernel/signal.c +++ b/trunk/arch/sparc64/kernel/signal.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/sparc64/kernel/signal32.c b/trunk/arch/sparc64/kernel/signal32.c index c45f21b881d5..8c1c121330fb 100644 --- a/trunk/arch/sparc64/kernel/signal32.c +++ b/trunk/arch/sparc64/kernel/signal32.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc64/kernel/smp.c b/trunk/arch/sparc64/kernel/smp.c index 1fac215252e4..8087d67a0cf8 100644 --- a/trunk/arch/sparc64/kernel/smp.c +++ b/trunk/arch/sparc64/kernel/smp.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc64/kernel/stacktrace.c b/trunk/arch/sparc64/kernel/stacktrace.c index c4d15f2762b9..47f92a59be18 100644 --- a/trunk/arch/sparc64/kernel/stacktrace.c +++ b/trunk/arch/sparc64/kernel/stacktrace.c @@ -3,22 +3,16 @@ #include #include -void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +void save_stack_trace(struct stack_trace *trace) { unsigned long ksp, fp, thread_base; - struct thread_info *tp; + struct thread_info *tp = task_thread_info(current); - if (!task) - task = current; - tp = task_thread_info(task); - if (task == current) { - flushw_all(); - __asm__ __volatile__( - "mov %%fp, %0" - : "=r" (ksp) - ); - } else - ksp = tp->ksp; + flushw_all(); + __asm__ __volatile__( + "mov %%fp, %0" + : "=r" (ksp) + ); fp = ksp + STACK_BIAS; thread_base = (unsigned long) tp; diff --git a/trunk/arch/sparc64/kernel/sunos_ioctl32.c b/trunk/arch/sparc64/kernel/sunos_ioctl32.c index a05e43d51755..75d2bad49839 100644 --- a/trunk/arch/sparc64/kernel/sunos_ioctl32.c +++ b/trunk/arch/sparc64/kernel/sunos_ioctl32.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/sparc64/kernel/sys_sparc.c b/trunk/arch/sparc64/kernel/sys_sparc.c index a53d4abb4b49..d108eeb0734f 100644 --- a/trunk/arch/sparc64/kernel/sys_sparc.c +++ b/trunk/arch/sparc64/kernel/sys_sparc.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc64/kernel/sys_sparc32.c b/trunk/arch/sparc64/kernel/sys_sparc32.c index 7876a0226285..692e46a6b8da 100644 --- a/trunk/arch/sparc64/kernel/sys_sparc32.c +++ b/trunk/arch/sparc64/kernel/sys_sparc32.c @@ -775,15 +775,25 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, asmlinkage long sys32_utimes(char __user *filename, struct compat_timeval __user *tvs) { - struct timeval ktvs[2]; + struct timespec tv[2]; if (tvs) { + struct timeval ktvs[2]; if (get_tv32(&ktvs[0], tvs) || get_tv32(&ktvs[1], 1+tvs)) return -EFAULT; + + if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 || + ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000) + return -EINVAL; + + tv[0].tv_sec = ktvs[0].tv_sec; + tv[0].tv_nsec = 1000 * ktvs[0].tv_usec; + tv[1].tv_sec = ktvs[1].tv_sec; + tv[1].tv_nsec = 1000 * ktvs[1].tv_usec; } - return do_utimes(AT_FDCWD, filename, (tvs ? &ktvs[0] : NULL)); + return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL); } /* These are here just in case some old sparc32 binary calls it. */ diff --git a/trunk/arch/sparc64/kernel/traps.c b/trunk/arch/sparc64/kernel/traps.c index ad67784292db..dc652f210290 100644 --- a/trunk/arch/sparc64/kernel/traps.c +++ b/trunk/arch/sparc64/kernel/traps.c @@ -15,9 +15,9 @@ #include #include #include -#include #include #include +#include #include #include @@ -36,26 +36,12 @@ #include #include #include -#include #include #ifdef CONFIG_KMOD #include #endif #include -ATOMIC_NOTIFIER_HEAD(sparc64die_chain); - -int register_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&sparc64die_chain, nb); -} -EXPORT_SYMBOL(register_die_notifier); - -int unregister_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&sparc64die_chain, nb); -} -EXPORT_SYMBOL(unregister_die_notifier); /* When an irrecoverable trap occurs at tl > 0, the trap entry * code logs the trap state registers at every level in the trap diff --git a/trunk/arch/sparc64/kernel/unaligned.c b/trunk/arch/sparc64/kernel/unaligned.c index bc18d480dd1c..953be816fa25 100644 --- a/trunk/arch/sparc64/kernel/unaligned.c +++ b/trunk/arch/sparc64/kernel/unaligned.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/sparc64/mm/fault.c b/trunk/arch/sparc64/mm/fault.c index 55ae802dc0ad..c32e309f7788 100644 --- a/trunk/arch/sparc64/mm/fault.c +++ b/trunk/arch/sparc64/mm/fault.c @@ -15,11 +15,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include @@ -29,7 +29,6 @@ #include #include #include -#include #include #ifdef CONFIG_KPROBES diff --git a/trunk/arch/sparc64/mm/hugetlbpage.c b/trunk/arch/sparc64/mm/hugetlbpage.c index 00677b5e1d7d..eaba9b70b184 100644 --- a/trunk/arch/sparc64/mm/hugetlbpage.c +++ b/trunk/arch/sparc64/mm/hugetlbpage.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -175,6 +174,12 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, if (len > task_size) return -ENOMEM; + if (flags & MAP_FIXED) { + if (prepare_hugepage_range(addr, len, pgoff)) + return -EINVAL; + return addr; + } + if (addr) { addr = ALIGN(addr, HPAGE_SIZE); vma = find_vma(mm, addr); diff --git a/trunk/arch/sparc64/mm/init.c b/trunk/arch/sparc64/mm/init.c index cafadcbcdf38..d7004eaf1c8e 100644 --- a/trunk/arch/sparc64/mm/init.c +++ b/trunk/arch/sparc64/mm/init.c @@ -164,30 +164,6 @@ unsigned long sparc64_kern_sec_context __read_mostly; int bigkernel = 0; -struct kmem_cache *pgtable_cache __read_mostly; - -static void zero_ctor(void *addr, struct kmem_cache *cache, unsigned long flags) -{ - clear_page(addr); -} - -extern void tsb_cache_init(void); - -void pgtable_cache_init(void) -{ - pgtable_cache = kmem_cache_create("pgtable_cache", - PAGE_SIZE, PAGE_SIZE, - SLAB_HWCACHE_ALIGN | - SLAB_MUST_HWCACHE_ALIGN, - zero_ctor, - NULL); - if (!pgtable_cache) { - prom_printf("Could not create pgtable_cache\n"); - prom_halt(); - } - tsb_cache_init(); -} - #ifdef CONFIG_DEBUG_DCFLUSH atomic_t dcpage_flushes = ATOMIC_INIT(0); #ifdef CONFIG_SMP diff --git a/trunk/arch/sparc64/mm/tsb.c b/trunk/arch/sparc64/mm/tsb.c index 236d02f41a01..8eb8a7c76ec9 100644 --- a/trunk/arch/sparc64/mm/tsb.c +++ b/trunk/arch/sparc64/mm/tsb.c @@ -252,7 +252,7 @@ static const char *tsb_cache_names[8] = { "tsb_1MB", }; -void __init tsb_cache_init(void) +void __init pgtable_cache_init(void) { unsigned long i; @@ -262,8 +262,7 @@ void __init tsb_cache_init(void) tsb_caches[i] = kmem_cache_create(name, size, size, - SLAB_HWCACHE_ALIGN | - SLAB_MUST_HWCACHE_ALIGN, + 0, NULL, NULL); if (!tsb_caches[i]) { prom_printf("Could not create %s cache\n", name); diff --git a/trunk/arch/sparc64/solaris/ipc.c b/trunk/arch/sparc64/solaris/ipc.c index 8cef5fd57b2e..a531a2cdb381 100644 --- a/trunk/arch/sparc64/solaris/ipc.c +++ b/trunk/arch/sparc64/solaris/ipc.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/trunk/arch/sparc64/solaris/misc.c b/trunk/arch/sparc64/solaris/misc.c index 542c808ec2c8..3b67de7455f1 100644 --- a/trunk/arch/sparc64/solaris/misc.c +++ b/trunk/arch/sparc64/solaris/misc.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/trunk/arch/sparc64/solaris/signal.c b/trunk/arch/sparc64/solaris/signal.c index 7fa2634e2085..de10c9716cfb 100644 --- a/trunk/arch/sparc64/solaris/signal.c +++ b/trunk/arch/sparc64/solaris/signal.c @@ -5,7 +5,6 @@ */ #include -#include #include #include diff --git a/trunk/arch/sparc64/solaris/socket.c b/trunk/arch/sparc64/solaris/socket.c index d3a66ea74a7f..cc69847cf240 100644 --- a/trunk/arch/sparc64/solaris/socket.c +++ b/trunk/arch/sparc64/solaris/socket.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/trunk/arch/sparc64/solaris/socksys.c b/trunk/arch/sparc64/solaris/socksys.c index c2864447de82..e94f6e5d9455 100644 --- a/trunk/arch/sparc64/solaris/socksys.c +++ b/trunk/arch/sparc64/solaris/socksys.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/um/drivers/chan_kern.c b/trunk/arch/um/drivers/chan_kern.c index 9fdfad649536..3aa351611763 100644 --- a/trunk/arch/um/drivers/chan_kern.c +++ b/trunk/arch/um/drivers/chan_kern.c @@ -12,7 +12,6 @@ #include #include #include "chan_kern.h" -#include "user_util.h" #include "kern.h" #include "irq_user.h" #include "sigio.h" diff --git a/trunk/arch/um/drivers/chan_user.c b/trunk/arch/um/drivers/chan_user.c index 0cad3546cb89..13f0bf852b2a 100644 --- a/trunk/arch/um/drivers/chan_user.c +++ b/trunk/arch/um/drivers/chan_user.c @@ -14,7 +14,6 @@ #include #include #include "kern_util.h" -#include "user_util.h" #include "chan_user.h" #include "user.h" #include "os.h" @@ -158,7 +157,7 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out) */ err = run_helper_thread(winch_thread, &data, CLONE_FILES, &stack, 0); if(err < 0){ - printk("fork of winch_thread failed - errno = %d\n", errno); + printk("fork of winch_thread failed - errno = %d\n", -err); goto out_close; } @@ -204,14 +203,3 @@ void register_winch(int fd, struct tty_struct *tty) } } } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/drivers/cow_sys.h b/trunk/arch/um/drivers/cow_sys.h index c6a308464acb..15453845d2ba 100644 --- a/trunk/arch/um/drivers/cow_sys.h +++ b/trunk/arch/um/drivers/cow_sys.h @@ -2,14 +2,13 @@ #define __COW_SYS_H__ #include "kern_util.h" -#include "user_util.h" #include "os.h" #include "user.h" #include "um_malloc.h" static inline void *cow_malloc(int size) { - return(um_kmalloc(size)); + return um_kmalloc(size); } static inline void cow_free(void *ptr) @@ -21,29 +20,22 @@ static inline void cow_free(void *ptr) static inline char *cow_strdup(char *str) { - return(uml_strdup(str)); + return uml_strdup(str); } static inline int cow_seek_file(int fd, __u64 offset) { - return(os_seek_file(fd, offset)); + return os_seek_file(fd, offset); } static inline int cow_file_size(char *file, unsigned long long *size_out) { - return(os_file_size(file, size_out)); + return os_file_size(file, size_out); } static inline int cow_write_file(int fd, void *buf, int size) { - return(os_write_file(fd, buf, size)); + return os_write_file(fd, buf, size); } #endif - -/* - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/drivers/daemon_user.c b/trunk/arch/um/drivers/daemon_user.c index 021b82c7a759..b869e3899683 100644 --- a/trunk/arch/um/drivers/daemon_user.c +++ b/trunk/arch/um/drivers/daemon_user.c @@ -14,7 +14,6 @@ #include "net_user.h" #include "daemon.h" #include "kern_util.h" -#include "user_util.h" #include "user.h" #include "os.h" #include "um_malloc.h" @@ -39,11 +38,11 @@ static struct sockaddr_un *new_addr(void *name, int len) sun = um_kmalloc(sizeof(struct sockaddr_un)); if(sun == NULL){ printk("new_addr: allocation of sockaddr_un failed\n"); - return(NULL); + return NULL; } sun->sun_family = AF_UNIX; memcpy(sun->sun_path, name, len); - return(sun); + return sun; } static int connect_to_switch(struct daemon_data *pri) @@ -112,7 +111,7 @@ static int connect_to_switch(struct daemon_data *pri) } pri->data_addr = sun; - return(fd); + return fd; out_free: kfree(sun); @@ -120,10 +119,10 @@ static int connect_to_switch(struct daemon_data *pri) os_close_file(fd); out: os_close_file(pri->control); - return(err); + return err; } -static void daemon_user_init(void *data, void *dev) +static int daemon_user_init(void *data, void *dev) { struct daemon_data *pri = data; struct timeval tv; @@ -146,13 +145,16 @@ static void daemon_user_init(void *data, void *dev) if(pri->fd < 0){ kfree(pri->local_addr); pri->local_addr = NULL; + return pri->fd; } + + return 0; } static int daemon_open(void *data) { struct daemon_data *pri = data; - return(pri->fd); + return pri->fd; } static void daemon_remove(void *data) @@ -176,12 +178,12 @@ int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri) { struct sockaddr_un *data_addr = pri->data_addr; - return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr))); + return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)); } static int daemon_set_mtu(int mtu, void *data) { - return(mtu); + return mtu; } const struct net_user_info daemon_user_info = { @@ -194,14 +196,3 @@ const struct net_user_info daemon_user_info = { .delete_address = NULL, .max_packet = MAX_PACKET - ETH_HEADER_OTHER }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/drivers/fd.c b/trunk/arch/um/drivers/fd.c index 218aa0e9b792..7f083ec47a4f 100644 --- a/trunk/arch/um/drivers/fd.c +++ b/trunk/arch/um/drivers/fd.c @@ -9,7 +9,6 @@ #include #include #include "user.h" -#include "user_util.h" #include "chan_user.h" #include "os.h" #include "um_malloc.h" diff --git a/trunk/arch/um/drivers/harddog_user.c b/trunk/arch/um/drivers/harddog_user.c index c495ecf263b1..5eeecf8917c3 100644 --- a/trunk/arch/um/drivers/harddog_user.c +++ b/trunk/arch/um/drivers/harddog_user.c @@ -6,7 +6,6 @@ #include #include #include -#include "user_util.h" #include "user.h" #include "mconsole.h" #include "os.h" diff --git a/trunk/arch/um/drivers/line.c b/trunk/arch/um/drivers/line.c index f75d7b05c481..ced99106f798 100644 --- a/trunk/arch/um/drivers/line.c +++ b/trunk/arch/um/drivers/line.c @@ -13,7 +13,6 @@ #include "irq_user.h" #include "line.h" #include "kern.h" -#include "user_util.h" #include "kern_util.h" #include "os.h" #include "irq_kern.h" diff --git a/trunk/arch/um/drivers/mcast_user.c b/trunk/arch/um/drivers/mcast_user.c index b827e82884c9..d319db16d4ec 100644 --- a/trunk/arch/um/drivers/mcast_user.c +++ b/trunk/arch/um/drivers/mcast_user.c @@ -20,7 +20,6 @@ #include "net_user.h" #include "mcast.h" #include "kern_util.h" -#include "user_util.h" #include "user.h" #include "os.h" #include "um_malloc.h" @@ -34,20 +33,21 @@ static struct sockaddr_in *new_addr(char *addr, unsigned short port) sin = um_kmalloc(sizeof(struct sockaddr_in)); if(sin == NULL){ printk("new_addr: allocation of sockaddr_in failed\n"); - return(NULL); + return NULL; } sin->sin_family = AF_INET; sin->sin_addr.s_addr = in_aton(addr); sin->sin_port = htons(port); - return(sin); + return sin; } -static void mcast_user_init(void *data, void *dev) +static int mcast_user_init(void *data, void *dev) { struct mcast_data *pri = data; pri->mcast_addr = new_addr(pri->addr, pri->port); pri->dev = dev; + return 0; } static void mcast_remove(void *data) @@ -107,8 +107,8 @@ static int mcast_open(void *data) err = -errno; printk("mcast_open : data bind failed, errno = %d\n", errno); goto out_close; - } - + } + /* subscribe to the multicast group */ mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr; mreq.imr_interface.s_addr = 0; @@ -153,12 +153,12 @@ int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri) { struct sockaddr_in *data_addr = pri->mcast_addr; - return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr))); + return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)); } static int mcast_set_mtu(int mtu, void *data) { - return(mtu); + return mtu; } const struct net_user_info mcast_user_info = { diff --git a/trunk/arch/um/drivers/mconsole_kern.c b/trunk/arch/um/drivers/mconsole_kern.c index 65ad2932672c..542c9ef858f8 100644 --- a/trunk/arch/um/drivers/mconsole_kern.c +++ b/trunk/arch/um/drivers/mconsole_kern.c @@ -25,7 +25,6 @@ #include "linux/console.h" #include "asm/irq.h" #include "asm/uaccess.h" -#include "user_util.h" #include "kern_util.h" #include "kern.h" #include "mconsole.h" diff --git a/trunk/arch/um/drivers/mconsole_user.c b/trunk/arch/um/drivers/mconsole_user.c index f02634fbf32a..62e5ad63181a 100644 --- a/trunk/arch/um/drivers/mconsole_user.c +++ b/trunk/arch/um/drivers/mconsole_user.c @@ -17,7 +17,6 @@ #include "sysdep/ptrace.h" #include "mconsole.h" #include "os.h" -#include "user_util.h" static struct mconsole_command commands[] = { /* With uts namespaces, uts information becomes process-specific, so diff --git a/trunk/arch/um/drivers/mmapper_kern.c b/trunk/arch/um/drivers/mmapper_kern.c index df3516e47d4d..e41a08f04694 100644 --- a/trunk/arch/um/drivers/mmapper_kern.c +++ b/trunk/arch/um/drivers/mmapper_kern.c @@ -15,7 +15,6 @@ #include #include #include "mem_user.h" -#include "user_util.h" /* These are set in mmapper_init, which is called at boot time */ static unsigned long mmapper_size; diff --git a/trunk/arch/um/drivers/net_kern.c b/trunk/arch/um/drivers/net_kern.c index 859303730b2f..72773dd54425 100644 --- a/trunk/arch/um/drivers/net_kern.c +++ b/trunk/arch/um/drivers/net_kern.c @@ -21,7 +21,6 @@ #include "linux/ethtool.h" #include "linux/platform_device.h" #include "asm/uaccess.h" -#include "user_util.h" #include "kern_util.h" #include "net_kern.h" #include "net_user.h" @@ -284,7 +283,7 @@ void uml_net_user_timer_expire(unsigned long _conn) #endif } -static void setup_etheraddr(char *str, unsigned char *addr) +static void setup_etheraddr(char *str, unsigned char *addr, char *name) { char *end; int i; @@ -303,15 +302,34 @@ static void setup_etheraddr(char *str, unsigned char *addr) } str = end + 1; } - if(addr[0] & 1){ + if (is_multicast_ether_addr(addr)) { printk(KERN_ERR - "Attempt to assign a broadcast ethernet address to a " + "Attempt to assign a multicast ethernet address to a " "device disallowed\n"); goto random; } + if (!is_valid_ether_addr(addr)) { + printk(KERN_ERR + "Attempt to assign an invalid ethernet address to a " + "device disallowed\n"); + goto random; + } + if (!is_local_ether_addr(addr)) { + printk(KERN_WARNING + "Warning: attempt to assign a globally valid ethernet " + "address to a device\n"); + printk(KERN_WARNING "You should better enable the 2nd " + "rightmost bit in the first byte of the MAC,\n"); + printk(KERN_WARNING "i.e. %02x:%02x:%02x:%02x:%02x:%02x\n", + addr[0] | 0x02, addr[1], addr[2], addr[3], addr[4], + addr[5]); + goto random; + } return; random: + printk(KERN_INFO + "Choosing a random ethernet address for device %s\n", name); random_ether_addr(addr); } @@ -325,31 +343,53 @@ static struct platform_driver uml_net_driver = { }; static int driver_registered; -static int eth_configure(int n, void *init, char *mac, - struct transport *transport) +static void net_device_release(struct device *dev) +{ + struct uml_net *device = dev->driver_data; + struct net_device *netdev = device->dev; + struct uml_net_private *lp = netdev->priv; + + if(lp->remove != NULL) + (*lp->remove)(&lp->user); + list_del(&device->list); + kfree(device); + free_netdev(netdev); +} + +static void eth_configure(int n, void *init, char *mac, + struct transport *transport) { struct uml_net *device; struct net_device *dev; struct uml_net_private *lp; - int save, err, size; + int err, size; - size = transport->private_size + sizeof(struct uml_net_private) + - sizeof(((struct uml_net_private *) 0)->user); + size = transport->private_size + sizeof(struct uml_net_private); device = kzalloc(sizeof(*device), GFP_KERNEL); if (device == NULL) { - printk(KERN_ERR "eth_configure failed to allocate uml_net\n"); - return(1); + printk(KERN_ERR "eth_configure failed to allocate struct " + "uml_net\n"); + return; + } + + dev = alloc_etherdev(size); + if (dev == NULL) { + printk(KERN_ERR "eth_configure: failed to allocate struct " + "net_device for eth%d\n", n); + goto out_free_device; } INIT_LIST_HEAD(&device->list); device->index = n; - spin_lock(&devices_lock); - list_add(&device->list, &devices); - spin_unlock(&devices_lock); + /* If this name ends up conflicting with an existing registered + * netdevice, that is OK, register_netdev{,ice}() will notice this + * and fail. + */ + snprintf(dev->name, sizeof(dev->name), "eth%d", n); - setup_etheraddr(mac, device->mac); + setup_etheraddr(mac, device->mac, dev->name); printk(KERN_INFO "Netdevice %d ", n); printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", @@ -357,11 +397,6 @@ static int eth_configure(int n, void *init, char *mac, device->mac[2], device->mac[3], device->mac[4], device->mac[5]); printk(": "); - dev = alloc_etherdev(size); - if (dev == NULL) { - printk(KERN_ERR "eth_configure: failed to allocate device\n"); - return 1; - } lp = dev->priv; /* This points to the transport private data. It's still clear, but we @@ -376,47 +411,20 @@ static int eth_configure(int n, void *init, char *mac, } device->pdev.id = n; device->pdev.name = DRIVER_NAME; - platform_device_register(&device->pdev); + device->pdev.dev.release = net_device_release; + device->pdev.dev.driver_data = device; + if(platform_device_register(&device->pdev)) + goto out_free_netdev; SET_NETDEV_DEV(dev,&device->pdev.dev); - /* If this name ends up conflicting with an existing registered - * netdevice, that is OK, register_netdev{,ice}() will notice this - * and fail. - */ - snprintf(dev->name, sizeof(dev->name), "eth%d", n); device->dev = dev; + /* + * These just fill in a data structure, so there's no failure + * to be worried about. + */ (*transport->kern->init)(dev, init); - dev->mtu = transport->user->max_packet; - dev->open = uml_net_open; - dev->hard_start_xmit = uml_net_start_xmit; - dev->stop = uml_net_close; - dev->get_stats = uml_net_get_stats; - dev->set_multicast_list = uml_net_set_multicast_list; - dev->tx_timeout = uml_net_tx_timeout; - dev->set_mac_address = uml_net_set_mac; - dev->change_mtu = uml_net_change_mtu; - dev->ethtool_ops = ¨_net_ethtool_ops; - dev->watchdog_timeo = (HZ >> 1); - dev->irq = UM_ETH_IRQ; - - rtnl_lock(); - err = register_netdevice(dev); - rtnl_unlock(); - if (err) { - device->dev = NULL; - /* XXX: should we call ->remove() here? */ - free_netdev(dev); - return 1; - } - - /* lp.user is the first four bytes of the transport data, which - * has already been initialized. This structure assignment will - * overwrite that, so we make sure that .user gets overwritten with - * what it already has. - */ - save = lp->user[0]; *lp = ((struct uml_net_private) { .list = LIST_HEAD_INIT(lp->list), .dev = dev, @@ -430,20 +438,53 @@ static int eth_configure(int n, void *init, char *mac, .write = transport->kern->write, .add_address = transport->user->add_address, .delete_address = transport->user->delete_address, - .set_mtu = transport->user->set_mtu, - .user = { save } }); + .set_mtu = transport->user->set_mtu }); init_timer(&lp->tl); spin_lock_init(&lp->lock); lp->tl.function = uml_net_user_timer_expire; memcpy(lp->mac, device->mac, sizeof(lp->mac)); - if (transport->user->init) - (*transport->user->init)(&lp->user, dev); + if ((transport->user->init != NULL) && + ((*transport->user->init)(&lp->user, dev) != 0)) + goto out_unregister; set_ether_mac(dev, device->mac); + dev->mtu = transport->user->max_packet; + dev->open = uml_net_open; + dev->hard_start_xmit = uml_net_start_xmit; + dev->stop = uml_net_close; + dev->get_stats = uml_net_get_stats; + dev->set_multicast_list = uml_net_set_multicast_list; + dev->tx_timeout = uml_net_tx_timeout; + dev->set_mac_address = uml_net_set_mac; + dev->change_mtu = uml_net_change_mtu; + dev->ethtool_ops = ¨_net_ethtool_ops; + dev->watchdog_timeo = (HZ >> 1); + dev->irq = UM_ETH_IRQ; - return 0; + rtnl_lock(); + err = register_netdevice(dev); + rtnl_unlock(); + if (err) + goto out_undo_user_init; + + spin_lock(&devices_lock); + list_add(&device->list, &devices); + spin_unlock(&devices_lock); + + return; + +out_undo_user_init: + if (transport->user->remove != NULL) + (*transport->user->remove)(&lp->user); +out_unregister: + platform_device_unregister(&device->pdev); + return; /* platform_device_unregister frees dev and device */ +out_free_netdev: + free_netdev(dev); +out_free_device: + kfree(device); } static struct uml_net *find_device(int n) @@ -666,13 +707,9 @@ static int net_remove(int n, char **error_out) lp = dev->priv; if(lp->fd > 0) return -EBUSY; - if(lp->remove != NULL) (*lp->remove)(&lp->user); unregister_netdev(dev); platform_device_unregister(&device->pdev); - list_del(&device->list); - kfree(device); - free_netdev(dev); return 0; } diff --git a/trunk/arch/um/drivers/net_user.c b/trunk/arch/um/drivers/net_user.c index 0ffd7ac295d4..3503cff867c3 100644 --- a/trunk/arch/um/drivers/net_user.c +++ b/trunk/arch/um/drivers/net_user.c @@ -14,11 +14,11 @@ #include #include #include "user.h" -#include "user_util.h" #include "kern_util.h" #include "net_user.h" #include "os.h" #include "um_malloc.h" +#include "kern_constants.h" int tap_open_common(void *dev, char *gate_addr) { @@ -216,7 +216,7 @@ static void change(char *dev, char *what, unsigned char *addr, sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], netmask[2], netmask[3]); - output_len = page_size(); + output_len = UM_KERN_PAGE_SIZE; output = um_kmalloc(output_len); if(output == NULL) printk("change : failed to allocate output buffer\n"); diff --git a/trunk/arch/um/drivers/pcap_kern.c b/trunk/arch/um/drivers/pcap_kern.c index 948849343ca4..c329931673d6 100644 --- a/trunk/arch/um/drivers/pcap_kern.c +++ b/trunk/arch/um/drivers/pcap_kern.c @@ -29,21 +29,25 @@ void pcap_init(struct net_device *dev, void *data) ppri->promisc = init->promisc; ppri->optimize = init->optimize; ppri->filter = init->filter; + + printk("pcap backend, host interface %s\n", ppri->host_if); } -static int pcap_read(int fd, struct sk_buff **skb, +static int pcap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) { *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); - if(*skb == NULL) return(-ENOMEM); - return(pcap_user_read(fd, skb_mac_header(*skb), + if(*skb == NULL) + return -ENOMEM; + + return pcap_user_read(fd, skb_mac_header(*skb), (*skb)->dev->mtu + ETH_HEADER_OTHER, - (struct pcap_data *) &lp->user)); + (struct pcap_data *) &lp->user); } static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp) { - return(-EPERM); + return -EPERM; } static const struct net_kern_info pcap_kern_info = { @@ -65,12 +69,12 @@ int pcap_setup(char *str, char **mac_out, void *data) .optimize = 0, .filter = NULL }); - remain = split_if_spec(str, &host_if, &init->filter, - &options[0], &options[1], NULL); + remain = split_if_spec(str, &host_if, &init->filter, + &options[0], &options[1], mac_out, NULL); if(remain != NULL){ printk(KERN_ERR "pcap_setup - Extra garbage on " "specification : '%s'\n", remain); - return(0); + return 0; } if(host_if != NULL) @@ -87,10 +91,13 @@ int pcap_setup(char *str, char **mac_out, void *data) init->optimize = 1; else if(!strcmp(options[i], "nooptimize")) init->optimize = 0; - else printk("pcap_setup : bad option - '%s'\n", options[i]); + else { + printk("pcap_setup : bad option - '%s'\n", options[i]); + return 0; + } } - return(1); + return 1; } static struct transport pcap_transport = { diff --git a/trunk/arch/um/drivers/pcap_user.c b/trunk/arch/um/drivers/pcap_user.c index 11921a7baa7b..483aa15222a4 100644 --- a/trunk/arch/um/drivers/pcap_user.c +++ b/trunk/arch/um/drivers/pcap_user.c @@ -13,12 +13,13 @@ #include "pcap_user.h" #include "user.h" #include "um_malloc.h" +#include "kern_constants.h" #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) #define PCAP_FD(p) (*(int *)(p)) -static void pcap_user_init(void *data, void *dev) +static int pcap_user_init(void *data, void *dev) { struct pcap_data *pri = data; pcap_t *p; @@ -26,13 +27,14 @@ static void pcap_user_init(void *data, void *dev) p = pcap_open_live(pri->host_if, MAX_PACKET, pri->promisc, 0, errors); if(p == NULL){ - printk("pcap_user_init : pcap_open_live failed - '%s'\n", - errors); - return; + printk(UM_KERN_ERR "pcap_user_init : pcap_open_live failed - " + "'%s'\n", errors); + return -EINVAL; } pri->dev = dev; pri->pcap = p; + return 0; } static int pcap_open(void *data) @@ -42,39 +44,39 @@ static int pcap_open(void *data) int err; if(pri->pcap == NULL) - return(-ENODEV); + return -ENODEV; if(pri->filter != NULL){ err = dev_netmask(pri->dev, &netmask); if(err < 0){ - printk("pcap_open : dev_netmask failed\n"); - return(-EIO); + printk(UM_KERN_ERR "pcap_open : dev_netmask failed\n"); + return -EIO; } pri->compiled = um_kmalloc(sizeof(struct bpf_program)); if(pri->compiled == NULL){ - printk("pcap_open : kmalloc failed\n"); - return(-ENOMEM); + printk(UM_KERN_ERR "pcap_open : kmalloc failed\n"); + return -ENOMEM; } - + err = pcap_compile(pri->pcap, (struct bpf_program *) pri->compiled, pri->filter, pri->optimize, netmask); if(err < 0){ - printk("pcap_open : pcap_compile failed - '%s'\n", - pcap_geterr(pri->pcap)); - return(-EIO); + printk(UM_KERN_ERR "pcap_open : pcap_compile failed - " + "'%s'\n", pcap_geterr(pri->pcap)); + return -EIO; } err = pcap_setfilter(pri->pcap, pri->compiled); if(err < 0){ - printk("pcap_open : pcap_setfilter failed - '%s'\n", - pcap_geterr(pri->pcap)); - return(-EIO); + printk(UM_KERN_ERR "pcap_open : pcap_setfilter " + "failed - '%s'\n", pcap_geterr(pri->pcap)); + return -EIO; } } - - return(PCAP_FD(pri->pcap)); + + return PCAP_FD(pri->pcap); } static void pcap_remove(void *data) @@ -84,7 +86,8 @@ static void pcap_remove(void *data) if(pri->compiled != NULL) pcap_freecode(pri->compiled); - pcap_close(pri->pcap); + if(pri->pcap != NULL) + pcap_close(pri->pcap); } struct pcap_handler_data { @@ -113,12 +116,13 @@ int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri) n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata); if(n < 0){ - printk("pcap_dispatch failed - %s\n", pcap_geterr(pri->pcap)); - return(-EIO); + printk(UM_KERN_ERR "pcap_dispatch failed - %s\n", + pcap_geterr(pri->pcap)); + return -EIO; } else if(n == 0) - return(0); - return(hdata.len); + return 0; + return hdata.len; } const struct net_user_info pcap_user_info = { @@ -131,14 +135,3 @@ const struct net_user_info pcap_user_info = { .delete_address = NULL, .max_packet = MAX_PACKET - ETH_HEADER_OTHER }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/drivers/port_user.c b/trunk/arch/um/drivers/port_user.c index 80508023054f..3f6357d24bee 100644 --- a/trunk/arch/um/drivers/port_user.c +++ b/trunk/arch/um/drivers/port_user.c @@ -13,7 +13,6 @@ #include #include #include -#include "user_util.h" #include "kern_util.h" #include "user.h" #include "chan_user.h" diff --git a/trunk/arch/um/drivers/pty.c b/trunk/arch/um/drivers/pty.c index 829a5eca8c07..df4976c9eef2 100644 --- a/trunk/arch/um/drivers/pty.c +++ b/trunk/arch/um/drivers/pty.c @@ -4,13 +4,13 @@ */ #include +#include #include #include #include #include #include "chan_user.h" #include "user.h" -#include "user_util.h" #include "kern_util.h" #include "os.h" #include "um_malloc.h" diff --git a/trunk/arch/um/drivers/slip_user.c b/trunk/arch/um/drivers/slip_user.c index 7eddacc53b6e..78f0e515da8f 100644 --- a/trunk/arch/um/drivers/slip_user.c +++ b/trunk/arch/um/drivers/slip_user.c @@ -8,7 +8,6 @@ #include #include #include -#include "user_util.h" #include "kern_util.h" #include "user.h" #include "net_user.h" @@ -16,12 +15,14 @@ #include "slip_common.h" #include "os.h" #include "um_malloc.h" +#include "kern_constants.h" -void slip_user_init(void *data, void *dev) +static int slip_user_init(void *data, void *dev) { struct slip_data *pri = data; pri->dev = dev; + return 0; } static int set_up_tty(int fd) @@ -89,7 +90,7 @@ static int slip_tramp(char **argv, int fd) goto out_close; pid = err; - output_len = page_size(); + output_len = UM_KERN_PAGE_SIZE; output = um_kmalloc(output_len); if(output == NULL){ printk("slip_tramp : failed to allocate output buffer\n"); diff --git a/trunk/arch/um/drivers/slirp_user.c b/trunk/arch/um/drivers/slirp_user.c index ce5e85d1de3d..39f889fe9949 100644 --- a/trunk/arch/um/drivers/slirp_user.c +++ b/trunk/arch/um/drivers/slirp_user.c @@ -7,7 +7,6 @@ #include #include #include -#include "user_util.h" #include "kern_util.h" #include "user.h" #include "net_user.h" @@ -15,11 +14,12 @@ #include "slip_common.h" #include "os.h" -void slirp_user_init(void *data, void *dev) +static int slirp_user_init(void *data, void *dev) { struct slirp_data *pri = data; pri->dev = dev; + return 0; } struct slirp_pre_exec_data { diff --git a/trunk/arch/um/drivers/ssl.c b/trunk/arch/um/drivers/ssl.c index 4b382a6e710f..fd09ad9e9c0a 100644 --- a/trunk/arch/um/drivers/ssl.c +++ b/trunk/arch/um/drivers/ssl.c @@ -15,7 +15,6 @@ #include "line.h" #include "ssl.h" #include "chan_kern.h" -#include "user_util.h" #include "kern_util.h" #include "kern.h" #include "init.h" @@ -192,12 +191,12 @@ static int ssl_init(void) ssl_driver = register_lines(&driver, &ssl_ops, serial_lines, ARRAY_SIZE(serial_lines)); - lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts); - new_title = add_xterm_umid(opts.xterm_title); if (new_title != NULL) opts.xterm_title = new_title; + lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts); + ssl_init_done = 1; register_console(&ssl_cons); return 0; diff --git a/trunk/arch/um/drivers/stdio_console.c b/trunk/arch/um/drivers/stdio_console.c index 76d1f1c980ef..2bb4193ac1aa 100644 --- a/trunk/arch/um/drivers/stdio_console.c +++ b/trunk/arch/um/drivers/stdio_console.c @@ -22,7 +22,6 @@ #include "stdio_console.h" #include "line.h" #include "chan_kern.h" -#include "user_util.h" #include "kern_util.h" #include "irq_user.h" #include "mconsole_kern.h" @@ -167,12 +166,12 @@ int stdio_init(void) return -1; printk(KERN_INFO "Initialized stdio console driver\n"); - lines_init(vts, ARRAY_SIZE(vts), &opts); - new_title = add_xterm_umid(opts.xterm_title); if(new_title != NULL) opts.xterm_title = new_title; + lines_init(vts, ARRAY_SIZE(vts), &opts); + con_init_done = 1; register_console(&stdiocons); return 0; diff --git a/trunk/arch/um/drivers/tty.c b/trunk/arch/um/drivers/tty.c index d95d64309eaf..c07d0d562780 100644 --- a/trunk/arch/um/drivers/tty.c +++ b/trunk/arch/um/drivers/tty.c @@ -8,7 +8,6 @@ #include #include #include "chan_user.h" -#include "user_util.h" #include "user.h" #include "os.h" #include "um_malloc.h" diff --git a/trunk/arch/um/drivers/ubd_kern.c b/trunk/arch/um/drivers/ubd_kern.c index 8bd9204ac1ab..70509ddaac03 100644 --- a/trunk/arch/um/drivers/ubd_kern.c +++ b/trunk/arch/um/drivers/ubd_kern.c @@ -39,7 +39,6 @@ #include "asm/irq.h" #include "asm/types.h" #include "asm/tlbflush.h" -#include "user_util.h" #include "mem_user.h" #include "kern_util.h" #include "kern.h" @@ -90,7 +89,7 @@ static inline int ubd_test_bit(__u64 bit, unsigned char *data) bits = sizeof(data[0]) * 8; n = bit / bits; off = bit % bits; - return((data[n] & (1 << off)) != 0); + return (data[n] & (1 << off)) != 0; } static inline void ubd_set_bit(__u64 bit, unsigned char *data) @@ -147,10 +146,13 @@ struct cow { unsigned long *bitmap; unsigned long bitmap_len; int bitmap_offset; - int data_offset; + int data_offset; }; +#define MAX_SG 64 + struct ubd { + struct list_head restart; /* name (and fd, below) of the file opened for writing, either the * backing or the cow file. */ char *file; @@ -165,15 +167,17 @@ struct ubd { struct platform_device pdev; struct request_queue *queue; spinlock_t lock; - int active; + struct scatterlist sg[MAX_SG]; + struct request *request; + int start_sg, end_sg; }; #define DEFAULT_COW { \ .file = NULL, \ - .fd = -1, \ - .bitmap = NULL, \ + .fd = -1, \ + .bitmap = NULL, \ .bitmap_offset = 0, \ - .data_offset = 0, \ + .data_offset = 0, \ } #define DEFAULT_UBD { \ @@ -183,11 +187,13 @@ struct ubd { .size = -1, \ .boot_openflags = OPEN_FLAGS, \ .openflags = OPEN_FLAGS, \ - .no_cow = 0, \ + .no_cow = 0, \ .shared = 0, \ - .cow = DEFAULT_COW, \ + .cow = DEFAULT_COW, \ .lock = SPIN_LOCK_UNLOCKED, \ - .active = 0, \ + .request = NULL, \ + .start_sg = 0, \ + .end_sg = 0, \ } /* Protected by ubd_lock */ @@ -243,7 +249,7 @@ static void make_ide_entries(char *dev_name) static int fake_ide_setup(char *str) { fake_ide = 1; - return(1); + return 1; } __setup("fake_ide", fake_ide_setup); @@ -261,7 +267,7 @@ static int parse_unit(char **ptr) if(isdigit(*str)) { n = simple_strtoul(str, &end, 0); if(end == str) - return(-1); + return -1; *ptr = end; } else if (('a' <= *str) && (*str <= 'z')) { @@ -269,7 +275,7 @@ static int parse_unit(char **ptr) str++; *ptr = str; } - return(n); + return n; } /* If *index_out == -1 at exit, the passed option was a general one; @@ -436,7 +442,7 @@ static int udb_setup(char *str) { printk("udb%s specified on command line is almost certainly a ubd -> " "udb TYPO\n", str); - return(1); + return 1; } __setup("udb", udb_setup); @@ -467,66 +473,75 @@ static void do_ubd_request(request_queue_t * q); /* Only changed by ubd_init, which is an initcall. */ int thread_fd = -1; -/* call ubd_finish if you need to serialize */ -static void __ubd_finish(struct request *req, int error) +static void ubd_end_request(struct request *req, int bytes, int uptodate) { - int nsect; - - if(error){ - end_request(req, 0); - return; + if (!end_that_request_first(req, uptodate, bytes >> 9)) { + struct ubd *dev = req->rq_disk->private_data; + unsigned long flags; + + add_disk_randomness(req->rq_disk); + spin_lock_irqsave(&dev->lock, flags); + end_that_request_last(req, uptodate); + spin_unlock_irqrestore(&dev->lock, flags); } - nsect = req->current_nr_sectors; - req->sector += nsect; - req->buffer += nsect << 9; - req->errors = 0; - req->nr_sectors -= nsect; - req->current_nr_sectors = 0; - end_request(req, 1); } /* Callable only from interrupt context - otherwise you need to do * spin_lock_irq()/spin_lock_irqsave() */ -static inline void ubd_finish(struct request *req, int error) +static inline void ubd_finish(struct request *req, int bytes) { - struct ubd *dev = req->rq_disk->private_data; - - spin_lock(&dev->lock); - __ubd_finish(req, error); - spin_unlock(&dev->lock); + if(bytes < 0){ + ubd_end_request(req, 0, 0); + return; + } + ubd_end_request(req, bytes, 1); } +static LIST_HEAD(restart); + /* XXX - move this inside ubd_intr. */ /* Called without dev->lock held, and only in interrupt context. */ static void ubd_handler(void) { - struct io_thread_req req; + struct io_thread_req *req; struct request *rq; - struct ubd *dev; + struct ubd *ubd; + struct list_head *list, *next_ele; + unsigned long flags; int n; - n = os_read_file(thread_fd, &req, sizeof(req)); - if(n != sizeof(req)){ - printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " - "err = %d\n", os_getpid(), -n); - return; - } - - rq = req.req; - dev = rq->rq_disk->private_data; - dev->active = 0; + while(1){ + n = os_read_file(thread_fd, &req, + sizeof(struct io_thread_req *)); + if(n != sizeof(req)){ + if(n == -EAGAIN) + break; + printk(KERN_ERR "spurious interrupt in ubd_handler, " + "err = %d\n", -n); + return; + } - ubd_finish(rq, req.error); + rq = req->req; + rq->nr_sectors -= req->length >> 9; + if(rq->nr_sectors == 0) + ubd_finish(rq, rq->hard_nr_sectors << 9); + kfree(req); + } reactivate_fd(thread_fd, UBD_IRQ); - spin_lock(&dev->lock); - do_ubd_request(dev->queue); - spin_unlock(&dev->lock); + + list_for_each_safe(list, next_ele, &restart){ + ubd = container_of(list, struct ubd, restart); + list_del_init(&ubd->restart); + spin_lock_irqsave(&ubd->lock, flags); + do_ubd_request(ubd->queue); + spin_unlock_irqrestore(&ubd->lock, flags); + } } static irqreturn_t ubd_intr(int irq, void *dev) { ubd_handler(); - return(IRQ_HANDLED); + return IRQ_HANDLED; } /* Only changed by ubd_init, which is an initcall. */ @@ -545,7 +560,7 @@ static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out) char *file; file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file; - return(os_file_size(file, size_out)); + return os_file_size(file, size_out); } static void ubd_close_dev(struct ubd *ubd_dev) @@ -617,10 +632,18 @@ static int ubd_open_dev(struct ubd *ubd_dev) if(err < 0) goto error; ubd_dev->cow.fd = err; } - return(0); + return 0; error: os_close_file(ubd_dev->fd); - return(err); + return err; +} + +static void ubd_device_release(struct device *dev) +{ + struct ubd *ubd_dev = dev->driver_data; + + blk_cleanup_queue(ubd_dev->queue); + *ubd_dev = ((struct ubd) DEFAULT_UBD); } static int ubd_disk_register(int major, u64 size, int unit, @@ -630,7 +653,7 @@ static int ubd_disk_register(int major, u64 size, int unit, disk = alloc_disk(1 << UBD_SHIFT); if(disk == NULL) - return(-ENOMEM); + return -ENOMEM; disk->major = major; disk->first_minor = unit << UBD_SHIFT; @@ -645,6 +668,8 @@ static int ubd_disk_register(int major, u64 size, int unit, if (major == MAJOR_NR) { ubd_devs[unit].pdev.id = unit; ubd_devs[unit].pdev.name = DRIVER_NAME; + ubd_devs[unit].pdev.dev.release = ubd_device_release; + ubd_devs[unit].pdev.dev.driver_data = &ubd_devs[unit]; platform_device_register(&ubd_devs[unit].pdev); disk->driverfs_dev = &ubd_devs[unit].pdev.dev; } @@ -675,6 +700,8 @@ static int ubd_add(int n, char **error_out) ubd_dev->size = ROUND_BLOCK(ubd_dev->size); + INIT_LIST_HEAD(&ubd_dev->restart); + err = -ENOMEM; ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock); if (ubd_dev->queue == NULL) { @@ -683,6 +710,7 @@ static int ubd_add(int n, char **error_out) } ubd_dev->queue->queuedata = ubd_dev; + blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG); err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); if(err){ *error_out = "Failed to register device"; @@ -730,14 +758,14 @@ static int ubd_config(char *str, char **error_out) goto err_free; } - mutex_lock(&ubd_lock); + mutex_lock(&ubd_lock); ret = ubd_add(n, error_out); if (ret) ubd_devs[n].file = NULL; - mutex_unlock(&ubd_lock); + mutex_unlock(&ubd_lock); out: - return ret; + return ret; err_free: kfree(str); @@ -752,7 +780,7 @@ static int ubd_get_config(char *name, char *str, int size, char **error_out) n = parse_unit(&name); if((n >= MAX_DEV) || (n < 0)){ *error_out = "ubd_get_config : device number out of range"; - return(-1); + return -1; } ubd_dev = &ubd_devs[n]; @@ -773,29 +801,27 @@ static int ubd_get_config(char *name, char *str, int size, char **error_out) out: mutex_unlock(&ubd_lock); - return(len); + return len; } static int ubd_id(char **str, int *start_out, int *end_out) { - int n; + int n; n = parse_unit(str); - *start_out = 0; - *end_out = MAX_DEV - 1; - return n; + *start_out = 0; + *end_out = MAX_DEV - 1; + return n; } static int ubd_remove(int n, char **error_out) { + struct gendisk *disk = ubd_gendisk[n]; struct ubd *ubd_dev; int err = -ENODEV; mutex_lock(&ubd_lock); - if(ubd_gendisk[n] == NULL) - goto out; - ubd_dev = &ubd_devs[n]; if(ubd_dev->file == NULL) @@ -806,9 +832,11 @@ static int ubd_remove(int n, char **error_out) if(ubd_dev->count > 0) goto out; - del_gendisk(ubd_gendisk[n]); - put_disk(ubd_gendisk[n]); ubd_gendisk[n] = NULL; + if(disk != NULL){ + del_gendisk(disk); + put_disk(disk); + } if(fake_gendisk[n] != NULL){ del_gendisk(fake_gendisk[n]); @@ -816,10 +844,8 @@ static int ubd_remove(int n, char **error_out) fake_gendisk[n] = NULL; } - blk_cleanup_queue(ubd_dev->queue); - platform_device_unregister(&ubd_dev->pdev); - *ubd_dev = ((struct ubd) DEFAULT_UBD); err = 0; + platform_device_unregister(&ubd_dev->pdev); out: mutex_unlock(&ubd_lock); return err; @@ -832,7 +858,7 @@ static struct mc_device ubd_mc = { .list = LIST_HEAD_INIT(ubd_mc.list), .name = "ubd", .config = ubd_config, - .get_config = ubd_get_config, + .get_config = ubd_get_config, .id = ubd_id, .remove = ubd_remove, }; @@ -854,7 +880,7 @@ static int __init ubd0_init(void) ubd_dev->file = "root_fs"; mutex_unlock(&ubd_lock); - return(0); + return 0; } __initcall(ubd0_init); @@ -882,14 +908,14 @@ static int __init ubd_init(void) return -1; } platform_driver_register(&ubd_driver); - mutex_lock(&ubd_lock); + mutex_lock(&ubd_lock); for (i = 0; i < MAX_DEV; i++){ err = ubd_add(i, &error); if(err) printk(KERN_ERR "Failed to initialize ubd device %d :" "%s\n", i, error); } - mutex_unlock(&ubd_lock); + mutex_unlock(&ubd_lock); return 0; } @@ -913,7 +939,7 @@ static int __init ubd_driver_init(void){ "ubd : Failed to start I/O thread (errno = %d) - " "falling back to synchronous I/O\n", -io_pid); io_pid = -1; - return(0); + return 0; } err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, IRQF_DISABLED, "ubd", ubd_devs); @@ -948,7 +974,7 @@ static int ubd_open(struct inode *inode, struct file *filp) err = -EROFS; }*/ out: - return(err); + return err; } static int ubd_release(struct inode * inode, struct file * file) @@ -958,7 +984,7 @@ static int ubd_release(struct inode * inode, struct file * file) if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev); - return(0); + return 0; } static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, @@ -1014,7 +1040,7 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) ubd_set_bit(i, (unsigned char *) &req->sector_mask); - } + } } else cowify_bitmap(req->offset, req->length, &req->sector_mask, &req->cow_offset, bitmap, bitmap_offset, @@ -1022,26 +1048,16 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, } /* Called with dev->lock held */ -static int prepare_request(struct request *req, struct io_thread_req *io_req) +static void prepare_request(struct request *req, struct io_thread_req *io_req, + unsigned long long offset, int page_offset, + int len, struct page *page) { struct gendisk *disk = req->rq_disk; struct ubd *ubd_dev = disk->private_data; - __u64 offset; - int len; - - /* This should be impossible now */ - if((rq_data_dir(req) == WRITE) && !ubd_dev->openflags.w){ - printk("Write attempted on readonly ubd device %s\n", - disk->disk_name); - end_request(req, 0); - return(1); - } - - offset = ((__u64) req->sector) << 9; - len = req->current_nr_sectors << 9; io_req->req = req; - io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd; + io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : + ubd_dev->fd; io_req->fds[1] = ubd_dev->fd; io_req->cow_offset = -1; io_req->offset = offset; @@ -1052,45 +1068,66 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; io_req->offsets[0] = 0; io_req->offsets[1] = ubd_dev->cow.data_offset; - io_req->buffer = req->buffer; + io_req->buffer = page_address(page) + page_offset; io_req->sectorsize = 1 << 9; if(ubd_dev->cow.file != NULL) - cowify_req(io_req, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset, - ubd_dev->cow.bitmap_len); + cowify_req(io_req, ubd_dev->cow.bitmap, + ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len); - return(0); } /* Called with dev->lock held */ static void do_ubd_request(request_queue_t *q) { - struct io_thread_req io_req; + struct io_thread_req *io_req; struct request *req; - int err, n; - - if(thread_fd == -1){ - while((req = elv_next_request(q)) != NULL){ - err = prepare_request(req, &io_req); - if(!err){ - do_io(&io_req); - __ubd_finish(req, io_req.error); - } - } - } - else { + int n; + + while(1){ struct ubd *dev = q->queuedata; - if(dev->active || (req = elv_next_request(q)) == NULL) - return; - err = prepare_request(req, &io_req); - if(!err){ - dev->active = 1; - n = os_write_file(thread_fd, (char *) &io_req, - sizeof(io_req)); - if(n != sizeof(io_req)) - printk("write to io thread failed, " - "errno = %d\n", -n); + if(dev->end_sg == 0){ + struct request *req = elv_next_request(q); + if(req == NULL) + return; + + dev->request = req; + blkdev_dequeue_request(req); + dev->start_sg = 0; + dev->end_sg = blk_rq_map_sg(q, req, dev->sg); } + + req = dev->request; + while(dev->start_sg < dev->end_sg){ + struct scatterlist *sg = &dev->sg[dev->start_sg]; + + io_req = kmalloc(sizeof(struct io_thread_req), + GFP_ATOMIC); + if(io_req == NULL){ + if(list_empty(&dev->restart)) + list_add(&dev->restart, &restart); + return; + } + prepare_request(req, io_req, + (unsigned long long) req->sector << 9, + sg->offset, sg->length, sg->page); + + n = os_write_file(thread_fd, &io_req, + sizeof(struct io_thread_req *)); + if(n != sizeof(struct io_thread_req *)){ + if(n != -EAGAIN) + printk("write to io thread failed, " + "errno = %d\n", -n); + else if(list_empty(&dev->restart)) + list_add(&dev->restart, &restart); + return; + } + + req->sector += sg->length >> 9; + dev->start_sg++; + } + dev->end_sg = 0; + dev->request = NULL; } } @@ -1120,21 +1157,21 @@ static int ubd_ioctl(struct inode * inode, struct file * file, ubd_id.cyls = ubd_dev->size / (128 * 32 * 512); if(copy_to_user((char __user *) arg, (char *) &ubd_id, sizeof(ubd_id))) - return(-EFAULT); - return(0); + return -EFAULT; + return 0; case CDROMVOLREAD: if(copy_from_user(&volume, (char __user *) arg, sizeof(volume))) - return(-EFAULT); + return -EFAULT; volume.channel0 = 255; volume.channel1 = 255; volume.channel2 = 255; volume.channel3 = 255; if(copy_to_user((char __user *) arg, &volume, sizeof(volume))) - return(-EFAULT); - return(0); + return -EFAULT; + return 0; } - return(-EINVAL); + return -EINVAL; } static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow) @@ -1176,29 +1213,29 @@ static int backing_file_mismatch(char *file, __u64 size, time_t mtime) if(err < 0){ printk("Failed to get modification time of backing file " "\"%s\", err = %d\n", file, -err); - return(err); + return err; } err = os_file_size(file, &actual); if(err < 0){ printk("Failed to get size of backing file \"%s\", " "err = %d\n", file, -err); - return(err); + return err; } - if(actual != size){ + if(actual != size){ /*__u64 can be a long on AMD64 and with %lu GCC complains; so * the typecast.*/ printk("Size mismatch (%llu vs %llu) of COW header vs backing " "file\n", (unsigned long long) size, actual); - return(-EINVAL); + return -EINVAL; } if(modtime != mtime){ printk("mtime mismatch (%ld vs %ld) of COW header vs backing " "file\n", mtime, modtime); - return(-EINVAL); + return -EINVAL; } - return(0); + return 0; } int read_cow_bitmap(int fd, void *buf, int offset, int len) @@ -1207,13 +1244,13 @@ int read_cow_bitmap(int fd, void *buf, int offset, int len) err = os_seek_file(fd, offset); if(err < 0) - return(err); + return err; err = os_read_file(fd, buf, len); if(err < 0) - return(err); + return err; - return(0); + return 0; } int open_ubd_file(char *file, struct openflags *openflags, int shared, @@ -1231,14 +1268,14 @@ int open_ubd_file(char *file, struct openflags *openflags, int shared, if (fd < 0) { if ((fd == -ENOENT) && (create_cow_out != NULL)) *create_cow_out = 1; - if (!openflags->w || - ((fd != -EROFS) && (fd != -EACCES))) + if (!openflags->w || + ((fd != -EROFS) && (fd != -EACCES))) return fd; openflags->w = 0; fd = os_open_file(file, *openflags, mode); if (fd < 0) return fd; - } + } if(shared) printk("Not locking \"%s\" on the host\n", file); @@ -1252,7 +1289,7 @@ int open_ubd_file(char *file, struct openflags *openflags, int shared, /* Successful return case! */ if(backing_file_out == NULL) - return(fd); + return fd; err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, &size, §orsize, &align, bitmap_offset_out); @@ -1262,7 +1299,7 @@ int open_ubd_file(char *file, struct openflags *openflags, int shared, goto out_close; } if(err) - return(fd); + return fd; asked_switch = path_requires_switch(*backing_file_out, backing_file, file); @@ -1285,7 +1322,7 @@ int open_ubd_file(char *file, struct openflags *openflags, int shared, cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, bitmap_len_out, data_offset_out); - return fd; + return fd; out_close: os_close_file(fd); return err; @@ -1310,10 +1347,10 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, bitmap_offset_out, bitmap_len_out, data_offset_out); if(!err) - return(fd); + return fd; os_close_file(fd); out: - return(err); + return err; } static int update_bitmap(struct io_thread_req *req) @@ -1321,23 +1358,23 @@ static int update_bitmap(struct io_thread_req *req) int n; if(req->cow_offset == -1) - return(0); + return 0; n = os_seek_file(req->fds[1], req->cow_offset); if(n < 0){ printk("do_io - bitmap lseek failed : err = %d\n", -n); - return(1); + return 1; } n = os_write_file(req->fds[1], &req->bitmap_words, - sizeof(req->bitmap_words)); + sizeof(req->bitmap_words)); if(n != sizeof(req->bitmap_words)){ printk("do_io - bitmap update failed, err = %d fd = %d\n", -n, req->fds[1]); - return(1); + return 1; } - return(0); + return 0; } void do_io(struct io_thread_req *req) @@ -1409,13 +1446,14 @@ static int io_count = 0; int io_thread(void *arg) { - struct io_thread_req req; + struct io_thread_req *req; int n; ignore_sigwinch_sig(); while(1){ - n = os_read_file(kernel_fd, &req, sizeof(req)); - if(n != sizeof(req)){ + n = os_read_file(kernel_fd, &req, + sizeof(struct io_thread_req *)); + if(n != sizeof(struct io_thread_req *)){ if(n < 0) printk("io_thread - read failed, fd = %d, " "err = %d\n", kernel_fd, -n); @@ -1426,9 +1464,10 @@ int io_thread(void *arg) continue; } io_count++; - do_io(&req); - n = os_write_file(kernel_fd, &req, sizeof(req)); - if(n != sizeof(req)) + do_io(req); + n = os_write_file(kernel_fd, &req, + sizeof(struct io_thread_req *)); + if(n != sizeof(struct io_thread_req *)) printk("io_thread - write failed, fd = %d, err = %d\n", kernel_fd, -n); } diff --git a/trunk/arch/um/drivers/ubd_user.c b/trunk/arch/um/drivers/ubd_user.c index b94d2bc4fe06..4707b3f14c2f 100644 --- a/trunk/arch/um/drivers/ubd_user.c +++ b/trunk/arch/um/drivers/ubd_user.c @@ -16,7 +16,6 @@ #include #include #include "asm/types.h" -#include "user_util.h" #include "kern_util.h" #include "user.h" #include "ubd_user.h" @@ -47,8 +46,8 @@ int start_io_thread(unsigned long sp, int *fd_out) pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, NULL); if(pid < 0){ - printk("start_io_thread - clone failed : errno = %d\n", errno); err = -errno; + printk("start_io_thread - clone failed : errno = %d\n", errno); goto out_close; } @@ -60,16 +59,5 @@ int start_io_thread(unsigned long sp, int *fd_out) kernel_fd = -1; *fd_out = -1; out: - return(err); + return err; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/drivers/xterm.c b/trunk/arch/um/drivers/xterm.c index 850221d9b4c9..571c2b3325d5 100644 --- a/trunk/arch/um/drivers/xterm.c +++ b/trunk/arch/um/drivers/xterm.c @@ -14,7 +14,6 @@ #include #include "kern_util.h" #include "chan_user.h" -#include "user_util.h" #include "user.h" #include "os.h" #include "xterm.h" diff --git a/trunk/arch/um/include/arch.h b/trunk/arch/um/include/arch.h new file mode 100644 index 000000000000..10ad52daa8c5 --- /dev/null +++ b/trunk/arch/um/include/arch.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __ARCH_H__ +#define __ARCH_H__ + +#include "sysdep/ptrace.h" + +extern void arch_check_bugs(void); +extern int arch_fixup(unsigned long address, union uml_pt_regs *regs); +extern int arch_handle_signal(int sig, union uml_pt_regs *regs); + +#endif diff --git a/trunk/arch/um/include/as-layout.h b/trunk/arch/um/include/as-layout.h new file mode 100644 index 000000000000..fccf187bf4e1 --- /dev/null +++ b/trunk/arch/um/include/as-layout.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + +#ifndef __START_H__ +#define __START_H__ + +#include "sysdep/ptrace.h" + +struct cpu_task { + int pid; + void *task; +}; + +extern struct cpu_task cpu_tasks[]; + +extern unsigned long low_physmem; +extern unsigned long high_physmem; +extern unsigned long uml_physmem; +extern unsigned long uml_reserved; +extern unsigned long end_vm; +extern unsigned long start_vm; +extern unsigned long long highmem; + +extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; +extern unsigned long _unprotected_end; +extern unsigned long brk_start; + +extern int linux_main(int argc, char **argv); +extern void set_cmdline(char *cmd); + +extern void (*sig_info[])(int, union uml_pt_regs *); + +#endif diff --git a/trunk/arch/um/include/common-offsets.h b/trunk/arch/um/include/common-offsets.h index 461175f8b1d9..5593a8027083 100644 --- a/trunk/arch/um/include/common-offsets.h +++ b/trunk/arch/um/include/common-offsets.h @@ -24,5 +24,7 @@ DEFINE(UM_ELF_CLASS, ELF_CLASS); DEFINE(UM_ELFCLASS32, ELFCLASS32); DEFINE(UM_ELFCLASS64, ELFCLASS64); +DEFINE(UM_NR_CPUS, NR_CPUS); + /* For crypto assembler code. */ DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); diff --git a/trunk/arch/um/include/kern_util.h b/trunk/arch/um/include/kern_util.h index 173af029d12b..50a49691e0e6 100644 --- a/trunk/arch/um/include/kern_util.h +++ b/trunk/arch/um/include/kern_util.h @@ -8,6 +8,7 @@ #include "sysdep/ptrace.h" #include "sysdep/faultinfo.h" +#include "uml-config.h" typedef void (*kern_hndl)(int, union uml_pt_regs *); @@ -23,7 +24,6 @@ struct kern_handlers { extern const struct kern_handlers handlinfo_kern; extern int ncpus; -extern char *linux_prog; extern char *gdb_init; extern int kmalloc_ok; extern int jail; @@ -34,7 +34,9 @@ extern int nsyscalls; UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1) extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg); +#ifdef UML_CONFIG_MODE_TT extern unsigned long stack_sp(unsigned long page); +#endif extern int kernel_thread_proc(void *data); extern void syscall_segv(int sig); extern int current_pid(void); @@ -42,7 +44,7 @@ extern unsigned long alloc_stack(int order, int atomic); extern int do_signal(void); extern int is_stack_fault(unsigned long sp); extern unsigned long segv(struct faultinfo fi, unsigned long ip, - int is_user, void *sc); + int is_user, union uml_pt_regs *regs); extern int handle_page_fault(unsigned long address, unsigned long ip, int is_write, int is_user, int *code_out); extern void syscall_ready(void); @@ -50,7 +52,6 @@ extern void set_tracing(void *t, int tracing); extern int is_tracing(void *task); extern int segv_syscall(void); extern void kern_finish_exec(void *task, int new_pid, unsigned long stack); -extern int page_size(void); extern unsigned long page_mask(void); extern int need_finish_fork(void); extern void free_stack(unsigned long stack, int order); @@ -58,7 +59,6 @@ extern void add_input_request(int op, void (*proc)(int), void *arg); extern char *current_cmd(void); extern void timer_handler(int sig, union uml_pt_regs *regs); extern int set_signals(int enable); -extern void force_sigbus(void); extern int pid_to_processor_id(int pid); extern void deliver_signals(void *t); extern int next_trap_index(int max); @@ -70,7 +70,6 @@ extern void *syscall_sp(void *t); extern void syscall_trace(union uml_pt_regs *regs, int entryexit); extern int hz(void); extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs); -extern int external_pid(void *t); extern void interrupt_end(void); extern void initial_thread_cb(void (*proc)(void *), void *arg); extern int debugger_signal(int status, int pid); @@ -81,7 +80,6 @@ extern int init_parent_proxy(int pid); extern int singlestepping(void *t); extern void check_stack_overflow(void *ptr); extern void relay_signal(int sig, union uml_pt_regs *regs); -extern void not_implemented(void); extern int user_context(unsigned long sp); extern void timer_irq(union uml_pt_regs *regs); extern void unprotect_stack(unsigned long stack); @@ -93,7 +91,6 @@ extern char *uml_strdup(char *string); extern void unprotect_kernel_mem(void); extern void protect_kernel_mem(void); extern void uml_cleanup(void); -extern void set_current(void *t); extern void lock_signalled_task(void *t); extern void IPI_handler(int cpu); extern int jail_setup(char *line, int *add); @@ -118,4 +115,6 @@ extern void time_init_kern(void); extern int __cant_sleep(void); extern void sigio_handler(int sig, union uml_pt_regs *regs); +extern void copy_sc(union uml_pt_regs *regs, void *from); + #endif diff --git a/trunk/arch/um/include/net_kern.h b/trunk/arch/um/include/net_kern.h index 125ab42df18a..9237056b9103 100644 --- a/trunk/arch/um/include/net_kern.h +++ b/trunk/arch/um/include/net_kern.h @@ -40,7 +40,7 @@ struct uml_net_private { void (*add_address)(unsigned char *, unsigned char *, void *); void (*delete_address)(unsigned char *, unsigned char *, void *); int (*set_mtu)(int mtu, void *); - int user[1]; + char user[0]; }; struct net_kern_info { diff --git a/trunk/arch/um/include/net_user.h b/trunk/arch/um/include/net_user.h index 19f207cd70fe..cfe7c50634b9 100644 --- a/trunk/arch/um/include/net_user.h +++ b/trunk/arch/um/include/net_user.h @@ -14,7 +14,7 @@ #define UML_NET_VERSION (4) struct net_user_info { - void (*init)(void *, void *); + int (*init)(void *, void *); int (*open)(void *); void (*close)(int, void *); void (*remove)(void *); diff --git a/trunk/arch/um/include/os.h b/trunk/arch/um/include/os.h index 5c74da410451..688d181b5f8a 100644 --- a/trunk/arch/um/include/os.h +++ b/trunk/arch/um/include/os.h @@ -16,6 +16,8 @@ #include "sysdep/tls.h" #include "sysdep/archsetjmp.h" +#define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR)) + #define OS_TYPE_FILE 1 #define OS_TYPE_DIR 2 #define OS_TYPE_SYMLINK 3 @@ -273,8 +275,9 @@ extern void stack_protections(unsigned long address); extern void task_protections(unsigned long address); extern int raw(int fd); extern void setup_machinename(char *machine_out); -extern void setup_hostinfo(void); +extern void setup_hostinfo(char *buf, int len); extern int setjmp_wrapper(void (*proc)(void *, void *), ...); +extern void os_dump_core(void); /* time.c */ #define BILLION (1000 * 1000 * 1000) @@ -297,13 +300,12 @@ extern long syscall_stub_data(struct mm_id * mm_idp, unsigned long *data, int data_count, void **addr, void **stub_addr); extern int map(struct mm_id * mm_idp, unsigned long virt, - unsigned long len, int r, int w, int x, int phys_fd, + unsigned long len, int prot, int phys_fd, unsigned long long offset, int done, void **data); -extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, +extern int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, int done, void **data); extern int protect(struct mm_id * mm_idp, unsigned long addr, - unsigned long len, int r, int w, int x, int done, - void **data); + unsigned long len, unsigned int prot, int done, void **data); /* skas/process.c */ extern int is_skas_winch(int pid, int fd, void *data); @@ -339,8 +341,11 @@ extern void maybe_sigio_broken(int fd, int read); /* skas/trap */ extern void sig_handler_common_skas(int sig, void *sc_ptr); -extern void user_signal(int sig, union uml_pt_regs *regs, int pid); +/* sys-x86_64/prctl.c */ extern int os_arch_prctl(int pid, int code, unsigned long *addr); +/* tty.c */ +int get_pty(void); + #endif diff --git a/trunk/arch/um/include/skas/mode_kern_skas.h b/trunk/arch/um/include/skas/mode_kern_skas.h index 9cd9c6ec9a63..8ee6285dfacc 100644 --- a/trunk/arch/um/include/skas/mode_kern_skas.h +++ b/trunk/arch/um/include/skas/mode_kern_skas.h @@ -33,6 +33,8 @@ extern unsigned long set_task_sizes_skas(unsigned long *task_size_out); extern int start_uml_skas(void); extern int external_pid_skas(struct task_struct *task); extern int thread_pid_skas(struct task_struct *task); +extern void flush_tlb_page_skas(struct vm_area_struct *vma, + unsigned long address); #define kmem_end_skas (host_task_size - 1024 * 1024) diff --git a/trunk/arch/um/include/tlb.h b/trunk/arch/um/include/tlb.h index 8efc1e0f1b84..bcd1a4afb842 100644 --- a/trunk/arch/um/include/tlb.h +++ b/trunk/arch/um/include/tlb.h @@ -14,9 +14,7 @@ struct host_vm_op { struct { unsigned long addr; unsigned long len; - unsigned int r:1; - unsigned int w:1; - unsigned int x:1; + unsigned int prot; int fd; __u64 offset; } mmap; @@ -27,9 +25,7 @@ struct host_vm_op { struct { unsigned long addr; unsigned long len; - unsigned int r:1; - unsigned int w:1; - unsigned int x:1; + unsigned int prot; } mprotect; } u; }; diff --git a/trunk/arch/um/include/tt/uaccess-tt.h b/trunk/arch/um/include/tt/uaccess-tt.h index b19645f32f24..13a64f61fcf4 100644 --- a/trunk/arch/um/include/tt/uaccess-tt.h +++ b/trunk/arch/um/include/tt/uaccess-tt.h @@ -27,8 +27,6 @@ extern unsigned long uml_physmem; #define access_ok_tt(type, addr, size) \ (is_stack(addr, size)) -extern unsigned long get_fault_addr(void); - extern int __do_copy_from_user(void *to, const void *from, int n, void **fault_addr, void **fault_catcher); extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, diff --git a/trunk/arch/um/include/um_malloc.h b/trunk/arch/um/include/um_malloc.h index 0363a9b53f8d..e6d7c5aa3f4e 100644 --- a/trunk/arch/um/include/um_malloc.h +++ b/trunk/arch/um/include/um_malloc.h @@ -11,7 +11,6 @@ extern void *um_kmalloc_atomic(int size); extern void kfree(const void *ptr); extern void *um_vmalloc(int size); -extern void *um_vmalloc_atomic(int size); extern void vfree(void *ptr); #endif /* __UM_MALLOC_H__ */ diff --git a/trunk/arch/um/include/user.h b/trunk/arch/um/include/user.h index acadce3f271f..d380e6d91a90 100644 --- a/trunk/arch/um/include/user.h +++ b/trunk/arch/um/include/user.h @@ -6,6 +6,19 @@ #ifndef __USER_H__ #define __USER_H__ +/* + * The usual definition - copied here because the kernel provides its own, + * fancier, type-safe, definition. Using that one would require + * copying too much infrastructure for my taste, so userspace files + * get less checking than kernel files. + */ +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/* + * This will provide the size_t definition in both kernel and userspace builds + */ +#include + extern void panic(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); extern int printk(const char *fmt, ...) @@ -13,19 +26,7 @@ extern int printk(const char *fmt, ...) extern void schedule(void); extern int in_aton(char *str); extern int open_gdb_chan(void); -/* These use size_t, however unsigned long is correct on both i386 and x86_64. */ -extern unsigned long strlcpy(char *, const char *, unsigned long); -extern unsigned long strlcat(char *, const char *, unsigned long); +extern size_t strlcpy(char *, const char *, size_t); +extern size_t strlcat(char *, const char *, size_t); #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/include/user_util.h b/trunk/arch/um/include/user_util.h deleted file mode 100644 index 023575f67343..000000000000 --- a/trunk/arch/um/include/user_util.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __USER_UTIL_H__ -#define __USER_UTIL_H__ - -#include "sysdep/ptrace.h" - -/* Copied from kernel.h */ -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -#define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR)) - -extern int mode_tt; - -extern int grantpt(int __fd); -extern int unlockpt(int __fd); -extern char *ptsname(int __fd); - -struct cpu_task { - int pid; - void *task; -}; - -extern struct cpu_task cpu_tasks[]; - -extern void (*sig_info[])(int, union uml_pt_regs *); - -extern unsigned long low_physmem; -extern unsigned long high_physmem; -extern unsigned long uml_physmem; -extern unsigned long uml_reserved; -extern unsigned long end_vm; -extern unsigned long start_vm; -extern unsigned long long highmem; - -extern char host_info[]; - -extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; -extern unsigned long _unprotected_end; -extern unsigned long brk_start; - -extern int pty_output_sigio; -extern int pty_close_sigio; - -extern void *add_signal_handler(int sig, void (*handler)(int)); -extern int linux_main(int argc, char **argv); -extern void set_cmdline(char *cmd); -extern void input_cb(void (*proc)(void *), void *arg, int arg_len); -extern int get_pty(void); -extern int switcheroo(int fd, int prot, void *from, void *to, int size); -extern void do_exec(int old_pid, int new_pid); -extern void tracer_panic(char *msg, ...) - __attribute__ ((format (printf, 1, 2))); -extern int detach(int pid, int sig); -extern int attach(int pid); -extern void kill_child_dead(int pid); -extern int cont(int pid); -extern void check_sigio(void); -extern void arch_check_bugs(void); -extern int cpu_feature(char *what, char *buf, int len); -extern int arch_handle_signal(int sig, union uml_pt_regs *regs); -extern int arch_fixup(unsigned long address, void *sc_ptr); -extern void arch_init_thread(void); -extern int raw(int fd); - -#endif diff --git a/trunk/arch/um/kernel/exec.c b/trunk/arch/um/kernel/exec.c index 121166400e25..356e50f5aaed 100644 --- a/trunk/arch/um/kernel/exec.c +++ b/trunk/arch/um/kernel/exec.c @@ -10,8 +10,8 @@ #include "asm/pgtable.h" #include "asm/tlbflush.h" #include "asm/uaccess.h" -#include "user_util.h" #include "kern_util.h" +#include "as-layout.h" #include "mem_user.h" #include "kern.h" #include "irq_user.h" diff --git a/trunk/arch/um/kernel/init_task.c b/trunk/arch/um/kernel/init_task.c index 8cde431348cc..cda91aa8e703 100644 --- a/trunk/arch/um/kernel/init_task.c +++ b/trunk/arch/um/kernel/init_task.c @@ -10,7 +10,6 @@ #include "linux/mqueue.h" #include "asm/uaccess.h" #include "asm/pgtable.h" -#include "user_util.h" #include "mem_user.h" #include "os.h" diff --git a/trunk/arch/um/kernel/initrd.c b/trunk/arch/um/kernel/initrd.c index 82ecf904b09c..16dc43e9d940 100644 --- a/trunk/arch/um/kernel/initrd.c +++ b/trunk/arch/um/kernel/initrd.c @@ -7,7 +7,6 @@ #include "linux/bootmem.h" #include "linux/initrd.h" #include "asm/types.h" -#include "user_util.h" #include "kern_util.h" #include "initrd.h" #include "init.h" @@ -22,12 +21,20 @@ static int __init read_initrd(void) long long size; int err; - if(initrd == NULL) return 0; + if(initrd == NULL) + return 0; + err = os_file_size(initrd, &size); - if(err) return 0; + if(err) + return 0; + area = alloc_bootmem(size); - if(area == NULL) return 0; - if(load_initrd(initrd, area, size) == -1) return 0; + if(area == NULL) + return 0; + + if(load_initrd(initrd, area, size) == -1) + return 0; + initrd_start = (unsigned long) area; initrd_end = initrd_start + size; return 0; @@ -54,25 +61,15 @@ int load_initrd(char *filename, void *buf, int size) fd = os_open_file(filename, of_read(OPENFLAGS()), 0); if(fd < 0){ printk("Opening '%s' failed - err = %d\n", filename, -fd); - return(-1); + return -1; } n = os_read_file(fd, buf, size); if(n != size){ printk("Read of %d bytes from '%s' failed, err = %d\n", size, filename, -n); - return(-1); + return -1; } os_close_file(fd); - return(0); + return 0; } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/kernel/irq.c b/trunk/arch/um/kernel/irq.c index dbf2f5bc842f..8f2ed3690315 100644 --- a/trunk/arch/um/kernel/irq.c +++ b/trunk/arch/um/kernel/irq.c @@ -25,7 +25,6 @@ #include "asm/system.h" #include "asm/errno.h" #include "asm/uaccess.h" -#include "user_util.h" #include "kern_util.h" #include "irq_user.h" #include "irq_kern.h" @@ -79,6 +78,14 @@ int show_interrupts(struct seq_file *p, void *v) return 0; } +/* + * This list is accessed under irq_lock, except in sigio_handler, + * where it is safe from being modified. IRQ handlers won't change it - + * if an IRQ source has vanished, it will be freed by free_irqs just + * before returning from sigio_handler. That will process a separate + * list of irqs to free, with its own locking, coming back here to + * remove list elements, taking the irq_lock to do so. + */ static struct irq_fd *active_fds = NULL; static struct irq_fd **last_irq_ptr = &active_fds; @@ -244,6 +251,7 @@ void free_irq_by_fd(int fd) free_irq_by_cb(same_fd, &fd); } +/* Must be called with irq_lock held */ static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) { struct irq_fd *irq; @@ -309,6 +317,12 @@ void deactivate_fd(int fd, int irqnum) ignore_sigio_fd(fd); } +/* + * Called just before shutdown in order to provide a clean exec + * environment in case the system is rebooting. No locking because + * that would cause a pointless shutdown hang if something hadn't + * released the lock. + */ int deactivate_all_fds(void) { struct irq_fd *irq; diff --git a/trunk/arch/um/kernel/ksyms.c b/trunk/arch/um/kernel/ksyms.c index 0e00cf93f900..7b3e53fb8070 100644 --- a/trunk/arch/um/kernel/ksyms.c +++ b/trunk/arch/um/kernel/ksyms.c @@ -16,7 +16,7 @@ #include "asm/page.h" #include "asm/tlbflush.h" #include "kern_util.h" -#include "user_util.h" +#include "as-layout.h" #include "mem_user.h" #include "os.h" diff --git a/trunk/arch/um/kernel/mem.c b/trunk/arch/um/kernel/mem.c index df7d662b98ce..72ff85693a39 100644 --- a/trunk/arch/um/kernel/mem.c +++ b/trunk/arch/um/kernel/mem.c @@ -13,8 +13,8 @@ #include "asm/page.h" #include "asm/fixmap.h" #include "asm/pgalloc.h" -#include "user_util.h" #include "kern_util.h" +#include "as-layout.h" #include "kern.h" #include "mem_user.h" #include "uml_uaccess.h" @@ -216,7 +216,7 @@ static void __init fixaddr_user_init( void) #endif } -void paging_init(void) +void __init paging_init(void) { unsigned long zones_size[MAX_NR_ZONES], vaddr; int i; diff --git a/trunk/arch/um/kernel/physmem.c b/trunk/arch/um/kernel/physmem.c index 638f3b5f6094..3ba6e4c841da 100644 --- a/trunk/arch/um/kernel/physmem.c +++ b/trunk/arch/um/kernel/physmem.c @@ -13,7 +13,7 @@ #include "asm/types.h" #include "asm/pgtable.h" #include "kern_util.h" -#include "user_util.h" +#include "as-layout.h" #include "mode_kern.h" #include "mem.h" #include "mem_user.h" @@ -21,229 +21,8 @@ #include "kern.h" #include "init.h" -struct phys_desc { - struct rb_node rb; - int fd; - __u64 offset; - void *virt; - unsigned long phys; - struct list_head list; -}; - -static struct rb_root phys_mappings = RB_ROOT; - -static struct rb_node **find_rb(void *virt) -{ - struct rb_node **n = &phys_mappings.rb_node; - struct phys_desc *d; - - while(*n != NULL){ - d = rb_entry(*n, struct phys_desc, rb); - if(d->virt == virt) - return n; - - if(d->virt > virt) - n = &(*n)->rb_left; - else - n = &(*n)->rb_right; - } - - return n; -} - -static struct phys_desc *find_phys_mapping(void *virt) -{ - struct rb_node **n = find_rb(virt); - - if(*n == NULL) - return NULL; - - return rb_entry(*n, struct phys_desc, rb); -} - -static void insert_phys_mapping(struct phys_desc *desc) -{ - struct rb_node **n = find_rb(desc->virt); - - if(*n != NULL) - panic("Physical remapping for %p already present", - desc->virt); - - rb_link_node(&desc->rb, rb_parent(*n), n); - rb_insert_color(&desc->rb, &phys_mappings); -} - -LIST_HEAD(descriptor_mappings); - -struct desc_mapping { - int fd; - struct list_head list; - struct list_head pages; -}; - -static struct desc_mapping *find_mapping(int fd) -{ - struct desc_mapping *desc; - struct list_head *ele; - - list_for_each(ele, &descriptor_mappings){ - desc = list_entry(ele, struct desc_mapping, list); - if(desc->fd == fd) - return desc; - } - - return NULL; -} - -static struct desc_mapping *descriptor_mapping(int fd) -{ - struct desc_mapping *desc; - - desc = find_mapping(fd); - if(desc != NULL) - return desc; - - desc = kmalloc(sizeof(*desc), GFP_ATOMIC); - if(desc == NULL) - return NULL; - - *desc = ((struct desc_mapping) - { .fd = fd, - .list = LIST_HEAD_INIT(desc->list), - .pages = LIST_HEAD_INIT(desc->pages) }); - list_add(&desc->list, &descriptor_mappings); - - return desc; -} - -int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) -{ - struct desc_mapping *fd_maps; - struct phys_desc *desc; - unsigned long phys; - int err; - - fd_maps = descriptor_mapping(fd); - if(fd_maps == NULL) - return -ENOMEM; - - phys = __pa(virt); - desc = find_phys_mapping(virt); - if(desc != NULL) - panic("Address 0x%p is already substituted\n", virt); - - err = -ENOMEM; - desc = kmalloc(sizeof(*desc), GFP_ATOMIC); - if(desc == NULL) - goto out; - - *desc = ((struct phys_desc) - { .fd = fd, - .offset = offset, - .virt = virt, - .phys = __pa(virt), - .list = LIST_HEAD_INIT(desc->list) }); - insert_phys_mapping(desc); - - list_add(&desc->list, &fd_maps->pages); - - virt = (void *) ((unsigned long) virt & PAGE_MASK); - err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0); - if(!err) - goto out; - - rb_erase(&desc->rb, &phys_mappings); - kfree(desc); - out: - return err; -} - static int physmem_fd = -1; -static void remove_mapping(struct phys_desc *desc) -{ - void *virt = desc->virt; - int err; - - rb_erase(&desc->rb, &phys_mappings); - list_del(&desc->list); - kfree(desc); - - err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0); - if(err) - panic("Failed to unmap block device page from physical memory, " - "errno = %d", -err); -} - -int physmem_remove_mapping(void *virt) -{ - struct phys_desc *desc; - - virt = (void *) ((unsigned long) virt & PAGE_MASK); - desc = find_phys_mapping(virt); - if(desc == NULL) - return 0; - - remove_mapping(desc); - return 1; -} - -void physmem_forget_descriptor(int fd) -{ - struct desc_mapping *desc; - struct phys_desc *page; - struct list_head *ele, *next; - __u64 offset; - void *addr; - int err; - - desc = find_mapping(fd); - if(desc == NULL) - return; - - list_for_each_safe(ele, next, &desc->pages){ - page = list_entry(ele, struct phys_desc, list); - offset = page->offset; - addr = page->virt; - remove_mapping(page); - err = os_seek_file(fd, offset); - if(err) - panic("physmem_forget_descriptor - failed to seek " - "to %lld in fd %d, error = %d\n", - offset, fd, -err); - err = os_read_file(fd, addr, PAGE_SIZE); - if(err < 0) - panic("physmem_forget_descriptor - failed to read " - "from fd %d to 0x%p, error = %d\n", - fd, addr, -err); - } - - list_del(&desc->list); - kfree(desc); -} - -EXPORT_SYMBOL(physmem_forget_descriptor); -EXPORT_SYMBOL(physmem_remove_mapping); -EXPORT_SYMBOL(physmem_subst_mapping); - -void arch_free_page(struct page *page, int order) -{ - void *virt; - int i; - - for(i = 0; i < (1 << order); i++){ - virt = __va(page_to_phys(page + i)); - physmem_remove_mapping(virt); - } -} - -int is_remapped(void *virt) -{ - struct phys_desc *desc = find_phys_mapping(virt); - - return desc != NULL; -} - /* Changed during early boot */ unsigned long high_physmem; @@ -350,14 +129,9 @@ void setup_physmem(unsigned long start, unsigned long reserve_end, int phys_mapping(unsigned long phys, __u64 *offset_out) { - struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK)); int fd = -1; - if(desc != NULL){ - fd = desc->fd; - *offset_out = desc->offset; - } - else if(phys < physmem_size){ + if(phys < physmem_size){ fd = physmem_fd; *offset_out = phys; } diff --git a/trunk/arch/um/kernel/process.c b/trunk/arch/um/kernel/process.c index 348b272bb766..8d2c5496532b 100644 --- a/trunk/arch/um/kernel/process.c +++ b/trunk/arch/um/kernel/process.c @@ -32,8 +32,8 @@ #include "asm/tlbflush.h" #include "asm/uaccess.h" #include "asm/user.h" -#include "user_util.h" #include "kern_util.h" +#include "as-layout.h" #include "kern.h" #include "signal_kern.h" #include "init.h" @@ -54,11 +54,9 @@ */ struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; -int external_pid(void *t) +static inline int external_pid(struct task_struct *task) { - struct task_struct *task = t ? t : current; - - return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task)); + return CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task); } int pid_to_processor_id(int pid) @@ -66,9 +64,10 @@ int pid_to_processor_id(int pid) int i; for(i = 0; i < ncpus; i++){ - if(cpu_tasks[i].pid == pid) return(i); + if(cpu_tasks[i].pid == pid) + return i; } - return(-1); + return -1; } void free_stack(unsigned long stack, int order) @@ -85,9 +84,9 @@ unsigned long alloc_stack(int order, int atomic) flags = GFP_ATOMIC; page = __get_free_pages(flags, order); if(page == 0) - return(0); + return 0; stack_protections(page); - return(page); + return page; } int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) @@ -98,15 +97,11 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) current->thread.request.u.thread.arg = arg; pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, ¤t->thread.regs, 0, NULL, NULL); - if(pid < 0) - panic("do_fork failed in kernel_thread, errno = %d", pid); - return(pid); + return pid; } -void set_current(void *t) +static inline void set_current(struct task_struct *task) { - struct task_struct *task = t; - cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task) { external_pid(task), task }); } @@ -128,14 +123,16 @@ void *_switch_to(void *prev, void *next, void *last) prev= current; } while(current->thread.saved_task); - return(current->thread.prev_sched); + return current->thread.prev_sched; } void interrupt_end(void) { - if(need_resched()) schedule(); - if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal(); + if(need_resched()) + schedule(); + if(test_tsk_thread_flag(current, TIF_SIGPENDING)) + do_signal(); } void release_thread(struct task_struct *task) @@ -150,7 +147,7 @@ void exit_thread(void) void *get_current(void) { - return(current); + return current; } int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, @@ -188,15 +185,12 @@ void initial_thread_cb(void (*proc)(void *), void *arg) kmalloc_ok = save_kmalloc_ok; } +#ifdef CONFIG_MODE_TT unsigned long stack_sp(unsigned long page) { - return(page + PAGE_SIZE - sizeof(void *)); -} - -int current_pid(void) -{ - return(current->pid); + return page + PAGE_SIZE - sizeof(void *); } +#endif void default_idle(void) { @@ -221,11 +215,6 @@ void cpu_idle(void) CHOOSE_MODE(init_idle_tt(), init_idle_skas()); } -int page_size(void) -{ - return(PAGE_SIZE); -} - void *um_virt_to_phys(struct task_struct *task, unsigned long addr, pte_t *pte_out) { @@ -236,68 +225,43 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr, pte_t ptent; if(task->mm == NULL) - return(ERR_PTR(-EINVAL)); + return ERR_PTR(-EINVAL); pgd = pgd_offset(task->mm, addr); if(!pgd_present(*pgd)) - return(ERR_PTR(-EINVAL)); + return ERR_PTR(-EINVAL); pud = pud_offset(pgd, addr); if(!pud_present(*pud)) - return(ERR_PTR(-EINVAL)); + return ERR_PTR(-EINVAL); pmd = pmd_offset(pud, addr); if(!pmd_present(*pmd)) - return(ERR_PTR(-EINVAL)); + return ERR_PTR(-EINVAL); pte = pte_offset_kernel(pmd, addr); ptent = *pte; if(!pte_present(ptent)) - return(ERR_PTR(-EINVAL)); + return ERR_PTR(-EINVAL); if(pte_out != NULL) *pte_out = ptent; - return((void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK)); + return (void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK); } char *current_cmd(void) { #if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM) - return("(Unknown)"); + return "(Unknown)"; #else void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL); return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr); #endif } -void force_sigbus(void) -{ - printk(KERN_ERR "Killing pid %d because of a lack of memory\n", - current->pid); - lock_kernel(); - sigaddset(¤t->pending.signal, SIGBUS); - recalc_sigpending(); - current->flags |= PF_SIGNALED; - do_exit(SIGBUS | 0x80); -} - void dump_thread(struct pt_regs *regs, struct user *u) { } -void enable_hlt(void) -{ - panic("enable_hlt"); -} - -EXPORT_SYMBOL(enable_hlt); - -void disable_hlt(void) -{ - panic("disable_hlt"); -} - -EXPORT_SYMBOL(disable_hlt); - void *um_kmalloc(int size) { return kmalloc(size, GFP_KERNEL); @@ -313,36 +277,17 @@ void *um_vmalloc(int size) return vmalloc(size); } -void *um_vmalloc_atomic(int size) -{ - return __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM, PAGE_KERNEL); -} - int __cant_sleep(void) { return in_atomic() || irqs_disabled() || in_interrupt(); /* Is in_interrupt() really needed? */ } -unsigned long get_fault_addr(void) -{ - return((unsigned long) current->thread.fault_addr); -} - -EXPORT_SYMBOL(get_fault_addr); - -void not_implemented(void) -{ - printk(KERN_DEBUG "Something isn't implemented in here\n"); -} - -EXPORT_SYMBOL(not_implemented); - int user_context(unsigned long sp) { unsigned long stack; stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER); - return(stack != (unsigned long) current_thread); + return stack != (unsigned long) current_thread; } extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end; @@ -363,22 +308,22 @@ char *uml_strdup(char *string) int copy_to_user_proc(void __user *to, void *from, int size) { - return(copy_to_user(to, from, size)); + return copy_to_user(to, from, size); } int copy_from_user_proc(void *to, void __user *from, int size) { - return(copy_from_user(to, from, size)); + return copy_from_user(to, from, size); } int clear_user_proc(void __user *buf, int size) { - return(clear_user(buf, size)); + return clear_user(buf, size); } int strlen_user_proc(char __user *str) { - return(strlen_user(str)); + return strlen_user(str); } int smp_sigio_handler(void) @@ -387,14 +332,14 @@ int smp_sigio_handler(void) int cpu = current_thread->cpu; IPI_handler(cpu); if(cpu != 0) - return(1); + return 1; #endif - return(0); + return 0; } int cpu(void) { - return(current_thread->cpu); + return current_thread->cpu; } static atomic_t using_sysemu = ATOMIC_INIT(0); @@ -443,7 +388,7 @@ int __init make_proc_sysemu(void) if (ent == NULL) { printk(KERN_WARNING "Failed to register /proc/sysemu\n"); - return(0); + return 0; } ent->read_proc = proc_read_sysemu; diff --git a/trunk/arch/um/kernel/reboot.c b/trunk/arch/um/kernel/reboot.c index f602623644aa..7e4305a1fd3c 100644 --- a/trunk/arch/um/kernel/reboot.c +++ b/trunk/arch/um/kernel/reboot.c @@ -6,7 +6,6 @@ #include "linux/module.h" #include "linux/sched.h" #include "asm/smp.h" -#include "user_util.h" #include "kern_util.h" #include "kern.h" #include "os.h" diff --git a/trunk/arch/um/kernel/signal.c b/trunk/arch/um/kernel/signal.c index 3c798cdde550..c4020c3d7857 100644 --- a/trunk/arch/um/kernel/signal.c +++ b/trunk/arch/um/kernel/signal.c @@ -17,7 +17,6 @@ #include "asm/signal.h" #include "asm/uaccess.h" #include "asm/unistd.h" -#include "user_util.h" #include "asm/ucontext.h" #include "kern_util.h" #include "signal_kern.h" diff --git a/trunk/arch/um/kernel/skas/exec.c b/trunk/arch/um/kernel/skas/exec.c index 54b795951372..580eb6468949 100644 --- a/trunk/arch/um/kernel/skas/exec.c +++ b/trunk/arch/um/kernel/skas/exec.c @@ -17,7 +17,17 @@ void flush_thread_skas(void) { - force_flush_all(); + void *data = NULL; + unsigned long end = proc_mm ? task_size : CONFIG_STUB_START; + int ret; + + ret = unmap(¤t->mm->context.skas.id, 0, end, 1, &data); + if(ret){ + printk("flush_thread_skas - clearing address space failed, " + "err = %d\n", ret); + force_sig(SIGKILL, current); + } + switch_mm_skas(¤t->mm->context.skas.id); } diff --git a/trunk/arch/um/kernel/skas/process.c b/trunk/arch/um/kernel/skas/process.c index ae4fa71d3b8b..ef36facd8fe9 100644 --- a/trunk/arch/um/kernel/skas/process.c +++ b/trunk/arch/um/kernel/skas/process.c @@ -13,9 +13,9 @@ #include "asm/uaccess.h" #include "asm/atomic.h" #include "kern_util.h" +#include "as-layout.h" #include "skas.h" #include "os.h" -#include "user_util.h" #include "tlb.h" #include "kern.h" #include "mode.h" diff --git a/trunk/arch/um/kernel/skas/tlb.c b/trunk/arch/um/kernel/skas/tlb.c index 27eb29ce666b..c0f0693743ba 100644 --- a/trunk/arch/um/kernel/skas/tlb.c +++ b/trunk/arch/um/kernel/skas/tlb.c @@ -10,7 +10,6 @@ #include "asm/page.h" #include "asm/pgtable.h" #include "asm/mmu.h" -#include "user_util.h" #include "mem_user.h" #include "mem.h" #include "skas.h" @@ -28,19 +27,17 @@ static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last, switch(op->type){ case MMAP: ret = map(&mmu->skas.id, op->u.mmap.addr, - op->u.mmap.len, op->u.mmap.r, op->u.mmap.w, - op->u.mmap.x, op->u.mmap.fd, - op->u.mmap.offset, finished, flush); + op->u.mmap.len, op->u.mmap.prot, + op->u.mmap.fd, op->u.mmap.offset, finished, + flush); break; case MUNMAP: - ret = unmap(&mmu->skas.id, - (void *) op->u.munmap.addr, + ret = unmap(&mmu->skas.id, op->u.munmap.addr, op->u.munmap.len, finished, flush); break; case MPROTECT: ret = protect(&mmu->skas.id, op->u.mprotect.addr, - op->u.mprotect.len, op->u.mprotect.r, - op->u.mprotect.w, op->u.mprotect.x, + op->u.mprotect.len, op->u.mprotect.prot, finished, flush); break; default: @@ -92,6 +89,76 @@ void flush_tlb_mm_skas(struct mm_struct *mm) void force_flush_all_skas(void) { - unsigned long end = proc_mm ? task_size : CONFIG_STUB_START; - fix_range(current->mm, 0, end, 1); + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma = mm->mmap; + + while(vma != NULL) { + fix_range(mm, vma->vm_start, vma->vm_end, 1); + vma = vma->vm_next; + } +} + +void flush_tlb_page_skas(struct vm_area_struct *vma, unsigned long address) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + struct mm_struct *mm = vma->vm_mm; + void *flush = NULL; + int r, w, x, prot, err = 0; + struct mm_id *mm_id; + + pgd = pgd_offset(mm, address); + if(!pgd_present(*pgd)) + goto kill; + + pud = pud_offset(pgd, address); + if(!pud_present(*pud)) + goto kill; + + pmd = pmd_offset(pud, address); + if(!pmd_present(*pmd)) + goto kill; + + pte = pte_offset_kernel(pmd, address); + + r = pte_read(*pte); + w = pte_write(*pte); + x = pte_exec(*pte); + if (!pte_young(*pte)) { + r = 0; + w = 0; + } else if (!pte_dirty(*pte)) { + w = 0; + } + + mm_id = &mm->context.skas.id; + prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | + (x ? UM_PROT_EXEC : 0)); + if(pte_newpage(*pte)){ + if(pte_present(*pte)){ + unsigned long long offset; + int fd; + + fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset); + err = map(mm_id, address, PAGE_SIZE, prot, fd, offset, + 1, &flush); + } + else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush); + } + else if(pte_newprot(*pte)) + err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush); + + if(err) + goto kill; + + *pte = pte_mkuptodate(*pte); + + return; + +kill: + printk("Failed to flush page for address 0x%lx\n", address); + force_sig(SIGKILL, current); } + diff --git a/trunk/arch/um/kernel/smp.c b/trunk/arch/um/kernel/smp.c index 759b07053160..e6a7778006ad 100644 --- a/trunk/arch/um/kernel/smp.c +++ b/trunk/arch/um/kernel/smp.c @@ -21,7 +21,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); #include "asm/smp.h" #include "asm/processor.h" #include "asm/spinlock.h" -#include "user_util.h" #include "kern_util.h" #include "kern.h" #include "irq_user.h" @@ -90,7 +89,7 @@ static int idle_proc(void *cpup) cpu_set(cpu, cpu_online_map); default_idle(); - return(0); + return 0; } static struct task_struct *idle_thread(int cpu) @@ -98,8 +97,8 @@ static struct task_struct *idle_thread(int cpu) struct task_struct *new_task; unsigned char c; - current->thread.request.u.thread.proc = idle_proc; - current->thread.request.u.thread.arg = (void *) cpu; + current->thread.request.u.thread.proc = idle_proc; + current->thread.request.u.thread.arg = (void *) cpu; new_task = fork_idle(cpu); if(IS_ERR(new_task)) panic("copy_process failed in idle_thread, error = %ld", @@ -110,9 +109,9 @@ static struct task_struct *idle_thread(int cpu) .task = new_task } ); idle_threads[cpu] = new_task; CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c, - sizeof(c)), + sizeof(c)), ({ panic("skas mode doesn't support SMP"); })); - return(new_task); + return new_task; } void smp_prepare_cpus(unsigned int maxcpus) @@ -163,13 +162,13 @@ int __cpu_up(unsigned int cpu) cpu_set(cpu, smp_commenced_mask); while (!cpu_isset(cpu, cpu_online_map)) mb(); - return(0); + return 0; } int setup_profiling_timer(unsigned int multiplier) { printk(KERN_INFO "setup_profiling_timer\n"); - return(0); + return 0; } void smp_call_function_slave(int cpu); @@ -205,7 +204,7 @@ void IPI_handler(int cpu) int hard_smp_processor_id(void) { - return(pid_to_processor_id(os_getpid())); + return pid_to_processor_id(os_getpid()); } static DEFINE_SPINLOCK(call_lock); @@ -254,14 +253,3 @@ int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, } #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/kernel/syscall.c b/trunk/arch/um/kernel/syscall.c index 2828c5283227..237c4eab7cfd 100644 --- a/trunk/arch/um/kernel/syscall.c +++ b/trunk/arch/um/kernel/syscall.c @@ -18,7 +18,6 @@ #include "asm/mman.h" #include "asm/uaccess.h" #include "kern_util.h" -#include "user_util.h" #include "sysdep/syscalls.h" #include "mode_kern.h" #include "choose-mode.h" diff --git a/trunk/arch/um/kernel/sysrq.c b/trunk/arch/um/kernel/sysrq.c index f9e02b31a97a..93263571d813 100644 --- a/trunk/arch/um/kernel/sysrq.c +++ b/trunk/arch/um/kernel/sysrq.c @@ -10,7 +10,6 @@ #include "asm/page.h" #include "asm/processor.h" #include "sysrq.h" -#include "user_util.h" /* Catch non-i386 SUBARCH's. */ #if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT) diff --git a/trunk/arch/um/kernel/time.c b/trunk/arch/um/kernel/time.c index b1f8b0752419..259c49da7ff5 100644 --- a/trunk/arch/um/kernel/time.c +++ b/trunk/arch/um/kernel/time.c @@ -18,7 +18,6 @@ #include "asm/param.h" #include "asm/current.h" #include "kern_util.h" -#include "user_util.h" #include "mode.h" #include "os.h" @@ -35,8 +34,8 @@ unsigned long long sched_clock(void) return (unsigned long long)jiffies_64 * (1000000000 / HZ); } -static unsigned long long prev_nsecs[NR_CPUS]; #ifdef CONFIG_UML_REAL_TIME_CLOCK +static unsigned long long prev_nsecs[NR_CPUS]; static long long delta[NR_CPUS]; /* Deviation per interval */ #endif @@ -95,7 +94,12 @@ irqreturn_t um_timer(int irq, void *dev) do_timer(1); +#ifdef CONFIG_UML_REAL_TIME_CLOCK nsecs = get_time(); +#else + nsecs = (unsigned long long) xtime.tv_sec * BILLION + xtime.tv_nsec + + BILLION / HZ; +#endif xtime.tv_sec = nsecs / NSEC_PER_SEC; xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC; @@ -128,13 +132,18 @@ void time_init(void) nsecs = os_nsecs(); set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION, -nsecs % BILLION); + set_normalized_timespec(&xtime, nsecs / BILLION, nsecs % BILLION); late_time_init = register_timer; } void do_gettimeofday(struct timeval *tv) { +#ifdef CONFIG_UML_REAL_TIME_CLOCK unsigned long long nsecs = get_time(); - +#else + unsigned long long nsecs = (unsigned long long) xtime.tv_sec * BILLION + + xtime.tv_nsec; +#endif tv->tv_sec = nsecs / NSEC_PER_SEC; /* Careful about calculations here - this was originally done as * (nsecs - tv->tv_sec * NSEC_PER_SEC) / NSEC_PER_USEC @@ -168,6 +177,8 @@ int do_settimeofday(struct timespec *tv) void timer_handler(int sig, union uml_pt_regs *regs) { + if(current_thread->cpu == 0) + timer_irq(regs); local_irq_disable(); irq_enter(); update_process_times(CHOOSE_MODE( @@ -175,6 +186,4 @@ void timer_handler(int sig, union uml_pt_regs *regs) (regs)->skas.is_user)); irq_exit(); local_irq_enable(); - if(current_thread->cpu == 0) - timer_irq(regs); } diff --git a/trunk/arch/um/kernel/tlb.c b/trunk/arch/um/kernel/tlb.c index 54a5ff25645a..8a8d52851443 100644 --- a/trunk/arch/um/kernel/tlb.c +++ b/trunk/arch/um/kernel/tlb.c @@ -6,17 +6,18 @@ #include "linux/mm.h" #include "asm/page.h" #include "asm/pgalloc.h" +#include "asm/pgtable.h" #include "asm/tlbflush.h" #include "choose-mode.h" #include "mode_kern.h" -#include "user_util.h" +#include "as-layout.h" #include "tlb.h" #include "mem.h" #include "mem_user.h" #include "os.h" static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, - int r, int w, int x, struct host_vm_op *ops, int *index, + unsigned int prot, struct host_vm_op *ops, int *index, int last_filled, union mm_context *mmu, void **flush, int (*do_ops)(union mm_context *, struct host_vm_op *, int, int, void **)) @@ -30,8 +31,7 @@ static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, last = &ops[*index]; if((last->type == MMAP) && (last->u.mmap.addr + last->u.mmap.len == virt) && - (last->u.mmap.r == r) && (last->u.mmap.w == w) && - (last->u.mmap.x == x) && (last->u.mmap.fd == fd) && + (last->u.mmap.prot == prot) && (last->u.mmap.fd == fd) && (last->u.mmap.offset + last->u.mmap.len == offset)){ last->u.mmap.len += len; return 0; @@ -47,9 +47,7 @@ static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, .u = { .mmap = { .addr = virt, .len = len, - .r = r, - .w = w, - .x = x, + .prot = prot, .fd = fd, .offset = offset } } }); @@ -86,8 +84,8 @@ static int add_munmap(unsigned long addr, unsigned long len, return ret; } -static int add_mprotect(unsigned long addr, unsigned long len, int r, int w, - int x, struct host_vm_op *ops, int *index, +static int add_mprotect(unsigned long addr, unsigned long len, + unsigned int prot, struct host_vm_op *ops, int *index, int last_filled, union mm_context *mmu, void **flush, int (*do_ops)(union mm_context *, struct host_vm_op *, int, int, void **)) @@ -99,8 +97,7 @@ static int add_mprotect(unsigned long addr, unsigned long len, int r, int w, last = &ops[*index]; if((last->type == MPROTECT) && (last->u.mprotect.addr + last->u.mprotect.len == addr) && - (last->u.mprotect.r == r) && (last->u.mprotect.w == w) && - (last->u.mprotect.x == x)){ + (last->u.mprotect.prot == prot)){ last->u.mprotect.len += len; return 0; } @@ -115,114 +112,145 @@ static int add_mprotect(unsigned long addr, unsigned long len, int r, int w, .u = { .mprotect = { .addr = addr, .len = len, - .r = r, - .w = w, - .x = x } } }); + .prot = prot } } }); return ret; } #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) +static inline int update_pte_range(pmd_t *pmd, unsigned long addr, + unsigned long end, struct host_vm_op *ops, + int last_op, int *op_index, int force, + union mm_context *mmu, void **flush, + int (*do_ops)(union mm_context *, + struct host_vm_op *, int, int, + void **)) +{ + pte_t *pte; + int r, w, x, prot, ret = 0; + + pte = pte_offset_kernel(pmd, addr); + do { + r = pte_read(*pte); + w = pte_write(*pte); + x = pte_exec(*pte); + if (!pte_young(*pte)) { + r = 0; + w = 0; + } else if (!pte_dirty(*pte)) { + w = 0; + } + prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | + (x ? UM_PROT_EXEC : 0)); + if(force || pte_newpage(*pte)){ + if(pte_present(*pte)) + ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK, + PAGE_SIZE, prot, ops, op_index, + last_op, mmu, flush, do_ops); + else ret = add_munmap(addr, PAGE_SIZE, ops, op_index, + last_op, mmu, flush, do_ops); + } + else if(pte_newprot(*pte)) + ret = add_mprotect(addr, PAGE_SIZE, prot, ops, op_index, + last_op, mmu, flush, do_ops); + *pte = pte_mkuptodate(*pte); + } while (pte++, addr += PAGE_SIZE, ((addr != end) && !ret)); + return ret; +} + +static inline int update_pmd_range(pud_t *pud, unsigned long addr, + unsigned long end, struct host_vm_op *ops, + int last_op, int *op_index, int force, + union mm_context *mmu, void **flush, + int (*do_ops)(union mm_context *, + struct host_vm_op *, int, int, + void **)) +{ + pmd_t *pmd; + unsigned long next; + int ret = 0; + + pmd = pmd_offset(pud, addr); + do { + next = pmd_addr_end(addr, end); + if(!pmd_present(*pmd)){ + if(force || pmd_newpage(*pmd)){ + ret = add_munmap(addr, next - addr, ops, + op_index, last_op, mmu, + flush, do_ops); + pmd_mkuptodate(*pmd); + } + } + else ret = update_pte_range(pmd, addr, next, ops, last_op, + op_index, force, mmu, flush, + do_ops); + } while (pmd++, addr = next, ((addr != end) && !ret)); + return ret; +} + +static inline int update_pud_range(pgd_t *pgd, unsigned long addr, + unsigned long end, struct host_vm_op *ops, + int last_op, int *op_index, int force, + union mm_context *mmu, void **flush, + int (*do_ops)(union mm_context *, + struct host_vm_op *, int, int, + void **)) +{ + pud_t *pud; + unsigned long next; + int ret = 0; + + pud = pud_offset(pgd, addr); + do { + next = pud_addr_end(addr, end); + if(!pud_present(*pud)){ + if(force || pud_newpage(*pud)){ + ret = add_munmap(addr, next - addr, ops, + op_index, last_op, mmu, + flush, do_ops); + pud_mkuptodate(*pud); + } + } + else ret = update_pmd_range(pud, addr, next, ops, last_op, + op_index, force, mmu, flush, + do_ops); + } while (pud++, addr = next, ((addr != end) && !ret)); + return ret; +} + void fix_range_common(struct mm_struct *mm, unsigned long start_addr, unsigned long end_addr, int force, int (*do_ops)(union mm_context *, struct host_vm_op *, int, int, void **)) { - pgd_t *npgd; - pud_t *npud; - pmd_t *npmd; - pte_t *npte; + pgd_t *pgd; union mm_context *mmu = &mm->context; - unsigned long addr, end; - int r, w, x; struct host_vm_op ops[1]; + unsigned long addr = start_addr, next; + int ret = 0, last_op = ARRAY_SIZE(ops) - 1, op_index = -1; void *flush = NULL; - int op_index = -1, last_op = ARRAY_SIZE(ops) - 1; - int ret = 0; - - if(mm == NULL) - return; ops[0].type = NONE; - for(addr = start_addr; addr < end_addr && !ret;){ - npgd = pgd_offset(mm, addr); - if(!pgd_present(*npgd)){ - end = ADD_ROUND(addr, PGDIR_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pgd_newpage(*npgd)){ - ret = add_munmap(addr, end - addr, ops, - &op_index, last_op, mmu, - &flush, do_ops); - pgd_mkuptodate(*npgd); - } - addr = end; - continue; - } - - npud = pud_offset(npgd, addr); - if(!pud_present(*npud)){ - end = ADD_ROUND(addr, PUD_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pud_newpage(*npud)){ - ret = add_munmap(addr, end - addr, ops, - &op_index, last_op, mmu, - &flush, do_ops); - pud_mkuptodate(*npud); - } - addr = end; - continue; - } - - npmd = pmd_offset(npud, addr); - if(!pmd_present(*npmd)){ - end = ADD_ROUND(addr, PMD_SIZE); - if(end > end_addr) - end = end_addr; - if(force || pmd_newpage(*npmd)){ - ret = add_munmap(addr, end - addr, ops, + pgd = pgd_offset(mm, addr); + do { + next = pgd_addr_end(addr, end_addr); + if(!pgd_present(*pgd)){ + if (force || pgd_newpage(*pgd)){ + ret = add_munmap(addr, next - addr, ops, &op_index, last_op, mmu, &flush, do_ops); - pmd_mkuptodate(*npmd); + pgd_mkuptodate(*pgd); } - addr = end; - continue; - } - - npte = pte_offset_kernel(npmd, addr); - r = pte_read(*npte); - w = pte_write(*npte); - x = pte_exec(*npte); - if (!pte_young(*npte)) { - r = 0; - w = 0; - } else if (!pte_dirty(*npte)) { - w = 0; - } - if(force || pte_newpage(*npte)){ - if(pte_present(*npte)) - ret = add_mmap(addr, - pte_val(*npte) & PAGE_MASK, - PAGE_SIZE, r, w, x, ops, - &op_index, last_op, mmu, - &flush, do_ops); - else ret = add_munmap(addr, PAGE_SIZE, ops, - &op_index, last_op, mmu, - &flush, do_ops); } - else if(pte_newprot(*npte)) - ret = add_mprotect(addr, PAGE_SIZE, r, w, x, ops, - &op_index, last_op, mmu, - &flush, do_ops); + else ret = update_pud_range(pgd, addr, next, ops, last_op, + &op_index, force, mmu, &flush, + do_ops); + } while (pgd++, addr = next, ((addr != end_addr) && !ret)); - *npte = pte_mkuptodate(*npte); - addr += PAGE_SIZE; - } if(!ret) ret = (*do_ops)(mmu, ops, op_index, 1, &flush); -/* This is not an else because ret is modified above */ + /* This is not an else because ret is modified above */ if(ret) { printk("fix_range_common: failed, killing current process\n"); force_sig(SIGKILL, current); @@ -343,12 +371,6 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr) return(pte_offset_map(pmd, addr)); } -void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) -{ - address &= PAGE_MASK; - flush_tlb_range(vma, address, address + PAGE_SIZE); -} - void flush_tlb_all(void) { flush_tlb_mm(current->mm); diff --git a/trunk/arch/um/kernel/trap.c b/trunk/arch/um/kernel/trap.c index 26f15c458574..abab90c3803f 100644 --- a/trunk/arch/um/kernel/trap.c +++ b/trunk/arch/um/kernel/trap.c @@ -18,8 +18,9 @@ #include "asm/current.h" #include "asm/irq.h" #include "sysdep/sigcontext.h" -#include "user_util.h" #include "kern_util.h" +#include "as-layout.h" +#include "arch.h" #include "kern.h" #include "chan_kern.h" #include "mconsole_kern.h" @@ -71,8 +72,8 @@ int handle_page_fault(unsigned long address, unsigned long ip, goto out; /* Don't require VM_READ|VM_EXEC for write faults! */ - if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC))) - goto out; + if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC))) + goto out; do { survive: @@ -156,20 +157,23 @@ static void segv_handler(int sig, union uml_pt_regs *regs) * the info in the regs. A pointer to the info then would * give us bad data! */ -unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) +unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, + union uml_pt_regs *regs) { struct siginfo si; void *catcher; int err; - int is_write = FAULT_WRITE(fi); - unsigned long address = FAULT_ADDRESS(fi); + int is_write = FAULT_WRITE(fi); + unsigned long address = FAULT_ADDRESS(fi); - if(!is_user && (address >= start_vm) && (address < end_vm)){ - flush_tlb_kernel_vm(); - return(0); - } - else if(current->mm == NULL) - panic("Segfault with no mm"); + if(!is_user && (address >= start_vm) && (address < end_vm)){ + flush_tlb_kernel_vm(); + return 0; + } + else if(current->mm == NULL) { + show_regs(container_of(regs, struct pt_regs, regs)); + panic("Segfault with no mm"); + } if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi)) err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); @@ -182,26 +186,28 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) catcher = current->thread.fault_catcher; if(!err) - return(0); + return 0; else if(catcher != NULL){ current->thread.fault_addr = (void *) address; do_longjmp(catcher, 1); } else if(current->thread.fault_addr != NULL) panic("fault_addr set but no fault catcher"); - else if(!is_user && arch_fixup(ip, sc)) - return(0); + else if(!is_user && arch_fixup(ip, regs)) + return 0; - if(!is_user) + if(!is_user) { + show_regs(container_of(regs, struct pt_regs, regs)); panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", address, ip); + } if (err == -EACCES) { si.si_signo = SIGBUS; si.si_errno = 0; si.si_code = BUS_ADRERR; si.si_addr = (void __user *)address; - current->thread.arch.faultinfo = fi; + current->thread.arch.faultinfo = fi; force_sig_info(SIGBUS, &si, current); } else if (err == -ENOMEM) { printk("VM: killing process %s\n", current->comm); @@ -210,10 +216,10 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) BUG_ON(err != -EFAULT); si.si_signo = SIGSEGV; si.si_addr = (void __user *) address; - current->thread.arch.faultinfo = fi; + current->thread.arch.faultinfo = fi; force_sig_info(SIGSEGV, &si, current); } - return(0); + return 0; } void relay_signal(int sig, union uml_pt_regs *regs) @@ -223,12 +229,12 @@ void relay_signal(int sig, union uml_pt_regs *regs) if(!UPT_IS_USER(regs)){ if(sig == SIGBUS) - printk("Bus error - the /dev/shm or /tmp mount likely " - "just ran out of space\n"); + printk("Bus error - the host /dev/shm or /tmp mount " + "likely just ran out of space\n"); panic("Kernel mode signal %d", sig); } - current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); + current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); force_sig(sig, current); } diff --git a/trunk/arch/um/kernel/tt/exec_kern.c b/trunk/arch/um/kernel/tt/exec_kern.c index ad66df17d9d7..98e21743e604 100644 --- a/trunk/arch/um/kernel/tt/exec_kern.c +++ b/trunk/arch/um/kernel/tt/exec_kern.c @@ -10,7 +10,6 @@ #include "asm/uaccess.h" #include "asm/pgalloc.h" #include "asm/tlbflush.h" -#include "user_util.h" #include "kern_util.h" #include "irq_user.h" #include "mem_user.h" diff --git a/trunk/arch/um/kernel/tt/exec_user.c b/trunk/arch/um/kernel/tt/exec_user.c index a92c02ff2ce3..7b5f2181cf51 100644 --- a/trunk/arch/um/kernel/tt/exec_user.c +++ b/trunk/arch/um/kernel/tt/exec_user.c @@ -10,7 +10,6 @@ #include #include #include -#include "user_util.h" #include "kern_util.h" #include "user.h" #include "ptrace_user.h" diff --git a/trunk/arch/um/kernel/tt/gdb.c b/trunk/arch/um/kernel/tt/gdb.c index 8eba8f7dca68..030e4658f36b 100644 --- a/trunk/arch/um/kernel/tt/gdb.c +++ b/trunk/arch/um/kernel/tt/gdb.c @@ -17,7 +17,6 @@ #include "user.h" #include "debug.h" #include "kern_util.h" -#include "user_util.h" #include "tt.h" #include "sysdep/thread.h" #include "os.h" @@ -115,6 +114,8 @@ struct gdb_data { int err; }; +extern char *linux_prog; + static void config_gdb_cb(void *arg) { struct gdb_data *data = arg; diff --git a/trunk/arch/um/kernel/tt/include/mode_kern-tt.h b/trunk/arch/um/kernel/tt/include/mode_kern-tt.h deleted file mode 100644 index 2a35b15c5fef..000000000000 --- a/trunk/arch/um/kernel/tt/include/mode_kern-tt.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __TT_MODE_KERN_H__ -#define __TT_MODE_KERN_H__ - -#include "linux/sched.h" -#include "asm/page.h" -#include "asm/ptrace.h" -#include "asm/uaccess.h" - -extern void switch_to_tt(void *prev, void *next); -extern void flush_thread_tt(void); -extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, - unsigned long esp); -extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, - unsigned long stack_top, struct task_struct *p, - struct pt_regs *regs); -extern void release_thread_tt(struct task_struct *task); -extern void initial_thread_cb_tt(void (*proc)(void *), void *arg); -extern void init_idle_tt(void); -extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end); -extern void flush_tlb_kernel_vm_tt(void); -extern void __flush_tlb_one_tt(unsigned long addr); -extern void flush_tlb_range_tt(struct vm_area_struct *vma, - unsigned long start, unsigned long end); -extern void flush_tlb_mm_tt(struct mm_struct *mm); -extern void force_flush_all_tt(void); -extern long execute_syscall_tt(void *r); -extern void before_mem_tt(unsigned long brk_start); -extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, - unsigned long *task_size_out); -extern int start_uml_tt(void); -extern int external_pid_tt(struct task_struct *task); -extern int thread_pid_tt(struct task_struct *task); - -#define kmem_end_tt (host_task_size - ABOVE_KMEM) - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/kernel/tt/mem.c b/trunk/arch/um/kernel/tt/mem.c index 4d1929dfa285..d0c3c4975f28 100644 --- a/trunk/arch/um/kernel/tt/mem.c +++ b/trunk/arch/um/kernel/tt/mem.c @@ -8,7 +8,6 @@ #include "asm/uaccess.h" #include "mem_user.h" #include "kern_util.h" -#include "user_util.h" #include "kern.h" #include "tt.h" diff --git a/trunk/arch/um/kernel/tt/mem_user.c b/trunk/arch/um/kernel/tt/mem_user.c index 03e589895388..9774f6360c32 100644 --- a/trunk/arch/um/kernel/tt/mem_user.c +++ b/trunk/arch/um/kernel/tt/mem_user.c @@ -11,7 +11,6 @@ #include #include "tt.h" #include "mem_user.h" -#include "user_util.h" #include "os.h" void remap_data(void *segment_start, void *segment_end, int w) diff --git a/trunk/arch/um/kernel/tt/process_kern.c b/trunk/arch/um/kernel/tt/process_kern.c index 1e86f0bfef72..c631303cb800 100644 --- a/trunk/arch/um/kernel/tt/process_kern.c +++ b/trunk/arch/um/kernel/tt/process_kern.c @@ -14,7 +14,6 @@ #include "asm/tlbflush.h" #include "irq_user.h" #include "kern_util.h" -#include "user_util.h" #include "os.h" #include "kern.h" #include "sigcontext.h" @@ -65,7 +64,8 @@ void switch_to_tt(void *prev, void *next) if(from->thread.mode.tt.switch_pipe[0] == -1) os_kill_process(os_getpid(), 0); - err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); + err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, + sizeof(c)); if(err != sizeof(c)) panic("read of switch_pipe failed, errno = %d", -err); diff --git a/trunk/arch/um/kernel/tt/ptproxy/proxy.c b/trunk/arch/um/kernel/tt/ptproxy/proxy.c index 58800c50b10e..420c23f311f3 100644 --- a/trunk/arch/um/kernel/tt/ptproxy/proxy.c +++ b/trunk/arch/um/kernel/tt/ptproxy/proxy.c @@ -26,7 +26,6 @@ Jeff Dike (jdike@karaya.com) : Modified for integration into uml #include "sysdep.h" #include "wait.h" -#include "user_util.h" #include "user.h" #include "os.h" #include "tempfile.h" @@ -339,11 +338,12 @@ int start_debugger(char *prog, int startup, int stop, int *fd_out) "err = %d\n", -fd); exit(1); } - os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1); + os_write_file(fd, gdb_init_string, + sizeof(gdb_init_string) - 1); if(startup){ if(stop){ os_write_file(fd, "b start_kernel\n", - strlen("b start_kernel\n")); + strlen("b start_kernel\n")); } os_write_file(fd, "c\n", strlen("c\n")); } diff --git a/trunk/arch/um/kernel/tt/ptproxy/ptrace.c b/trunk/arch/um/kernel/tt/ptproxy/ptrace.c index 03774427d468..4b4f6179b212 100644 --- a/trunk/arch/um/kernel/tt/ptproxy/ptrace.c +++ b/trunk/arch/um/kernel/tt/ptproxy/ptrace.c @@ -16,7 +16,6 @@ Jeff Dike (jdike@karaya.com) : Modified for integration into uml #include "ptproxy.h" #include "debug.h" -#include "user_util.h" #include "kern_util.h" #include "ptrace_user.h" #include "tt.h" diff --git a/trunk/arch/um/kernel/tt/ptproxy/sysdep.c b/trunk/arch/um/kernel/tt/ptproxy/sysdep.c index 99f178319d03..e0e1ab0588ad 100644 --- a/trunk/arch/um/kernel/tt/ptproxy/sysdep.c +++ b/trunk/arch/um/kernel/tt/ptproxy/sysdep.c @@ -13,7 +13,6 @@ terms and conditions. #include #include #include "ptrace_user.h" -#include "user_util.h" #include "user.h" #include "os.h" diff --git a/trunk/arch/um/kernel/tt/ptproxy/wait.c b/trunk/arch/um/kernel/tt/ptproxy/wait.c index 12f6319d8d76..bdd4af4b65fc 100644 --- a/trunk/arch/um/kernel/tt/ptproxy/wait.c +++ b/trunk/arch/um/kernel/tt/ptproxy/wait.c @@ -13,7 +13,6 @@ terms and conditions. #include "ptproxy.h" #include "sysdep.h" #include "wait.h" -#include "user_util.h" #include "ptrace_user.h" #include "sysdep/ptrace.h" #include "sysdep/sigcontext.h" diff --git a/trunk/arch/um/kernel/tt/syscall_user.c b/trunk/arch/um/kernel/tt/syscall_user.c index 902987bf379b..f52b47aff1d2 100644 --- a/trunk/arch/um/kernel/tt/syscall_user.c +++ b/trunk/arch/um/kernel/tt/syscall_user.c @@ -11,7 +11,6 @@ #include "sigcontext.h" #include "ptrace_user.h" #include "task.h" -#include "user_util.h" #include "kern_util.h" #include "syscall.h" #include "tt.h" diff --git a/trunk/arch/um/kernel/tt/tlb.c b/trunk/arch/um/kernel/tt/tlb.c index ae6217c86135..7caa24fe05df 100644 --- a/trunk/arch/um/kernel/tt/tlb.c +++ b/trunk/arch/um/kernel/tt/tlb.c @@ -12,7 +12,6 @@ #include "asm/pgtable.h" #include "asm/uaccess.h" #include "asm/tlbflush.h" -#include "user_util.h" #include "mem_user.h" #include "os.h" #include "tlb.h" diff --git a/trunk/arch/um/kernel/tt/tracer.c b/trunk/arch/um/kernel/tt/tracer.c index b9195355075a..c23588393f6e 100644 --- a/trunk/arch/um/kernel/tt/tracer.c +++ b/trunk/arch/um/kernel/tt/tracer.c @@ -19,7 +19,6 @@ #include "sigcontext.h" #include "sysdep/sigcontext.h" #include "os.h" -#include "user_util.h" #include "mem_user.h" #include "process.h" #include "kern_util.h" diff --git a/trunk/arch/um/kernel/tt/trap_user.c b/trunk/arch/um/kernel/tt/trap_user.c index b5d9d64d91e4..3032eb5e2467 100644 --- a/trunk/arch/um/kernel/tt/trap_user.c +++ b/trunk/arch/um/kernel/tt/trap_user.c @@ -8,7 +8,6 @@ #include #include "sysdep/ptrace.h" #include "sysdep/sigcontext.h" -#include "user_util.h" #include "kern_util.h" #include "task.h" #include "tt.h" diff --git a/trunk/arch/um/kernel/tt/uaccess_user.c b/trunk/arch/um/kernel/tt/uaccess_user.c index ed1abcf4d057..0e5c82c5e5b7 100644 --- a/trunk/arch/um/kernel/tt/uaccess_user.c +++ b/trunk/arch/um/kernel/tt/uaccess_user.c @@ -5,7 +5,6 @@ */ #include -#include "user_util.h" #include "uml_uaccess.h" #include "task.h" #include "kern_util.h" diff --git a/trunk/arch/um/kernel/um_arch.c b/trunk/arch/um/kernel/um_arch.c index 89c6dba731f8..1cf954a47fd7 100644 --- a/trunk/arch/um/kernel/um_arch.c +++ b/trunk/arch/um/kernel/um_arch.c @@ -17,6 +17,7 @@ #include "linux/seq_file.h" #include "linux/delay.h" #include "linux/module.h" +#include "linux/utsname.h" #include "asm/page.h" #include "asm/pgtable.h" #include "asm/ptrace.h" @@ -25,8 +26,9 @@ #include "asm/setup.h" #include "ubd_user.h" #include "asm/current.h" -#include "user_util.h" #include "kern_util.h" +#include "as-layout.h" +#include "arch.h" #include "kern.h" #include "mem_user.h" #include "mem.h" @@ -42,7 +44,7 @@ #define DEFAULT_COMMAND_LINE "root=98:0" -/* Changed in linux_main and setup_arch, which run before SMP is started */ +/* Changed in add_arg and setup_arch, which run before SMP is started */ static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 }; static void __init add_arg(char *arg) @@ -56,17 +58,25 @@ static void __init add_arg(char *arg) strcat(command_line, arg); } -struct cpuinfo_um boot_cpu_data = { +/* + * These fields are initialized at boot time and not changed. + * XXX This structure is used only in the non-SMP case. Maybe this + * should be moved to smp.c. + */ +struct cpuinfo_um boot_cpu_data = { .loops_per_jiffy = 0, .ipi_pipe = { -1, -1 } }; unsigned long thread_saved_pc(struct task_struct *task) { - return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, - task))); + return os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, + task)); } +/* Changed in setup_arch, which is called in early boot */ +static char host_info[(__NEW_UTS_LEN + 1) * 5]; + static int show_cpuinfo(struct seq_file *m, void *v) { int index = 0; @@ -86,7 +96,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ)) % 100); - return(0); + return 0; } static void *c_start(struct seq_file *m, loff_t *pos) @@ -114,14 +124,12 @@ const struct seq_operations cpuinfo_op = { /* Set in linux_main */ unsigned long host_task_size; unsigned long task_size; - -unsigned long uml_start; - -/* Set in early boot */ unsigned long uml_physmem; -unsigned long uml_reserved; +unsigned long uml_reserved; /* Also modified in mem_init */ unsigned long start_vm; unsigned long end_vm; + +/* Set in uml_ncpus_setup */ int ncpus = 1; #ifdef CONFIG_CMDLINE_ON_HOST @@ -135,6 +143,8 @@ static char *argv1_end = NULL; /* Set in early boot */ static int have_root __initdata = 0; + +/* Set in uml_mem_setup and modified in linux_main */ long long physmem_size = 32 * 1024 * 1024; void set_cmdline(char *cmd) @@ -212,12 +222,12 @@ __uml_setup("debug", no_skas_debug_setup, #ifdef CONFIG_SMP static int __init uml_ncpus_setup(char *line, int *add) { - if (!sscanf(line, "%d", &ncpus)) { - printf("Couldn't parse [%s]\n", line); - return -1; - } + if (!sscanf(line, "%d", &ncpus)) { + printf("Couldn't parse [%s]\n", line); + return -1; + } - return 0; + return 0; } __uml_setup("ncpus=", uml_ncpus_setup, @@ -234,7 +244,7 @@ static int force_tt = 0; static int __init mode_tt_setup(char *line, int *add) { force_tt = 1; - return(0); + return 0; } #else @@ -245,7 +255,7 @@ static int __init mode_tt_setup(char *line, int *add) static int __init mode_tt_setup(char *line, int *add) { printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); - return(0); + return 0; } #else @@ -256,7 +266,7 @@ static int __init mode_tt_setup(char *line, int *add) static int __init mode_tt_setup(char *line, int *add) { printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); - return(0); + return 0; } #endif @@ -274,16 +284,15 @@ int mode_tt = DEFAULT_TT; static int __init Usage(char *line, int *add) { - const char **p; + const char **p; printf(usage_string, init_utsname()->release); - p = &__uml_help_start; - while (p < &__uml_help_end) { - printf("%s", *p); - p++; - } + p = &__uml_help_start; + while (p < &__uml_help_end) { + printf("%s", *p); + p++; + } exit(0); - return 0; } @@ -374,13 +383,12 @@ int __init linux_main(int argc, char **argv) printf("UML running in %s mode\n", mode); - uml_start = (unsigned long) &__binary_start; host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, &task_size); /* - * Setting up handlers to 'sig_info' struct - */ + * Setting up handlers to 'sig_info' struct + */ os_fill_handlinfo(handlinfo_kern); brk_start = (unsigned long) sbrk(0); @@ -396,7 +404,7 @@ int __init linux_main(int argc, char **argv) physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); } - uml_physmem = uml_start & PAGE_MASK; + uml_physmem = (unsigned long) &__binary_start & PAGE_MASK; /* Reserve up to 4M after the current brk */ uml_reserved = ROUND_4M(brk_start) + (1 << 22); @@ -407,7 +415,7 @@ int __init linux_main(int argc, char **argv) argv1_begin = argv[1]; argv1_end = &argv[1][strlen(argv[1])]; #endif - + highmem = 0; iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; @@ -449,12 +457,12 @@ int __init linux_main(int argc, char **argv) printf("Kernel virtual memory size shrunk to %lu bytes\n", virtmem_size); - uml_postsetup(); + uml_postsetup(); task_protections((unsigned long) &init_thread_info); os_flush_stdout(); - return(CHOOSE_MODE(start_uml_tt(), start_uml_skas())); + return CHOOSE_MODE(start_uml_tt(), start_uml_skas()); } extern int uml_exitcode; @@ -466,8 +474,8 @@ static int panic_exit(struct notifier_block *self, unsigned long unused1, show_regs(&(current->thread.regs)); bust_spinlocks(0); uml_exitcode = 1; - machine_halt(); - return(0); + os_dump_core(); + return 0; } static struct notifier_block panic_exit_notifier = { @@ -482,14 +490,14 @@ void __init setup_arch(char **cmdline_p) &panic_exit_notifier); paging_init(); strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); - *cmdline_p = command_line; - setup_hostinfo(); + *cmdline_p = command_line; + setup_hostinfo(host_info, sizeof host_info); } void __init check_bugs(void) { arch_check_bugs(); - os_check_bugs(); + os_check_bugs(); } void apply_alternatives(struct alt_instr *start, struct alt_instr *end) diff --git a/trunk/arch/um/os-Linux/aio.c b/trunk/arch/um/os-Linux/aio.c index 6ff12743a0bd..9bf944f6a1db 100644 --- a/trunk/arch/um/os-Linux/aio.c +++ b/trunk/arch/um/os-Linux/aio.c @@ -132,10 +132,10 @@ static int aio_thread(void *arg) { .data = (void *) (long) event.data, .err = event.res }); reply_fd = ((struct aio_context *) reply.data)->reply_fd; - err = os_write_file(reply_fd, &reply, sizeof(reply)); + err = write(reply_fd, &reply, sizeof(reply)); if(err != sizeof(reply)) printk("aio_thread - write failed, fd = %d, " - "err = %d\n", reply_fd, -err); + "err = %d\n", reply_fd, errno); } } return 0; @@ -146,38 +146,31 @@ static int aio_thread(void *arg) static int do_not_aio(struct aio_thread_req *req) { char c; - int err; + unsigned long long actual; + int n; + + actual = lseek64(req->io_fd, req->offset, SEEK_SET); + if(actual != req->offset) + return -errno; switch(req->type){ case AIO_READ: - err = os_seek_file(req->io_fd, req->offset); - if(err) - goto out; - - err = os_read_file(req->io_fd, req->buf, req->len); + n = read(req->io_fd, req->buf, req->len); break; case AIO_WRITE: - err = os_seek_file(req->io_fd, req->offset); - if(err) - goto out; - - err = os_write_file(req->io_fd, req->buf, req->len); + n = write(req->io_fd, req->buf, req->len); break; case AIO_MMAP: - err = os_seek_file(req->io_fd, req->offset); - if(err) - goto out; - - err = os_read_file(req->io_fd, &c, sizeof(c)); + n = read(req->io_fd, &c, sizeof(c)); break; default: printk("do_not_aio - bad request type : %d\n", req->type); - err = -EINVAL; - break; + return -EINVAL; } -out: - return err; + if(n < 0) + return -errno; + return 0; } /* These are initialized in initcalls and not changed */ @@ -193,12 +186,12 @@ static int not_aio_thread(void *arg) signal(SIGWINCH, SIG_IGN); while(1){ - err = os_read_file(aio_req_fd_r, &req, sizeof(req)); + err = read(aio_req_fd_r, &req, sizeof(req)); if(err != sizeof(req)){ if(err < 0) printk("not_aio_thread - read failed, " "fd = %d, err = %d\n", aio_req_fd_r, - -err); + errno); else { printk("not_aio_thread - short read, fd = %d, " "length = %d\n", aio_req_fd_r, err); @@ -207,11 +200,11 @@ static int not_aio_thread(void *arg) } err = do_not_aio(&req); reply = ((struct aio_thread_reply) { .data = req.aio, - .err = err }); - err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply)); + .err = err }); + err = write(req.aio->reply_fd, &reply, sizeof(reply)); if(err != sizeof(reply)) printk("not_aio_thread - write failed, fd = %d, " - "err = %d\n", req.aio->reply_fd, -err); + "err = %d\n", req.aio->reply_fd, errno); } return 0; @@ -228,6 +221,11 @@ static int init_aio_24(void) aio_req_fd_w = fds[0]; aio_req_fd_r = fds[1]; + + err = os_set_fd_block(aio_req_fd_w, 0); + if(err) + goto out_close_pipe; + err = run_helper_thread(not_aio_thread, NULL, CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0); if(err < 0) @@ -285,10 +283,12 @@ static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, if(err){ reply = ((struct aio_thread_reply) { .data = aio, .err = err }); - err = os_write_file(aio->reply_fd, &reply, sizeof(reply)); - if(err != sizeof(reply)) + err = write(aio->reply_fd, &reply, sizeof(reply)); + if(err != sizeof(reply)){ + err = -errno; printk("submit_aio_26 - write failed, " "fd = %d, err = %d\n", aio->reply_fd, -err); + } else err = 0; } @@ -383,9 +383,10 @@ static int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len, }; int err; - err = os_write_file(aio_req_fd_w, &req, sizeof(req)); + err = write(aio_req_fd_w, &req, sizeof(req)); if(err == sizeof(req)) err = 0; + else err = -errno; return err; } diff --git a/trunk/arch/um/os-Linux/drivers/ethertap_user.c b/trunk/arch/um/os-Linux/drivers/ethertap_user.c index 863981ba1468..acba30161287 100644 --- a/trunk/arch/um/os-Linux/drivers/ethertap_user.c +++ b/trunk/arch/um/os-Linux/drivers/ethertap_user.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and * James Leu (jleu@mindspring.net). * Copyright (C) 2001 by various other people who didn't put their name here. * Licensed under the GPL. @@ -16,19 +16,20 @@ #include #include "user.h" #include "kern_util.h" -#include "user_util.h" #include "net_user.h" #include "etap.h" #include "os.h" #include "um_malloc.h" +#include "kern_constants.h" #define MAX_PACKET ETH_MAX_PACKET -void etap_user_init(void *data, void *dev) +static int etap_user_init(void *data, void *dev) { struct ethertap_data *pri = data; pri->dev = dev; + return 0; } struct addr_change { @@ -47,13 +48,16 @@ static void etap_change(int op, unsigned char *addr, unsigned char *netmask, change.what = op; memcpy(change.addr, addr, sizeof(change.addr)); memcpy(change.netmask, netmask, sizeof(change.netmask)); - n = os_write_file(fd, &change, sizeof(change)); - if(n != sizeof(change)) - printk("etap_change - request failed, err = %d\n", -n); - output = um_kmalloc(page_size()); + CATCH_EINTR(n = write(fd, &change, sizeof(change))); + if(n != sizeof(change)){ + printk("etap_change - request failed, err = %d\n", errno); + return; + } + + output = um_kmalloc(UM_KERN_PAGE_SIZE); if(output == NULL) printk("etap_change : Failed to allocate output buffer\n"); - read_output(fd, output, page_size()); + read_output(fd, output, UM_KERN_PAGE_SIZE); if(output != NULL){ printk("%s", output); kfree(output); @@ -115,13 +119,15 @@ static int etap_tramp(char *dev, char *gate, int control_me, pe_data.data_me = data_me; pid = run_helper(etap_pre_exec, &pe_data, args, NULL); - if(pid < 0) err = pid; + if(pid < 0) + err = pid; os_close_file(data_remote); os_close_file(control_remote); - n = os_read_file(control_me, &c, sizeof(c)); + CATCH_EINTR(n = read(control_me, &c, sizeof(c))); if(n != sizeof(c)){ - printk("etap_tramp : read of status failed, err = %d\n", -n); - return(-EINVAL); + err = -errno; + printk("etap_tramp : read of status failed, err = %d\n", -err); + return err; } if(c != 1){ printk("etap_tramp : uml_net failed\n"); @@ -132,7 +138,7 @@ static int etap_tramp(char *dev, char *gate, int control_me, else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) printk("uml_net didn't exit with status 1\n"); } - return(err); + return err; } static int etap_open(void *data) @@ -142,23 +148,24 @@ static int etap_open(void *data) int data_fds[2], control_fds[2], err, output_len; err = tap_open_common(pri->dev, pri->gate_addr); - if(err) return(err); + if(err) + return err; err = os_pipe(data_fds, 0, 0); if(err < 0){ printk("data os_pipe failed - err = %d\n", -err); - return(err); + return err; } err = os_pipe(control_fds, 1, 0); if(err < 0){ printk("control os_pipe failed - err = %d\n", -err); - return(err); + return err; } - + err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], control_fds[1], data_fds[0], data_fds[1]); - output_len = page_size(); + output_len = UM_KERN_PAGE_SIZE; output = um_kmalloc(output_len); read_output(control_fds[0], output, output_len); @@ -171,13 +178,13 @@ static int etap_open(void *data) if(err < 0){ printk("etap_tramp failed - err = %d\n", -err); - return(err); + return err; } pri->data_fd = data_fds[0]; pri->control_fd = control_fds[0]; iter_addresses(pri->dev, etap_open_addr, &pri->control_fd); - return(data_fds[0]); + return data_fds[0]; } static void etap_close(int fd, void *data) @@ -195,7 +202,7 @@ static void etap_close(int fd, void *data) static int etap_set_mtu(int mtu, void *data) { - return(mtu); + return mtu; } static void etap_add_addr(unsigned char *addr, unsigned char *netmask, @@ -204,7 +211,8 @@ static void etap_add_addr(unsigned char *addr, unsigned char *netmask, struct ethertap_data *pri = data; tap_check_ips(pri->gate_addr, addr); - if(pri->control_fd == -1) return; + if(pri->control_fd == -1) + return; etap_open_addr(addr, netmask, &pri->control_fd); } @@ -213,7 +221,8 @@ static void etap_del_addr(unsigned char *addr, unsigned char *netmask, { struct ethertap_data *pri = data; - if(pri->control_fd == -1) return; + if(pri->control_fd == -1) + return; etap_close_addr(addr, netmask, &pri->control_fd); } @@ -227,14 +236,3 @@ const struct net_user_info ethertap_user_info = { .delete_address = etap_del_addr, .max_packet = MAX_PACKET - ETH_HEADER_ETHERTAP }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/os-Linux/drivers/tuntap_user.c b/trunk/arch/um/os-Linux/drivers/tuntap_user.c index e846b23f7558..11a9779dc9f1 100644 --- a/trunk/arch/um/os-Linux/drivers/tuntap_user.c +++ b/trunk/arch/um/os-Linux/drivers/tuntap_user.c @@ -18,17 +18,17 @@ #include "net_user.h" #include "tuntap.h" #include "kern_util.h" -#include "user_util.h" #include "user.h" #include "os.h" #define MAX_PACKET ETH_MAX_PACKET -void tuntap_user_init(void *data, void *dev) +static int tuntap_user_init(void *data, void *dev) { struct tuntap_data *pri = data; pri->dev = dev; + return 0; } static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask, @@ -37,7 +37,8 @@ static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask, struct tuntap_data *pri = data; tap_check_ips(pri->gate_addr, addr); - if((pri->fd == -1) || pri->fixed_config) return; + if((pri->fd == -1) || pri->fixed_config) + return; open_addr(addr, netmask, pri->dev_name); } @@ -46,7 +47,8 @@ static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask, { struct tuntap_data *pri = data; - if((pri->fd == -1) || pri->fixed_config) return; + if((pri->fd == -1) || pri->fixed_config) + return; close_addr(addr, netmask, pri->dev_name); } @@ -58,7 +60,7 @@ struct tuntap_pre_exec_data { static void tuntap_pre_exec(void *arg) { struct tuntap_pre_exec_data *data = arg; - + dup2(data->stdout, 1); os_close_file(data->close_me); } @@ -83,7 +85,8 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, pid = run_helper(tuntap_pre_exec, &data, argv, NULL); - if(pid < 0) return(-pid); + if(pid < 0) + return -pid; os_close_file(remote); @@ -114,16 +117,16 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, cmsg = CMSG_FIRSTHDR(&msg); if(cmsg == NULL){ printk("tuntap_open_tramp : didn't receive a message\n"); - return(-EINVAL); + return -EINVAL; } if((cmsg->cmsg_level != SOL_SOCKET) || (cmsg->cmsg_type != SCM_RIGHTS)){ printk("tuntap_open_tramp : didn't receive a descriptor\n"); - return(-EINVAL); + return -EINVAL; } *fd_out = ((int *) CMSG_DATA(cmsg))[0]; os_set_exec_close(*fd_out, 1); - return(0); + return 0; } static int tuntap_open(void *data) @@ -135,7 +138,7 @@ static int tuntap_open(void *data) err = tap_open_common(pri->dev, pri->gate_addr); if(err < 0) - return(err); + return err; if(pri->fixed_config){ pri->fd = os_open_file("/dev/net/tun", @@ -143,7 +146,7 @@ static int tuntap_open(void *data) if(pri->fd < 0){ printk("Failed to open /dev/net/tun, err = %d\n", -pri->fd); - return(pri->fd); + return pri->fd; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; @@ -160,7 +163,7 @@ static int tuntap_open(void *data) if(err < 0){ printk("tuntap_open : os_pipe failed - err = %d\n", -err); - return(err); + return err; } buffer = get_output_buffer(&len); @@ -175,7 +178,7 @@ static int tuntap_open(void *data) printk("%s", output); free_output_buffer(buffer); printk("tuntap_open_tramp failed - err = %d\n", -err); - return(err); + return err; } pri->dev_name = uml_strdup(buffer); @@ -187,7 +190,7 @@ static int tuntap_open(void *data) iter_addresses(pri->dev, open_addr, pri->dev_name); } - return(pri->fd); + return pri->fd; } static void tuntap_close(int fd, void *data) @@ -202,7 +205,7 @@ static void tuntap_close(int fd, void *data) static int tuntap_set_mtu(int mtu, void *data) { - return(mtu); + return mtu; } const struct net_user_info tuntap_user_info = { @@ -215,14 +218,3 @@ const struct net_user_info tuntap_user_info = { .delete_address = tuntap_del_addr, .max_packet = MAX_PACKET }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/os-Linux/file.c b/trunk/arch/um/os-Linux/file.c index 371b4335f46d..6f92f732d253 100644 --- a/trunk/arch/um/os-Linux/file.c +++ b/trunk/arch/um/os-Linux/file.c @@ -18,7 +18,6 @@ #include "os.h" #include "user.h" #include "kern_util.h" -#include "user_util.h" static void copy_stat(struct uml_stat *dst, struct stat64 *src) { @@ -291,54 +290,22 @@ int os_seek_file(int fd, __u64 offset) return 0; } -static int fault_buffer(void *start, int len, - int (*copy_proc)(void *addr, void *buf, int len)) -{ - int page = getpagesize(), i; - char c; - - for(i = 0; i < len; i += page){ - if((*copy_proc)(start + i, &c, sizeof(c))) - return -EFAULT; - } - if((len % page) != 0){ - if((*copy_proc)(start + len - 1, &c, sizeof(c))) - return -EFAULT; - } - return 0; -} - -static int file_io(int fd, void *buf, int len, - int (*io_proc)(int fd, void *buf, int len), - int (*copy_user_proc)(void *addr, void *buf, int len)) +int os_read_file(int fd, void *buf, int len) { - int n, err; - - do { - n = (*io_proc)(fd, buf, len); - if((n < 0) && (errno == EFAULT)){ - err = fault_buffer(buf, len, copy_user_proc); - if(err) - return err; - n = (*io_proc)(fd, buf, len); - } - } while((n < 0) && (errno == EINTR)); + int n = read(fd, buf, len); if(n < 0) return -errno; return n; } -int os_read_file(int fd, void *buf, int len) -{ - return file_io(fd, buf, len, (int (*)(int, void *, int)) read, - copy_from_user_proc); -} - int os_write_file(int fd, const void *buf, int len) { - return file_io(fd, (void *) buf, len, - (int (*)(int, void *, int)) write, copy_to_user_proc); + int n = write(fd, (void *) buf, len); + + if(n < 0) + return -errno; + return n; } int os_file_size(char *file, unsigned long long *size_out) diff --git a/trunk/arch/um/os-Linux/helper.c b/trunk/arch/um/os-Linux/helper.c index c7ad6306e22f..97bed16bf4c7 100644 --- a/trunk/arch/um/os-Linux/helper.c +++ b/trunk/arch/um/os-Linux/helper.c @@ -13,9 +13,9 @@ #include #include "user.h" #include "kern_util.h" -#include "user_util.h" #include "os.h" #include "um_malloc.h" +#include "kern_constants.h" struct helper_data { void (*pre_exec)(void*); @@ -25,28 +25,18 @@ struct helper_data { char *buf; }; -/* Debugging aid, changed only from gdb */ -int helper_pause = 0; - -static void helper_hup(int sig) -{ -} - static int helper_child(void *arg) { struct helper_data *data = arg; char **argv = data->argv; int errval; - if (helper_pause){ - signal(SIGHUP, helper_hup); - pause(); - } if (data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); errval = execvp_noalloc(data->buf, argv[0], argv); - printk("helper_child - execvp of '%s' failed - errno = %d\n", argv[0], -errval); - os_write_file(data->fd, &errval, sizeof(errval)); + printk("helper_child - execvp of '%s' failed - errno = %d\n", argv[0], + -errval); + write(data->fd, &errval, sizeof(errval)); kill(os_getpid(), SIGKILL); return 0; } @@ -81,7 +71,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, goto out_close; } - sp = stack + page_size() - sizeof(void *); + sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); data.pre_exec = pre_exec; data.pre_data = pre_data; data.argv = argv; @@ -98,13 +88,16 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, close(fds[1]); fds[1] = -1; - /* Read the errno value from the child, if the exec failed, or get 0 if - * the exec succeeded because the pipe fd was set as close-on-exec. */ - n = os_read_file(fds[0], &ret, sizeof(ret)); + /* + * Read the errno value from the child, if the exec failed, or get 0 if + * the exec succeeded because the pipe fd was set as close-on-exec. + */ + n = read(fds[0], &ret, sizeof(ret)); if (n == 0) { ret = pid; } else { if (n < 0) { + n = -errno; printk("run_helper : read on pipe failed, ret = %d\n", -n); ret = n; @@ -135,7 +128,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, if (stack == 0) return -ENOMEM; - sp = stack + (page_size() << stack_order) - sizeof(void *); + sp = stack + (UM_KERN_PAGE_SIZE << stack_order) - sizeof(void *); pid = clone(proc, (void *) sp, flags | SIGCHLD, arg); if (pid < 0) { err = -errno; diff --git a/trunk/arch/um/os-Linux/irq.c b/trunk/arch/um/os-Linux/irq.c index d1b61d474e0a..a633fa8e0a94 100644 --- a/trunk/arch/um/os-Linux/irq.c +++ b/trunk/arch/um/os-Linux/irq.c @@ -11,7 +11,6 @@ #include #include #include -#include "user_util.h" #include "kern_util.h" #include "user.h" #include "process.h" diff --git a/trunk/arch/um/os-Linux/main.c b/trunk/arch/um/os-Linux/main.c index 685feaab65d2..ea9a23696f36 100644 --- a/trunk/arch/um/os-Linux/main.c +++ b/trunk/arch/um/os-Linux/main.c @@ -13,8 +13,8 @@ #include #include #include -#include "user_util.h" #include "kern_util.h" +#include "as-layout.h" #include "mem_user.h" #include "irq_user.h" #include "user.h" @@ -25,12 +25,7 @@ #include "os.h" #include "um_malloc.h" -/* Set in set_stklim, which is called from main and __wrap_malloc. - * __wrap_malloc only calls it if main hasn't started. - */ -unsigned long stacksizelim; - -/* Set in main */ +/* Set in main, unchanged thereafter */ char *linux_prog; #define PGD_BOUND (4 * 1024 * 1024) @@ -52,7 +47,6 @@ static void set_stklim(void) exit(1); } } - stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1); } static __init void do_uml_initcalls(void) @@ -126,7 +120,7 @@ extern int uml_exitcode; extern void scan_elf_aux( char **envp); -int main(int argc, char **argv, char **envp) +int __init main(int argc, char **argv, char **envp) { char **new_argv; int ret, i, err; @@ -224,7 +218,7 @@ int main(int argc, char **argv, char **envp) ret = 1; } printf("\n"); - return(uml_exitcode); + return uml_exitcode; } #define CAN_KMALLOC() \ @@ -237,7 +231,7 @@ void *__wrap_malloc(int size) void *ret; if(!CAN_KMALLOC()) - return(__real_malloc(size)); + return __real_malloc(size); else if(size <= PAGE_SIZE) /* finding contiguos pages can be hard*/ ret = um_kmalloc(size); else ret = um_vmalloc(size); @@ -248,16 +242,17 @@ void *__wrap_malloc(int size) if(ret == NULL) errno = ENOMEM; - return(ret); + return ret; } void *__wrap_calloc(int n, int size) { void *ptr = __wrap_malloc(n * size); - if(ptr == NULL) return(NULL); + if(ptr == NULL) + return NULL; memset(ptr, 0, n * size); - return(ptr); + return ptr; } extern void __real_free(void *); diff --git a/trunk/arch/um/os-Linux/mem.c b/trunk/arch/um/os-Linux/mem.c index f1ea169db85e..c6378c6d10d2 100644 --- a/trunk/arch/um/os-Linux/mem.c +++ b/trunk/arch/um/os-Linux/mem.c @@ -11,7 +11,6 @@ #include #include "kern_util.h" #include "user.h" -#include "user_util.h" #include "mem_user.h" #include "init.h" #include "os.h" @@ -165,7 +164,8 @@ static void which_tmpdir(void) * (file: kernel/tt/ptproxy/proxy.c, proc: start_debugger). * So it isn't 'static' yet. */ -int make_tempfile(const char *template, char **out_tempname, int do_unlink) +int __init make_tempfile(const char *template, char **out_tempname, + int do_unlink) { char *tempname; int fd; @@ -206,7 +206,7 @@ int make_tempfile(const char *template, char **out_tempname, int do_unlink) * This proc is used in start_up.c * So it isn't 'static'. */ -int create_tmp_file(unsigned long long len) +int __init create_tmp_file(unsigned long long len) { int fd, err; char zero; @@ -232,17 +232,16 @@ int create_tmp_file(unsigned long long len) zero = 0; - err = os_write_file(fd, &zero, 1); + err = write(fd, &zero, 1); if(err != 1){ - errno = -err; - perror("os_write_file"); + perror("write"); exit(1); } return fd; } -int create_mem_file(unsigned long long len) +int __init create_mem_file(unsigned long long len) { int err, fd; @@ -257,7 +256,7 @@ int create_mem_file(unsigned long long len) } -void check_tmpexec(void) +void __init check_tmpexec(void) { void *addr; int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE); diff --git a/trunk/arch/um/os-Linux/process.c b/trunk/arch/um/os-Linux/process.c index 76bdd6712417..92a7b59120d6 100644 --- a/trunk/arch/um/os-Linux/process.c +++ b/trunk/arch/um/os-Linux/process.c @@ -14,7 +14,6 @@ #include "ptrace_user.h" #include "os.h" #include "user.h" -#include "user_util.h" #include "process.h" #include "irq_user.h" #include "kern_util.h" @@ -22,6 +21,7 @@ #include "skas_ptrace.h" #include "kern_constants.h" #include "uml-config.h" +#include "init.h" #define ARBITRARY_ADDR -1 #define FAILURE_PID -1 @@ -40,14 +40,14 @@ unsigned long os_process_pc(int pid) if(fd < 0){ printk("os_process_pc - couldn't open '%s', err = %d\n", proc_stat, -fd); - return(ARBITRARY_ADDR); + return ARBITRARY_ADDR; } - err = os_read_file(fd, buf, sizeof(buf)); + CATCH_EINTR(err = read(fd, buf, sizeof(buf))); if(err < 0){ printk("os_process_pc - couldn't read '%s', err = %d\n", - proc_stat, -err); + proc_stat, errno); os_close_file(fd); - return(ARBITRARY_ADDR); + return ARBITRARY_ADDR; } os_close_file(fd); pc = ARBITRARY_ADDR; @@ -56,7 +56,7 @@ unsigned long os_process_pc(int pid) "%*d %*d %*d %*d %*d %lu", &pc) != 1){ printk("os_process_pc - couldn't find pc in '%s'\n", buf); } - return(pc); + return pc; } int os_process_parent(int pid) @@ -65,21 +65,22 @@ int os_process_parent(int pid) char data[256]; int parent, n, fd; - if(pid == -1) return(-1); + if(pid == -1) + return -1; snprintf(stat, sizeof(stat), "/proc/%d/stat", pid); fd = os_open_file(stat, of_read(OPENFLAGS()), 0); if(fd < 0){ printk("Couldn't open '%s', err = %d\n", stat, -fd); - return(FAILURE_PID); + return FAILURE_PID; } - n = os_read_file(fd, data, sizeof(data)); + CATCH_EINTR(n = read(fd, data, sizeof(data))); os_close_file(fd); if(n < 0){ - printk("Couldn't read '%s', err = %d\n", stat, -n); - return(FAILURE_PID); + printk("Couldn't read '%s', err = %d\n", stat, errno); + return FAILURE_PID; } parent = FAILURE_PID; @@ -87,7 +88,7 @@ int os_process_parent(int pid) if(n != 1) printk("Failed to scan '%s'\n", data); - return(parent); + return parent; } void os_stop_process(int pid) @@ -145,7 +146,7 @@ void os_usr1_process(int pid) int os_getpid(void) { - return(syscall(__NR_getpid)); + return syscall(__NR_getpid); } int os_getpgrp(void) @@ -165,8 +166,8 @@ int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, fd, off); if(loc == MAP_FAILED) - return(-errno); - return(0); + return -errno; + return 0; } int os_protect_memory(void *addr, unsigned long len, int r, int w, int x) @@ -175,8 +176,8 @@ int os_protect_memory(void *addr, unsigned long len, int r, int w, int x) (x ? PROT_EXEC : 0)); if(mprotect(addr, len, prot) < 0) - return(-errno); - return(0); + return -errno; + return 0; } int os_unmap_memory(void *addr, int len) @@ -185,15 +186,15 @@ int os_unmap_memory(void *addr, int len) err = munmap(addr, len); if(err < 0) - return(-errno); - return(0); + return -errno; + return 0; } #ifndef MADV_REMOVE #define MADV_REMOVE KERNEL_MADV_REMOVE #endif -int os_drop_memory(void *addr, int length) +int __init os_drop_memory(void *addr, int length) { int err; @@ -203,7 +204,7 @@ int os_drop_memory(void *addr, int length) return err; } -int can_drop_memory(void) +int __init can_drop_memory(void) { void *addr; int fd, ok = 0; @@ -244,7 +245,7 @@ void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) if(sig_stack != NULL){ pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER); - set_sigstack(sig_stack, pages * page_size()); + set_sigstack(sig_stack, pages * UM_KERN_PAGE_SIZE); flags = SA_ONSTACK; } if(usr1_handler){ diff --git a/trunk/arch/um/os-Linux/sigio.c b/trunk/arch/um/os-Linux/sigio.c index 3fc43b33db66..8d4e0c6b8c92 100644 --- a/trunk/arch/um/os-Linux/sigio.c +++ b/trunk/arch/um/os-Linux/sigio.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -16,10 +17,10 @@ #include "init.h" #include "user.h" #include "kern_util.h" -#include "user_util.h" #include "sigio.h" #include "os.h" #include "um_malloc.h" +#include "init.h" /* Protected by sigio_lock(), also used by sigio_cleanup, which is an * exitcall. @@ -68,11 +69,12 @@ static int write_sigio_thread(void *unused) p = &fds->poll[i]; if(p->revents == 0) continue; if(p->fd == sigio_private[1]){ - n = os_read_file(sigio_private[1], &c, sizeof(c)); + CATCH_EINTR(n = read(sigio_private[1], &c, + sizeof(c))); if(n != sizeof(c)) printk("write_sigio_thread : " "read on socket failed, " - "err = %d\n", -n); + "err = %d\n", errno); tmp = current_poll; current_poll = next_poll; next_poll = tmp; @@ -85,10 +87,10 @@ static int write_sigio_thread(void *unused) (fds->used - i) * sizeof(*fds->poll)); } - n = os_write_file(respond_fd, &c, sizeof(c)); + CATCH_EINTR(n = write(respond_fd, &c, sizeof(c))); if(n != sizeof(c)) printk("write_sigio_thread : write on socket " - "failed, err = %d\n", -n); + "failed, err = %d\n", errno); } } @@ -126,15 +128,15 @@ static void update_thread(void) char c; flags = set_signals(0); - n = os_write_file(sigio_private[0], &c, sizeof(c)); + n = write(sigio_private[0], &c, sizeof(c)); if(n != sizeof(c)){ - printk("update_thread : write failed, err = %d\n", -n); + printk("update_thread : write failed, err = %d\n", errno); goto fail; } - n = os_read_file(sigio_private[0], &c, sizeof(c)); + CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c))); if(n != sizeof(c)){ - printk("update_thread : read failed, err = %d\n", -n); + printk("update_thread : read failed, err = %d\n", errno); goto fail; } @@ -320,6 +322,10 @@ static void write_sigio_workaround(void) close(l_write_sigio_fds[1]); } +/* Changed during early boot */ +static int pty_output_sigio = 0; +static int pty_close_sigio = 0; + void maybe_sigio_broken(int fd, int read) { int err; @@ -357,3 +363,143 @@ static void sigio_cleanup(void) } __uml_exitcall(sigio_cleanup); + +/* Used as a flag during SIGIO testing early in boot */ +static volatile int got_sigio = 0; + +static void __init handler(int sig) +{ + got_sigio = 1; +} + +struct openpty_arg { + int master; + int slave; + int err; +}; + +static void openpty_cb(void *arg) +{ + struct openpty_arg *info = arg; + + info->err = 0; + if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) + info->err = -errno; +} + +static int async_pty(int master, int slave) +{ + int flags; + + flags = fcntl(master, F_GETFL); + if(flags < 0) + return -errno; + + if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || + (fcntl(master, F_SETOWN, os_getpid()) < 0)) + return -errno; + + if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) + return -errno; + + return(0); +} + +static void __init check_one_sigio(void (*proc)(int, int)) +{ + struct sigaction old, new; + struct openpty_arg pty = { .master = -1, .slave = -1 }; + int master, slave, err; + + initial_thread_cb(openpty_cb, &pty); + if(pty.err){ + printk("openpty failed, errno = %d\n", -pty.err); + return; + } + + master = pty.master; + slave = pty.slave; + + if((master == -1) || (slave == -1)){ + printk("openpty failed to allocate a pty\n"); + return; + } + + /* Not now, but complain so we now where we failed. */ + err = raw(master); + if (err < 0) + panic("check_sigio : __raw failed, errno = %d\n", -err); + + err = async_pty(master, slave); + if(err < 0) + panic("tty_fds : sigio_async failed, err = %d\n", -err); + + if(sigaction(SIGIO, NULL, &old) < 0) + panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); + new = old; + new.sa_handler = handler; + if(sigaction(SIGIO, &new, NULL) < 0) + panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); + + got_sigio = 0; + (*proc)(master, slave); + + close(master); + close(slave); + + if(sigaction(SIGIO, &old, NULL) < 0) + panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); +} + +static void tty_output(int master, int slave) +{ + int n; + char buf[512]; + + printk("Checking that host ptys support output SIGIO..."); + + memset(buf, 0, sizeof(buf)); + + while(write(master, buf, sizeof(buf)) > 0) ; + if(errno != EAGAIN) + panic("tty_output : write failed, errno = %d\n", errno); + while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; + + if(got_sigio){ + printk("Yes\n"); + pty_output_sigio = 1; + } + else if(n == -EAGAIN) + printk("No, enabling workaround\n"); + else panic("tty_output : read failed, err = %d\n", n); +} + +static void tty_close(int master, int slave) +{ + printk("Checking that host ptys support SIGIO on close..."); + + close(slave); + if(got_sigio){ + printk("Yes\n"); + pty_close_sigio = 1; + } + else printk("No, enabling workaround\n"); +} + +void __init check_sigio(void) +{ + if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && + (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ + printk("No pseudo-terminals available - skipping pty SIGIO " + "check\n"); + return; + } + check_one_sigio(tty_output); + check_one_sigio(tty_close); +} + +/* Here because it only does the SIGIO testing for now */ +void __init os_check_bugs(void) +{ + check_sigio(); +} diff --git a/trunk/arch/um/os-Linux/signal.c b/trunk/arch/um/os-Linux/signal.c index 266768629fee..48d493415301 100644 --- a/trunk/arch/um/os-Linux/signal.c +++ b/trunk/arch/um/os-Linux/signal.c @@ -11,7 +11,6 @@ #include #include #include -#include "user_util.h" #include "user.h" #include "signal_kern.h" #include "sysdep/sigcontext.h" diff --git a/trunk/arch/um/os-Linux/skas/mem.c b/trunk/arch/um/os-Linux/skas/mem.c index 9383e8751ae7..8e490fff3d47 100644 --- a/trunk/arch/um/os-Linux/skas/mem.c +++ b/trunk/arch/um/os-Linux/skas/mem.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -17,17 +18,17 @@ #include "os.h" #include "proc_mm.h" #include "ptrace_user.h" -#include "user_util.h" #include "kern_util.h" #include "task.h" #include "registers.h" #include "uml-config.h" #include "sysdep/ptrace.h" #include "sysdep/stub.h" +#include "init.h" extern unsigned long batch_syscall_stub, __syscall_stub_start; -extern void wait_stub_done(int pid, int sig, char * fname); +extern void wait_stub_done(int pid); static inline unsigned long *check_init_stack(struct mm_id * mm_idp, unsigned long *stack) @@ -39,6 +40,19 @@ static inline unsigned long *check_init_stack(struct mm_id * mm_idp, return stack; } +static unsigned long syscall_regs[MAX_REG_NR]; + +static int __init init_syscall_regs(void) +{ + get_safe_registers(syscall_regs, NULL); + syscall_regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + + ((unsigned long) &batch_syscall_stub - + (unsigned long) &__syscall_stub_start); + return 0; +} + +__initcall(init_syscall_regs); + extern int proc_mm; int single_count = 0; @@ -47,12 +61,11 @@ int multi_op_count = 0; static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) { - unsigned long regs[MAX_REG_NR]; int n, i; long ret, offset; unsigned long * data; unsigned long * syscall; - int pid = mm_idp->u.pid; + int err, pid = mm_idp->u.pid; if(proc_mm) #warning Need to look up userspace_pid by cpu @@ -60,21 +73,21 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) multi_count++; - get_safe_registers(regs, NULL); - regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + - ((unsigned long) &batch_syscall_stub - - (unsigned long) &__syscall_stub_start); - - n = ptrace_setregs(pid, regs); + n = ptrace_setregs(pid, syscall_regs); if(n < 0){ printk("Registers - \n"); for(i = 0; i < MAX_REG_NR; i++) - printk("\t%d\t0x%lx\n", i, regs[i]); + printk("\t%d\t0x%lx\n", i, syscall_regs[i]); panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", -n); } - wait_stub_done(pid, 0, "do_syscall_stub"); + err = ptrace(PTRACE_CONT, pid, 0, 0); + if(err) + panic("Failed to continue stub, pid = %d, errno = %d\n", pid, + errno); + + wait_stub_done(pid); /* When the stub stops, we find the following values on the * beginning of the stack: @@ -176,14 +189,10 @@ long syscall_stub_data(struct mm_id * mm_idp, return 0; } -int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, - int r, int w, int x, int phys_fd, unsigned long long offset, - int done, void **data) +int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot, + int phys_fd, unsigned long long offset, int done, void **data) { - int prot, ret; - - prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | - (x ? PROT_EXEC : 0); + int ret; if(proc_mm){ struct proc_mm_op map; @@ -200,9 +209,11 @@ int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, .fd = phys_fd, .offset= offset } } } ); - ret = os_write_file(fd, &map, sizeof(map)); - if(ret != sizeof(map)) + CATCH_EINTR(ret = write(fd, &map, sizeof(map))); + if(ret != sizeof(map)){ + ret = -errno; printk("map : /proc/mm map failed, err = %d\n", -ret); + } else ret = 0; } else { @@ -217,8 +228,8 @@ int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, return ret; } -int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done, - void **data) +int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, + int done, void **data) { int ret; @@ -232,9 +243,11 @@ int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done, { .addr = (unsigned long) addr, .len = len } } } ); - ret = os_write_file(fd, &unmap, sizeof(unmap)); - if(ret != sizeof(unmap)) + CATCH_EINTR(ret = write(fd, &unmap, sizeof(unmap))); + if(ret != sizeof(unmap)){ + ret = -errno; printk("unmap - proc_mm write returned %d\n", ret); + } else ret = 0; } else { @@ -249,13 +262,11 @@ int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done, } int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, - int r, int w, int x, int done, void **data) + unsigned int prot, int done, void **data) { struct proc_mm_op protect; - int prot, ret; + int ret; - prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | - (x ? PROT_EXEC : 0); if(proc_mm){ int fd = mm_idp->u.mm_fd; @@ -267,9 +278,11 @@ int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, .len = len, .prot = prot } } } ); - ret = os_write_file(fd, &protect, sizeof(protect)); - if(ret != sizeof(protect)) + CATCH_EINTR(ret = write(fd, &protect, sizeof(protect))); + if(ret != sizeof(protect)){ + ret = -errno; printk("protect failed, err = %d", -ret); + } else ret = 0; } else { diff --git a/trunk/arch/um/os-Linux/skas/process.c b/trunk/arch/um/os-Linux/skas/process.c index 0564422c155f..5c088a55396c 100644 --- a/trunk/arch/um/os-Linux/skas/process.c +++ b/trunk/arch/um/os-Linux/skas/process.c @@ -18,7 +18,6 @@ #include #include "user.h" #include "sysdep/ptrace.h" -#include "user_util.h" #include "kern_util.h" #include "skas.h" #include "stub-data.h" @@ -34,6 +33,8 @@ #include "uml-config.h" #include "process.h" #include "longjmp.h" +#include "kern_constants.h" +#include "as-layout.h" int is_skas_winch(int pid, int fd, void *data) { @@ -44,45 +45,58 @@ int is_skas_winch(int pid, int fd, void *data) return(1); } -void wait_stub_done(int pid, int sig, char * fname) +static int ptrace_dump_regs(int pid) { - int n, status, err; + unsigned long regs[MAX_REG_NR]; + int i; + + if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) + return -errno; + else { + printk("Stub registers -\n"); + for(i = 0; i < ARRAY_SIZE(regs); i++) + printk("\t%d - %lx\n", i, regs[i]); + } + + return 0; +} - do { - if ( sig != -1 ) { - err = ptrace(PTRACE_CONT, pid, 0, sig); - if(err) - panic("%s : continue failed, errno = %d\n", - fname, errno); - } - sig = 0; +/* + * Signals that are OK to receive in the stub - we'll just continue it. + * SIGWINCH will happen when UML is inside a detached screen. + */ +#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH)) + +/* Signals that the stub will finish with - anything else is an error */ +#define STUB_DONE_MASK ((1 << SIGUSR1) | (1 << SIGTRAP)) + +void wait_stub_done(int pid) +{ + int n, status, err; + while(1){ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); - } while((n >= 0) && WIFSTOPPED(status) && - ((WSTOPSIG(status) == SIGVTALRM) || - /* running UML inside a detached screen can cause - * SIGWINCHes - */ - (WSTOPSIG(status) == SIGWINCH))); - - if((n < 0) || !WIFSTOPPED(status) || - (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){ - unsigned long regs[MAX_REG_NR]; - - if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) - printk("Failed to get registers from stub, " - "errno = %d\n", errno); - else { - int i; - - printk("Stub registers -\n"); - for(i = 0; i < ARRAY_SIZE(regs); i++) - printk("\t%d - %lx\n", i, regs[i]); - } - panic("%s : failed to wait for SIGUSR1/SIGTRAP, " - "pid = %d, n = %d, errno = %d, status = 0x%x\n", - fname, pid, n, errno, status); + if((n < 0) || !WIFSTOPPED(status)) + goto bad_wait; + + if(((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0) + break; + + err = ptrace(PTRACE_CONT, pid, 0, 0); + if(err) + panic("wait_stub_done : continue failed, errno = %d\n", + errno); } + + if(((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0) + return; + +bad_wait: + err = ptrace_dump_regs(pid); + if(err) + printk("Failed to get registers from stub, errno = %d\n", -err); + panic("wait_stub_done : failed to wait for SIGUSR1/SIGTRAP, pid = %d, " + "n = %d, errno = %d, status = 0x%x\n", pid, n, errno, status); } extern unsigned long current_stub_stack(void); @@ -104,7 +118,11 @@ void get_skas_faultinfo(int pid, struct faultinfo * fi) sizeof(struct ptrace_faultinfo)); } else { - wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo"); + err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV); + if(err) + panic("Failed to continue stub, pid = %d, errno = %d\n", + pid, errno); + wait_stub_done(pid); /* faultinfo is prepared by the stub-segv-handler at start of * the stub stack page. We just have to copy it. @@ -142,9 +160,14 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if((err < 0) || !WIFSTOPPED(status) || - (WSTOPSIG(status) != SIGTRAP + 0x80)) + (WSTOPSIG(status) != SIGTRAP + 0x80)){ + err = ptrace_dump_regs(pid); + if(err) + printk("Failed to get registers from process, " + "errno = %d\n", -err); panic("handle_trap - failed to wait at end of syscall, " "errno = %d, status = %d\n", errno, status); + } } handle_syscall(regs); @@ -172,7 +195,7 @@ static int userspace_tramp(void *stack) int fd; __u64 offset; fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); - addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(), + addr = mmap64((void *) UML_CONFIG_STUB_CODE, UM_KERN_PAGE_SIZE, PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); if(addr == MAP_FAILED){ printk("mapping mmap stub failed, errno = %d\n", @@ -182,8 +205,8 @@ static int userspace_tramp(void *stack) if(stack != NULL){ fd = phys_mapping(to_phys(stack), &offset); - addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(), - PROT_READ | PROT_WRITE, + addr = mmap((void *) UML_CONFIG_STUB_DATA, + UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, offset); if(addr == MAP_FAILED){ printk("mapping segfault stack failed, " @@ -199,7 +222,7 @@ static int userspace_tramp(void *stack) (unsigned long) stub_segv_handler - (unsigned long) &__syscall_stub_start; - set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size()); + set_sigstack((void *) UML_CONFIG_STUB_DATA, UM_KERN_PAGE_SIZE); sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGIO); sigaddset(&sa.sa_mask, SIGWINCH); @@ -291,10 +314,13 @@ void userspace(union uml_pt_regs *regs) UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ if(WIFSTOPPED(status)){ - switch(WSTOPSIG(status)){ + int sig = WSTOPSIG(status); + switch(sig){ case SIGSEGV: - if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo) - user_signal(SIGSEGV, regs, pid); + if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo){ + get_skas_faultinfo(pid, ®s->skas.faultinfo); + (*sig_info[SIGSEGV])(SIGSEGV, regs); + } else handle_segv(pid, regs); break; case SIGTRAP + 0x80: @@ -309,11 +335,13 @@ void userspace(union uml_pt_regs *regs) case SIGBUS: case SIGFPE: case SIGWINCH: - user_signal(WSTOPSIG(status), regs, pid); + block_signals(); + (*sig_info[sig])(sig, regs); + unblock_signals(); break; default: printk("userspace - child stopped with signal " - "%d\n", WSTOPSIG(status)); + "%d\n", sig); } pid = userspace_pid[0]; interrupt_end(); @@ -325,11 +353,29 @@ void userspace(union uml_pt_regs *regs) } } +static unsigned long thread_regs[MAX_REG_NR]; +static unsigned long thread_fp_regs[HOST_FP_SIZE]; + +static int __init init_thread_regs(void) +{ + get_safe_registers(thread_regs, thread_fp_regs); + /* Set parent's instruction pointer to start of clone-stub */ + thread_regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + + (unsigned long) stub_clone_handler - + (unsigned long) &__syscall_stub_start; + thread_regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE - + sizeof(void *); +#ifdef __SIGNAL_FRAMESIZE + thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; +#endif + return 0; +} + +__initcall(init_thread_regs); + int copy_context_skas0(unsigned long new_stack, int pid) { int err; - unsigned long regs[MAX_REG_NR]; - unsigned long fp_regs[HOST_FP_SIZE]; unsigned long current_stack = current_stub_stack(); struct stub_data *data = (struct stub_data *) current_stack; struct stub_data *child_data = (struct stub_data *) new_stack; @@ -344,23 +390,12 @@ int copy_context_skas0(unsigned long new_stack, int pid) .timer = ((struct itimerval) { { 0, 1000000 / hz() }, { 0, 1000000 / hz() }})}); - get_safe_registers(regs, fp_regs); - - /* Set parent's instruction pointer to start of clone-stub */ - regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + - (unsigned long) stub_clone_handler - - (unsigned long) &__syscall_stub_start; - regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE - - sizeof(void *); -#ifdef __SIGNAL_FRAMESIZE - regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; -#endif - err = ptrace_setregs(pid, regs); + err = ptrace_setregs(pid, thread_regs); if(err < 0) panic("copy_context_skas0 : PTRACE_SETREGS failed, " "pid = %d, errno = %d\n", pid, -err); - err = ptrace_setfpregs(pid, fp_regs); + err = ptrace_setfpregs(pid, thread_fp_regs); if(err < 0) panic("copy_context_skas0 : PTRACE_SETFPREGS failed, " "pid = %d, errno = %d\n", pid, -err); @@ -371,7 +406,11 @@ int copy_context_skas0(unsigned long new_stack, int pid) /* Wait, until parent has finished its work: read child's pid from * parent's stack, and check, if bad result. */ - wait_stub_done(pid, 0, "copy_context_skas0"); + err = ptrace(PTRACE_CONT, pid, 0, 0); + if(err) + panic("Failed to continue new process, pid = %d, " + "errno = %d\n", pid, errno); + wait_stub_done(pid); pid = data->err; if(pid < 0) @@ -381,7 +420,7 @@ int copy_context_skas0(unsigned long new_stack, int pid) /* Wait, until child has finished too: read child's result from * child's stack and check it. */ - wait_stub_done(pid, -1, "copy_context_skas0"); + wait_stub_done(pid); if (child_data->err != UML_CONFIG_STUB_DATA) panic("copy_context_skas0 - stub-child reports error %ld\n", child_data->err); @@ -396,7 +435,7 @@ int copy_context_skas0(unsigned long new_stack, int pid) /* * This is used only, if stub pages are needed, while proc_mm is - * availabl. Opening /proc/mm creates a new mm_context, which lacks + * available. Opening /proc/mm creates a new mm_context, which lacks * the stub-pages. Thus, we map them using /proc/mm-fd */ void map_stub_pages(int fd, unsigned long code, @@ -418,12 +457,13 @@ void map_stub_pages(int fd, unsigned long code, .fd = code_fd, .offset = code_offset } } }); - n = os_write_file(fd, &mmop, sizeof(mmop)); + CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop))); if(n != sizeof(mmop)){ + n = errno; printk("mmap args - addr = 0x%lx, fd = %d, offset = %llx\n", code, code_fd, (unsigned long long) code_offset); panic("map_stub_pages : /proc/mm map for code failed, " - "err = %d\n", -n); + "err = %d\n", n); } if ( stack ) { @@ -440,10 +480,10 @@ void map_stub_pages(int fd, unsigned long code, .fd = map_fd, .offset = map_offset } } }); - n = os_write_file(fd, &mmop, sizeof(mmop)); + CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop))); if(n != sizeof(mmop)) panic("map_stub_pages : /proc/mm map for data failed, " - "err = %d\n", -n); + "err = %d\n", errno); } } @@ -480,7 +520,15 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, SIGVTALRM, -1); - n = UML_SETJMP(&initial_jmpbuf); + /* + * Can't use UML_SETJMP or UML_LONGJMP here because they save + * and restore signals, with the possible side-effect of + * trying to handle any signals which came when they were + * blocked, which can't be done on this stack. + * Signals must be blocked when jumping back here and restored + * after returning to the jumper. + */ + n = setjmp(initial_jmpbuf); switch(n){ case INIT_JMP_NEW_THREAD: (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler; @@ -490,7 +538,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) break; case INIT_JMP_CALLBACK: (*cb_proc)(cb_arg); - UML_LONGJMP(cb_back, 1); + longjmp(*cb_back, 1); break; case INIT_JMP_HALT: kmalloc_ok = 0; @@ -501,7 +549,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) default: panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); } - UML_LONGJMP(switch_buf, 1); + longjmp(*switch_buf, 1); } void initial_thread_cb_skas(void (*proc)(void *), void *arg) diff --git a/trunk/arch/um/os-Linux/skas/trap.c b/trunk/arch/um/os-Linux/skas/trap.c index 9ad5fbec4593..3b600c2e63b8 100644 --- a/trunk/arch/um/os-Linux/skas/trap.c +++ b/trunk/arch/um/os-Linux/skas/trap.c @@ -5,8 +5,8 @@ #include #include -#include "user_util.h" #include "kern_util.h" +#include "as-layout.h" #include "task.h" #include "sigcontext.h" #include "skas.h" @@ -15,29 +15,39 @@ #include "sysdep/ptrace_user.h" #include "os.h" +static union uml_pt_regs ksig_regs[UM_NR_CPUS]; + void sig_handler_common_skas(int sig, void *sc_ptr) { struct sigcontext *sc = sc_ptr; - struct skas_regs *r; + union uml_pt_regs *r; void (*handler)(int, union uml_pt_regs *); - int save_errno = errno; - int save_user; + int save_user, save_errno = errno; /* This is done because to allow SIGSEGV to be delivered inside a SEGV * handler. This can happen in copy_user, and if SEGV is disabled, * the process will die. * XXX Figure out why this is better than SA_NODEFER */ - if(sig == SIGSEGV) + if(sig == SIGSEGV) { change_sig(SIGSEGV, 1); + /* For segfaults, we want the data from the + * sigcontext. In this case, we don't want to mangle + * the process registers, so use a static set of + * registers. For other signals, the process + * registers are OK. + */ + r = &ksig_regs[cpu()]; + copy_sc(r, sc_ptr); + } + else r = TASK_REGS(get_current()); - r = &TASK_REGS(get_current())->skas; - save_user = r->is_user; - r->is_user = 0; + save_user = r->skas.is_user; + r->skas.is_user = 0; if ( sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGTRAP ) { - GET_FAULTINFO_FROM_SC(r->faultinfo, sc); + GET_FAULTINFO_FROM_SC(r->skas.faultinfo, sc); } change_sig(SIGUSR1, 1); @@ -49,25 +59,8 @@ void sig_handler_common_skas(int sig, void *sc_ptr) sig != SIGVTALRM && sig != SIGALRM) unblock_signals(); - handler(sig, (union uml_pt_regs *) r); + handler(sig, r); errno = save_errno; - r->is_user = save_user; -} - -extern int ptrace_faultinfo; - -void user_signal(int sig, union uml_pt_regs *regs, int pid) -{ - void (*handler)(int, union uml_pt_regs *); - int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) || - (sig == SIGILL) || (sig == SIGTRAP)); - - if (segv) - get_skas_faultinfo(pid, ®s->skas.faultinfo); - - handler = sig_info[sig]; - handler(sig, (union uml_pt_regs *) regs); - - unblock_signals(); + r->skas.is_user = save_user; } diff --git a/trunk/arch/um/os-Linux/start_up.c b/trunk/arch/um/os-Linux/start_up.c index 5178eba9afa5..79471f85eb89 100644 --- a/trunk/arch/um/os-Linux/start_up.c +++ b/trunk/arch/um/os-Linux/start_up.c @@ -17,10 +17,10 @@ #include #include #include +#include #include #include #include -#include "user_util.h" #include "kern_util.h" #include "user.h" #include "signal_kern.h" @@ -329,8 +329,32 @@ static void __init check_ptrace(void) extern void check_tmpexec(void); -void os_early_checks(void) +static void __init check_coredump_limit(void) { + struct rlimit lim; + int err = getrlimit(RLIMIT_CORE, &lim); + + if(err){ + perror("Getting core dump limit"); + return; + } + + printf("Core dump limits :\n\tsoft - "); + if(lim.rlim_cur == RLIM_INFINITY) + printf("NONE\n"); + else printf("%lu\n", lim.rlim_cur); + + printf("\thard - "); + if(lim.rlim_max == RLIM_INFINITY) + printf("NONE\n"); + else printf("%lu\n", lim.rlim_max); +} + +void __init os_early_checks(void) +{ + /* Print out the core dump limits early */ + check_coredump_limit(); + check_ptrace(); /* Need to check this early because mmapping happens before the @@ -528,148 +552,3 @@ int __init parse_iomem(char *str, int *add) out: return 1; } - - -/* Changed during early boot */ -int pty_output_sigio = 0; -int pty_close_sigio = 0; - -/* Used as a flag during SIGIO testing early in boot */ -static volatile int got_sigio = 0; - -static void __init handler(int sig) -{ - got_sigio = 1; -} - -struct openpty_arg { - int master; - int slave; - int err; -}; - -static void openpty_cb(void *arg) -{ - struct openpty_arg *info = arg; - - info->err = 0; - if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) - info->err = -errno; -} - -static int async_pty(int master, int slave) -{ - int flags; - - flags = fcntl(master, F_GETFL); - if(flags < 0) - return -errno; - - if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || - (fcntl(master, F_SETOWN, os_getpid()) < 0)) - return -errno; - - if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) - return -errno; - - return(0); -} - -static void __init check_one_sigio(void (*proc)(int, int)) -{ - struct sigaction old, new; - struct openpty_arg pty = { .master = -1, .slave = -1 }; - int master, slave, err; - - initial_thread_cb(openpty_cb, &pty); - if(pty.err){ - printk("openpty failed, errno = %d\n", -pty.err); - return; - } - - master = pty.master; - slave = pty.slave; - - if((master == -1) || (slave == -1)){ - printk("openpty failed to allocate a pty\n"); - return; - } - - /* Not now, but complain so we now where we failed. */ - err = raw(master); - if (err < 0) - panic("check_sigio : __raw failed, errno = %d\n", -err); - - err = async_pty(master, slave); - if(err < 0) - panic("tty_fds : sigio_async failed, err = %d\n", -err); - - if(sigaction(SIGIO, NULL, &old) < 0) - panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); - new = old; - new.sa_handler = handler; - if(sigaction(SIGIO, &new, NULL) < 0) - panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); - - got_sigio = 0; - (*proc)(master, slave); - - close(master); - close(slave); - - if(sigaction(SIGIO, &old, NULL) < 0) - panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); -} - -static void tty_output(int master, int slave) -{ - int n; - char buf[512]; - - printk("Checking that host ptys support output SIGIO..."); - - memset(buf, 0, sizeof(buf)); - - while(os_write_file(master, buf, sizeof(buf)) > 0) ; - if(errno != EAGAIN) - panic("check_sigio : write failed, errno = %d\n", errno); - while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; - - if(got_sigio){ - printk("Yes\n"); - pty_output_sigio = 1; - } - else if(n == -EAGAIN) printk("No, enabling workaround\n"); - else panic("check_sigio : read failed, err = %d\n", n); -} - -static void tty_close(int master, int slave) -{ - printk("Checking that host ptys support SIGIO on close..."); - - close(slave); - if(got_sigio){ - printk("Yes\n"); - pty_close_sigio = 1; - } - else printk("No, enabling workaround\n"); -} - -void __init check_sigio(void) -{ - if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && - (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ - printk("No pseudo-terminals available - skipping pty SIGIO " - "check\n"); - return; - } - check_one_sigio(tty_output); - check_one_sigio(tty_close); -} - -void os_check_bugs(void) -{ - check_ptrace(); - check_sigio(); -} - diff --git a/trunk/arch/um/os-Linux/sys-i386/tls.c b/trunk/arch/um/os-Linux/sys-i386/tls.c index 256532034c62..32ed41ec1a3d 100644 --- a/trunk/arch/um/os-Linux/sys-i386/tls.c +++ b/trunk/arch/um/os-Linux/sys-i386/tls.c @@ -5,7 +5,7 @@ #include #include "sysdep/tls.h" -#include "user_util.h" +#include "user.h" /* Checks whether host supports TLS, and sets *tls_min according to the value * valid on the host. diff --git a/trunk/arch/um/os-Linux/time.c b/trunk/arch/um/os-Linux/time.c index 2115b8beb541..5de169b168f6 100644 --- a/trunk/arch/um/os-Linux/time.c +++ b/trunk/arch/um/os-Linux/time.c @@ -10,7 +10,6 @@ #include #include #include -#include "user_util.h" #include "kern_util.h" #include "user.h" #include "process.h" diff --git a/trunk/arch/um/os-Linux/trap.c b/trunk/arch/um/os-Linux/trap.c index d221214d2ed5..295da657931a 100644 --- a/trunk/arch/um/os-Linux/trap.c +++ b/trunk/arch/um/os-Linux/trap.c @@ -6,7 +6,6 @@ #include #include #include "kern_util.h" -#include "user_util.h" #include "os.h" #include "mode.h" #include "longjmp.h" diff --git a/trunk/arch/um/os-Linux/tt.c b/trunk/arch/um/os-Linux/tt.c index 3dc3a02d6263..bcf9359c4e9f 100644 --- a/trunk/arch/um/os-Linux/tt.c +++ b/trunk/arch/um/os-Linux/tt.c @@ -18,7 +18,6 @@ #include #include #include -#include "user_util.h" #include "kern_util.h" #include "user.h" #include "signal_kern.h" @@ -32,6 +31,7 @@ #include "choose-mode.h" #include "mode.h" #include "tempfile.h" +#include "kern_constants.h" int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, int must_succeed) @@ -143,7 +143,7 @@ int outer_tramp(void *arg) int sig = sigkill; t = arg; - t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2, + t->pid = clone(t->tramp, (void *) t->temp_stack + UM_KERN_PAGE_SIZE/2, t->flags, t->tramp_data); if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL); kill(os_getpid(), sig); diff --git a/trunk/arch/um/os-Linux/tty_log.c b/trunk/arch/um/os-Linux/tty_log.c index c6ba56c1560f..d11a55baa6bd 100644 --- a/trunk/arch/um/os-Linux/tty_log.c +++ b/trunk/arch/um/os-Linux/tty_log.c @@ -53,9 +53,9 @@ int open_tty_log(void *tty, void *current_tty) .direction = 0, .sec = tv.tv_sec, .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); - os_write_file(tty_log_fd, ¤t_tty, data.len); - return(tty_log_fd); + write(tty_log_fd, &data, sizeof(data)); + write(tty_log_fd, ¤t_tty, data.len); + return tty_log_fd; } sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, @@ -67,7 +67,7 @@ int open_tty_log(void *tty, void *current_tty) printk("open_tty_log : couldn't open '%s', errno = %d\n", buf, -fd); } - return(fd); + return fd; } void close_tty_log(int fd, void *tty) @@ -83,7 +83,7 @@ void close_tty_log(int fd, void *tty) .direction = 0, .sec = tv.tv_sec, .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); + write(tty_log_fd, &data, sizeof(data)); return; } os_close_file(fd); @@ -98,21 +98,21 @@ static int log_chunk(int fd, const char *buf, int len) try = (len > sizeof(chunk)) ? sizeof(chunk) : len; missed = copy_from_user_proc(chunk, (char *) buf, try); try -= missed; - n = os_write_file(fd, chunk, try); + n = write(fd, chunk, try); if(n != try) { if(n < 0) - return(n); - return(-EIO); + return -errno; + return -EIO; } if(missed != 0) - return(-EFAULT); + return -EFAULT; len -= try; total += try; buf += try; } - return(total); + return total; } int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) @@ -130,10 +130,10 @@ int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) .direction = direction, .sec = tv.tv_sec, .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); + write(tty_log_fd, &data, sizeof(data)); } - return(log_chunk(fd, buf, len)); + return log_chunk(fd, buf, len); } void log_exec(char **argv, void *tty) @@ -161,7 +161,7 @@ void log_exec(char **argv, void *tty) .direction = 0, .sec = tv.tv_sec, .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); + write(tty_log_fd, &data, sizeof(data)); for(ptr = argv; ; ptr++){ if(copy_from_user_proc(&arg, ptr, sizeof(arg))) @@ -179,7 +179,7 @@ extern void register_tty_logger(int (*opener)(void *, void *), static int register_logger(void) { register_tty_logger(open_tty_log, write_tty_log, close_tty_log); - return(0); + return 0; } __uml_initcall(register_logger); diff --git a/trunk/arch/um/os-Linux/util.c b/trunk/arch/um/os-Linux/util.c index 56b8a50e8bc2..c307a89ed259 100644 --- a/trunk/arch/um/os-Linux/util.c +++ b/trunk/arch/um/os-Linux/util.c @@ -21,7 +21,6 @@ #include #include #include -#include "user_util.h" #include "kern_util.h" #include "user.h" #include "mem_user.h" @@ -30,28 +29,29 @@ #include "uml-config.h" #include "os.h" #include "longjmp.h" +#include "kern_constants.h" void stack_protections(unsigned long address) { int prot = PROT_READ | PROT_WRITE | PROT_EXEC; - if(mprotect((void *) address, page_size(), prot) < 0) + if(mprotect((void *) address, UM_KERN_PAGE_SIZE, prot) < 0) panic("protecting stack failed, errno = %d", errno); } void task_protections(unsigned long address) { - unsigned long guard = address + page_size(); - unsigned long stack = guard + page_size(); + unsigned long guard = address + UM_KERN_PAGE_SIZE; + unsigned long stack = guard + UM_KERN_PAGE_SIZE; int prot = 0, pages; #ifdef notdef - if(mprotect((void *) stack, page_size(), prot) < 0) + if(mprotect((void *) stack, UM_KERN_PAGE_SIZE, prot) < 0) panic("protecting guard page failed, errno = %d", errno); #endif pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2; prot = PROT_READ | PROT_WRITE | PROT_EXEC; - if(mprotect((void *) stack, pages * page_size(), prot) < 0) + if(mprotect((void *) stack, pages * UM_KERN_PAGE_SIZE, prot) < 0) panic("protecting stack failed, errno = %d", errno); } @@ -96,15 +96,13 @@ void setup_machinename(char *machine_out) strcpy(machine_out, host.machine); } -char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1]; - -void setup_hostinfo(void) +void setup_hostinfo(char *buf, int len) { struct utsname host; uname(&host); - sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename, - host.release, host.version, host.machine); + snprintf(buf, len, "%s %s %s %s %s", host.sysname, host.nodename, + host.release, host.version, host.machine); } int setjmp_wrapper(void (*proc)(void *, void *), ...) @@ -121,3 +119,9 @@ int setjmp_wrapper(void (*proc)(void *, void *), ...) va_end(args); return n; } + +void os_dump_core(void) +{ + signal(SIGSEGV, SIG_DFL); + abort(); +} diff --git a/trunk/arch/um/sys-i386/bugs.c b/trunk/arch/um/sys-i386/bugs.c index f1bcd399ac90..0393e44813e7 100644 --- a/trunk/arch/um/sys-i386/bugs.c +++ b/trunk/arch/um/sys-i386/bugs.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -13,7 +13,6 @@ #include "sysdep/ptrace.h" #include "task.h" #include "os.h" -#include "user_util.h" #define MAXTOKEN 64 @@ -32,21 +31,21 @@ static char token(int fd, char *buf, int len, char stop) n = os_read_file(fd, ptr, sizeof(*ptr)); c = *ptr++; if(n != sizeof(*ptr)){ - if(n == 0) return(0); + if(n == 0) + return 0; printk("Reading /proc/cpuinfo failed, err = %d\n", -n); if(n < 0) - return(n); - else - return(-EIO); + return n; + else return -EIO; } } while((c != '\n') && (c != stop) && (ptr < end)); if(ptr == end){ printk("Failed to find '%c' in /proc/cpuinfo\n", stop); - return(-1); + return -1; } *(ptr - 1) = '\0'; - return(c); + return c; } static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) @@ -58,48 +57,25 @@ static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) while(1){ c = token(fd, scratch, len - 1, ':'); if(c <= 0) - return(0); + return 0; else if(c != ':'){ printk("Failed to find ':' in /proc/cpuinfo\n"); - return(0); + return 0; } if(!strncmp(scratch, key, strlen(key))) - return(1); + return 1; do { n = os_read_file(fd, &c, sizeof(c)); if(n != sizeof(c)){ printk("Failed to find newline in " "/proc/cpuinfo, err = %d\n", -n); - return(0); + return 0; } } while(c != '\n'); } - return(0); -} - -int cpu_feature(char *what, char *buf, int len) -{ - int fd, ret = 0; - - fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); - return(0); - } - - if(!find_cpuinfo_line(fd, what, buf, len)){ - printk("Couldn't find '%s' line in /proc/cpuinfo\n", what); - goto out_close; - } - - token(fd, buf, len, '\n'); - ret = 1; - - out_close: - os_close_file(fd); - return(ret); + return 0; } static int check_cpu_flag(char *feature, int *have_it) @@ -119,7 +95,8 @@ static int check_cpu_flag(char *feature, int *have_it) goto out; c = token(fd, buf, len - 1, ' '); - if(c < 0) goto out; + if(c < 0) + goto out; else if(c != ' '){ printk("Failed to find ' ' in /proc/cpuinfo\n"); goto out; @@ -127,7 +104,8 @@ static int check_cpu_flag(char *feature, int *have_it) while(1){ c = token(fd, buf, len - 1, ' '); - if(c < 0) goto out; + if(c < 0) + goto out; else if(c == '\n') break; if(!strcmp(buf, feature)){ @@ -136,8 +114,10 @@ static int check_cpu_flag(char *feature, int *have_it) } } out: - if(*have_it == 0) printk("No\n"); - else if(*have_it == 1) printk("Yes\n"); + if(*have_it == 0) + printk("No\n"); + else if(*have_it == 1) + printk("Yes\n"); os_close_file(fd); return 1; } @@ -189,12 +169,13 @@ int arch_handle_signal(int sig, union uml_pt_regs *regs) /* This is testing for a cmov (0x0f 0x4x) instruction causing a * SIGILL in init. */ - if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0); + if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) + return 0; if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) panic("SIGILL in init, could not read instructions!\n"); if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40)) - return(0); + return 0; if(host_has_cmov == 0) panic("SIGILL caused by cmov, which this processor doesn't " @@ -208,16 +189,5 @@ int arch_handle_signal(int sig, union uml_pt_regs *regs) "implements it, boot a filesystem compiled for older " "processors"); else panic("Bad value for host_has_cmov (%d)", host_has_cmov); - return(0); + return 0; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-i386/fault.c b/trunk/arch/um/sys-i386/fault.c index d0bbcdfdb53f..745b4fd49e9f 100644 --- a/trunk/arch/um/sys-i386/fault.c +++ b/trunk/arch/um/sys-i386/fault.c @@ -3,9 +3,7 @@ * Licensed under the GPL */ -#include #include "sysdep/ptrace.h" -#include "sysdep/sigcontext.h" /* These two are from asm-um/uaccess.h and linux/module.h, check them. */ struct exception_table_entry @@ -17,26 +15,14 @@ struct exception_table_entry const struct exception_table_entry *search_exception_tables(unsigned long add); /* Compare this to arch/i386/mm/extable.c:fixup_exception() */ -int arch_fixup(unsigned long address, void *sc_ptr) +int arch_fixup(unsigned long address, union uml_pt_regs *regs) { - struct sigcontext *sc = sc_ptr; const struct exception_table_entry *fixup; fixup = search_exception_tables(address); if(fixup != 0){ - sc->eip = fixup->fixup; + UPT_IP(regs) = fixup->fixup; return(1); } return(0); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-i386/ptrace_user.c b/trunk/arch/um/sys-i386/ptrace_user.c index 01212c88fcc4..40ff0c831bd0 100644 --- a/trunk/arch/um/sys-i386/ptrace_user.c +++ b/trunk/arch/um/sys-i386/ptrace_user.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -15,7 +15,6 @@ #include "user.h" #include "os.h" #include "uml-config.h" -#include "user_util.h" int ptrace_getregs(long pid, unsigned long *regs_out) { @@ -45,7 +44,8 @@ int ptrace_setfpregs(long pid, unsigned long *regs) return 0; } -/* All the below stuff is of interest for TT mode only */ +#ifdef UML_CONFIG_MODE_TT + static void write_debugregs(int pid, unsigned long *regs) { struct user *dummy; @@ -128,13 +128,4 @@ void update_debugregs(int seq) } #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +#endif diff --git a/trunk/arch/um/sys-i386/signal.c b/trunk/arch/um/sys-i386/signal.c index 3f6acd667717..1cbf95f6858a 100644 --- a/trunk/arch/um/sys-i386/signal.c +++ b/trunk/arch/um/sys-i386/signal.c @@ -18,6 +18,28 @@ #include "skas.h" +void copy_sc(union uml_pt_regs *regs, void *from) +{ + struct sigcontext *sc = from; + + REGS_GS(regs->skas.regs) = sc->gs; + REGS_FS(regs->skas.regs) = sc->fs; + REGS_ES(regs->skas.regs) = sc->es; + REGS_DS(regs->skas.regs) = sc->ds; + REGS_EDI(regs->skas.regs) = sc->edi; + REGS_ESI(regs->skas.regs) = sc->esi; + REGS_EBP(regs->skas.regs) = sc->ebp; + REGS_SP(regs->skas.regs) = sc->esp; + REGS_EBX(regs->skas.regs) = sc->ebx; + REGS_EDX(regs->skas.regs) = sc->edx; + REGS_ECX(regs->skas.regs) = sc->ecx; + REGS_EAX(regs->skas.regs) = sc->eax; + REGS_IP(regs->skas.regs) = sc->eip; + REGS_CS(regs->skas.regs) = sc->cs; + REGS_EFLAGS(regs->skas.regs) = sc->eflags; + REGS_SS(regs->skas.regs) = sc->ss; +} + static int copy_sc_from_user_skas(struct pt_regs *regs, struct sigcontext __user *from) { @@ -28,33 +50,18 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, err = copy_from_user(&sc, from, sizeof(sc)); err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs)); if(err) - return(err); - - REGS_GS(regs->regs.skas.regs) = sc.gs; - REGS_FS(regs->regs.skas.regs) = sc.fs; - REGS_ES(regs->regs.skas.regs) = sc.es; - REGS_DS(regs->regs.skas.regs) = sc.ds; - REGS_EDI(regs->regs.skas.regs) = sc.edi; - REGS_ESI(regs->regs.skas.regs) = sc.esi; - REGS_EBP(regs->regs.skas.regs) = sc.ebp; - REGS_SP(regs->regs.skas.regs) = sc.esp; - REGS_EBX(regs->regs.skas.regs) = sc.ebx; - REGS_EDX(regs->regs.skas.regs) = sc.edx; - REGS_ECX(regs->regs.skas.regs) = sc.ecx; - REGS_EAX(regs->regs.skas.regs) = sc.eax; - REGS_IP(regs->regs.skas.regs) = sc.eip; - REGS_CS(regs->regs.skas.regs) = sc.cs; - REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags; - REGS_SS(regs->regs.skas.regs) = sc.ss; + return err; + + copy_sc(®s->regs, &sc); err = restore_fp_registers(userspace_pid[0], fpregs); - if(err < 0){ + if(err < 0) { printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, " - "errno = %d\n", err); - return(1); + "errno = %d\n", -err); + return err; } - return(0); + return 0; } int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *to_fp, @@ -90,16 +97,16 @@ int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *t if(err < 0){ printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, " "errno = %d\n", err); - return(1); + return 1; } to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1)); sc.fpstate = to_fp; if(err) - return(err); + return err; - return(copy_to_user(to, &sc, sizeof(sc)) || - copy_to_user(to_fp, fpregs, sizeof(fpregs))); + return copy_to_user(to, &sc, sizeof(sc)) || + copy_to_user(to_fp, fpregs, sizeof(fpregs)); } #endif @@ -129,7 +136,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from, to->fpstate = to_fp; if(to_fp != NULL) err |= copy_from_user(to_fp, from_fp, fpsize); - return(err); + return err; } int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp, @@ -164,15 +171,15 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from) ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, sizeof(struct _fpstate)), copy_sc_from_user_skas(to, from)); - return(ret); + return ret; } static int copy_sc_to_user(struct sigcontext __user *to, struct _fpstate __user *fp, struct pt_regs *from, unsigned long sp) { - return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), + return CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), sizeof(*fp), sp), - copy_sc_to_user_skas(to, fp, from, sp))); + copy_sc_to_user_skas(to, fp, from, sp)); } static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp, @@ -185,7 +192,7 @@ static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __u err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs, sp); err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); - return(err); + return err; } struct sigframe @@ -359,7 +366,7 @@ long sys_sigreturn(struct pt_regs regs) /* Avoid ERESTART handling */ PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; - return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); + return PT_REGS_SYSCALL_RET(¤t->thread.regs); segfault: force_sig(SIGSEGV, current); @@ -389,20 +396,9 @@ long sys_rt_sigreturn(struct pt_regs regs) /* Avoid ERESTART handling */ PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; - return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); + return PT_REGS_SYSCALL_RET(¤t->thread.regs); segfault: force_sig(SIGSEGV, current); return 0; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-i386/tls.c b/trunk/arch/um/sys-i386/tls.c index 643dab585727..fea8e5e15cc4 100644 --- a/trunk/arch/um/sys-i386/tls.c +++ b/trunk/arch/um/sys-i386/tls.c @@ -23,9 +23,13 @@ #include "skas.h" #endif -/* If needed we can detect when it's uninitialized. */ +/* + * If needed we can detect when it's uninitialized. + * + * These are initialized in an initcall and unchanged thereafter. + */ static int host_supports_tls = -1; -int host_gdt_entry_tls_min = -1; +int host_gdt_entry_tls_min; #ifdef CONFIG_MODE_SKAS int do_set_thread_area_skas(struct user_desc *info) @@ -361,7 +365,8 @@ int ptrace_get_thread_area(struct task_struct *child, int idx, /* XXX: This part is probably common to i386 and x86-64. Don't create a common * file for now, do that when implementing x86-64 support.*/ -static int __init __setup_host_supports_tls(void) { +static int __init __setup_host_supports_tls(void) +{ check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min); if (host_supports_tls) { printk(KERN_INFO "Host TLS support detected\n"); diff --git a/trunk/arch/um/sys-i386/user-offsets.c b/trunk/arch/um/sys-i386/user-offsets.c index 447306b20aea..29118cf5ff25 100644 --- a/trunk/arch/um/sys-i386/user-offsets.c +++ b/trunk/arch/um/sys-i386/user-offsets.c @@ -1,9 +1,10 @@ #include +#include #include +#include +#include #include #include -#include -#include #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) @@ -47,7 +48,6 @@ void foo(void) OFFSET(HOST_SC_FP_ST, _fpstate, _st); OFFSET(HOST_SC_FXSR_ENV, _fpstate, _fxsr_env); - DEFINE(HOST_FRAME_SIZE, FRAME_SIZE); DEFINE_LONGS(HOST_FP_SIZE, sizeof(struct user_i387_struct)); DEFINE_LONGS(HOST_XFP_SIZE, sizeof(struct user_fxsr_struct)); @@ -73,4 +73,8 @@ void foo(void) DEFINE(UM_POLLIN, POLLIN); DEFINE(UM_POLLPRI, POLLPRI); DEFINE(UM_POLLOUT, POLLOUT); + + DEFINE(UM_PROT_READ, PROT_READ); + DEFINE(UM_PROT_WRITE, PROT_WRITE); + DEFINE(UM_PROT_EXEC, PROT_EXEC); } diff --git a/trunk/arch/um/sys-ppc/sigcontext.c b/trunk/arch/um/sys-ppc/sigcontext.c index 5d430fc994af..4bdc15c89edd 100644 --- a/trunk/arch/um/sys-ppc/sigcontext.c +++ b/trunk/arch/um/sys-ppc/sigcontext.c @@ -1,7 +1,6 @@ #include "asm/ptrace.h" #include "asm/sigcontext.h" #include "sysdep/ptrace.h" -#include "user_util.h" /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/trunk/arch/um/sys-x86_64/bugs.c b/trunk/arch/um/sys-x86_64/bugs.c index fdce7ea98ca7..095478890371 100644 --- a/trunk/arch/um/sys-x86_64/bugs.c +++ b/trunk/arch/um/sys-x86_64/bugs.c @@ -4,12 +4,7 @@ * Licensed under the GPL */ -#include "linux/sched.h" -#include "linux/errno.h" -#include "asm/system.h" -#include "asm/pda.h" #include "sysdep/ptrace.h" -#include "os.h" void arch_init_thread(void) { @@ -21,102 +16,5 @@ void arch_check_bugs(void) int arch_handle_signal(int sig, union uml_pt_regs *regs) { - return(0); + return 0; } - -#define MAXTOKEN 64 - -/* Set during early boot */ -int host_has_cmov = 1; -int host_has_xmm = 0; - -static char token(int fd, char *buf, int len, char stop) -{ - int n; - char *ptr, *end, c; - - ptr = buf; - end = &buf[len]; - do { - n = os_read_file(fd, ptr, sizeof(*ptr)); - c = *ptr++; - if(n != sizeof(*ptr)){ - if(n == 0) return(0); - printk("Reading /proc/cpuinfo failed, err = %d\n", -n); - if(n < 0) - return(n); - else - return(-EIO); - } - } while((c != '\n') && (c != stop) && (ptr < end)); - - if(ptr == end){ - printk("Failed to find '%c' in /proc/cpuinfo\n", stop); - return(-1); - } - *(ptr - 1) = '\0'; - return(c); -} - -static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) -{ - int n; - char c; - - scratch[len - 1] = '\0'; - while(1){ - c = token(fd, scratch, len - 1, ':'); - if(c <= 0) - return(0); - else if(c != ':'){ - printk("Failed to find ':' in /proc/cpuinfo\n"); - return(0); - } - - if(!strncmp(scratch, key, strlen(key))) - return(1); - - do { - n = os_read_file(fd, &c, sizeof(c)); - if(n != sizeof(c)){ - printk("Failed to find newline in " - "/proc/cpuinfo, err = %d\n", -n); - return(0); - } - } while(c != '\n'); - } - return(0); -} - -int cpu_feature(char *what, char *buf, int len) -{ - int fd, ret = 0; - - fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); - return(0); - } - - if(!find_cpuinfo_line(fd, what, buf, len)){ - printk("Couldn't find '%s' line in /proc/cpuinfo\n", what); - goto out_close; - } - - token(fd, buf, len, '\n'); - ret = 1; - - out_close: - os_close_file(fd); - return(ret); -} - -/* Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-x86_64/fault.c b/trunk/arch/um/sys-x86_64/fault.c index cee1513c5c31..4636b1465b6c 100644 --- a/trunk/arch/um/sys-x86_64/fault.c +++ b/trunk/arch/um/sys-x86_64/fault.c @@ -4,20 +4,24 @@ * Licensed under the GPL */ -#include "user.h" +#include "sysdep/ptrace.h" -int arch_fixup(unsigned long address, void *sc_ptr) +/* These two are from asm-um/uaccess.h and linux/module.h, check them. */ +struct exception_table_entry { - /* XXX search_exception_tables() */ + unsigned long insn; + unsigned long fixup; +}; + +const struct exception_table_entry *search_exception_tables(unsigned long add); +int arch_fixup(unsigned long address, union uml_pt_regs *regs) +{ + const struct exception_table_entry *fixup; + + fixup = search_exception_tables(address); + if(fixup != 0){ + UPT_IP(regs) = fixup->fixup; + return(1); + } return(0); } - -/* Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-x86_64/signal.c b/trunk/arch/um/sys-x86_64/signal.c index af2f017617b4..fe8ec04d35bb 100644 --- a/trunk/arch/um/sys-x86_64/signal.c +++ b/trunk/arch/um/sys-x86_64/signal.c @@ -20,6 +20,36 @@ #include "skas.h" +void copy_sc(union uml_pt_regs *regs, void *from) +{ + struct sigcontext *sc = from; + +#define GETREG(regs, regno, sc, regname) \ + (regs)->skas.regs[(regno) / sizeof(unsigned long)] = (sc)->regname + + GETREG(regs, R8, sc, r8); + GETREG(regs, R9, sc, r9); + GETREG(regs, R10, sc, r10); + GETREG(regs, R11, sc, r11); + GETREG(regs, R12, sc, r12); + GETREG(regs, R13, sc, r13); + GETREG(regs, R14, sc, r14); + GETREG(regs, R15, sc, r15); + GETREG(regs, RDI, sc, rdi); + GETREG(regs, RSI, sc, rsi); + GETREG(regs, RBP, sc, rbp); + GETREG(regs, RBX, sc, rbx); + GETREG(regs, RDX, sc, rdx); + GETREG(regs, RAX, sc, rax); + GETREG(regs, RCX, sc, rcx); + GETREG(regs, RSP, sc, rsp); + GETREG(regs, RIP, sc, rip); + GETREG(regs, EFLAGS, sc, eflags); + GETREG(regs, CS, sc, cs); + +#undef GETREG +} + static int copy_sc_from_user_skas(struct pt_regs *regs, struct sigcontext __user *from) { @@ -51,7 +81,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, #undef GETREG - return(err); + return err; } int copy_sc_to_user_skas(struct sigcontext __user *to, diff --git a/trunk/arch/um/sys-x86_64/user-offsets.c b/trunk/arch/um/sys-x86_64/user-offsets.c index 899cebb57c3f..0d5fd764c21f 100644 --- a/trunk/arch/um/sys-x86_64/user-offsets.c +++ b/trunk/arch/um/sys-x86_64/user-offsets.c @@ -2,6 +2,7 @@ #include #include #include +#include #define __FRAME_OFFSETS #include #include @@ -57,7 +58,6 @@ void foo(void) OFFSET(HOST_SC_SS, sigcontext, ss); #endif - DEFINE_LONGS(HOST_FRAME_SIZE, FRAME_SIZE); DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long)); DEFINE(HOST_XFP_SIZE, 0); DEFINE_LONGS(HOST_RBX, RBX); @@ -94,4 +94,8 @@ void foo(void) DEFINE(UM_POLLIN, POLLIN); DEFINE(UM_POLLPRI, POLLPRI); DEFINE(UM_POLLOUT, POLLOUT); + + DEFINE(UM_PROT_READ, PROT_READ); + DEFINE(UM_PROT_WRITE, PROT_WRITE); + DEFINE(UM_PROT_EXEC, PROT_EXEC); } diff --git a/trunk/arch/v850/Kconfig b/trunk/arch/v850/Kconfig index 50ccc7f57cd0..5f54c1236c18 100644 --- a/trunk/arch/v850/Kconfig +++ b/trunk/arch/v850/Kconfig @@ -37,6 +37,10 @@ config GENERIC_IRQ_PROBE bool default y +config GENERIC_TIME + bool + default y + config TIME_LOW_RES bool default y diff --git a/trunk/arch/v850/kernel/process.c b/trunk/arch/v850/kernel/process.c index c4f844c86e50..e4a4b8e7d5a3 100644 --- a/trunk/arch/v850/kernel/process.c +++ b/trunk/arch/v850/kernel/process.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/v850/kernel/ptrace.c b/trunk/arch/v850/kernel/ptrace.c index 67e057509664..a9b09343097d 100644 --- a/trunk/arch/v850/kernel/ptrace.c +++ b/trunk/arch/v850/kernel/ptrace.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/v850/kernel/signal.c b/trunk/arch/v850/kernel/signal.c index 17c2d4359b04..bf166e7e762c 100644 --- a/trunk/arch/v850/kernel/signal.c +++ b/trunk/arch/v850/kernel/signal.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include diff --git a/trunk/arch/v850/kernel/syscalls.c b/trunk/arch/v850/kernel/syscalls.c index d2b1fb19d243..f9f00ccf5324 100644 --- a/trunk/arch/v850/kernel/syscalls.c +++ b/trunk/arch/v850/kernel/syscalls.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/v850/kernel/time.c b/trunk/arch/v850/kernel/time.c index 486e3a441c86..f0905b03523b 100644 --- a/trunk/arch/v850/kernel/time.c +++ b/trunk/arch/v850/kernel/time.c @@ -90,81 +90,6 @@ static irqreturn_t timer_interrupt (int irq, void *dummy, struct pt_regs *regs) return IRQ_HANDLED; } -/* - * This version of gettimeofday has near microsecond resolution. - */ -void do_gettimeofday (struct timeval *tv) -{ -#if 0 /* DAVIDM later if possible */ - extern volatile unsigned long lost_ticks; - unsigned long lost; -#endif - unsigned long flags; - unsigned long usec, sec; - unsigned long seq; - - do { - seq = read_seqbegin_irqsave(&xtime_lock, flags); - -#if 0 - usec = mach_gettimeoffset ? mach_gettimeoffset () : 0; -#else - usec = 0; -#endif -#if 0 /* DAVIDM later if possible */ - lost = lost_ticks; - if (lost) - usec += lost * (1000000/HZ); -#endif - sec = xtime.tv_sec; - usec += xtime.tv_nsec / 1000; - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -EXPORT_SYMBOL(do_gettimeofday); - -int do_settimeofday(struct timespec *tv) -{ - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irq (&xtime_lock); - - /* This is revolting. We need to set the xtime.tv_nsec - * correctly. However, the value in this location is - * is value at the last tick. - * Discover what correction gettimeofday - * would have done, and then undo it! - */ -#if 0 - tv->tv_nsec -= mach_gettimeoffset() * 1000; -#endif - - while (tv->tv_nsec < 0) { - tv->tv_nsec += NSEC_PER_SEC; - tv->tv_sec--; - } - - xtime.tv_sec = tv->tv_sec; - xtime.tv_nsec = tv->tv_nsec; - - ntp_clear(); - - write_sequnlock_irq (&xtime_lock); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); - static int timer_dev_id; static struct irqaction timer_irqaction = { timer_interrupt, diff --git a/trunk/arch/x86_64/ia32/ia32_signal.c b/trunk/arch/x86_64/ia32/ia32_signal.c index 359eacc38509..6ea19c25f90d 100644 --- a/trunk/arch/x86_64/ia32/ia32_signal.c +++ b/trunk/arch/x86_64/ia32/ia32_signal.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/ia32/ia32entry.S b/trunk/arch/x86_64/ia32/ia32entry.S index c48087db6f75..f21068378272 100644 --- a/trunk/arch/x86_64/ia32/ia32entry.S +++ b/trunk/arch/x86_64/ia32/ia32entry.S @@ -710,9 +710,10 @@ ia32_sys_call_table: .quad compat_sys_get_robust_list .quad sys_splice .quad sys_sync_file_range - .quad sys_tee + .quad sys_tee /* 315 */ .quad compat_sys_vmsplice .quad compat_sys_move_pages .quad sys_getcpu .quad sys_epoll_pwait + .quad compat_sys_utimensat /* 320 */ ia32_syscall_end: diff --git a/trunk/arch/x86_64/kernel/Makefile b/trunk/arch/x86_64/kernel/Makefile index 4d94c51803d8..de1de8a2fd84 100644 --- a/trunk/arch/x86_64/kernel/Makefile +++ b/trunk/arch/x86_64/kernel/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_IOMMU) += pci-gart.o aperture.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary.o tce.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o +obj-$(CONFIG_SERIAL_8250) += legacy_serial.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o obj-$(CONFIG_X86_VSMP) += vsmp.o @@ -49,6 +50,7 @@ CFLAGS_vsyscall.o := $(PROFILING) -g0 therm_throt-y += ../../i386/kernel/cpu/mcheck/therm_throt.o bootflag-y += ../../i386/kernel/bootflag.o +legacy_serial-y += ../../i386/kernel/legacy_serial.o cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o topology-y += ../../i386/kernel/topology.o microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o diff --git a/trunk/arch/x86_64/kernel/apic.c b/trunk/arch/x86_64/kernel/apic.c index d198f7d82e5a..1b0e07bb8728 100644 --- a/trunk/arch/x86_64/kernel/apic.c +++ b/trunk/arch/x86_64/kernel/apic.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/kernel/crash.c b/trunk/arch/x86_64/kernel/crash.c index 95a7a2c13131..13432a1ae904 100644 --- a/trunk/arch/x86_64/kernel/crash.c +++ b/trunk/arch/x86_64/kernel/crash.c @@ -17,13 +17,13 @@ #include #include #include +#include #include #include #include #include #include -#include /* This keeps a track of which one is crashing cpu. */ static int crashing_cpu; diff --git a/trunk/arch/x86_64/kernel/e820.c b/trunk/arch/x86_64/kernel/e820.c index be8965427a93..13c6c37610e0 100644 --- a/trunk/arch/x86_64/kernel/e820.c +++ b/trunk/arch/x86_64/kernel/e820.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -256,22 +258,6 @@ void __init e820_reserve_resources(void) } } -/* Mark pages corresponding to given address range as nosave */ -static void __init -e820_mark_nosave_range(unsigned long start, unsigned long end) -{ - unsigned long pfn, max_pfn; - - if (start >= end) - return; - - printk("Nosave address range: %016lx - %016lx\n", start, end); - max_pfn = end >> PAGE_SHIFT; - for (pfn = start >> PAGE_SHIFT; pfn < max_pfn; pfn++) - if (pfn_valid(pfn)) - SetPageNosave(pfn_to_page(pfn)); -} - /* * Find the ranges of physical addresses that do not correspond to * e820 RAM areas and mark the corresponding pages as nosave for software @@ -290,13 +276,13 @@ void __init e820_mark_nosave_regions(void) struct e820entry *ei = &e820.map[i]; if (paddr < ei->addr) - e820_mark_nosave_range(paddr, - round_up(ei->addr, PAGE_SIZE)); + register_nosave_region(PFN_DOWN(paddr), + PFN_UP(ei->addr)); paddr = round_down(ei->addr + ei->size, PAGE_SIZE); if (ei->type != E820_RAM) - e820_mark_nosave_range(round_up(ei->addr, PAGE_SIZE), - paddr); + register_nosave_region(PFN_UP(ei->addr), + PFN_DOWN(paddr)); if (paddr >= (end_pfn << PAGE_SHIFT)) break; diff --git a/trunk/arch/x86_64/kernel/early_printk.c b/trunk/arch/x86_64/kernel/early_printk.c index 92213d2b7c11..56eaa259782b 100644 --- a/trunk/arch/x86_64/kernel/early_printk.c +++ b/trunk/arch/x86_64/kernel/early_printk.c @@ -243,22 +243,12 @@ static int __init setup_early_printk(char *buf) early_console = &simnow_console; keep_early = 1; } + + if (keep_early) + early_console->flags &= ~CON_BOOT; + else + early_console->flags |= CON_BOOT; register_console(early_console); return 0; } - early_param("earlyprintk", setup_early_printk); - -void __init disable_early_printk(void) -{ - if (!early_console_initialized || !early_console) - return; - if (!keep_early) { - printk("disabling early console\n"); - unregister_console(early_console); - early_console_initialized = 0; - } else { - printk("keeping early console\n"); - } -} - diff --git a/trunk/arch/x86_64/kernel/i8259.c b/trunk/arch/x86_64/kernel/i8259.c index 489426682772..4b326655b208 100644 --- a/trunk/arch/x86_64/kernel/i8259.c +++ b/trunk/arch/x86_64/kernel/i8259.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/kernel/io_apic.c b/trunk/arch/x86_64/kernel/io_apic.c index 2a2df14dab7e..4d582589fa89 100644 --- a/trunk/arch/x86_64/kernel/io_apic.c +++ b/trunk/arch/x86_64/kernel/io_apic.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/kernel/ioport.c b/trunk/arch/x86_64/kernel/ioport.c index 387d347b0e07..653efa30b0f4 100644 --- a/trunk/arch/x86_64/kernel/ioport.c +++ b/trunk/arch/x86_64/kernel/ioport.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/kernel/kprobes.c b/trunk/arch/x86_64/kernel/kprobes.c index 209c8c0bec71..d4a0d0ac9935 100644 --- a/trunk/arch/x86_64/kernel/kprobes.c +++ b/trunk/arch/x86_64/kernel/kprobes.c @@ -37,10 +37,10 @@ #include #include #include +#include #include #include -#include #include void jprobe_return_end(void); @@ -266,23 +266,14 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) } /* Called with kretprobe_lock held */ -void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, +void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { unsigned long *sara = (unsigned long *)regs->rsp; - struct kretprobe_instance *ri; - if ((ri = get_free_rp_inst(rp)) != NULL) { - ri->rp = rp; - ri->task = current; - ri->ret_addr = (kprobe_opcode_t *) *sara; - - /* Replace the return addr with trampoline addr */ - *sara = (unsigned long) &kretprobe_trampoline; - add_rp_inst(ri); - } else { - rp->nmissed++; - } + ri->ret_addr = (kprobe_opcode_t *) *sara; + /* Replace the return addr with trampoline addr */ + *sara = (unsigned long) &kretprobe_trampoline; } int __kprobes kprobe_handler(struct pt_regs *regs) @@ -447,7 +438,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) break; } - BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); + kretprobe_assert(ri, orig_ret_address, trampoline_address); regs->rip = orig_ret_address; reset_current_kprobe(); @@ -752,3 +743,11 @@ int __init arch_init_kprobes(void) { return register_kprobe(&trampoline_p); } + +int __kprobes arch_trampoline_kprobe(struct kprobe *p) +{ + if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline) + return 1; + + return 0; +} diff --git a/trunk/arch/x86_64/kernel/ldt.c b/trunk/arch/x86_64/kernel/ldt.c index d7e5d0cf4285..bc9ffd5c19cc 100644 --- a/trunk/arch/x86_64/kernel/ldt.c +++ b/trunk/arch/x86_64/kernel/ldt.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/x86_64/kernel/machine_kexec.c b/trunk/arch/x86_64/kernel/machine_kexec.c index a8bb33c1a8f2..c3a554703672 100644 --- a/trunk/arch/x86_64/kernel/machine_kexec.c +++ b/trunk/arch/x86_64/kernel/machine_kexec.c @@ -189,21 +189,21 @@ NORET_TYPE void machine_kexec(struct kimage *image) control_page = page_address(image->control_code_page) + PAGE_SIZE; memcpy(control_page, relocate_kernel, PAGE_SIZE); - page_list[PA_CONTROL_PAGE] = __pa(control_page); + page_list[PA_CONTROL_PAGE] = virt_to_phys(control_page); page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel; - page_list[PA_PGD] = __pa_symbol(&kexec_pgd); + page_list[PA_PGD] = virt_to_phys(&kexec_pgd); page_list[VA_PGD] = (unsigned long)kexec_pgd; - page_list[PA_PUD_0] = __pa_symbol(&kexec_pud0); + page_list[PA_PUD_0] = virt_to_phys(&kexec_pud0); page_list[VA_PUD_0] = (unsigned long)kexec_pud0; - page_list[PA_PMD_0] = __pa_symbol(&kexec_pmd0); + page_list[PA_PMD_0] = virt_to_phys(&kexec_pmd0); page_list[VA_PMD_0] = (unsigned long)kexec_pmd0; - page_list[PA_PTE_0] = __pa_symbol(&kexec_pte0); + page_list[PA_PTE_0] = virt_to_phys(&kexec_pte0); page_list[VA_PTE_0] = (unsigned long)kexec_pte0; - page_list[PA_PUD_1] = __pa_symbol(&kexec_pud1); + page_list[PA_PUD_1] = virt_to_phys(&kexec_pud1); page_list[VA_PUD_1] = (unsigned long)kexec_pud1; - page_list[PA_PMD_1] = __pa_symbol(&kexec_pmd1); + page_list[PA_PMD_1] = virt_to_phys(&kexec_pmd1); page_list[VA_PMD_1] = (unsigned long)kexec_pmd1; - page_list[PA_PTE_1] = __pa_symbol(&kexec_pte1); + page_list[PA_PTE_1] = virt_to_phys(&kexec_pte1); page_list[VA_PTE_1] = (unsigned long)kexec_pte1; page_list[PA_TABLE_PAGE] = diff --git a/trunk/arch/x86_64/kernel/mce.c b/trunk/arch/x86_64/kernel/mce.c index fa2672682477..442169640e45 100644 --- a/trunk/arch/x86_64/kernel/mce.c +++ b/trunk/arch/x86_64/kernel/mce.c @@ -20,10 +20,10 @@ #include #include #include +#include #include #include #include -#include #include #include diff --git a/trunk/arch/x86_64/kernel/mpparse.c b/trunk/arch/x86_64/kernel/mpparse.c index d0dc4891599b..61ae57eb9e4c 100644 --- a/trunk/arch/x86_64/kernel/mpparse.c +++ b/trunk/arch/x86_64/kernel/mpparse.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/kernel/nmi.c b/trunk/arch/x86_64/kernel/nmi.c index 6cd2b30e2ffc..931c64bad5e6 100644 --- a/trunk/arch/x86_64/kernel/nmi.c +++ b/trunk/arch/x86_64/kernel/nmi.c @@ -21,11 +21,11 @@ #include #include #include +#include #include #include #include -#include #include int unknown_nmi_panic; diff --git a/trunk/arch/x86_64/kernel/pci-gart.c b/trunk/arch/x86_64/kernel/pci-gart.c index 0a762e10f2be..373ef66ca1dc 100644 --- a/trunk/arch/x86_64/kernel/pci-gart.c +++ b/trunk/arch/x86_64/kernel/pci-gart.c @@ -22,13 +22,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/kernel/process.c b/trunk/arch/x86_64/kernel/process.c index 4f21765078b7..5909039f37aa 100644 --- a/trunk/arch/x86_64/kernel/process.c +++ b/trunk/arch/x86_64/kernel/process.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/kernel/ptrace.c b/trunk/arch/x86_64/kernel/ptrace.c index 4326a690a509..9409117b9f19 100644 --- a/trunk/arch/x86_64/kernel/ptrace.c +++ b/trunk/arch/x86_64/kernel/ptrace.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/kernel/reboot.c b/trunk/arch/x86_64/kernel/reboot.c index 2d6769847456..c116b54d422e 100644 --- a/trunk/arch/x86_64/kernel/reboot.c +++ b/trunk/arch/x86_64/kernel/reboot.c @@ -7,8 +7,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/kernel/setup.c b/trunk/arch/x86_64/kernel/setup.c index db30b5bcef61..db51577bda32 100644 --- a/trunk/arch/x86_64/kernel/setup.c +++ b/trunk/arch/x86_64/kernel/setup.c @@ -245,12 +245,11 @@ void __init setup_arch(char **cmdline_p) init_mm.end_code = (unsigned long) &_etext; init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; - init_mm.pgd = __va(__pa_symbol(&init_level4_pgt)); - code_resource.start = __pa_symbol(&_text); - code_resource.end = __pa_symbol(&_etext)-1; - data_resource.start = __pa_symbol(&_etext); - data_resource.end = __pa_symbol(&_edata)-1; + code_resource.start = virt_to_phys(&_text); + code_resource.end = virt_to_phys(&_etext)-1; + data_resource.start = virt_to_phys(&_etext); + data_resource.end = virt_to_phys(&_edata)-1; early_identify_cpu(&boot_cpu_data); diff --git a/trunk/arch/x86_64/kernel/signal.c b/trunk/arch/x86_64/kernel/signal.c index c819625f3316..290f5d8037cd 100644 --- a/trunk/arch/x86_64/kernel/signal.c +++ b/trunk/arch/x86_64/kernel/signal.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/kernel/smp.c b/trunk/arch/x86_64/kernel/smp.c index 22abae4e9f39..2ff468591625 100644 --- a/trunk/arch/x86_64/kernel/smp.c +++ b/trunk/arch/x86_64/kernel/smp.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -76,7 +75,7 @@ static inline void leave_mm(int cpu) if (read_pda(mmu_state) == TLBSTATE_OK) BUG(); cpu_clear(cpu, read_pda(active_mm)->cpu_vm_mask); - load_cr3(init_mm.pgd); + load_cr3(swapper_pg_dir); } /* diff --git a/trunk/arch/x86_64/kernel/smpboot.c b/trunk/arch/x86_64/kernel/smpboot.c index 4d9dacfae575..32f50783edc8 100644 --- a/trunk/arch/x86_64/kernel/smpboot.c +++ b/trunk/arch/x86_64/kernel/smpboot.c @@ -42,18 +42,17 @@ #include #include -#include #include #include #include #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/trunk/arch/x86_64/kernel/stacktrace.c b/trunk/arch/x86_64/kernel/stacktrace.c index 65ac2c6b34a6..cb9109113584 100644 --- a/trunk/arch/x86_64/kernel/stacktrace.c +++ b/trunk/arch/x86_64/kernel/stacktrace.c @@ -21,8 +21,7 @@ save_stack_warning_symbol(void *data, char *msg, unsigned long symbol) static int save_stack_stack(void *data, char *name) { - struct stack_trace *trace = (struct stack_trace *)data; - return trace->all_contexts ? 0 : -1; + return -1; } static void save_stack_address(void *data, unsigned long addr) @@ -46,11 +45,10 @@ static struct stacktrace_ops save_stack_ops = { /* * Save stack-backtrace addresses into a stack_trace buffer. */ -void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +void save_stack_trace(struct stack_trace *trace) { - dump_trace(task, NULL, NULL, &save_stack_ops, trace); + dump_trace(current, NULL, NULL, &save_stack_ops, trace); if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = ULONG_MAX; } EXPORT_SYMBOL(save_stack_trace); - diff --git a/trunk/arch/x86_64/kernel/sys_x86_64.c b/trunk/arch/x86_64/kernel/sys_x86_64.c index 76bf7c241fe4..d067d9a2ad27 100644 --- a/trunk/arch/x86_64/kernel/sys_x86_64.c +++ b/trunk/arch/x86_64/kernel/sys_x86_64.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -93,6 +92,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long start_addr; unsigned long begin, end; + if (flags & MAP_FIXED) + return addr; + find_start_end(flags, &begin, &end); if (len > end) diff --git a/trunk/arch/x86_64/kernel/time.c b/trunk/arch/x86_64/kernel/time.c index 0652e173813b..4a0895bacf51 100644 --- a/trunk/arch/x86_64/kernel/time.c +++ b/trunk/arch/x86_64/kernel/time.c @@ -363,7 +363,10 @@ void stop_timer_interrupt(void) } static struct irqaction irq0 = { - timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL + .handler = timer_interrupt, + .flags = IRQF_DISABLED | IRQF_IRQPOLL, + .mask = CPU_MASK_NONE, + .name = "timer" }; void __init time_init(void) diff --git a/trunk/arch/x86_64/kernel/traps.c b/trunk/arch/x86_64/kernel/traps.c index d76fc32d4599..8c2ac41187c1 100644 --- a/trunk/arch/x86_64/kernel/traps.c +++ b/trunk/arch/x86_64/kernel/traps.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -39,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -71,22 +71,6 @@ asmlinkage void alignment_check(void); asmlinkage void machine_check(void); asmlinkage void spurious_interrupt_bug(void); -ATOMIC_NOTIFIER_HEAD(die_chain); -EXPORT_SYMBOL(die_chain); - -int register_die_notifier(struct notifier_block *nb) -{ - vmalloc_sync_all(); - return atomic_notifier_chain_register(&die_chain, nb); -} -EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */ - -int unregister_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&die_chain, nb); -} -EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ - static inline void conditional_sti(struct pt_regs *regs) { if (regs->eflags & X86_EFLAGS_IF) @@ -792,6 +776,8 @@ asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs) */ if (nmi_watchdog_tick(regs,reason)) return; + if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0) + == NOTIFY_STOP) if (!do_nmi_callback(regs,cpu)) unknown_nmi_error(reason, regs); diff --git a/trunk/arch/x86_64/mm/fault.c b/trunk/arch/x86_64/mm/fault.c index de99dba2c515..bfb62a13d7ee 100644 --- a/trunk/arch/x86_64/mm/fault.c +++ b/trunk/arch/x86_64/mm/fault.c @@ -15,22 +15,22 @@ #include #include #include -#include #include #include #include #include /* For unblank_screen() */ #include +#include #include #include #include +#include #include #include #include #include #include -#include #include /* Page fault error code bits */ diff --git a/trunk/arch/x86_64/mm/init.c b/trunk/arch/x86_64/mm/init.c index 282b0a8f00ad..1336da8bdee1 100644 --- a/trunk/arch/x86_64/mm/init.c +++ b/trunk/arch/x86_64/mm/init.c @@ -172,7 +172,7 @@ __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t prot) set_pte_phys(address, phys, prot); } -unsigned long __initdata table_start, table_end; +unsigned long __meminitdata table_start, table_end; static __meminit void *alloc_low_page(unsigned long *phys) { @@ -204,7 +204,7 @@ static __meminit void unmap_low_page(void *adr) } /* Must run before zap_low_mappings */ -__init void *early_ioremap(unsigned long addr, unsigned long size) +__meminit void *early_ioremap(unsigned long addr, unsigned long size) { unsigned long vaddr; pmd_t *pmd, *last_pmd; @@ -233,7 +233,7 @@ __init void *early_ioremap(unsigned long addr, unsigned long size) } /* To avoid virtual aliases later */ -__init void early_iounmap(void *addr, unsigned long size) +__meminit void early_iounmap(void *addr, unsigned long size) { unsigned long vaddr; pmd_t *pmd; @@ -572,13 +572,13 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); for (addr = begin; addr < end; addr += PAGE_SIZE) { - struct page *page = pfn_to_page(addr >> PAGE_SHIFT); - ClearPageReserved(page); - init_page_count(page); - memset(page_address(page), POISON_FREE_INITMEM, PAGE_SIZE); + ClearPageReserved(virt_to_page(addr)); + init_page_count(virt_to_page(addr)); + memset((void *)(addr & ~(PAGE_SIZE-1)), + POISON_FREE_INITMEM, PAGE_SIZE); if (addr >= __START_KERNEL_map) change_page_attr_addr(addr, 1, __pgprot(0)); - __free_page(page); + free_page(addr); totalram_pages++; } if (addr > __START_KERNEL_map) @@ -588,26 +588,31 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) void free_initmem(void) { free_init_pages("unused kernel memory", - __pa_symbol(&__init_begin), - __pa_symbol(&__init_end)); + (unsigned long)(&__init_begin), + (unsigned long)(&__init_end)); } #ifdef CONFIG_DEBUG_RODATA void mark_rodata_ro(void) { - unsigned long start = PFN_ALIGN(__va(__pa_symbol(&_stext))), size; + unsigned long start = (unsigned long)_stext, end; #ifdef CONFIG_HOTPLUG_CPU /* It must still be possible to apply SMP alternatives. */ if (num_possible_cpus() > 1) - start = PFN_ALIGN(__va(__pa_symbol(&_etext))); + start = (unsigned long)_etext; #endif - size = (unsigned long)__va(__pa_symbol(&__end_rodata)) - start; - change_page_attr_addr(start, size >> PAGE_SHIFT, PAGE_KERNEL_RO); + end = (unsigned long)__end_rodata; + start = (start + PAGE_SIZE - 1) & PAGE_MASK; + end &= PAGE_MASK; + if (end <= start) + return; + + change_page_attr_addr(start, (end - start) >> PAGE_SHIFT, PAGE_KERNEL_RO); printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", - size >> 10); + (end - start) >> 10); /* * change_page_attr_addr() requires a global_flush_tlb() call after it. @@ -622,7 +627,7 @@ void mark_rodata_ro(void) #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { - free_init_pages("initrd memory", __pa(start), __pa(end)); + free_init_pages("initrd memory", start, end); } #endif diff --git a/trunk/arch/x86_64/mm/ioremap.c b/trunk/arch/x86_64/mm/ioremap.c index c6e5e8d401a4..6cac90aa5032 100644 --- a/trunk/arch/x86_64/mm/ioremap.c +++ b/trunk/arch/x86_64/mm/ioremap.c @@ -13,12 +13,21 @@ #include #include #include + #include #include #include #include #include +unsigned long __phys_addr(unsigned long x) +{ + if (x >= __START_KERNEL_map) + return x - __START_KERNEL_map + phys_base; + return x - PAGE_OFFSET; +} +EXPORT_SYMBOL(__phys_addr); + #define ISA_START_ADDRESS 0xa0000 #define ISA_END_ADDRESS 0x100000 diff --git a/trunk/arch/x86_64/mm/pageattr.c b/trunk/arch/x86_64/mm/pageattr.c index bf4aa8dd4254..d653d0bf3df6 100644 --- a/trunk/arch/x86_64/mm/pageattr.c +++ b/trunk/arch/x86_64/mm/pageattr.c @@ -51,6 +51,7 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot, SetPagePrivate(base); page_private(base) = 0; + address = __pa(address); addr = address & LARGE_PAGE_MASK; pbase = (pte_t *)page_address(base); for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) { @@ -100,12 +101,13 @@ static inline void save_page(struct page *fpage) * No more special protections in this 2/4MB area - revert to a * large page again. */ -static void revert_page(unsigned long address, unsigned long pfn, pgprot_t ref_prot) +static void revert_page(unsigned long address, pgprot_t ref_prot) { pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t large_pte; + unsigned long pfn; pgd = pgd_offset_k(address); BUG_ON(pgd_none(*pgd)); @@ -113,6 +115,7 @@ static void revert_page(unsigned long address, unsigned long pfn, pgprot_t ref_p BUG_ON(pud_none(*pud)); pmd = pmd_offset(pud, address); BUG_ON(pmd_val(*pmd) & _PAGE_PSE); + pfn = (__pa(address) & LARGE_PAGE_MASK) >> PAGE_SHIFT; large_pte = pfn_pte(pfn, ref_prot); large_pte = pte_mkhuge(large_pte); set_pte((pte_t *)pmd, large_pte); @@ -138,8 +141,7 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot, */ struct page *split; ref_prot2 = pte_pgprot(pte_clrhuge(*kpte)); - split = split_large_page(pfn << PAGE_SHIFT, prot, - ref_prot2); + split = split_large_page(address, prot, ref_prot2); if (!split) return -ENOMEM; set_pte(kpte, mk_pte(split, ref_prot2)); @@ -158,7 +160,7 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot, if (page_private(kpte_page) == 0) { save_page(kpte_page); - revert_page(address, pfn, ref_prot); + revert_page(address, ref_prot); } return 0; } @@ -178,7 +180,6 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot, */ int change_page_attr_addr(unsigned long address, int numpages, pgprot_t prot) { - unsigned long phys_base_pfn = __pa_symbol(__START_KERNEL_map) >> PAGE_SHIFT; int err = 0, kernel_map = 0; int i; @@ -199,11 +200,10 @@ int change_page_attr_addr(unsigned long address, int numpages, pgprot_t prot) } /* Handle kernel mapping too which aliases part of the * lowmem */ - if ((pfn >= phys_base_pfn) && - ((pfn - phys_base_pfn) < (KERNEL_TEXT_SIZE >> PAGE_SHIFT))) { + if (__pa(address) < KERNEL_TEXT_SIZE) { unsigned long addr2; pgprot_t prot2; - addr2 = __START_KERNEL_map + ((pfn - phys_base_pfn) << PAGE_SHIFT); + addr2 = __START_KERNEL_map + __pa(address); /* Make sure the kernel mappings stay executable */ prot2 = pte_pgprot(pte_mkexec(pfn_pte(0, prot))); err = __change_page_attr(addr2, pfn, prot2, diff --git a/trunk/arch/xtensa/kernel/process.c b/trunk/arch/xtensa/kernel/process.c index 795bd5ac6f4c..ce758bab95b1 100644 --- a/trunk/arch/xtensa/kernel/process.c +++ b/trunk/arch/xtensa/kernel/process.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/xtensa/kernel/ptrace.c b/trunk/arch/xtensa/kernel/ptrace.c index 8b6d3d0623b6..14104ff63093 100644 --- a/trunk/arch/xtensa/kernel/ptrace.c +++ b/trunk/arch/xtensa/kernel/ptrace.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/trunk/arch/xtensa/kernel/signal.c b/trunk/arch/xtensa/kernel/signal.c index c6d9880a4cdb..58107672a619 100644 --- a/trunk/arch/xtensa/kernel/signal.c +++ b/trunk/arch/xtensa/kernel/signal.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/xtensa/platform-iss/network.c b/trunk/arch/xtensa/platform-iss/network.c index ab05bff40104..4bfe333be229 100644 --- a/trunk/arch/xtensa/platform-iss/network.c +++ b/trunk/arch/xtensa/platform-iss/network.c @@ -251,7 +251,7 @@ static int tuntap_open(struct iss_net_private *lp) memset(&ifr, 0, sizeof ifr); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name - 1); + strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name); if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) { printk("Failed to set interface, returned %d " diff --git a/trunk/block/as-iosched.c b/trunk/block/as-iosched.c index ef126277b4b3..640aa839d63f 100644 --- a/trunk/block/as-iosched.c +++ b/trunk/block/as-iosched.c @@ -569,7 +569,7 @@ static void as_update_iohist(struct as_data *ad, struct as_io_context *aic, static int as_close_req(struct as_data *ad, struct as_io_context *aic, struct request *rq) { - unsigned long delay; /* milliseconds */ + unsigned long delay; /* jiffies */ sector_t last = ad->last_sector[ad->batch_data_dir]; sector_t next = rq->sector; sector_t delta; /* acceptable close offset (in sectors) */ @@ -578,11 +578,11 @@ static int as_close_req(struct as_data *ad, struct as_io_context *aic, if (ad->antic_status == ANTIC_OFF || !ad->ioc_finished) delay = 0; else - delay = ((jiffies - ad->antic_start) * 1000) / HZ; + delay = jiffies - ad->antic_start; if (delay == 0) delta = 8192; - else if (delay <= 20 && delay <= ad->antic_expire) + else if (delay <= (20 * HZ / 1000) && delay <= ad->antic_expire) delta = 8192 << delay; else return 1; diff --git a/trunk/block/cfq-iosched.c b/trunk/block/cfq-iosched.c index 64df3fa303b0..baef5fc7cff8 100644 --- a/trunk/block/cfq-iosched.c +++ b/trunk/block/cfq-iosched.c @@ -2090,13 +2090,11 @@ static void cfq_slab_kill(void) static int __init cfq_slab_setup(void) { - cfq_pool = kmem_cache_create("cfq_pool", sizeof(struct cfq_queue), 0, 0, - NULL, NULL); + cfq_pool = KMEM_CACHE(cfq_queue, 0); if (!cfq_pool) goto fail; - cfq_ioc_pool = kmem_cache_create("cfq_ioc_pool", - sizeof(struct cfq_io_context), 0, 0, NULL, NULL); + cfq_ioc_pool = KMEM_CACHE(cfq_io_context, 0); if (!cfq_ioc_pool) goto fail; diff --git a/trunk/block/ioctl.c b/trunk/block/ioctl.c index e06dbe9bc858..f7e3e8abf887 100644 --- a/trunk/block/ioctl.c +++ b/trunk/block/ioctl.c @@ -80,7 +80,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user } /* all seems OK */ fsync_bdev(bdevp); - invalidate_bdev(bdevp, 0); + invalidate_bdev(bdevp); mutex_lock_nested(&bdev->bd_mutex, 1); delete_partition(disk, part); @@ -236,7 +236,7 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, lock_kernel(); fsync_bdev(bdev); - invalidate_bdev(bdev, 0); + invalidate_bdev(bdev); unlock_kernel(); return 0; diff --git a/trunk/block/ll_rw_blk.c b/trunk/block/ll_rw_blk.c index 5873861e1dbb..d99d402953a3 100644 --- a/trunk/block/ll_rw_blk.c +++ b/trunk/block/ll_rw_blk.c @@ -2558,6 +2558,7 @@ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, bio->bi_rw |= (1 << BIO_RW); blk_rq_bio_prep(q, rq, bio); + blk_queue_bounce(q, &rq->bio); rq->buffer = rq->data = NULL; return 0; } diff --git a/trunk/drivers/acpi/glue.c b/trunk/drivers/acpi/glue.c index 4334c208841a..41427a41f620 100644 --- a/trunk/drivers/acpi/glue.c +++ b/trunk/drivers/acpi/glue.c @@ -245,6 +245,35 @@ arch_initcall(init_acpi_device_notify); #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) +#ifdef CONFIG_PM +static u32 rtc_handler(void *context) +{ + acpi_clear_event(ACPI_EVENT_RTC); + acpi_disable_event(ACPI_EVENT_RTC, 0); + return ACPI_INTERRUPT_HANDLED; +} + +static inline void rtc_wake_setup(void) +{ + acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); +} + +static void rtc_wake_on(struct device *dev) +{ + acpi_clear_event(ACPI_EVENT_RTC); + acpi_enable_event(ACPI_EVENT_RTC, 0); +} + +static void rtc_wake_off(struct device *dev) +{ + acpi_disable_event(ACPI_EVENT_RTC, 0); +} +#else +#define rtc_wake_setup() do{}while(0) +#define rtc_wake_on NULL +#define rtc_wake_off NULL +#endif + /* 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 @@ -283,11 +312,24 @@ static int __init acpi_rtc_init(void) struct device *dev = get_rtc_dev(); if (dev) { + rtc_wake_setup(); + rtc_info.wake_on = rtc_wake_on; + rtc_info.wake_off = rtc_wake_off; + + /* workaround bug in some ACPI tables */ + if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) { + DBG("bogus FADT month_alarm\n"); + acpi_gbl_FADT.month_alarm = 0; + } + 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 */ + /* NOTE: S4_RTC_WAKE is NOT currently useful to Linux */ + if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE) + printk(PREFIX "RTC can wake from S4\n"); + dev->platform_data = &rtc_info; @@ -296,7 +338,7 @@ static int __init acpi_rtc_init(void) put_device(dev); } else - pr_debug("ACPI: RTC unavailable?\n"); + DBG("RTC unavailable?\n"); return 0; } /* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */ diff --git a/trunk/drivers/acpi/numa.c b/trunk/drivers/acpi/numa.c index 8fcd6a15517f..4dd0dabe81cb 100644 --- a/trunk/drivers/acpi/numa.c +++ b/trunk/drivers/acpi/numa.c @@ -228,7 +228,7 @@ int __init acpi_numa_init(void) return 0; } -int acpi_get_pxm(acpi_handle h) +int __meminit acpi_get_pxm(acpi_handle h) { unsigned long pxm; acpi_status status; @@ -246,7 +246,7 @@ int acpi_get_pxm(acpi_handle h) } EXPORT_SYMBOL(acpi_get_pxm); -int acpi_get_node(acpi_handle *handle) +int __meminit acpi_get_node(acpi_handle *handle) { int pxm, node = -1; diff --git a/trunk/drivers/acpi/osl.c b/trunk/drivers/acpi/osl.c index 971eca4864fa..c2bed56915e1 100644 --- a/trunk/drivers/acpi/osl.c +++ b/trunk/drivers/acpi/osl.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/acpi/scan.c b/trunk/drivers/acpi/scan.c index d80dd84e5bfd..6b3b8a522476 100644 --- a/trunk/drivers/acpi/scan.c +++ b/trunk/drivers/acpi/scan.c @@ -302,7 +302,7 @@ static void acpi_device_shutdown(struct device *dev) return ; } -static struct bus_type acpi_bus_type = { +struct bus_type acpi_bus_type = { .name = "acpi", .suspend = acpi_device_suspend, .resume = acpi_device_resume, diff --git a/trunk/drivers/acpi/sleep/proc.c b/trunk/drivers/acpi/sleep/proc.c index 2d912b71e543..5a76e5be61d5 100644 --- a/trunk/drivers/acpi/sleep/proc.c +++ b/trunk/drivers/acpi/sleep/proc.c @@ -60,7 +60,7 @@ acpi_system_write_sleep(struct file *file, state = simple_strtoul(str, NULL, 0); #ifdef CONFIG_SOFTWARE_SUSPEND if (state == 4) { - error = software_suspend(); + error = pm_suspend(PM_SUSPEND_DISK); goto Done; } #endif @@ -70,6 +70,14 @@ acpi_system_write_sleep(struct file *file, } #endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ +#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) +/* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */ +#else +#define HAVE_ACPI_LEGACY_ALARM +#endif + +#ifdef HAVE_ACPI_LEGACY_ALARM + static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) { u32 sec, min, hr; @@ -341,6 +349,8 @@ acpi_system_write_alarm(struct file *file, end: return_VALUE(result ? result : count); } +#endif /* HAVE_ACPI_LEGACY_ALARM */ + extern struct list_head acpi_wakeup_device_list; extern spinlock_t acpi_device_lock; @@ -464,6 +474,7 @@ static const struct file_operations acpi_system_sleep_fops = { }; #endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ +#ifdef HAVE_ACPI_LEGACY_ALARM static const struct file_operations acpi_system_alarm_fops = { .open = acpi_system_alarm_open_fs, .read = seq_read, @@ -479,8 +490,9 @@ static u32 rtc_handler(void *context) return ACPI_INTERRUPT_HANDLED; } +#endif /* HAVE_ACPI_LEGACY_ALARM */ -static int acpi_sleep_proc_init(void) +static int __init acpi_sleep_proc_init(void) { struct proc_dir_entry *entry = NULL; @@ -496,6 +508,7 @@ static int acpi_sleep_proc_init(void) entry->proc_fops = &acpi_system_sleep_fops; #endif +#ifdef HAVE_ACPI_LEGACY_ALARM /* 'alarm' [R/W] */ entry = create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR, @@ -503,6 +516,9 @@ static int acpi_sleep_proc_init(void) if (entry) entry->proc_fops = &acpi_system_alarm_fops; + acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); +#endif /* HAVE_ACPI_LEGACY_ALARM */ + /* 'wakeup device' [R/W] */ entry = create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR, @@ -510,7 +526,6 @@ static int acpi_sleep_proc_init(void) if (entry) entry->proc_fops = &acpi_system_wakeup_device_fops; - acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); return 0; } diff --git a/trunk/drivers/ata/Kconfig b/trunk/drivers/ata/Kconfig index 365c306c7cf8..45dbdc14915f 100644 --- a/trunk/drivers/ata/Kconfig +++ b/trunk/drivers/ata/Kconfig @@ -550,13 +550,21 @@ config PATA_WINBOND_VLB config PATA_PLATFORM tristate "Generic platform device PATA support" - depends on EMBEDDED + depends on EMBEDDED || ARCH_RPC help This option enables support for generic directly connected ATA devices commonly found on embedded systems. If unsure, say N. +config PATA_ICSIDE + tristate "Acorn ICS PATA support" + depends on ARM && ARCH_ACORN + help + On Acorn systems, say Y here if you wish to use the ICS PATA + interface card. This is not required for ICS partition support. + If you are unsure, say N to this. + config PATA_IXP4XX_CF tristate "IXP4XX Compact Flash support" depends on ARCH_IXP4XX diff --git a/trunk/drivers/ata/Makefile b/trunk/drivers/ata/Makefile index b7055e302650..6f42a0e2812d 100644 --- a/trunk/drivers/ata/Makefile +++ b/trunk/drivers/ata/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o obj-$(CONFIG_PATA_SCC) += pata_scc.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o +obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o # Should be last but one libata driver obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver diff --git a/trunk/drivers/ata/ahci.c b/trunk/drivers/ata/ahci.c index 34c5534ed64c..d9617892fc23 100644 --- a/trunk/drivers/ata/ahci.c +++ b/trunk/drivers/ata/ahci.c @@ -874,7 +874,8 @@ static int ahci_clo(struct ata_port *ap) return 0; } -static int ahci_softreset(struct ata_port *ap, unsigned int *class) +static int ahci_softreset(struct ata_port *ap, unsigned int *class, + unsigned long deadline) { struct ahci_port_priv *pp = ap->private_data; void __iomem *port_mmio = ahci_port_base(ap); @@ -959,15 +960,13 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) */ msleep(150); - *class = ATA_DEV_NONE; - if (ata_port_online(ap)) { - if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { - rc = -EIO; - reason = "device not ready"; - goto fail; - } - *class = ahci_dev_classify(ap); + rc = ata_wait_ready(ap, deadline); + /* link occupied, -ENODEV too is an error */ + if (rc) { + reason = "device not ready"; + goto fail; } + *class = ahci_dev_classify(ap); DPRINTK("EXIT, class=%u\n", *class); return 0; @@ -979,7 +978,8 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) return rc; } -static int ahci_hardreset(struct ata_port *ap, unsigned int *class) +static int ahci_hardreset(struct ata_port *ap, unsigned int *class, + unsigned long deadline) { struct ahci_port_priv *pp = ap->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; @@ -995,7 +995,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) tf.command = 0x80; ata_tf_to_fis(&tf, d2h_fis, 0); - rc = sata_std_hardreset(ap, class); + rc = sata_std_hardreset(ap, class, deadline); ahci_start_engine(ap); @@ -1008,7 +1008,8 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) return rc; } -static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) +static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, + unsigned long deadline) { int rc; @@ -1016,7 +1017,8 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) ahci_stop_engine(ap); - rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context)); + rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context), + deadline); /* vt8251 needs SError cleared for the port to operate */ ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR)); diff --git a/trunk/drivers/ata/ata_piix.c b/trunk/drivers/ata/ata_piix.c index 55d306a3e538..4a795fdb6a02 100644 --- a/trunk/drivers/ata/ata_piix.c +++ b/trunk/drivers/ata/ata_piix.c @@ -625,17 +625,18 @@ static int ich_pata_cable_detect(struct ata_port *ap) /** * piix_pata_prereset - prereset for PATA host controller * @ap: Target port + * @deadline: deadline jiffies for the operation * * LOCKING: * None (inherited from caller). */ -static int piix_pata_prereset(struct ata_port *ap) +static int piix_pata_prereset(struct ata_port *ap, unsigned long deadline) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + return ata_std_prereset(ap, deadline); } static void piix_pata_error_handler(struct ata_port *ap) @@ -644,7 +645,6 @@ static void piix_pata_error_handler(struct ata_port *ap) ata_std_postreset); } - static void piix_sata_error_handler(struct ata_port *ap) { ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL, diff --git a/trunk/drivers/ata/libata-core.c b/trunk/drivers/ata/libata-core.c index ca67484af1eb..a7950885d18e 100644 --- a/trunk/drivers/ata/libata-core.c +++ b/trunk/drivers/ata/libata-core.c @@ -2979,23 +2979,71 @@ int ata_busy_sleep(struct ata_port *ap, return 0; } -static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask) +/** + * ata_wait_ready - sleep until BSY clears, or timeout + * @ap: port containing status register to be polled + * @deadline: deadline jiffies for the operation + * + * Sleep until ATA Status register bit BSY clears, or timeout + * occurs. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int ata_wait_ready(struct ata_port *ap, unsigned long deadline) +{ + unsigned long start = jiffies; + int warned = 0; + + while (1) { + u8 status = ata_chk_status(ap); + unsigned long now = jiffies; + + if (!(status & ATA_BUSY)) + return 0; + if (status == 0xff) + return -ENODEV; + if (time_after(now, deadline)) + return -EBUSY; + + if (!warned && time_after(now, start + 5 * HZ) && + (deadline - now > 3 * HZ)) { + ata_port_printk(ap, KERN_WARNING, + "port is slow to respond, please be patient " + "(Status 0x%x)\n", status); + warned = 1; + } + + msleep(50); + } +} + +static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask, + unsigned long deadline) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int dev0 = devmask & (1 << 0); unsigned int dev1 = devmask & (1 << 1); - unsigned long timeout; + int rc, ret = 0; /* if device 0 was found in ata_devchk, wait for its * BSY bit to clear */ - if (dev0) - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + if (dev0) { + rc = ata_wait_ready(ap, deadline); + if (rc) { + if (rc != -ENODEV) + return rc; + ret = rc; + } + } /* if device 1 was found in ata_devchk, wait for * register access, then wait for BSY to clear */ - timeout = jiffies + ATA_TMOUT_BOOT; while (dev1) { u8 nsect, lbal; @@ -3004,14 +3052,18 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask) lbal = ioread8(ioaddr->lbal_addr); if ((nsect == 1) && (lbal == 1)) break; - if (time_after(jiffies, timeout)) { - dev1 = 0; - break; - } + if (time_after(jiffies, deadline)) + return -EBUSY; msleep(50); /* give drive a breather */ } - if (dev1) - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + if (dev1) { + rc = ata_wait_ready(ap, deadline); + if (rc) { + if (rc != -ENODEV) + return rc; + ret = rc; + } + } /* is all this really necessary? */ ap->ops->dev_select(ap, 0); @@ -3019,10 +3071,12 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask) ap->ops->dev_select(ap, 1); if (dev0) ap->ops->dev_select(ap, 0); + + return ret; } -static unsigned int ata_bus_softreset(struct ata_port *ap, - unsigned int devmask) +static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, + unsigned long deadline) { struct ata_ioports *ioaddr = &ap->ioaddr; @@ -3052,11 +3106,9 @@ static unsigned int ata_bus_softreset(struct ata_port *ap, * pulldown resistor. */ if (ata_check_status(ap) == 0xFF) - return 0; - - ata_bus_post_reset(ap, devmask); + return -ENODEV; - return 0; + return ata_bus_post_reset(ap, devmask, deadline); } /** @@ -3085,6 +3137,7 @@ void ata_bus_reset(struct ata_port *ap) unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; u8 err; unsigned int dev0, dev1 = 0, devmask = 0; + int rc; DPRINTK("ENTER, host %u, port %u\n", ap->print_id, ap->port_no); @@ -3106,9 +3159,11 @@ void ata_bus_reset(struct ata_port *ap) ap->ops->dev_select(ap, 0); /* issue bus reset */ - if (ap->flags & ATA_FLAG_SRST) - if (ata_bus_softreset(ap, devmask)) + if (ap->flags & ATA_FLAG_SRST) { + rc = ata_bus_softreset(ap, devmask, jiffies + 40 * HZ); + if (rc && rc != -ENODEV) goto err_out; + } /* * determine by signature whether we have ATA or ATAPI devices @@ -3150,29 +3205,37 @@ void ata_bus_reset(struct ata_port *ap) * sata_phy_debounce - debounce SATA phy status * @ap: ATA port to debounce SATA phy status for * @params: timing parameters { interval, duratinon, timeout } in msec + * @deadline: deadline jiffies for the operation * * Make sure SStatus of @ap reaches stable state, determined by * holding the same value where DET is not 1 for @duration polled * every @interval, before @timeout. Timeout constraints the - * beginning of the stable state. Because, after hot unplugging, - * DET gets stuck at 1 on some controllers, this functions waits + * beginning of the stable state. Because DET gets stuck at 1 on + * some controllers after hot unplugging, this functions waits * until timeout then returns 0 if DET is stable at 1. * + * @timeout is further limited by @deadline. The sooner of the + * two is used. + * * LOCKING: * Kernel thread context (may sleep) * * RETURNS: * 0 on success, -errno on failure. */ -int sata_phy_debounce(struct ata_port *ap, const unsigned long *params) +int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, + unsigned long deadline) { unsigned long interval_msec = params[0]; - unsigned long duration = params[1] * HZ / 1000; - unsigned long timeout = jiffies + params[2] * HZ / 1000; - unsigned long last_jiffies; + unsigned long duration = msecs_to_jiffies(params[1]); + unsigned long last_jiffies, t; u32 last, cur; int rc; + t = jiffies + msecs_to_jiffies(params[2]); + if (time_before(t, deadline)) + deadline = t; + if ((rc = sata_scr_read(ap, SCR_STATUS, &cur))) return rc; cur &= 0xf; @@ -3188,7 +3251,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params) /* DET stable? */ if (cur == last) { - if (cur == 1 && time_before(jiffies, timeout)) + if (cur == 1 && time_before(jiffies, deadline)) continue; if (time_after(jiffies, last_jiffies + duration)) return 0; @@ -3199,8 +3262,8 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params) last = cur; last_jiffies = jiffies; - /* check timeout */ - if (time_after(jiffies, timeout)) + /* check deadline */ + if (time_after(jiffies, deadline)) return -EBUSY; } } @@ -3209,6 +3272,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params) * sata_phy_resume - resume SATA phy * @ap: ATA port to resume SATA phy for * @params: timing parameters { interval, duratinon, timeout } in msec + * @deadline: deadline jiffies for the operation * * Resume SATA phy of @ap and debounce it. * @@ -3218,7 +3282,8 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params) * RETURNS: * 0 on success, -errno on failure. */ -int sata_phy_resume(struct ata_port *ap, const unsigned long *params) +int sata_phy_resume(struct ata_port *ap, const unsigned long *params, + unsigned long deadline) { u32 scontrol; int rc; @@ -3236,43 +3301,19 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params) */ msleep(200); - return sata_phy_debounce(ap, params); -} - -static void ata_wait_spinup(struct ata_port *ap) -{ - struct ata_eh_context *ehc = &ap->eh_context; - unsigned long end, secs; - int rc; - - /* first, debounce phy if SATA */ - if (ap->cbl == ATA_CBL_SATA) { - rc = sata_phy_debounce(ap, sata_deb_timing_hotplug); - - /* if debounced successfully and offline, no need to wait */ - if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap)) - return; - } - - /* okay, let's give the drive time to spin up */ - end = ehc->i.hotplug_timestamp + ATA_SPINUP_WAIT * HZ / 1000; - secs = ((end - jiffies) + HZ - 1) / HZ; - - if (time_after(jiffies, end)) - return; - - if (secs > 5) - ata_port_printk(ap, KERN_INFO, "waiting for device to spin up " - "(%lu secs)\n", secs); - - schedule_timeout_uninterruptible(end - jiffies); + return sata_phy_debounce(ap, params, deadline); } /** * ata_std_prereset - prepare for reset * @ap: ATA port to be reset + * @deadline: deadline jiffies for the operation * - * @ap is about to be reset. Initialize it. + * @ap is about to be reset. Initialize it. Failure from + * prereset makes libata abort whole reset sequence and give up + * that port, so prereset should be best-effort. It does its + * best to prepare for reset sequence but if things go wrong, it + * should just whine, not fail. * * LOCKING: * Kernel thread context (may sleep) @@ -3280,41 +3321,41 @@ static void ata_wait_spinup(struct ata_port *ap) * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_prereset(struct ata_port *ap) +int ata_std_prereset(struct ata_port *ap, unsigned long deadline) { struct ata_eh_context *ehc = &ap->eh_context; const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; - /* handle link resume & hotplug spinup */ + /* handle link resume */ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) && (ap->flags & ATA_FLAG_HRST_TO_RESUME)) ehc->i.action |= ATA_EH_HARDRESET; - if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) && - (ap->flags & ATA_FLAG_SKIP_D2H_BSY)) - ata_wait_spinup(ap); - /* if we're about to do hardreset, nothing more to do */ if (ehc->i.action & ATA_EH_HARDRESET) return 0; /* if SATA, resume phy */ if (ap->cbl == ATA_CBL_SATA) { - rc = sata_phy_resume(ap, timing); - if (rc && rc != -EOPNOTSUPP) { - /* phy resume failed */ + rc = sata_phy_resume(ap, timing, deadline); + /* whine about phy resume failure but proceed */ + if (rc && rc != -EOPNOTSUPP) ata_port_printk(ap, KERN_WARNING, "failed to resume " "link for reset (errno=%d)\n", rc); - return rc; - } } /* Wait for !BSY if the controller can wait for the first D2H * Reg FIS and we don't know that no device is attached. */ - if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) { + rc = ata_wait_ready(ap, deadline); + if (rc) { + ata_port_printk(ap, KERN_WARNING, "device not ready " + "(errno=%d), forcing hardreset\n", rc); + ehc->i.action |= ATA_EH_HARDRESET; + } + } return 0; } @@ -3323,6 +3364,7 @@ int ata_std_prereset(struct ata_port *ap) * ata_std_softreset - reset host port via ATA SRST * @ap: port to reset * @classes: resulting classes of attached devices + * @deadline: deadline jiffies for the operation * * Reset host port using ATA SRST. * @@ -3332,10 +3374,12 @@ int ata_std_prereset(struct ata_port *ap) * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_softreset(struct ata_port *ap, unsigned int *classes) +int ata_std_softreset(struct ata_port *ap, unsigned int *classes, + unsigned long deadline) { unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; - unsigned int devmask = 0, err_mask; + unsigned int devmask = 0; + int rc; u8 err; DPRINTK("ENTER\n"); @@ -3356,11 +3400,11 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) /* issue bus reset */ DPRINTK("about to softreset, devmask=%x\n", devmask); - err_mask = ata_bus_softreset(ap, devmask); - if (err_mask) { - ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n", - err_mask); - return -EIO; + rc = ata_bus_softreset(ap, devmask, deadline); + /* if link is occupied, -ENODEV too is an error */ + if (rc && (rc != -ENODEV || sata_scr_valid(ap))) { + ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc); + return rc; } /* determine by signature whether we have ATA or ATAPI devices */ @@ -3377,6 +3421,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) * sata_port_hardreset - reset port via SATA phy reset * @ap: port to reset * @timing: timing parameters { interval, duratinon, timeout } in msec + * @deadline: deadline jiffies for the operation * * SATA phy-reset host port using DET bits of SControl register. * @@ -3386,7 +3431,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) * RETURNS: * 0 on success, -errno otherwise. */ -int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing) +int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, + unsigned long deadline) { u32 scontrol; int rc; @@ -3425,7 +3471,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing) msleep(1); /* bring phy back */ - rc = sata_phy_resume(ap, timing); + rc = sata_phy_resume(ap, timing, deadline); out: DPRINTK("EXIT, rc=%d\n", rc); return rc; @@ -3435,6 +3481,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing) * sata_std_hardreset - reset host port via SATA phy reset * @ap: port to reset * @class: resulting class of attached device + * @deadline: deadline jiffies for the operation * * SATA phy-reset host port using DET bits of SControl register, * wait for !BSY and classify the attached device. @@ -3445,7 +3492,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing) * RETURNS: * 0 on success, -errno otherwise. */ -int sata_std_hardreset(struct ata_port *ap, unsigned int *class) +int sata_std_hardreset(struct ata_port *ap, unsigned int *class, + unsigned long deadline) { const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); int rc; @@ -3453,7 +3501,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) DPRINTK("ENTER\n"); /* do hardreset */ - rc = sata_port_hardreset(ap, timing); + rc = sata_port_hardreset(ap, timing, deadline); if (rc) { ata_port_printk(ap, KERN_ERR, "COMRESET failed (errno=%d)\n", rc); @@ -3470,10 +3518,12 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) /* wait a while before checking status, see SRST for more info */ msleep(150); - if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { + rc = ata_wait_ready(ap, deadline); + /* link occupied, -ENODEV too is an error */ + if (rc) { ata_port_printk(ap, KERN_ERR, - "COMRESET failed (device not ready)\n"); - return -EIO; + "COMRESET failed (errno=%d)\n", rc); + return rc; } ap->ops->dev_select(ap, 0); /* probably unnecessary */ @@ -6793,6 +6843,7 @@ EXPORT_SYMBOL_GPL(ata_port_disable); EXPORT_SYMBOL_GPL(ata_ratelimit); EXPORT_SYMBOL_GPL(ata_wait_register); EXPORT_SYMBOL_GPL(ata_busy_sleep); +EXPORT_SYMBOL_GPL(ata_wait_ready); EXPORT_SYMBOL_GPL(ata_port_queue_task); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); diff --git a/trunk/drivers/ata/libata-eh.c b/trunk/drivers/ata/libata-eh.c index 2bff9adcacf1..8256655ce7d9 100644 --- a/trunk/drivers/ata/libata-eh.c +++ b/trunk/drivers/ata/libata-eh.c @@ -50,6 +50,28 @@ enum { ATA_EH_SPDN_FALLBACK_TO_PIO = (1 << 2), }; +/* Waiting in ->prereset can never be reliable. It's sometimes nice + * to wait there but it can't be depended upon; otherwise, we wouldn't + * be resetting. Just give it enough time for most drives to spin up. + */ +enum { + ATA_EH_PRERESET_TIMEOUT = 10 * HZ, +}; + +/* The following table determines how we sequence resets. Each entry + * represents timeout for that try. The first try can be soft or + * hardreset. All others are hardreset if available. In most cases + * the first reset w/ 10sec timeout should succeed. Following entries + * are mostly for error handling, hotplug and retarded devices. + */ +static const unsigned long ata_eh_reset_timeouts[] = { + 10 * HZ, /* most drives spin up by 10sec */ + 10 * HZ, /* > 99% working drives spin up before 20sec */ + 35 * HZ, /* give > 30 secs of idleness for retarded devices */ + 5 * HZ, /* and sweet one last chance */ + /* > 1 min has elapsed, give up */ +}; + static void __ata_port_freeze(struct ata_port *ap); static void ata_eh_finish(struct ata_port *ap); #ifdef CONFIG_PM @@ -1558,14 +1580,14 @@ static void ata_eh_report(struct ata_port *ap) } static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, - unsigned int *classes) + unsigned int *classes, unsigned long deadline) { int i, rc; for (i = 0; i < ATA_MAX_DEVICES; i++) classes[i] = ATA_DEV_UNKNOWN; - rc = reset(ap, classes); + rc = reset(ap, classes, deadline); if (rc) return rc; @@ -1603,8 +1625,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify, { struct ata_eh_context *ehc = &ap->eh_context; unsigned int *classes = ehc->classes; - int tries = ATA_EH_RESET_TRIES; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); + int try = 0; + unsigned long deadline; unsigned int action; ata_reset_fn_t reset; int i, did_followup_srst, rc; @@ -1624,7 +1647,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ehc->i.action |= ATA_EH_HARDRESET; if (prereset) { - rc = prereset(ap); + rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT); if (rc) { if (rc == -ENOENT) { ata_port_printk(ap, KERN_DEBUG, @@ -1665,6 +1688,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, } retry: + deadline = jiffies + ata_eh_reset_timeouts[try++]; + /* shut up during boot probing */ if (verbose) ata_port_printk(ap, KERN_INFO, "%s resetting port\n", @@ -1676,7 +1701,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, else ehc->i.flags |= ATA_EHI_DID_SOFTRESET; - rc = ata_do_reset(ap, reset, classes); + rc = ata_do_reset(ap, reset, classes, deadline); did_followup_srst = 0; if (reset == hardreset && @@ -1693,7 +1718,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, } ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); - rc = ata_do_reset(ap, reset, classes); + rc = ata_do_reset(ap, reset, classes, deadline); if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN) { @@ -1703,22 +1728,21 @@ static int ata_eh_reset(struct ata_port *ap, int classify, } } - if (rc && --tries) { - const char *type; + if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { + unsigned long now = jiffies; - if (reset == softreset) { - if (did_followup_srst) - type = "follow-up soft"; - else - type = "soft"; - } else - type = "hard"; + if (time_before(now, deadline)) { + unsigned long delta = deadline - jiffies; - ata_port_printk(ap, KERN_WARNING, - "%sreset failed, retrying in 5 secs\n", type); - ssleep(5); + ata_port_printk(ap, KERN_WARNING, "reset failed " + "(errno=%d), retrying in %u secs\n", + rc, (jiffies_to_msecs(delta) + 999) / 1000); + + schedule_timeout_uninterruptible(delta); + } - if (reset == hardreset) + if (reset == hardreset && + try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1) sata_down_spd_limit(ap); if (hardreset) reset = hardreset; diff --git a/trunk/drivers/ata/pata_amd.c b/trunk/drivers/ata/pata_amd.c index 536ee892ab72..67c7e87dec04 100644 --- a/trunk/drivers/ata/pata_amd.c +++ b/trunk/drivers/ata/pata_amd.c @@ -121,12 +121,13 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse /** * amd_probe_init - perform reset handling * @ap: ATA port + * @deadline: deadline jiffies for the operation * * Reset sequence checking enable bits to see which ports are * active. */ -static int amd_pre_reset(struct ata_port *ap) +static int amd_pre_reset(struct ata_port *ap, unsigned long deadline) { static const struct pci_bits amd_enable_bits[] = { { 0x40, 1, 0x02, 0x02 }, @@ -138,8 +139,7 @@ static int amd_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); - + return ata_std_prereset(ap, deadline); } static void amd_error_handler(struct ata_port *ap) @@ -227,7 +227,8 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev) * space for us. */ -static int nv_pre_reset(struct ata_port *ap) { +static int nv_pre_reset(struct ata_port *ap, unsigned long deadline) +{ static const struct pci_bits nv_enable_bits[] = { { 0x50, 1, 0x02, 0x02 }, { 0x50, 1, 0x01, 0x01 } @@ -238,7 +239,7 @@ static int nv_pre_reset(struct ata_port *ap) { if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + return ata_std_prereset(ap, deadline); } static void nv_error_handler(struct ata_port *ap) diff --git a/trunk/drivers/ata/pata_artop.c b/trunk/drivers/ata/pata_artop.c index 00e9ec342db0..ef51940c3adb 100644 --- a/trunk/drivers/ata/pata_artop.c +++ b/trunk/drivers/ata/pata_artop.c @@ -39,7 +39,7 @@ static int clock = 0; -static int artop6210_pre_reset(struct ata_port *ap) +static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); const struct pci_bits artop_enable_bits[] = { @@ -49,7 +49,8 @@ static int artop6210_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } /** @@ -70,12 +71,13 @@ static void artop6210_error_handler(struct ata_port *ap) /** * artop6260_pre_reset - check for 40/80 pin * @ap: Port + * @deadline: deadline jiffies for the operation * * The ARTOP hardware reports the cable detect bits in register 0x49. * Nothing complicated needed here. */ -static int artop6260_pre_reset(struct ata_port *ap) +static int artop6260_pre_reset(struct ata_port *ap, unsigned long deadline) { static const struct pci_bits artop_enable_bits[] = { { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */ @@ -87,7 +89,8 @@ static int artop6260_pre_reset(struct ata_port *ap) /* Odd numbered device ids are the units with enable bits (the -R cards) */ if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_atiixp.c b/trunk/drivers/ata/pata_atiixp.c index 39c871a3ddac..21515381b5b3 100644 --- a/trunk/drivers/ata/pata_atiixp.c +++ b/trunk/drivers/ata/pata_atiixp.c @@ -33,7 +33,7 @@ enum { ATIIXP_IDE_UDMA_MODE = 0x56 }; -static int atiixp_pre_reset(struct ata_port *ap) +static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline) { static const struct pci_bits atiixp_enable_bits[] = { { 0x48, 1, 0x01, 0x00 }, @@ -44,7 +44,7 @@ static int atiixp_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + return ata_std_prereset(ap, deadline); } static void atiixp_error_handler(struct ata_port *ap) diff --git a/trunk/drivers/ata/pata_cs5535.c b/trunk/drivers/ata/pata_cs5535.c index 08cccc9c659b..22006ae71941 100644 --- a/trunk/drivers/ata/pata_cs5535.c +++ b/trunk/drivers/ata/pata_cs5535.c @@ -72,6 +72,7 @@ /** * cs5535_cable_detect - detect cable type * @ap: Port to detect on + * @deadline: deadline jiffies for the operation * * Perform cable detection for ATA66 capable cable. Return a libata * cable type. diff --git a/trunk/drivers/ata/pata_efar.c b/trunk/drivers/ata/pata_efar.c index a3216850bba1..d0f52e034906 100644 --- a/trunk/drivers/ata/pata_efar.c +++ b/trunk/drivers/ata/pata_efar.c @@ -27,12 +27,13 @@ /** * efar_pre_reset - Enable bits * @ap: Port + * @deadline: deadline jiffies for the operation * * Perform cable detection for the EFAR ATA interface. This is * different to the PIIX arrangement */ -static int efar_pre_reset(struct ata_port *ap) +static int efar_pre_reset(struct ata_port *ap, unsigned long deadline) { static const struct pci_bits efar_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ @@ -43,7 +44,7 @@ static int efar_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_hpt366.c b/trunk/drivers/ata/pata_hpt366.c index 93cfa6d300a5..e64e05e5c7fe 100644 --- a/trunk/drivers/ata/pata_hpt366.c +++ b/trunk/drivers/ata/pata_hpt366.c @@ -220,7 +220,7 @@ static int hpt36x_cable_detect(struct ata_port *ap) return ATA_CBL_PATA80; } -static int hpt36x_pre_reset(struct ata_port *ap) +static int hpt36x_pre_reset(struct ata_port *ap, unsigned long deadline) { static const struct pci_bits hpt36x_enable_bits[] = { { 0x50, 1, 0x04, 0x04 }, @@ -231,7 +231,7 @@ static int hpt36x_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_hpt37x.c b/trunk/drivers/ata/pata_hpt37x.c index 41d831296347..1614e8c822a4 100644 --- a/trunk/drivers/ata/pata_hpt37x.c +++ b/trunk/drivers/ata/pata_hpt37x.c @@ -307,11 +307,12 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask) /** * hpt37x_pre_reset - reset the hpt37x bus * @ap: ATA port to reset + * @deadline: deadline jiffies for the operation * * Perform the initial reset handling for the 370/372 and 374 func 0 */ -static int hpt37x_pre_reset(struct ata_port *ap) +static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline) { u8 scr2, ata66; struct pci_dev *pdev = to_pci_dev(ap->host->dev); @@ -338,7 +339,7 @@ static int hpt37x_pre_reset(struct ata_port *ap) pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap); + return ata_std_prereset(ap, deadline); } /** @@ -353,7 +354,7 @@ static void hpt37x_error_handler(struct ata_port *ap) ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset); } -static int hpt374_pre_reset(struct ata_port *ap) +static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline) { static const struct pci_bits hpt37x_enable_bits[] = { { 0x50, 1, 0x04, 0x04 }, @@ -388,7 +389,7 @@ static int hpt374_pre_reset(struct ata_port *ap) pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap); + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_hpt3x2n.c b/trunk/drivers/ata/pata_hpt3x2n.c index 6a34521b9e01..ea1037d67860 100644 --- a/trunk/drivers/ata/pata_hpt3x2n.c +++ b/trunk/drivers/ata/pata_hpt3x2n.c @@ -148,13 +148,14 @@ static int hpt3x2n_cable_detect(struct ata_port *ap) * Reset the hardware and state machine, */ -static int hpt3xn_pre_reset(struct ata_port *ap) +static int hpt3xn_pre_reset(struct ata_port *ap, unsigned long deadline) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); /* Reset the state machine */ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_icside.c b/trunk/drivers/ata/pata_icside.c new file mode 100644 index 000000000000..dbc8ee2adcf0 --- /dev/null +++ b/trunk/drivers/ata/pata_icside.c @@ -0,0 +1,686 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "pata_icside" + +#define ICS_IDENT_OFFSET 0x2280 + +#define ICS_ARCIN_V5_INTRSTAT 0x0000 +#define ICS_ARCIN_V5_INTROFFSET 0x0004 + +#define ICS_ARCIN_V6_INTROFFSET_1 0x2200 +#define ICS_ARCIN_V6_INTRSTAT_1 0x2290 +#define ICS_ARCIN_V6_INTROFFSET_2 0x3200 +#define ICS_ARCIN_V6_INTRSTAT_2 0x3290 + +struct portinfo { + unsigned int dataoffset; + unsigned int ctrloffset; + unsigned int stepping; +}; + +static const struct portinfo pata_icside_portinfo_v5 = { + .dataoffset = 0x2800, + .ctrloffset = 0x2b80, + .stepping = 6, +}; + +static const struct portinfo pata_icside_portinfo_v6_1 = { + .dataoffset = 0x2000, + .ctrloffset = 0x2380, + .stepping = 6, +}; + +static const struct portinfo pata_icside_portinfo_v6_2 = { + .dataoffset = 0x3000, + .ctrloffset = 0x3380, + .stepping = 6, +}; + +#define PATA_ICSIDE_MAX_SG 128 + +struct pata_icside_state { + void __iomem *irq_port; + void __iomem *ioc_base; + unsigned int type; + unsigned int dma; + struct { + u8 port_sel; + u8 disabled; + unsigned int speed[ATA_MAX_DEVICES]; + } port[2]; + struct scatterlist sg[PATA_ICSIDE_MAX_SG]; +}; + +#define ICS_TYPE_A3IN 0 +#define ICS_TYPE_A3USER 1 +#define ICS_TYPE_V6 3 +#define ICS_TYPE_V5 15 +#define ICS_TYPE_NOTYPE ((unsigned int)-1) + +/* ---------------- Version 5 PCB Support Functions --------------------- */ +/* Prototype: pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) + * Purpose : enable interrupts from card + */ +static void pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + + writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET); +} + +/* Prototype: pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) + * Purpose : disable interrupts from card + */ +static void pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + + readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET); +} + +static const expansioncard_ops_t pata_icside_ops_arcin_v5 = { + .irqenable = pata_icside_irqenable_arcin_v5, + .irqdisable = pata_icside_irqdisable_arcin_v5, +}; + + +/* ---------------- Version 6 PCB Support Functions --------------------- */ +/* Prototype: pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) + * Purpose : enable interrupts from card + */ +static void pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + void __iomem *base = state->irq_port; + + if (!state->port[0].disabled) + writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1); + if (!state->port[1].disabled) + writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2); +} + +/* Prototype: pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) + * Purpose : disable interrupts from card + */ +static void pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + + readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); + readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); +} + +/* Prototype: pata_icside_irqprobe(struct expansion_card *ec) + * Purpose : detect an active interrupt from card + */ +static int pata_icside_irqpending_arcin_v6(struct expansion_card *ec) +{ + struct pata_icside_state *state = ec->irq_data; + + return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || + readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; +} + +static const expansioncard_ops_t pata_icside_ops_arcin_v6 = { + .irqenable = pata_icside_irqenable_arcin_v6, + .irqdisable = pata_icside_irqdisable_arcin_v6, + .irqpending = pata_icside_irqpending_arcin_v6, +}; + + +/* + * SG-DMA support. + * + * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers. + * There is only one DMA controller per card, which means that only + * one drive can be accessed at one time. NOTE! We do not enforce that + * here, but we rely on the main IDE driver spotting that both + * interfaces use the same IRQ, which should guarantee this. + */ + +/* + * Configure the IOMD to give the appropriate timings for the transfer + * mode being requested. We take the advice of the ATA standards, and + * calculate the cycle time based on the transfer mode, and the EIDE + * MW DMA specs that the drive provides in the IDENTIFY command. + * + * We have the following IOMD DMA modes to choose from: + * + * Type Active Recovery Cycle + * A 250 (250) 312 (550) 562 (800) + * B 187 (200) 250 (550) 437 (750) + * C 125 (125) 125 (375) 250 (500) + * D 62 (50) 125 (375) 187 (425) + * + * (figures in brackets are actual measured timings on DIOR/DIOW) + * + * However, we also need to take care of the read/write active and + * recovery timings: + * + * Read Write + * Mode Active -- Recovery -- Cycle IOMD type + * MW0 215 50 215 480 A + * MW1 80 50 50 150 C + * MW2 70 25 25 120 C + */ +static void pata_icside_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + struct pata_icside_state *state = ap->host->private_data; + struct ata_timing t; + unsigned int cycle; + char iomd_type; + + /* + * DMA is based on a 16MHz clock + */ + if (ata_timing_compute(adev, adev->dma_mode, &t, 1000, 1)) + return; + + /* + * Choose the IOMD cycle timing which ensure that the interface + * satisfies the measured active, recovery and cycle times. + */ + if (t.active <= 50 && t.recover <= 375 && t.cycle <= 425) + iomd_type = 'D', cycle = 187; + else if (t.active <= 125 && t.recover <= 375 && t.cycle <= 500) + iomd_type = 'C', cycle = 250; + else if (t.active <= 200 && t.recover <= 550 && t.cycle <= 750) + iomd_type = 'B', cycle = 437; + else + iomd_type = 'A', cycle = 562; + + ata_dev_printk(adev, KERN_INFO, "timings: act %dns rec %dns cyc %dns (%c)\n", + t.active, t.recover, t.cycle, iomd_type); + + state->port[ap->port_no].speed[adev->devno] = cycle; +} + +static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pata_icside_state *state = ap->host->private_data; + struct scatterlist *sg, *rsg = state->sg; + unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE; + + /* + * We are simplex; BUG if we try to fiddle with DMA + * while it's active. + */ + BUG_ON(dma_channel_active(state->dma)); + + /* + * Copy ATAs scattered sg list into a contiguous array of sg + */ + ata_for_each_sg(sg, qc) { + memcpy(rsg, sg, sizeof(*sg)); + rsg++; + } + + /* + * Route the DMA signals to the correct interface + */ + writeb(state->port[ap->port_no].port_sel, state->ioc_base); + + set_dma_speed(state->dma, state->port[ap->port_no].speed[qc->dev->devno]); + set_dma_sg(state->dma, state->sg, rsg - state->sg); + set_dma_mode(state->dma, write ? DMA_MODE_WRITE : DMA_MODE_READ); + + /* issue r/w command */ + ap->ops->exec_command(ap, &qc->tf); +} + +static void pata_icside_bmdma_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pata_icside_state *state = ap->host->private_data; + + BUG_ON(dma_channel_active(state->dma)); + enable_dma(state->dma); +} + +static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pata_icside_state *state = ap->host->private_data; + + disable_dma(state->dma); + + /* see ata_bmdma_stop */ + ata_altstatus(ap); +} + +static u8 pata_icside_bmdma_status(struct ata_port *ap) +{ + struct pata_icside_state *state = ap->host->private_data; + void __iomem *irq_port; + + irq_port = state->irq_port + (ap->port_no ? ICS_ARCIN_V6_INTRSTAT_2 : + ICS_ARCIN_V6_INTRSTAT_1); + + return readb(irq_port) & 1 ? ATA_DMA_INTR : 0; +} + +static int icside_dma_init(struct ata_probe_ent *ae, struct expansion_card *ec) +{ + struct pata_icside_state *state = ae->private_data; + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + state->port[0].speed[i] = 480; + state->port[1].speed[i] = 480; + } + + if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) { + state->dma = ec->dma; + ae->mwdma_mask = 0x07; /* MW0..2 */ + } + + return 0; +} + + +static int pata_icside_port_start(struct ata_port *ap) +{ + /* No PRD to alloc */ + return ata_pad_alloc(ap, ap->dev); +} + +static struct scsi_host_template pata_icside_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = PATA_ICSIDE_MAX_SG, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ~0, /* no dma boundaries */ + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + +/* wish this was exported from libata-core */ +static void ata_dummy_noret(struct ata_port *port) +{ +} + +/* + * We need to shut down unused ports to prevent spurious interrupts. + * FIXME: the libata core doesn't call this function for PATA interfaces. + */ +static void pata_icside_port_disable(struct ata_port *ap) +{ + struct pata_icside_state *state = ap->host->private_data; + + ata_port_printk(ap, KERN_ERR, "disabling icside port\n"); + + ata_port_disable(ap); + + state->port[ap->port_no].disabled = 1; + + if (state->type == ICS_TYPE_V6) { + /* + * Disable interrupts from this port, otherwise we + * receive spurious interrupts from the floating + * interrupt line. + */ + void __iomem *irq_port = state->irq_port + + (ap->port_no ? ICS_ARCIN_V6_INTROFFSET_2 : ICS_ARCIN_V6_INTROFFSET_1); + readb(irq_port); + } +} + +static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq) +{ + unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; + u8 status; + + status = ata_busy_wait(ap, bits, 1000); + if (status & bits) + if (ata_msg_err(ap)) + printk(KERN_ERR "abnormal status 0x%X\n", status); + + if (ata_msg_intr(ap)) + printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n", + __FUNCTION__, status); + + return status; +} + +static struct ata_port_operations pata_icside_port_ops = { + .port_disable = pata_icside_port_disable, + + .set_dmamode = pata_icside_set_dmamode, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + + .bmdma_setup = pata_icside_bmdma_setup, + .bmdma_start = pata_icside_bmdma_start, + + .data_xfer = ata_data_xfer_noirq, + + /* no need to build any PRD tables for DMA */ + .qc_prep = ata_noop_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = pata_icside_bmdma_stop, + + .irq_handler = ata_interrupt, + .irq_clear = ata_dummy_noret, + .irq_on = ata_irq_on, + .irq_ack = pata_icside_irq_ack, + + .port_start = pata_icside_port_start, + + .bmdma_stop = pata_icside_bmdma_stop, + .bmdma_status = pata_icside_bmdma_status, +}; + +static void +pata_icside_add_port(struct ata_probe_ent *ae, void __iomem *base, + const struct portinfo *info) +{ + struct ata_ioports *ioaddr = &ae->port[ae->n_ports++]; + void __iomem *cmd = base + info->dataoffset; + + ioaddr->cmd_addr = cmd; + ioaddr->data_addr = cmd + (ATA_REG_DATA << info->stepping); + ioaddr->error_addr = cmd + (ATA_REG_ERR << info->stepping); + ioaddr->feature_addr = cmd + (ATA_REG_FEATURE << info->stepping); + ioaddr->nsect_addr = cmd + (ATA_REG_NSECT << info->stepping); + ioaddr->lbal_addr = cmd + (ATA_REG_LBAL << info->stepping); + ioaddr->lbam_addr = cmd + (ATA_REG_LBAM << info->stepping); + ioaddr->lbah_addr = cmd + (ATA_REG_LBAH << info->stepping); + ioaddr->device_addr = cmd + (ATA_REG_DEVICE << info->stepping); + ioaddr->status_addr = cmd + (ATA_REG_STATUS << info->stepping); + ioaddr->command_addr = cmd + (ATA_REG_CMD << info->stepping); + + ioaddr->ctl_addr = base + info->ctrloffset; + ioaddr->altstatus_addr = ioaddr->ctl_addr; +} + +static int __init +pata_icside_register_v5(struct ata_probe_ent *ae, struct expansion_card *ec) +{ + struct pata_icside_state *state = ae->private_data; + void __iomem *base; + + base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), + ecard_resource_len(ec, ECARD_RES_MEMC)); + if (!base) + return -ENOMEM; + + state->irq_port = base; + + ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT; + ec->irqmask = 1; + ec->irq_data = state; + ec->ops = &pata_icside_ops_arcin_v5; + + /* + * Be on the safe side - disable interrupts + */ + ec->ops->irqdisable(ec, ec->irq); + + pata_icside_add_port(ae, base, &pata_icside_portinfo_v5); + + return 0; +} + +static int __init +pata_icside_register_v6(struct ata_probe_ent *ae, struct expansion_card *ec) +{ + struct pata_icside_state *state = ae->private_data; + void __iomem *ioc_base, *easi_base; + unsigned int sel = 0; + int ret; + + ioc_base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST), + ecard_resource_len(ec, ECARD_RES_IOCFAST)); + if (!ioc_base) { + ret = -ENOMEM; + goto out; + } + + easi_base = ioc_base; + + if (ecard_resource_flags(ec, ECARD_RES_EASI)) { + easi_base = ioremap(ecard_resource_start(ec, ECARD_RES_EASI), + ecard_resource_len(ec, ECARD_RES_EASI)); + if (!easi_base) { + ret = -ENOMEM; + goto unmap_slot; + } + + /* + * Enable access to the EASI region. + */ + sel = 1 << 5; + } + + writeb(sel, ioc_base); + + ec->irq_data = state; + ec->ops = &pata_icside_ops_arcin_v6; + + state->irq_port = easi_base; + state->ioc_base = ioc_base; + state->port[0].port_sel = sel; + state->port[1].port_sel = sel | 1; + + /* + * Be on the safe side - disable interrupts + */ + ec->ops->irqdisable(ec, ec->irq); + + /* + * Find and register the interfaces. + */ + pata_icside_add_port(ae, easi_base, &pata_icside_portinfo_v6_1); + pata_icside_add_port(ae, easi_base, &pata_icside_portinfo_v6_2); + + /* + * FIXME: work around libata's aversion to calling port_disable. + * This permanently disables interrupts on port 0 - bad luck if + * you have a drive on that port. + */ + state->port[0].disabled = 1; + + return icside_dma_init(ae, ec); + + unmap_slot: + iounmap(ioc_base); + out: + return ret; +} + +static int __devinit +pata_icside_probe(struct expansion_card *ec, const struct ecard_id *id) +{ + struct pata_icside_state *state; + struct ata_probe_ent ae; + void __iomem *idmem; + int ret; + + ret = ecard_request_resources(ec); + if (ret) + goto out; + + state = kzalloc(sizeof(struct pata_icside_state), GFP_KERNEL); + if (!state) { + ret = -ENOMEM; + goto release; + } + + state->type = ICS_TYPE_NOTYPE; + state->dma = NO_DMA; + + idmem = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST), + ecard_resource_len(ec, ECARD_RES_IOCFAST)); + if (idmem) { + unsigned int type; + + type = readb(idmem + ICS_IDENT_OFFSET) & 1; + type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1; + type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2; + type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3; + iounmap(idmem); + + state->type = type; + } + + memset(&ae, 0, sizeof(ae)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &ec->dev; + ae.port_ops = &pata_icside_port_ops; + ae.sht = &pata_icside_sht; + ae.pio_mask = 0x1f; + ae.irq = ec->irq; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + ae._host_flags = ATA_HOST_SIMPLEX; + ae.private_data = state; + + switch (state->type) { + case ICS_TYPE_A3IN: + dev_warn(&ec->dev, "A3IN unsupported\n"); + ret = -ENODEV; + break; + + case ICS_TYPE_A3USER: + dev_warn(&ec->dev, "A3USER unsupported\n"); + ret = -ENODEV; + break; + + case ICS_TYPE_V5: + ret = pata_icside_register_v5(&ae, ec); + break; + + case ICS_TYPE_V6: + ret = pata_icside_register_v6(&ae, ec); + break; + + default: + dev_warn(&ec->dev, "unknown interface type\n"); + ret = -ENODEV; + break; + } + + if (ret == 0) + ret = ata_device_add(&ae) == 0 ? -ENODEV : 0; + + if (ret == 0) + goto out; + + kfree(state); + release: + ecard_release_resources(ec); + out: + return ret; +} + +static void pata_icside_shutdown(struct expansion_card *ec) +{ + struct ata_host *host = ecard_get_drvdata(ec); + unsigned long flags; + + /* + * Disable interrupts from this card. We need to do + * this before disabling EASI since we may be accessing + * this register via that region. + */ + local_irq_save(flags); + if (ec->ops) + ec->ops->irqdisable(ec, ec->irq); + local_irq_restore(flags); + + /* + * Reset the ROM pointer so that we can read the ROM + * after a soft reboot. This also disables access to + * the IDE taskfile via the EASI region. + */ + if (host) { + struct pata_icside_state *state = host->private_data; + if (state->ioc_base) + writeb(0, state->ioc_base); + } +} + +static void __devexit pata_icside_remove(struct expansion_card *ec) +{ + struct ata_host *host = ecard_get_drvdata(ec); + struct pata_icside_state *state = host->private_data; + + ata_host_detach(host); + + pata_icside_shutdown(ec); + + /* + * don't NULL out the drvdata - devres/libata wants it + * to free the ata_host structure. + */ + ec->ops = NULL; + ec->irq_data = NULL; + + if (state->dma != NO_DMA) + free_dma(state->dma); + if (state->ioc_base) + iounmap(state->ioc_base); + if (state->ioc_base != state->irq_port) + iounmap(state->irq_port); + + kfree(state); + ecard_release_resources(ec); +} + +static const struct ecard_id pata_icside_ids[] = { + { MANU_ICS, PROD_ICS_IDE }, + { MANU_ICS2, PROD_ICS2_IDE }, + { 0xffff, 0xffff } +}; + +static struct ecard_driver pata_icside_driver = { + .probe = pata_icside_probe, + .remove = __devexit_p(pata_icside_remove), + .shutdown = pata_icside_shutdown, + .id_table = pata_icside_ids, + .drv = { + .name = DRV_NAME, + }, +}; + +static int __init pata_icside_init(void) +{ + return ecard_register_driver(&pata_icside_driver); +} + +static void __exit pata_icside_exit(void) +{ + ecard_remove_driver(&pata_icside_driver); +} + +MODULE_AUTHOR("Russell King "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ICS PATA driver"); + +module_init(pata_icside_init); +module_exit(pata_icside_exit); diff --git a/trunk/drivers/ata/pata_it8213.c b/trunk/drivers/ata/pata_it8213.c index 011306ef8334..17bf9f3ed013 100644 --- a/trunk/drivers/ata/pata_it8213.c +++ b/trunk/drivers/ata/pata_it8213.c @@ -24,12 +24,13 @@ /** * it8213_pre_reset - check for 40/80 pin * @ap: Port + * @deadline: deadline jiffies for the operation * * Filter out ports by the enable bits before doing the normal reset * and probe. */ -static int it8213_pre_reset(struct ata_port *ap) +static int it8213_pre_reset(struct ata_port *ap, unsigned long deadline) { static const struct pci_bits it8213_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ @@ -37,7 +38,8 @@ static int it8213_pre_reset(struct ata_port *ap) struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_jmicron.c b/trunk/drivers/ata/pata_jmicron.c index 43763c99ea02..1daf78ac6efb 100644 --- a/trunk/drivers/ata/pata_jmicron.c +++ b/trunk/drivers/ata/pata_jmicron.c @@ -30,16 +30,17 @@ typedef enum { /** * jmicron_pre_reset - check for 40/80 pin * @ap: Port + * @deadline: deadline jiffies for the operation * * Perform the PATA port setup we need. - + * * On the Jmicron 361/363 there is a single PATA port that can be mapped * either as primary or secondary (or neither). We don't do any policy * and setup here. We assume that has been done by init_one and the * BIOS. */ -static int jmicron_pre_reset(struct ata_port *ap) +static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 control; @@ -102,7 +103,7 @@ static int jmicron_pre_reset(struct ata_port *ap) ap->cbl = ATA_CBL_SATA; break; } - return ata_std_prereset(ap); + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_marvell.c b/trunk/drivers/ata/pata_marvell.c index d9b94a1b6954..837b7fe77dc7 100644 --- a/trunk/drivers/ata/pata_marvell.c +++ b/trunk/drivers/ata/pata_marvell.c @@ -25,11 +25,12 @@ /** * marvell_pre_reset - check for 40/80 pin * @ap: Port + * @deadline: deadline jiffies for the operation * * Perform the PATA port setup we need. */ -static int marvell_pre_reset(struct ata_port *ap) +static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 devices; @@ -52,7 +53,8 @@ static int marvell_pre_reset(struct ata_port *ap) if ((pdev->device == 0x6145) && (ap->port_no == 0) && (!(devices & 0x10))) /* PATA enable ? */ return -ENOENT; - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } static int marvell_cable_detect(struct ata_port *ap) @@ -67,6 +69,7 @@ static int marvell_cable_detect(struct ata_port *ap) case 1: /* Legacy SATA port */ return ATA_CBL_SATA; } + BUG(); return 0; /* Our BUG macro needs the right markup */ } diff --git a/trunk/drivers/ata/pata_mpiix.c b/trunk/drivers/ata/pata_mpiix.c index 987c5fafab08..3bfbd495f643 100644 --- a/trunk/drivers/ata/pata_mpiix.c +++ b/trunk/drivers/ata/pata_mpiix.c @@ -46,14 +46,15 @@ enum { SECONDARY = (1 << 14) }; -static int mpiix_pre_reset(struct ata_port *ap) +static int mpiix_pre_reset(struct ata_port *ap, unsigned long deadline) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 }; if (!pci_test_config_bits(pdev, &mpiix_enable_bits)) return -ENOENT; - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_ns87410.c b/trunk/drivers/ata/pata_ns87410.c index 078aeda9cf8d..ebc58a907d26 100644 --- a/trunk/drivers/ata/pata_ns87410.c +++ b/trunk/drivers/ata/pata_ns87410.c @@ -33,11 +33,12 @@ /** * ns87410_pre_reset - probe begin * @ap: ATA port + * @deadline: deadline jiffies for the operation * * Check enabled ports */ -static int ns87410_pre_reset(struct ata_port *ap) +static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits ns87410_enable_bits[] = { @@ -47,7 +48,8 @@ static int ns87410_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_oldpiix.c b/trunk/drivers/ata/pata_oldpiix.c index dea4690340d1..4d75d32e5826 100644 --- a/trunk/drivers/ata/pata_oldpiix.c +++ b/trunk/drivers/ata/pata_oldpiix.c @@ -30,11 +30,12 @@ /** * oldpiix_pre_reset - probe begin * @ap: ATA port + * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int oldpiix_pre_reset(struct ata_port *ap) +static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits oldpiix_enable_bits[] = { @@ -44,7 +45,8 @@ static int oldpiix_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_opti.c b/trunk/drivers/ata/pata_opti.c index 13b63e21838d..0af8a2c77cc9 100644 --- a/trunk/drivers/ata/pata_opti.c +++ b/trunk/drivers/ata/pata_opti.c @@ -47,11 +47,12 @@ enum { /** * opti_pre_reset - probe begin * @ap: ATA port + * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int opti_pre_reset(struct ata_port *ap) +static int opti_pre_reset(struct ata_port *ap, unsigned long deadline) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits opti_enable_bits[] = { @@ -61,7 +62,8 @@ static int opti_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_optidma.c b/trunk/drivers/ata/pata_optidma.c index b70e04c144df..2843e480f216 100644 --- a/trunk/drivers/ata/pata_optidma.c +++ b/trunk/drivers/ata/pata_optidma.c @@ -48,11 +48,12 @@ static int pci_clock; /* 0 = 33 1 = 25 */ /** * optidma_pre_reset - probe begin * @ap: ATA port + * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int optidma_pre_reset(struct ata_port *ap) +static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits optidma_enable_bits = { @@ -62,7 +63,7 @@ static int optidma_pre_reset(struct ata_port *ap) if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits)) return -ENOENT; - return ata_std_prereset(ap); + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_pdc2027x.c b/trunk/drivers/ata/pata_pdc2027x.c index a61cbc110688..0d2cc49fde4b 100644 --- a/trunk/drivers/ata/pata_pdc2027x.c +++ b/trunk/drivers/ata/pata_pdc2027x.c @@ -301,6 +301,7 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap) /** * pdc2027x_prereset - prereset for PATA host controller * @ap: Target port + * @deadline: deadline jiffies for the operation * * Probeinit including cable detection. * @@ -308,12 +309,12 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap) * None (inherited from caller). */ -static int pdc2027x_prereset(struct ata_port *ap) +static int pdc2027x_prereset(struct ata_port *ap, unsigned long deadline) { /* Check whether port enabled */ if (!pdc2027x_port_enabled(ap)) return -ENOENT; - return ata_std_prereset(ap); + return ata_std_prereset(ap, deadline); } /** diff --git a/trunk/drivers/ata/pata_serverworks.c b/trunk/drivers/ata/pata_serverworks.c index 3956ef26936d..b6e020383dd9 100644 --- a/trunk/drivers/ata/pata_serverworks.c +++ b/trunk/drivers/ata/pata_serverworks.c @@ -139,12 +139,14 @@ static struct sv_cable_table cable_detect[] = { /** * serverworks_cable_detect - cable detection * @ap: ATA port + * @deadline: deadline jiffies for the operation * * Perform cable detection according to the device and subvendor * identifications */ -static int serverworks_cable_detect(struct ata_port *ap) { +static int serverworks_cable_detect(struct ata_port *ap) +{ struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct sv_cable_table *cb = cable_detect; diff --git a/trunk/drivers/ata/pata_sil680.c b/trunk/drivers/ata/pata_sil680.c index 6770820cfca9..a5886f061c0b 100644 --- a/trunk/drivers/ata/pata_sil680.c +++ b/trunk/drivers/ata/pata_sil680.c @@ -94,11 +94,13 @@ static int sil680_cable_detect(struct ata_port *ap) { /** * sil680_bus_reset - reset the SIL680 bus * @ap: ATA port to reset + * @deadline: deadline jiffies for the operation * * Perform the SIL680 housekeeping when doing an ATA bus reset */ -static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes) +static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes, + unsigned long deadline) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); unsigned long addr = sil680_selreg(ap, 0); @@ -108,7 +110,7 @@ static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes) pci_write_config_byte(pdev, addr, reset | 0x03); udelay(25); pci_write_config_byte(pdev, addr, reset); - return ata_std_softreset(ap, classes); + return ata_std_softreset(ap, classes, deadline); } static void sil680_error_handler(struct ata_port *ap) diff --git a/trunk/drivers/ata/pata_sis.c b/trunk/drivers/ata/pata_sis.c index a3fbcee6fb33..f5838cc11728 100644 --- a/trunk/drivers/ata/pata_sis.c +++ b/trunk/drivers/ata/pata_sis.c @@ -88,6 +88,7 @@ static int sis_port_base(struct ata_device *adev) /** * sis_133_cable_detect - check for 40/80 pin * @ap: Port + * @deadline: deadline jiffies for the operation * * Perform cable detection for the later UDMA133 capable * SiS chipset. @@ -108,6 +109,7 @@ static int sis_133_cable_detect(struct ata_port *ap) /** * sis_66_cable_detect - check for 40/80 pin * @ap: Port + * @deadline: deadline jiffies for the operation * * Perform cable detection on the UDMA66, UDMA100 and early UDMA133 * SiS IDE controllers. @@ -130,11 +132,12 @@ static int sis_66_cable_detect(struct ata_port *ap) /** * sis_pre_reset - probe begin * @ap: ATA port + * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int sis_pre_reset(struct ata_port *ap) +static int sis_pre_reset(struct ata_port *ap, unsigned long deadline) { static const struct pci_bits sis_enable_bits[] = { { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */ @@ -145,7 +148,8 @@ static int sis_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } diff --git a/trunk/drivers/ata/pata_sl82c105.c b/trunk/drivers/ata/pata_sl82c105.c index da9e22b25753..9aeffdbe2829 100644 --- a/trunk/drivers/ata/pata_sl82c105.c +++ b/trunk/drivers/ata/pata_sl82c105.c @@ -44,11 +44,12 @@ enum { /** * sl82c105_pre_reset - probe begin * @ap: ATA port + * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int sl82c105_pre_reset(struct ata_port *ap) +static int sl82c105_pre_reset(struct ata_port *ap, unsigned long deadline) { static const struct pci_bits sl82c105_enable_bits[] = { { 0x40, 1, 0x01, 0x01 }, @@ -58,7 +59,7 @@ static int sl82c105_pre_reset(struct ata_port *ap) if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + return ata_std_prereset(ap, deadline); } diff --git a/trunk/drivers/ata/pata_triflex.c b/trunk/drivers/ata/pata_triflex.c index e618ffd6e944..349887bf5b93 100644 --- a/trunk/drivers/ata/pata_triflex.c +++ b/trunk/drivers/ata/pata_triflex.c @@ -48,11 +48,12 @@ /** * triflex_prereset - probe begin * @ap: ATA port + * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int triflex_prereset(struct ata_port *ap) +static int triflex_prereset(struct ata_port *ap, unsigned long deadline) { static const struct pci_bits triflex_enable_bits[] = { { 0x80, 1, 0x01, 0x01 }, @@ -63,7 +64,8 @@ static int triflex_prereset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } diff --git a/trunk/drivers/ata/pata_via.c b/trunk/drivers/ata/pata_via.c index 96b71791d2f4..362beb2f489c 100644 --- a/trunk/drivers/ata/pata_via.c +++ b/trunk/drivers/ata/pata_via.c @@ -154,7 +154,7 @@ static int via_cable_detect(struct ata_port *ap) { return ATA_CBL_PATA40; } -static int via_pre_reset(struct ata_port *ap) +static int via_pre_reset(struct ata_port *ap, unsigned long deadline) { const struct via_isa_bridge *config = ap->host->private_data; @@ -167,7 +167,8 @@ static int via_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &via_enable_bits[ap->port_no])) return -ENOENT; } - return ata_std_prereset(ap); + + return ata_std_prereset(ap, deadline); } diff --git a/trunk/drivers/ata/sata_inic162x.c b/trunk/drivers/ata/sata_inic162x.c index f099a1d83a00..b3b62e985f19 100644 --- a/trunk/drivers/ata/sata_inic162x.c +++ b/trunk/drivers/ata/sata_inic162x.c @@ -420,7 +420,8 @@ static void inic_thaw(struct ata_port *ap) * SRST and SControl hardreset don't give valid signature on this * controller. Only controller specific hardreset mechanism works. */ -static int inic_hardreset(struct ata_port *ap, unsigned int *class) +static int inic_hardreset(struct ata_port *ap, unsigned int *class, + unsigned long deadline) { void __iomem *port_base = inic_port_base(ap); void __iomem *idma_ctl = port_base + PORT_IDMA_CTL; @@ -437,7 +438,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class) msleep(1); writew(val & ~IDMA_CTL_RST_ATA, idma_ctl); - rc = sata_phy_resume(ap, timing); + rc = sata_phy_resume(ap, timing, deadline); if (rc) { ata_port_printk(ap, KERN_WARNING, "failed to resume " "link after reset (errno=%d)\n", rc); @@ -451,10 +452,12 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class) /* wait a while before checking status */ msleep(150); - if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { - ata_port_printk(ap, KERN_WARNING, - "device busy after hardreset\n"); - return -EIO; + rc = ata_wait_ready(ap, deadline); + /* link occupied, -ENODEV too is an error */ + if (rc) { + ata_port_printk(ap, KERN_WARNING, "device not ready " + "after hardreset (errno=%d)\n", rc); + return rc; } ata_tf_read(ap, &tf); diff --git a/trunk/drivers/ata/sata_nv.c b/trunk/drivers/ata/sata_nv.c index 02169740ed24..e2e795e58236 100644 --- a/trunk/drivers/ata/sata_nv.c +++ b/trunk/drivers/ata/sata_nv.c @@ -1405,7 +1405,8 @@ static void nv_ck804_thaw(struct ata_port *ap) writeb(mask, mmio_base + NV_INT_ENABLE_CK804); } -static int nv_hardreset(struct ata_port *ap, unsigned int *class) +static int nv_hardreset(struct ata_port *ap, unsigned int *class, + unsigned long deadline) { unsigned int dummy; @@ -1413,7 +1414,7 @@ static int nv_hardreset(struct ata_port *ap, unsigned int *class) * some controllers. Don't classify on hardreset. For more * info, see http://bugme.osdl.org/show_bug.cgi?id=3352 */ - return sata_std_hardreset(ap, &dummy); + return sata_std_hardreset(ap, &dummy, deadline); } static void nv_error_handler(struct ata_port *ap) diff --git a/trunk/drivers/ata/sata_sil24.c b/trunk/drivers/ata/sata_sil24.c index e6223ba667da..b97ee9f31aec 100644 --- a/trunk/drivers/ata/sata_sil24.c +++ b/trunk/drivers/ata/sata_sil24.c @@ -534,7 +534,8 @@ static int sil24_init_port(struct ata_port *ap) return 0; } -static int sil24_softreset(struct ata_port *ap, unsigned int *class) +static int sil24_softreset(struct ata_port *ap, unsigned int *class, + unsigned long deadline) { void __iomem *port = ap->ioaddr.cmd_addr; struct sil24_port_priv *pp = ap->private_data; @@ -566,7 +567,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT; irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0, - 100, ATA_TMOUT_BOOT / HZ * 1000); + 100, jiffies_to_msecs(deadline - jiffies)); writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */ irq_stat >>= PORT_IRQ_RAW_SHIFT; @@ -594,7 +595,8 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) return -EIO; } -static int sil24_hardreset(struct ata_port *ap, unsigned int *class) +static int sil24_hardreset(struct ata_port *ap, unsigned int *class, + unsigned long deadline) { void __iomem *port = ap->ioaddr.cmd_addr; const char *reason; @@ -615,7 +617,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) /* SStatus oscillates between zero and valid status after * DEV_RST, debounce it. */ - rc = sata_phy_debounce(ap, sata_deb_timing_long); + rc = sata_phy_debounce(ap, sata_deb_timing_long, deadline); if (rc) { reason = "PHY debouncing failed"; goto err; diff --git a/trunk/drivers/ata/sata_svw.c b/trunk/drivers/ata/sata_svw.c index cc07aac10e8c..17246734fe76 100644 --- a/trunk/drivers/ata/sata_svw.c +++ b/trunk/drivers/ata/sata_svw.c @@ -288,7 +288,7 @@ static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start, /* Match it to a port node */ index = (ap == ap->host->ports[0]) ? 0 : 1; for (np = np->child; np != NULL; np = np->sibling) { - const u32 *reg = get_property(np, "reg", NULL); + const u32 *reg = of_get_property(np, "reg", NULL); if (!reg) continue; if (index == *reg) diff --git a/trunk/drivers/ata/sata_via.c b/trunk/drivers/ata/sata_via.c index 1d855f55f5f7..305ab7c68ca5 100644 --- a/trunk/drivers/ata/sata_via.c +++ b/trunk/drivers/ata/sata_via.c @@ -268,6 +268,7 @@ static void svia_noop_freeze(struct ata_port *ap) /** * vt6420_prereset - prereset for vt6420 * @ap: target ATA port + * @deadline: deadline jiffies for the operation * * SCR registers on vt6420 are pieces of shit and may hang the * whole machine completely if accessed with the wrong timing. @@ -284,7 +285,7 @@ static void svia_noop_freeze(struct ata_port *ap) * RETURNS: * 0 on success, -errno otherwise. */ -static int vt6420_prereset(struct ata_port *ap) +static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) { struct ata_eh_context *ehc = &ap->eh_context; unsigned long timeout = jiffies + (HZ * 5); @@ -329,7 +330,7 @@ static int vt6420_prereset(struct ata_port *ap) skip_scr: /* wait for !BSY */ - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + ata_wait_ready(ap, deadline); return 0; } diff --git a/trunk/drivers/base/Makefile b/trunk/drivers/base/Makefile index e9eb7382ac3a..b39ea3f59c9b 100644 --- a/trunk/drivers/base/Makefile +++ b/trunk/drivers/base/Makefile @@ -2,10 +2,10 @@ obj-y := core.o sys.o bus.o dd.o \ driver.o class.o platform.o \ - cpu.o firmware.o init.o map.o dmapool.o \ - dma-mapping.o devres.o \ + cpu.o firmware.o init.o map.o devres.o \ attribute_container.o transport_class.o obj-y += power/ +obj-$(CONFIG_HAS_DMA) += dma-mapping.o dmapool.o obj-$(CONFIG_ISA) += isa.o obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o diff --git a/trunk/drivers/base/platform.c b/trunk/drivers/base/platform.c index 17b5ece8f82c..eb84d9d44645 100644 --- a/trunk/drivers/base/platform.c +++ b/trunk/drivers/base/platform.c @@ -160,6 +160,11 @@ static void platform_device_release(struct device *dev) * * Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. + * + * This device will be marked as not supporting hotpluggable drivers; no + * device add/remove uevents will be generated. In the unusual case that + * the device isn't being dynamically allocated as a legacy "probe the + * hardware" driver, infrastructure code should reverse this marking. */ struct platform_device *platform_device_alloc(const char *name, unsigned int id) { @@ -172,6 +177,12 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id) pa->pdev.id = id; device_initialize(&pa->pdev.dev); pa->pdev.dev.release = platform_device_release; + + /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in + * legacy probe-the-hardware drivers, which don't properly split + * out device enumeration logic from drivers. + */ + pa->pdev.dev.uevent_suppress = 1; } return pa ? &pa->pdev : NULL; @@ -351,6 +362,13 @@ EXPORT_SYMBOL_GPL(platform_device_unregister); * memory allocated for the device allows drivers using such devices * to be unloaded iwithout waiting for the last reference to the device * to be dropped. + * + * This interface is primarily intended for use with legacy drivers + * which probe hardware directly. Because such drivers create sysfs + * device nodes themselves, rather than letting system infrastructure + * handle such device enumeration tasks, they don't fully conform to + * the Linux driver model. In particular, when such drivers are built + * as modules, they can't be "hotplugged". */ struct platform_device *platform_device_register_simple(char *name, unsigned int id, struct resource *res, unsigned int num) diff --git a/trunk/drivers/block/acsi_slm.c b/trunk/drivers/block/acsi_slm.c index e2e043290963..1d9d9b4f48cc 100644 --- a/trunk/drivers/block/acsi_slm.c +++ b/trunk/drivers/block/acsi_slm.c @@ -65,7 +65,6 @@ not be guaranteed. There are several ways to assure this: #include #include #include -#include #include #include diff --git a/trunk/drivers/block/amiflop.c b/trunk/drivers/block/amiflop.c index 5d6562171533..27a139025ced 100644 --- a/trunk/drivers/block/amiflop.c +++ b/trunk/drivers/block/amiflop.c @@ -1480,7 +1480,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, break; case FDFMTEND: floppy_off(drive); - invalidate_bdev(inode->i_bdev, 0); + invalidate_bdev(inode->i_bdev); break; case FDGETPRM: memset((void *)&getprm, 0, sizeof (getprm)); diff --git a/trunk/drivers/block/cciss.c b/trunk/drivers/block/cciss.c index 65a725cd3422..370dfe1c422e 100644 --- a/trunk/drivers/block/cciss.c +++ b/trunk/drivers/block/cciss.c @@ -45,6 +45,10 @@ #include #include #include +#include +#include +#include +#include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) #define DRIVER_NAME "HP CISS Driver (v 3.6.14)" @@ -1152,6 +1156,30 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, kfree(ioc); return status; } + + /* scsi_cmd_ioctl handles these, below, though some are not */ + /* very meaningful for cciss. SG_IO is the main one people want. */ + + case SG_GET_VERSION_NUM: + case SG_SET_TIMEOUT: + case SG_GET_TIMEOUT: + case SG_GET_RESERVED_SIZE: + case SG_SET_RESERVED_SIZE: + case SG_EMULATED_HOST: + case SG_IO: + case SCSI_IOCTL_SEND_COMMAND: + return scsi_cmd_ioctl(filep, disk, cmd, argp); + + /* scsi_cmd_ioctl would normally handle these, below, but */ + /* they aren't a good fit for cciss, as CD-ROMs are */ + /* not supported, and we don't have any bus/target/lun */ + /* which we present to the kernel. */ + + case CDROM_SEND_PACKET: + case CDROMCLOSETRAY: + case CDROMEJECT: + case SCSI_IOCTL_GET_IDLUN: + case SCSI_IOCTL_GET_BUS_NUMBER: default: return -ENOTTY; } @@ -1234,7 +1262,7 @@ static void cciss_softirq_done(struct request *rq) pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); } - complete_buffers(rq->bio, rq->errors); + complete_buffers(rq->bio, (rq->errors == 0)); if (blk_fs_request(rq)) { const int rw = rq_data_dir(rq); @@ -1248,7 +1276,7 @@ static void cciss_softirq_done(struct request *rq) add_disk_randomness(rq->rq_disk); spin_lock_irqsave(&h->lock, flags); - end_that_request_last(rq, rq->errors); + end_that_request_last(rq, (rq->errors == 0)); cmd_free(h, cmd, 1); cciss_check_queues(h); spin_unlock_irqrestore(&h->lock, flags); @@ -2336,6 +2364,44 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) start_io(h); } +static inline int evaluate_target_status(CommandList_struct *cmd) +{ + unsigned char sense_key; + int error_count = 1; + + if (cmd->err_info->ScsiStatus != 0x02) { /* not check condition? */ + if (!blk_pc_request(cmd->rq)) + printk(KERN_WARNING "cciss: cmd %p " + "has SCSI Status 0x%x\n", + cmd, cmd->err_info->ScsiStatus); + return error_count; + } + + /* check the sense key */ + sense_key = 0xf & cmd->err_info->SenseInfo[2]; + /* no status or recovered error */ + if ((sense_key == 0x0) || (sense_key == 0x1)) + error_count = 0; + + if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ + if (error_count != 0) + printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" + " sense key = 0x%x\n", cmd, sense_key); + return error_count; + } + + /* SG_IO or similar, copy sense data back */ + if (cmd->rq->sense) { + if (cmd->rq->sense_len > cmd->err_info->SenseLen) + cmd->rq->sense_len = cmd->err_info->SenseLen; + memcpy(cmd->rq->sense, cmd->err_info->SenseInfo, + cmd->rq->sense_len); + } else + cmd->rq->sense_len = 0; + + return error_count; +} + /* checks the status of the job and calls complete buffers to mark all * buffers for the completed job. Note that this function does not need * to hold the hba/queue lock. @@ -2343,109 +2409,99 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, int timeout) { - int status = 1; int retry_cmd = 0; + struct request *rq = cmd->rq; + + rq->errors = 0; if (timeout) - status = 0; + rq->errors = 1; - if (cmd->err_info->CommandStatus != 0) { /* an error has occurred */ - switch (cmd->err_info->CommandStatus) { - unsigned char sense_key; - case CMD_TARGET_STATUS: - status = 0; + if (cmd->err_info->CommandStatus == 0) /* no error has occurred */ + goto after_error_processing; - if (cmd->err_info->ScsiStatus == 0x02) { - printk(KERN_WARNING "cciss: cmd %p " - "has CHECK CONDITION " - " byte 2 = 0x%x\n", cmd, - cmd->err_info->SenseInfo[2] - ); - /* check the sense key */ - sense_key = 0xf & cmd->err_info->SenseInfo[2]; - /* no status or recovered error */ - if ((sense_key == 0x0) || (sense_key == 0x1)) { - status = 1; - } - } else { - printk(KERN_WARNING "cciss: cmd %p " - "has SCSI Status 0x%x\n", - cmd, cmd->err_info->ScsiStatus); - } - break; - case CMD_DATA_UNDERRUN: + switch (cmd->err_info->CommandStatus) { + case CMD_TARGET_STATUS: + rq->errors = evaluate_target_status(cmd); + break; + case CMD_DATA_UNDERRUN: + if (blk_fs_request(cmd->rq)) { printk(KERN_WARNING "cciss: cmd %p has" " completed with data underrun " "reported\n", cmd); - break; - case CMD_DATA_OVERRUN: + cmd->rq->data_len = cmd->err_info->ResidualCnt; + } + break; + case CMD_DATA_OVERRUN: + if (blk_fs_request(cmd->rq)) printk(KERN_WARNING "cciss: cmd %p has" " completed with data overrun " "reported\n", cmd); - break; - case CMD_INVALID: - printk(KERN_WARNING "cciss: cmd %p is " - "reported invalid\n", cmd); - status = 0; - break; - case CMD_PROTOCOL_ERR: - printk(KERN_WARNING "cciss: cmd %p has " - "protocol error \n", cmd); - status = 0; - break; - case CMD_HARDWARE_ERR: - printk(KERN_WARNING "cciss: cmd %p had " - " hardware error\n", cmd); - status = 0; - break; - case CMD_CONNECTION_LOST: - printk(KERN_WARNING "cciss: cmd %p had " - "connection lost\n", cmd); - status = 0; - break; - case CMD_ABORTED: - printk(KERN_WARNING "cciss: cmd %p was " - "aborted\n", cmd); - status = 0; - break; - case CMD_ABORT_FAILED: - printk(KERN_WARNING "cciss: cmd %p reports " - "abort failed\n", cmd); - status = 0; - break; - case CMD_UNSOLICITED_ABORT: - printk(KERN_WARNING "cciss%d: unsolicited " - "abort %p\n", h->ctlr, cmd); - if (cmd->retry_count < MAX_CMD_RETRIES) { - retry_cmd = 1; - printk(KERN_WARNING - "cciss%d: retrying %p\n", h->ctlr, cmd); - cmd->retry_count++; - } else - printk(KERN_WARNING - "cciss%d: %p retried too " - "many times\n", h->ctlr, cmd); - status = 0; - break; - case CMD_TIMEOUT: - printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); - status = 0; - break; - default: - printk(KERN_WARNING "cciss: cmd %p returned " - "unknown status %x\n", cmd, - cmd->err_info->CommandStatus); - status = 0; - } + break; + case CMD_INVALID: + printk(KERN_WARNING "cciss: cmd %p is " + "reported invalid\n", cmd); + rq->errors = 1; + break; + case CMD_PROTOCOL_ERR: + printk(KERN_WARNING "cciss: cmd %p has " + "protocol error \n", cmd); + rq->errors = 1; + break; + case CMD_HARDWARE_ERR: + printk(KERN_WARNING "cciss: cmd %p had " + " hardware error\n", cmd); + rq->errors = 1; + break; + case CMD_CONNECTION_LOST: + printk(KERN_WARNING "cciss: cmd %p had " + "connection lost\n", cmd); + rq->errors = 1; + break; + case CMD_ABORTED: + printk(KERN_WARNING "cciss: cmd %p was " + "aborted\n", cmd); + rq->errors = 1; + break; + case CMD_ABORT_FAILED: + printk(KERN_WARNING "cciss: cmd %p reports " + "abort failed\n", cmd); + rq->errors = 1; + break; + case CMD_UNSOLICITED_ABORT: + printk(KERN_WARNING "cciss%d: unsolicited " + "abort %p\n", h->ctlr, cmd); + if (cmd->retry_count < MAX_CMD_RETRIES) { + retry_cmd = 1; + printk(KERN_WARNING + "cciss%d: retrying %p\n", h->ctlr, cmd); + cmd->retry_count++; + } else + printk(KERN_WARNING + "cciss%d: %p retried too " + "many times\n", h->ctlr, cmd); + rq->errors = 1; + break; + case CMD_TIMEOUT: + printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); + rq->errors = 1; + break; + default: + printk(KERN_WARNING "cciss: cmd %p returned " + "unknown status %x\n", cmd, + cmd->err_info->CommandStatus); + rq->errors = 1; } + +after_error_processing: + /* We need to return this command */ if (retry_cmd) { resend_cciss_cmd(h, cmd); return; } - + cmd->rq->data_len = 0; cmd->rq->completion_data = cmd; - cmd->rq->errors = status; blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE); blk_complete_request(cmd->rq); } @@ -2539,32 +2595,40 @@ static void do_cciss_request(request_queue_t *q) #endif /* CCISS_DEBUG */ c->Header.SGList = c->Header.SGTotal = seg; - if(h->cciss_read == CCISS_READ_10) { - c->Request.CDB[1] = 0; - c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB - c->Request.CDB[3] = (start_blk >> 16) & 0xff; - c->Request.CDB[4] = (start_blk >> 8) & 0xff; - c->Request.CDB[5] = start_blk & 0xff; - c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB - c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff; - c->Request.CDB[8] = creq->nr_sectors & 0xff; - c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; + if (likely(blk_fs_request(creq))) { + if(h->cciss_read == CCISS_READ_10) { + c->Request.CDB[1] = 0; + c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB + c->Request.CDB[3] = (start_blk >> 16) & 0xff; + c->Request.CDB[4] = (start_blk >> 8) & 0xff; + c->Request.CDB[5] = start_blk & 0xff; + c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB + c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff; + c->Request.CDB[8] = creq->nr_sectors & 0xff; + c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; + } else { + c->Request.CDBLen = 16; + c->Request.CDB[1]= 0; + c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB + c->Request.CDB[3]= (start_blk >> 48) & 0xff; + c->Request.CDB[4]= (start_blk >> 40) & 0xff; + c->Request.CDB[5]= (start_blk >> 32) & 0xff; + c->Request.CDB[6]= (start_blk >> 24) & 0xff; + c->Request.CDB[7]= (start_blk >> 16) & 0xff; + c->Request.CDB[8]= (start_blk >> 8) & 0xff; + c->Request.CDB[9]= start_blk & 0xff; + c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff; + c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff; + c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff; + c->Request.CDB[13]= creq->nr_sectors & 0xff; + c->Request.CDB[14] = c->Request.CDB[15] = 0; + } + } else if (blk_pc_request(creq)) { + c->Request.CDBLen = creq->cmd_len; + memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB); } else { - c->Request.CDBLen = 16; - c->Request.CDB[1]= 0; - c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB - c->Request.CDB[3]= (start_blk >> 48) & 0xff; - c->Request.CDB[4]= (start_blk >> 40) & 0xff; - c->Request.CDB[5]= (start_blk >> 32) & 0xff; - c->Request.CDB[6]= (start_blk >> 24) & 0xff; - c->Request.CDB[7]= (start_blk >> 16) & 0xff; - c->Request.CDB[8]= (start_blk >> 8) & 0xff; - c->Request.CDB[9]= start_blk & 0xff; - c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff; - c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff; - c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff; - c->Request.CDB[13]= creq->nr_sectors & 0xff; - c->Request.CDB[14] = c->Request.CDB[15] = 0; + printk(KERN_WARNING "cciss%d: bad request type %d\n", h->ctlr, creq->cmd_type); + BUG(); } spin_lock_irq(q->queue_lock); diff --git a/trunk/drivers/block/cciss_scsi.c b/trunk/drivers/block/cciss_scsi.c index bb15051ffbe0..90961a8ea895 100644 --- a/trunk/drivers/block/cciss_scsi.c +++ b/trunk/drivers/block/cciss_scsi.c @@ -35,7 +35,6 @@ #include -#include #include #include #include diff --git a/trunk/drivers/block/floppy.c b/trunk/drivers/block/floppy.c index 5231ed7e723f..3587cb434371 100644 --- a/trunk/drivers/block/floppy.c +++ b/trunk/drivers/block/floppy.c @@ -4334,7 +4334,10 @@ static int __init floppy_init(void) if (err) goto out_flush_work; - device_create_file(&floppy_device[drive].dev,&dev_attr_cmos); + err = device_create_file(&floppy_device[drive].dev,&dev_attr_cmos); + if (err) + goto out_unreg_platform_dev; + /* to be cleaned up... */ disks[drive]->private_data = (void *)(long)drive; disks[drive]->queue = floppy_queue; @@ -4345,6 +4348,8 @@ static int __init floppy_init(void) return 0; +out_unreg_platform_dev: + platform_device_unregister(&floppy_device[drive]); out_flush_work: flush_scheduled_work(); if (usage_count) diff --git a/trunk/drivers/block/loop.c b/trunk/drivers/block/loop.c index 6b5b64207407..af6d7274a7cc 100644 --- a/trunk/drivers/block/loop.c +++ b/trunk/drivers/block/loop.c @@ -77,9 +77,8 @@ #include -static int max_loop = 8; -static struct loop_device *loop_dev; -static struct gendisk **disks; +static LIST_HEAD(loop_devices); +static DEFINE_MUTEX(loop_devices_mutex); /* * Transfer functions @@ -183,7 +182,7 @@ figure_loop_size(struct loop_device *lo) if (unlikely((loff_t)x != size)) return -EFBIG; - set_capacity(disks[lo->lo_number], x); + set_capacity(lo->lo_disk, x); return 0; } @@ -812,7 +811,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, lo->lo_queue->queuedata = lo; lo->lo_queue->unplug_fn = loop_unplug; - set_capacity(disks[lo->lo_number], size); + set_capacity(lo->lo_disk, size); bd_set_size(bdev, size << 9); set_blocksize(bdev, lo_blocksize); @@ -832,8 +831,8 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, lo->lo_device = NULL; lo->lo_backing_file = NULL; lo->lo_flags = 0; - set_capacity(disks[lo->lo_number], 0); - invalidate_bdev(bdev, 0); + set_capacity(lo->lo_disk, 0); + invalidate_bdev(bdev); bd_set_size(bdev, 0); mapping_set_gfp_mask(mapping, lo->old_gfp_mask); lo->lo_state = Lo_unbound; @@ -917,8 +916,8 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); memset(lo->lo_file_name, 0, LO_NAME_SIZE); - invalidate_bdev(bdev, 0); - set_capacity(disks[lo->lo_number], 0); + invalidate_bdev(bdev); + set_capacity(lo->lo_disk, 0); bd_set_size(bdev, 0); mapping_set_gfp_mask(filp->f_mapping, gfp); lo->lo_state = Lo_unbound; @@ -1322,6 +1321,18 @@ static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a } #endif +static struct loop_device *loop_find_dev(int number) +{ + struct loop_device *lo; + + list_for_each_entry(lo, &loop_devices, lo_list) { + if (lo->lo_number == number) + return lo; + } + return NULL; +} + +static struct loop_device *loop_init_one(int i); static int lo_open(struct inode *inode, struct file *file) { struct loop_device *lo = inode->i_bdev->bd_disk->private_data; @@ -1330,6 +1341,11 @@ static int lo_open(struct inode *inode, struct file *file) lo->lo_refcnt++; mutex_unlock(&lo->lo_ctl_mutex); + mutex_lock(&loop_devices_mutex); + if (!loop_find_dev(lo->lo_number + 1)) + loop_init_one(lo->lo_number + 1); + mutex_unlock(&loop_devices_mutex); + return 0; } @@ -1357,8 +1373,9 @@ static struct block_device_operations lo_fops = { /* * And now the modules code and kernel interface. */ +static int max_loop; module_param(max_loop, int, 0); -MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-256)"); +MODULE_PARM_DESC(max_loop, "obsolete, loop device is created on-demand"); MODULE_LICENSE("GPL"); MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR); @@ -1383,7 +1400,7 @@ int loop_unregister_transfer(int number) xfer_funcs[n] = NULL; - for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) { + list_for_each_entry(lo, &loop_devices, lo_list) { mutex_lock(&lo->lo_ctl_mutex); if (lo->lo_encryption == xfer) @@ -1398,91 +1415,110 @@ int loop_unregister_transfer(int number) EXPORT_SYMBOL(loop_register_transfer); EXPORT_SYMBOL(loop_unregister_transfer); -static int __init loop_init(void) +static struct loop_device *loop_init_one(int i) +{ + struct loop_device *lo; + struct gendisk *disk; + + lo = kzalloc(sizeof(*lo), GFP_KERNEL); + if (!lo) + goto out; + + lo->lo_queue = blk_alloc_queue(GFP_KERNEL); + if (!lo->lo_queue) + goto out_free_dev; + + disk = lo->lo_disk = alloc_disk(1); + if (!disk) + goto out_free_queue; + + mutex_init(&lo->lo_ctl_mutex); + lo->lo_number = i; + lo->lo_thread = NULL; + init_waitqueue_head(&lo->lo_event); + spin_lock_init(&lo->lo_lock); + disk->major = LOOP_MAJOR; + disk->first_minor = i; + disk->fops = &lo_fops; + disk->private_data = lo; + disk->queue = lo->lo_queue; + sprintf(disk->disk_name, "loop%d", i); + add_disk(disk); + list_add_tail(&lo->lo_list, &loop_devices); + return lo; + +out_free_queue: + blk_cleanup_queue(lo->lo_queue); +out_free_dev: + kfree(lo); +out: + return ERR_PTR(-ENOMEM); +} + +static void loop_del_one(struct loop_device *lo) { - int i; + del_gendisk(lo->lo_disk); + blk_cleanup_queue(lo->lo_queue); + put_disk(lo->lo_disk); + list_del(&lo->lo_list); + kfree(lo); +} - if (max_loop < 1 || max_loop > 256) { - printk(KERN_WARNING "loop: invalid max_loop (must be between" - " 1 and 256), using default (8)\n"); - max_loop = 8; - } +static struct kobject *loop_probe(dev_t dev, int *part, void *data) +{ + unsigned int number = dev & MINORMASK; + struct loop_device *lo; + + mutex_lock(&loop_devices_mutex); + lo = loop_find_dev(number); + if (lo == NULL) + lo = loop_init_one(number); + mutex_unlock(&loop_devices_mutex); + + *part = 0; + if (IS_ERR(lo)) + return (void *)lo; + else + return &lo->lo_disk->kobj; +} + +static int __init loop_init(void) +{ + struct loop_device *lo; if (register_blkdev(LOOP_MAJOR, "loop")) return -EIO; + blk_register_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS, + THIS_MODULE, loop_probe, NULL, NULL); - loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL); - if (!loop_dev) - goto out_mem1; - memset(loop_dev, 0, max_loop * sizeof(struct loop_device)); + lo = loop_init_one(0); + if (IS_ERR(lo)) + goto out; - disks = kmalloc(max_loop * sizeof(struct gendisk *), GFP_KERNEL); - if (!disks) - goto out_mem2; + if (max_loop) { + printk(KERN_INFO "loop: the max_loop option is obsolete " + "and will be removed in March 2008\n"); - for (i = 0; i < max_loop; i++) { - disks[i] = alloc_disk(1); - if (!disks[i]) - goto out_mem3; } - - for (i = 0; i < max_loop; i++) { - struct loop_device *lo = &loop_dev[i]; - struct gendisk *disk = disks[i]; - - memset(lo, 0, sizeof(*lo)); - lo->lo_queue = blk_alloc_queue(GFP_KERNEL); - if (!lo->lo_queue) - goto out_mem4; - mutex_init(&lo->lo_ctl_mutex); - lo->lo_number = i; - lo->lo_thread = NULL; - init_waitqueue_head(&lo->lo_event); - spin_lock_init(&lo->lo_lock); - disk->major = LOOP_MAJOR; - disk->first_minor = i; - disk->fops = &lo_fops; - sprintf(disk->disk_name, "loop%d", i); - disk->private_data = lo; - disk->queue = lo->lo_queue; - } - - /* We cannot fail after we call this, so another loop!*/ - for (i = 0; i < max_loop; i++) - add_disk(disks[i]); - printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop); + printk(KERN_INFO "loop: module loaded\n"); return 0; -out_mem4: - while (i--) - blk_cleanup_queue(loop_dev[i].lo_queue); - i = max_loop; -out_mem3: - while (i--) - put_disk(disks[i]); - kfree(disks); -out_mem2: - kfree(loop_dev); -out_mem1: +out: unregister_blkdev(LOOP_MAJOR, "loop"); printk(KERN_ERR "loop: ran out of memory\n"); return -ENOMEM; } -static void loop_exit(void) +static void __exit loop_exit(void) { - int i; + struct loop_device *lo, *next; - for (i = 0; i < max_loop; i++) { - del_gendisk(disks[i]); - blk_cleanup_queue(loop_dev[i].lo_queue); - put_disk(disks[i]); - } + list_for_each_entry_safe(lo, next, &loop_devices, lo_list) + loop_del_one(lo); + + blk_unregister_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS); if (unregister_blkdev(LOOP_MAJOR, "loop")) printk(KERN_WARNING "loop: cannot unregister blkdev\n"); - - kfree(disks); - kfree(loop_dev); } module_init(loop_init); diff --git a/trunk/drivers/block/rd.c b/trunk/drivers/block/rd.c index 485aa87e9bcd..43d4ebcb3b44 100644 --- a/trunk/drivers/block/rd.c +++ b/trunk/drivers/block/rd.c @@ -403,7 +403,7 @@ static void __exit rd_cleanup(void) struct block_device *bdev = rd_bdev[i]; rd_bdev[i] = NULL; if (bdev) { - invalidate_bdev(bdev, 1); + invalidate_bdev(bdev); blkdev_put(bdev); } del_gendisk(rd_disks[i]); diff --git a/trunk/drivers/block/umem.c b/trunk/drivers/block/umem.c index 5872036e8ae6..6f5d6203d725 100644 --- a/trunk/drivers/block/umem.c +++ b/trunk/drivers/block/umem.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/bluetooth/hci_usb.c b/trunk/drivers/bluetooth/hci_usb.c index 406af579ac3a..b0238b46dded 100644 --- a/trunk/drivers/bluetooth/hci_usb.c +++ b/trunk/drivers/bluetooth/hci_usb.c @@ -114,10 +114,16 @@ static struct usb_device_id blacklist_ids[] = { { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 }, + /* Broadcom BCM2045 */ + { USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_WRONG_SCO_MTU }, + /* IBM/Lenovo ThinkPad with Broadcom chip */ { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_WRONG_SCO_MTU }, + /* Targus ACB10US */ + { USB_DEVICE(0x0a5c, 0x2100), .driver_info = HCI_RESET }, + /* ANYCOM Bluetooth USB-200 and USB-250 */ { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET }, diff --git a/trunk/drivers/cdrom/cdrom.c b/trunk/drivers/cdrom/cdrom.c index b36f44d4d1bf..3625a05bc3d3 100644 --- a/trunk/drivers/cdrom/cdrom.c +++ b/trunk/drivers/cdrom/cdrom.c @@ -2384,7 +2384,7 @@ static int cdrom_ioctl_reset(struct cdrom_device_info *cdi, return -EACCES; if (!CDROM_CAN(CDC_RESET)) return -ENOSYS; - invalidate_bdev(bdev, 0); + invalidate_bdev(bdev); return cdi->ops->reset(cdi); } diff --git a/trunk/drivers/char/Kconfig b/trunk/drivers/char/Kconfig index d0c978fbc204..1e32fb834eb8 100644 --- a/trunk/drivers/char/Kconfig +++ b/trunk/drivers/char/Kconfig @@ -127,7 +127,7 @@ config ROCKETPORT config CYCLADES tristate "Cyclades async mux support" - depends on SERIAL_NONSTANDARD + depends on SERIAL_NONSTANDARD && (PCI || ISA) ---help--- This driver supports Cyclades Z and Y multiserial boards. You would need something like this to connect more than two modems to @@ -905,8 +905,8 @@ config SONYPI To compile this driver as a module, choose M here: the module will be called sonypi. -config TANBAC_TB0219 - tristate "TANBAC TB0219 base board support" +config GPIO_TB0219 + tristate "TANBAC TB0219 GPIO support" depends on TANBAC_TB022X select GPIO_VR41XX @@ -1071,5 +1071,11 @@ config TELCLOCK /sys/devices/platform/telco_clock, with a number of files for controlling the behavior of this hardware. +config DEVPORT + bool + depends on !M68K + depends on ISA || PCI + default y + endmenu diff --git a/trunk/drivers/char/Makefile b/trunk/drivers/char/Makefile index ae8567cc529c..2f56ecc035aa 100644 --- a/trunk/drivers/char/Makefile +++ b/trunk/drivers/char/Makefile @@ -91,7 +91,7 @@ obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o -obj-$(CONFIG_TANBAC_TB0219) += tb0219.o +obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o obj-$(CONFIG_WATCHDOG) += watchdog/ diff --git a/trunk/drivers/char/agp/uninorth-agp.c b/trunk/drivers/char/agp/uninorth-agp.c index 91b062126a68..42c0a600b1ac 100644 --- a/trunk/drivers/char/agp/uninorth-agp.c +++ b/trunk/drivers/char/agp/uninorth-agp.c @@ -613,7 +613,7 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev, uninorth_node = of_find_node_by_name(NULL, "u3"); } if (uninorth_node) { - const int *revprop = get_property(uninorth_node, + const int *revprop = of_get_property(uninorth_node, "device-rev", NULL); if (revprop != NULL) uninorth_rev = *revprop & 0x3f; diff --git a/trunk/drivers/char/amiserial.c b/trunk/drivers/char/amiserial.c index 0e2b72f2b887..4eaceabd8cea 100644 --- a/trunk/drivers/char/amiserial.c +++ b/trunk/drivers/char/amiserial.c @@ -1574,7 +1574,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); #endif @@ -1700,7 +1700,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, #endif schedule(); } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); if (extra_count) state->count++; diff --git a/trunk/drivers/char/briq_panel.c b/trunk/drivers/char/briq_panel.c index c70d52ace8b2..ed53f541d9e8 100644 --- a/trunk/drivers/char/briq_panel.c +++ b/trunk/drivers/char/briq_panel.c @@ -206,7 +206,7 @@ static int __init briq_panel_init(void) const char *machine; int i; - machine = get_property(root, "model", NULL); + machine = of_get_property(root, "model", NULL); if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) { of_node_put(root); return -ENODEV; diff --git a/trunk/drivers/char/consolemap.c b/trunk/drivers/char/consolemap.c index b99b7561260d..fd40b959afdd 100644 --- a/trunk/drivers/char/consolemap.c +++ b/trunk/drivers/char/consolemap.c @@ -626,10 +626,10 @@ conv_uni_to_pc(struct vc_data *conp, long ucs) /* Only 16-bit codes supported at this time */ if (ucs > 0xffff) - ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */ - else if (ucs < 0x20 || ucs >= 0xfffe) + return -4; /* Not found */ + else if (ucs < 0x20) return -1; /* Not a printable character */ - else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f)) + else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f)) return -2; /* Zero-width space */ /* * UNI_DIRECT_BASE indicates the start of the region in the User Zone diff --git a/trunk/drivers/char/cs5535_gpio.c b/trunk/drivers/char/cs5535_gpio.c index c02d9e99e050..fe6d2407baed 100644 --- a/trunk/drivers/char/cs5535_gpio.c +++ b/trunk/drivers/char/cs5535_gpio.c @@ -44,6 +44,7 @@ static struct pci_device_id divil_pci[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, { } /* NULL entry */ }; +MODULE_DEVICE_TABLE(pci, divil_pci); static struct cdev cs5535_gpio_cdev; diff --git a/trunk/drivers/char/cyclades.c b/trunk/drivers/char/cyclades.c index 16dc5d1d3cb4..c72ee97d3892 100644 --- a/trunk/drivers/char/cyclades.c +++ b/trunk/drivers/char/cyclades.c @@ -10,15 +10,14 @@ * * Initially written by Randolph Bentson . * Modified and maintained by Marcio Saito . - * Currently maintained by Cyclades team . * - * For Technical support and installation problems, please send e-mail - * to support@cyclades.com. + * Copyright (C) 2007 Jiri Slaby * * Much of the design and some of the code came from serial.c * which was copyright (C) 1991, 1992 Linus Torvalds. It was * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92, * and then fixed as suggested by Michael K. Johnson 12/12/92. + * Converted to pci probing and cleaned up by Jiri Slaby. * * This version supports shared IRQ's (only for PCI boards). * @@ -591,7 +590,7 @@ * */ -#define CY_VERSION "2.4" +#define CY_VERSION "2.5" /* If you need to install more boards than NR_CARDS, change the constant in the definition below. No other change is necessary to support up to @@ -624,12 +623,6 @@ #undef CY_ENABLE_MONITORING #undef CY_PCI_DEBUG -#if 0 -#define PAUSE __asm__("nop") -#else -#define PAUSE do {} while (0) -#endif - /* * Include section */ @@ -659,17 +652,6 @@ #include #include -#define CY_LOCK(info,flags) \ - do { \ - spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \ - } while (0) - -#define CY_UNLOCK(info,flags) \ - do { \ - spin_unlock_irqrestore(&cy_card[info->card].card_lock, flags); \ - } while (0) - -#include #include #include @@ -682,13 +664,13 @@ static void cy_send_xchar(struct tty_struct *tty, char ch); #define IS_CYC_Z(card) ((card).num_chips == -1) #define Z_FPGA_CHECK(card) \ - ((cy_readl(&((struct RUNTIME_9060 __iomem *) \ + ((readl(&((struct RUNTIME_9060 __iomem *) \ ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0) -#define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 __iomem *) \ +#define ISZLOADED(card) (((ZO_V1==readl(&((struct RUNTIME_9060 __iomem *) \ ((card).ctl_addr))->mail_box_0)) || \ Z_FPGA_CHECK(card)) && \ - (ZFIRM_ID==cy_readl(&((struct FIRM_ID __iomem *) \ + (ZFIRM_ID==readl(&((struct FIRM_ID __iomem *) \ ((card).base_addr+ID_ADDRESS))->signature))) #ifndef SERIAL_XMIT_SIZE @@ -725,8 +707,8 @@ static unsigned int cy_isa_addresses[] = { #define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses) #ifdef MODULE -static long maddr[NR_CARDS] = { 0, }; -static int irq[NR_CARDS] = { 0, }; +static long maddr[NR_CARDS]; +static int irq[NR_CARDS]; module_param_array(maddr, long, NULL, 0); module_param_array(irq, int, NULL, 0); @@ -739,11 +721,6 @@ module_param_array(irq, int, NULL, 0); */ static struct cyclades_card cy_card[NR_CARDS]; -/* This is the per-channel data structure containing pointers, flags - and variables for the port. This driver supports a maximum of NR_PORTS. -*/ -static struct cyclades_port cy_port[NR_PORTS]; - static int cy_next_channel; /* next minor available */ /* @@ -825,9 +802,6 @@ static int cy_chip_offset[] = { 0x0000, /* PCI related definitions */ -static unsigned short cy_pci_nboard; -static unsigned short cy_isa_nboard; -static unsigned short cy_nboard; #ifdef CONFIG_PCI static struct pci_device_id cy_pci_dev_id[] __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, /* PCI < 1Mb */ @@ -845,7 +819,7 @@ MODULE_DEVICE_TABLE(pci, cy_pci_dev_id); static void cy_start(struct tty_struct *); static void set_line_char(struct cyclades_port *); -static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong); +static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32); #ifdef CONFIG_ISA static unsigned detect_isa_irq(void __iomem *); #endif /* CONFIG_ISA */ @@ -858,7 +832,6 @@ static void cyz_poll(unsigned long); /* The Cyclades-Z polling cycle is defined by this variable */ static long cyz_polling_cycle = CZ_DEF_POLL; -static int cyz_timeron = 0; static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0); #else /* CONFIG_CYZ_INTR */ @@ -871,21 +844,14 @@ static inline int serial_paranoia_check(struct cyclades_port *info, { #ifdef SERIAL_PARANOIA_CHECK if (!info) { - printk("cyc Warning: null cyclades_port for (%s) in %s\n", - name, routine); - return 1; - } - - if ((long)info < (long)(&cy_port[0]) || - (long)(&cy_port[NR_PORTS]) < (long)info) { - printk("cyc Warning: cyclades_port out of range for (%s) in " - "%s\n", name, routine); + printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) " + "in %s\n", name, routine); return 1; } if (info->magic != CYCLADES_MAGIC) { - printk("cyc Warning: bad magic number for serial struct (%s) " - "in %s\n", name, routine); + printk(KERN_WARNING "cyc Warning: bad magic number for serial " + "struct (%s) in %s\n", name, routine); return 1; } #endif @@ -943,22 +909,16 @@ do_softint(struct work_struct *work) if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) wake_up_interruptible(&info->open_wait); #ifdef CONFIG_CYZ_INTR - if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) { - if (cyz_rx_full_timer[info->line].function == NULL) { - cyz_rx_full_timer[info->line].expires = jiffies + 1; - cyz_rx_full_timer[info->line].function = cyz_rx_restart; - cyz_rx_full_timer[info->line].data = - (unsigned long)info; - add_timer(&cyz_rx_full_timer[info->line]); - } - } + if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event) && + !timer_pending(&cyz_rx_full_timer[info->line])) + mod_timer(&cyz_rx_full_timer[info->line], jiffies + 1); #endif if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event)) wake_up_interruptible(&info->delta_msr_wait); tty_wakeup(tty); #ifdef Z_WAKE if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) - wake_up_interruptible(&info->shutdown_wait); + complete(&info->shutdown_wait); #endif } /* do_softint */ @@ -975,11 +935,11 @@ do_softint(struct work_struct *work) */ static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index) { - volatile int i; + unsigned int i; /* Check to see that the previous command has completed */ for (i = 0; i < 100; i++) { - if (cy_readb(base_addr + (CyCCR << index)) == 0) { + if (readb(base_addr + (CyCCR << index)) == 0) { break; } udelay(10L); @@ -1022,7 +982,7 @@ static unsigned detect_isa_irq(void __iomem * address) cy_writeb(address + (CyCAR << index), 0); cy_writeb(address + (CySRER << index), - cy_readb(address + (CySRER << index)) | CyTxRdy); + readb(address + (CySRER << index)) | CyTxRdy); local_irq_restore(flags); /* Wait ... */ @@ -1032,11 +992,11 @@ static unsigned detect_isa_irq(void __iomem * address) irq = probe_irq_off(irqs); /* Clean up */ - save_xir = (u_char) cy_readb(address + (CyTIR << index)); - save_car = cy_readb(address + (CyCAR << index)); + save_xir = (u_char) readb(address + (CyTIR << index)); + save_car = readb(address + (CyCAR << index)); cy_writeb(address + (CyCAR << index), (save_xir & 0x3)); cy_writeb(address + (CySRER << index), - cy_readb(address + (CySRER << index)) & ~CyTxRdy); + readb(address + (CySRER << index)) & ~CyTxRdy); cy_writeb(address + (CyTIR << index), (save_xir & 0x3f)); cy_writeb(address + (CyCAR << index), (save_car)); cy_writeb(address + (Cy_ClrIntr << index), 0); @@ -1051,45 +1011,43 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, { struct cyclades_port *info; struct tty_struct *tty; - volatile int char_count; - int i, j, len, mdm_change, mdm_status, outch; + int char_count; + int j, len, mdm_change, mdm_status, outch; int save_xir, channel, save_car; char data; if (status & CySRReceive) { /* reception interrupt */ #ifdef CY_DEBUG_INTERRUPTS - printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip); + printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip); #endif /* determine the channel & change to that context */ spin_lock(&cinfo->card_lock); - save_xir = (u_char) cy_readb(base_addr + (CyRIR << index)); + save_xir = (u_char) readb(base_addr + (CyRIR << index)); channel = (u_short) (save_xir & CyIRChannel); - i = channel + chip * 4 + cinfo->first_line; - info = &cy_port[i]; - info->last_active = jiffies; - save_car = cy_readb(base_addr + (CyCAR << index)); + info = &cinfo->ports[channel + chip * 4]; + save_car = readb(base_addr + (CyCAR << index)); cy_writeb(base_addr + (CyCAR << index), save_xir); /* if there is nowhere to put the data, discard it */ - if (info->tty == 0) { - j = (cy_readb(base_addr + (CyRIVR << index)) & + if (info->tty == NULL) { + j = (readb(base_addr + (CyRIVR << index)) & CyIVRMask); if (j == CyIVRRxEx) { /* exception */ - data = cy_readb(base_addr + (CyRDSR << index)); + data = readb(base_addr + (CyRDSR << index)); } else { /* normal character reception */ - char_count = cy_readb(base_addr + + char_count = readb(base_addr + (CyRDCR << index)); while (char_count--) { - data = cy_readb(base_addr + + data = readb(base_addr + (CyRDSR << index)); } } } else { /* there is an open port for this data */ tty = info->tty; - j = (cy_readb(base_addr + (CyRIVR << index)) & + j = (readb(base_addr + (CyRIVR << index)) & CyIVRMask); if (j == CyIVRRxEx) { /* exception */ - data = cy_readb(base_addr + (CyRDSR << index)); + data = readb(base_addr + (CyRDSR << index)); /* For statistics only */ if (data & CyBREAK) @@ -1110,7 +1068,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, if (data & CyBREAK) { tty_insert_flip_char( tty, - cy_readb( + readb( base_addr + (CyRDSR << index)), @@ -1123,7 +1081,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, } else if (data & CyFRAME) { tty_insert_flip_char( tty, - cy_readb( + readb( base_addr + (CyRDSR << index)), @@ -1135,7 +1093,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, /* Pieces of seven... */ tty_insert_flip_char( tty, - cy_readb( + readb( base_addr + (CyRDSR << index)), @@ -1154,7 +1112,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, */ tty_insert_flip_char( tty, - cy_readb( + readb( base_addr + (CyRDSR << index)), @@ -1186,7 +1144,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, } } else { /* normal character reception */ /* load # chars available from the chip */ - char_count = cy_readb(base_addr + + char_count = readb(base_addr + (CyRDCR << index)); #ifdef CY_ENABLE_MONITORING @@ -1198,7 +1156,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, #endif len = tty_buffer_request_room(tty, char_count); while (len--) { - data = cy_readb(base_addr + + data = readb(base_addr + (CyRDSR << index)); tty_insert_flip_char(tty, data, TTY_NORMAL); @@ -1223,29 +1181,27 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, is empty, we know we can always stuff a dozen characters. */ #ifdef CY_DEBUG_INTERRUPTS - printk("cyy_interrupt: xmit intr, chip %d\n\r", chip); + printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip); #endif /* determine the channel & change to that context */ spin_lock(&cinfo->card_lock); - save_xir = (u_char) cy_readb(base_addr + (CyTIR << index)); + save_xir = (u_char) readb(base_addr + (CyTIR << index)); channel = (u_short) (save_xir & CyIRChannel); - i = channel + chip * 4 + cinfo->first_line; - save_car = cy_readb(base_addr + (CyCAR << index)); + save_car = readb(base_addr + (CyCAR << index)); cy_writeb(base_addr + (CyCAR << index), save_xir); /* validate the port# (as configured and open) */ - if ((i < 0) || (NR_PORTS <= i)) { + if (channel + chip * 4 >= cinfo->nports) { cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) & + readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto txend; } - info = &cy_port[i]; - info->last_active = jiffies; - if (info->tty == 0) { + info = &cinfo->ports[channel + chip * 4]; + if (info->tty == NULL) { cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) & + readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto txdone; } @@ -1278,29 +1234,29 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, while (char_count-- > 0) { if (!info->xmit_cnt) { - if (cy_readb(base_addr + (CySRER << index)) & + if (readb(base_addr + (CySRER << index)) & CyTxMpty) { cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + + readb(base_addr + (CySRER << index)) & ~CyTxMpty); } else { cy_writeb(base_addr + (CySRER << index), - (cy_readb(base_addr + + (readb(base_addr + (CySRER << index)) & ~CyTxRdy) | CyTxMpty); } goto txdone; } - if (info->xmit_buf == 0) { + if (info->xmit_buf == NULL) { cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index))& + readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto txdone; } if (info->tty->stopped || info->tty->hw_stopped) { cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index))& + readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto txdone; } @@ -1333,7 +1289,6 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, 0); info->icount.tx++; char_count--; - } else { } } } @@ -1353,19 +1308,16 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, /* determine the channel & change to that context */ spin_lock(&cinfo->card_lock); - save_xir = (u_char) cy_readb(base_addr + (CyMIR << index)); + save_xir = (u_char) readb(base_addr + (CyMIR << index)); channel = (u_short) (save_xir & CyIRChannel); - info = &cy_port[channel + chip * 4 + cinfo->first_line]; - info->last_active = jiffies; - save_car = cy_readb(base_addr + (CyCAR << index)); + info = &cinfo->ports[channel + chip * 4]; + save_car = readb(base_addr + (CyCAR << index)); cy_writeb(base_addr + (CyCAR << index), save_xir); - mdm_change = cy_readb(base_addr + (CyMISR << index)); - mdm_status = cy_readb(base_addr + (CyMSVR1 << index)); + mdm_change = readb(base_addr + (CyMISR << index)); + mdm_status = readb(base_addr + (CyMSVR1 << index)); - if (info->tty == 0) { /* no place for data, ignore it */ - ; - } else { + if (info->tty) { if (mdm_change & CyANY_DELTA) { /* For statistics only */ if (mdm_change & CyDCD) @@ -1398,7 +1350,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, info->tty->hw_stopped = 0; cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + + readb(base_addr + (CySRER << index))| CyTxRdy); @@ -1412,17 +1364,17 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, info->tty->hw_stopped = 1; cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + + readb(base_addr + (CySRER << index)) & ~CyTxRdy); } } } - if (mdm_change & CyDSR) { +/* if (mdm_change & CyDSR) { } if (mdm_change & CyRI) { - } + }*/ } /* end of service */ cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f)); @@ -1438,16 +1390,16 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, static irqreturn_t cyy_interrupt(int irq, void *dev_id) { int status; - struct cyclades_card *cinfo; + struct cyclades_card *cinfo = dev_id; void __iomem *base_addr, *card_base_addr; int chip; int index; int too_many; int had_work; - if ((cinfo = (struct cyclades_card *)dev_id) == 0) { + if (unlikely(cinfo == NULL)) { #ifdef CY_DEBUG_INTERRUPTS - printk("cyy_interrupt: spurious interrupt %d\n\r", irq); + printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",irq); #endif return IRQ_NONE; /* spurious interrupt */ } @@ -1455,6 +1407,10 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id) card_base_addr = cinfo->base_addr; index = cinfo->bus_index; + /* card was not initialized yet (e.g. DEBUG_SHIRQ) */ + if (unlikely(card_base_addr == NULL)) + return IRQ_HANDLED; + /* This loop checks all chips in the card. Make a note whenever _any_ chip had some work to do, as this is considered an indication that there will be more to do. Only when no chip @@ -1466,7 +1422,7 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id) base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); too_many = 0; - while ((status = cy_readb(base_addr + + while ((status = readb(base_addr + (CySVRR << index))) != 0x00) { had_work++; /* The purpose of the following test is to ensure that @@ -1498,7 +1454,7 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id) static int cyz_fetch_msg(struct cyclades_card *cinfo, - uclong * channel, ucchar * cmd, uclong * param) + __u32 * channel, __u8 * cmd, __u32 * param) { struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; @@ -1509,16 +1465,15 @@ cyz_fetch_msg(struct cyclades_card *cinfo, if (!ISZLOADED(*cinfo)) { return -1; } - zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & - 0xfffff); + zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; - loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *) + loc_doorbell = readl(&((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->loc_doorbell); if (loc_doorbell) { *cmd = (char)(0xff & loc_doorbell); - *channel = cy_readl(&board_ctrl->fwcmd_channel); - *param = (uclong) cy_readl(&board_ctrl->fwcmd_param); + *channel = readl(&board_ctrl->fwcmd_channel); + *param = (__u32) readl(&board_ctrl->fwcmd_param); cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))-> loc_doorbell, 0xffffffff); return 1; @@ -1528,28 +1483,27 @@ cyz_fetch_msg(struct cyclades_card *cinfo, static int cyz_issue_cmd(struct cyclades_card *cinfo, - uclong channel, ucchar cmd, uclong param) + __u32 channel, __u8 cmd, __u32 param) { struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; struct BOARD_CTRL __iomem *board_ctrl; - unsigned long __iomem *pci_doorbell; + __u32 __iomem *pci_doorbell; int index; firm_id = cinfo->base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)) { return -1; } - zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & - 0xfffff); + zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; index = 0; pci_doorbell = &((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell; - while ((cy_readl(pci_doorbell) & 0xff) != 0) { + while ((readl(pci_doorbell) & 0xff) != 0) { if (index++ == 1000) { - return (int)(cy_readl(pci_doorbell) & 0xff); + return (int)(readl(pci_doorbell) & 0xff); } udelay(50L); } @@ -1561,34 +1515,30 @@ cyz_issue_cmd(struct cyclades_card *cinfo, } /* cyz_issue_cmd */ static void -cyz_handle_rx(struct cyclades_port *info, - volatile struct CH_CTRL __iomem * ch_ctrl, - volatile struct BUF_CTRL __iomem * buf_ctrl) +cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl, + struct BUF_CTRL __iomem *buf_ctrl) { - struct cyclades_card *cinfo = &cy_card[info->card]; + struct cyclades_card *cinfo = info->card; struct tty_struct *tty = info->tty; - volatile int char_count; + int char_count; int len; #ifdef BLOCKMOVE - int small_count; + unsigned char *buf; #else char data; #endif - volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr; + __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr; - rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get); - rx_put = cy_readl(&buf_ctrl->rx_put); - rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize); - rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr); + rx_get = new_rx_get = readl(&buf_ctrl->rx_get); + rx_put = readl(&buf_ctrl->rx_put); + rx_bufsize = readl(&buf_ctrl->rx_bufsize); + rx_bufaddr = readl(&buf_ctrl->rx_bufaddr); if (rx_put >= rx_get) char_count = rx_put - rx_get; else char_count = rx_put - rx_get + rx_bufsize; if (char_count) { - info->last_active = jiffies; - info->jiffies[1] = jiffies; - #ifdef CY_ENABLE_MONITORING info->mon.int_count++; info->mon.char_count += char_count; @@ -1596,7 +1546,7 @@ cyz_handle_rx(struct cyclades_port *info, info->mon.char_max = char_count; info->mon.char_last = char_count; #endif - if (tty == 0) { + if (tty == NULL) { /* flush received characters */ new_rx_get = (new_rx_get + char_count) & (rx_bufsize - 1); @@ -1606,30 +1556,28 @@ cyz_handle_rx(struct cyclades_port *info, /* we'd like to use memcpy(t, f, n) and memset(s, c, count) for performance, but because of buffer boundaries, there may be several steps to the operation */ - while (0 < (small_count = min_t(unsigned int, - rx_bufsize - new_rx_get, - min_t(unsigned int, TTY_FLIPBUF_SIZE - - tty->flip.count, char_count)))){ - memcpy_fromio(tty->flip.char_buf_ptr, - (char *)(cinfo->base_addr + rx_bufaddr + - new_rx_get), - small_count); + while (1) { + len = tty_prepare_flip_string(tty, &buf, + char_count); + if (!len) + break; - tty->flip.char_buf_ptr += small_count; - memset(tty->flip.flag_buf_ptr, TTY_NORMAL, - small_count); - tty->flip.flag_buf_ptr += small_count; - new_rx_get = (new_rx_get + small_count) & + len = min_t(unsigned int, min(len, char_count), + rx_bufsize - new_rx_get); + + memcpy_fromio(buf, cinfo->base_addr + + rx_bufaddr + new_rx_get, len); + + new_rx_get = (new_rx_get + len) & (rx_bufsize - 1); - char_count -= small_count; - info->icount.rx += small_count; - info->idle_stats.recv_bytes += small_count; - tty->flip.count += small_count; + char_count -= len; + info->icount.rx += len; + info->idle_stats.recv_bytes += len; } #else len = tty_buffer_request_room(tty, char_count); while (len--) { - data = cy_readb(cinfo->base_addr + rx_bufaddr + + data = readb(cinfo->base_addr + rx_bufaddr + new_rx_get); new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1); tty_insert_flip_char(tty, data, TTY_NORMAL); @@ -1640,13 +1588,12 @@ cyz_handle_rx(struct cyclades_port *info, #ifdef CONFIG_CYZ_INTR /* Recalculate the number of chars in the RX buffer and issue a cmd in case it's higher than the RX high water mark */ - rx_put = cy_readl(&buf_ctrl->rx_put); + rx_put = readl(&buf_ctrl->rx_put); if (rx_put >= rx_get) char_count = rx_put - rx_get; else char_count = rx_put - rx_get + rx_bufsize; - if (char_count >= (int)cy_readl(&buf_ctrl-> - rx_threshold)) { + if (char_count >= (int)readl(&buf_ctrl->rx_threshold)) { cy_sched_event(info, Cy_EVENT_Z_RX_FULL); } #endif @@ -1659,26 +1606,25 @@ cyz_handle_rx(struct cyclades_port *info, } static void -cyz_handle_tx(struct cyclades_port *info, - volatile struct CH_CTRL __iomem * ch_ctrl, - volatile struct BUF_CTRL __iomem * buf_ctrl) +cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl, + struct BUF_CTRL __iomem *buf_ctrl) { - struct cyclades_card *cinfo = &cy_card[info->card]; + struct cyclades_card *cinfo = info->card; struct tty_struct *tty = info->tty; char data; - volatile int char_count; + int char_count; #ifdef BLOCKMOVE int small_count; #endif - volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr; + __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr; if (info->xmit_cnt <= 0) /* Nothing to transmit */ return; - tx_get = cy_readl(&buf_ctrl->tx_get); - tx_put = cy_readl(&buf_ctrl->tx_put); - tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize); - tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr); + tx_get = readl(&buf_ctrl->tx_get); + tx_put = readl(&buf_ctrl->tx_put); + tx_bufsize = readl(&buf_ctrl->tx_bufsize); + tx_bufaddr = readl(&buf_ctrl->tx_bufaddr); if (tx_put >= tx_get) char_count = tx_get - tx_put - 1 + tx_bufsize; else @@ -1686,9 +1632,8 @@ cyz_handle_tx(struct cyclades_port *info, if (char_count) { - if (tty == 0) { + if (tty == NULL) goto ztxdone; - } if (info->x_char) { /* send special char */ data = info->x_char; @@ -1698,8 +1643,6 @@ cyz_handle_tx(struct cyclades_port *info, info->x_char = 0; char_count--; info->icount.tx++; - info->last_active = jiffies; - info->jiffies[2] = jiffies; } #ifdef BLOCKMOVE while (0 < (small_count = min_t(unsigned int, @@ -1719,8 +1662,6 @@ cyz_handle_tx(struct cyclades_port *info, info->xmit_cnt -= small_count; info->xmit_tail = (info->xmit_tail + small_count) & (SERIAL_XMIT_SIZE - 1); - info->last_active = jiffies; - info->jiffies[2] = jiffies; } #else while (info->xmit_cnt && char_count) { @@ -1733,8 +1674,6 @@ cyz_handle_tx(struct cyclades_port *info, tx_put = (tx_put + 1) & (tx_bufsize - 1); char_count--; info->icount.tx++; - info->last_active = jiffies; - info->jiffies[2] = jiffies; } #endif ztxdone: @@ -1750,33 +1689,32 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) { struct tty_struct *tty; struct cyclades_port *info; - static volatile struct FIRM_ID __iomem *firm_id; - static volatile struct ZFW_CTRL __iomem *zfw_ctrl; - static volatile struct BOARD_CTRL __iomem *board_ctrl; - static volatile struct CH_CTRL __iomem *ch_ctrl; - static volatile struct BUF_CTRL __iomem *buf_ctrl; - uclong channel; - ucchar cmd; - uclong param; - uclong hw_ver, fw_ver; + static struct FIRM_ID __iomem *firm_id; + static struct ZFW_CTRL __iomem *zfw_ctrl; + static struct BOARD_CTRL __iomem *board_ctrl; + static struct CH_CTRL __iomem *ch_ctrl; + static struct BUF_CTRL __iomem *buf_ctrl; + __u32 channel; + __u8 cmd; + __u32 param; + __u32 hw_ver, fw_ver; int special_count; int delta_count; firm_id = cinfo->base_addr + ID_ADDRESS; - zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & - 0xfffff); + zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; - fw_ver = cy_readl(&board_ctrl->fw_version); - hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))-> + fw_ver = readl(&board_ctrl->fw_version); + hw_ver = readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))-> mail_box_0); while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { special_count = 0; delta_count = 0; - info = &cy_port[channel + cinfo->first_line]; - if ((tty = info->tty) == 0) { + info = &cinfo->ports[channel]; + if ((tty = info->tty) == NULL) continue; - } + ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); @@ -1801,7 +1739,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) delta_count++; if (info->flags & ASYNC_CHECK_CD) { if ((fw_ver > 241 ? ((u_long) param) : - cy_readl(&ch_ctrl->rs_status)) & + readl(&ch_ctrl->rs_status)) & C_RS_DCD) { cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); @@ -1833,8 +1771,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) case C_CM_INTBACK2: /* Reception Interrupt */ #ifdef CY_DEBUG_INTERRUPTS - printk("cyz_interrupt: rcvd intr, card %d, " - "port %ld\n\r", info->card, channel); + printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " + "port %ld\n", info->card, channel); #endif cyz_handle_rx(info, ch_ctrl, buf_ctrl); break; @@ -1843,8 +1781,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) case C_CM_INTBACK: /* Transmission Interrupt */ #ifdef CY_DEBUG_INTERRUPTS - printk("cyz_interrupt: xmit intr, card %d, " - "port %ld\n\r", info->card, channel); + printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " + "port %ld\n", info->card, channel); #endif cyz_handle_tx(info, ch_ctrl, buf_ctrl); break; @@ -1865,18 +1803,19 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) #ifdef CONFIG_CYZ_INTR static irqreturn_t cyz_interrupt(int irq, void *dev_id) { - struct cyclades_card *cinfo; + struct cyclades_card *cinfo = dev_id; - if ((cinfo = (struct cyclades_card *)dev_id) == 0) { + if (unlikely(cinfo == NULL)) { #ifdef CY_DEBUG_INTERRUPTS - printk("cyz_interrupt: spurious interrupt %d\n\r", irq); + printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq); #endif return IRQ_NONE; /* spurious interrupt */ } - if (!ISZLOADED(*cinfo)) { + if (unlikely(!ISZLOADED(*cinfo))) { #ifdef CY_DEBUG_INTERRUPTS - printk("cyz_interrupt: board not yet loaded (IRQ%d).\n\r", irq); + printk(KERN_DEBUG "cyz_interrupt: board not yet loaded " + "(IRQ%d).\n", irq); #endif return IRQ_NONE; } @@ -1890,19 +1829,18 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id) static void cyz_rx_restart(unsigned long arg) { struct cyclades_port *info = (struct cyclades_port *)arg; + struct cyclades_card *card = info->card; int retval; - int card = info->card; - uclong channel = (info->line) - (cy_card[card].first_line); + __u32 channel = info->line - card->first_line; unsigned long flags; - CY_LOCK(info, flags); - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L); + spin_lock_irqsave(&card->card_lock, flags); + retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L); if (retval != 0) { - printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n", + printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n", info->line, retval); } - cyz_rx_full_timer[info->line].function = NULL; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } #else /* CONFIG_CYZ_INTR */ @@ -1912,14 +1850,14 @@ static void cyz_poll(unsigned long arg) struct cyclades_card *cinfo; struct cyclades_port *info; struct tty_struct *tty; - static volatile struct FIRM_ID *firm_id; - static volatile struct ZFW_CTRL *zfw_ctrl; - static volatile struct BOARD_CTRL *board_ctrl; - static volatile struct CH_CTRL *ch_ctrl; - static volatile struct BUF_CTRL *buf_ctrl; + static struct FIRM_ID *firm_id; + static struct ZFW_CTRL *zfw_ctrl; + static struct BOARD_CTRL *board_ctrl; + static struct CH_CTRL *ch_ctrl; + static struct BUF_CTRL *buf_ctrl; + unsigned long expires = jiffies + HZ; int card, port; - cyz_timerlist.expires = jiffies + (HZ); for (card = 0; card < NR_CARDS; card++) { cinfo = &cy_card[card]; @@ -1930,12 +1868,12 @@ static void cyz_poll(unsigned long arg) firm_id = cinfo->base_addr + ID_ADDRESS; zfw_ctrl = cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &(zfw_ctrl->board_ctrl); /* Skip first polling cycle to avoid racing conditions with the FW */ if (!cinfo->intr_enabled) { - cinfo->nports = (int)cy_readl(&board_ctrl->n_channel); + cinfo->nports = (int)readl(&board_ctrl->n_channel); cinfo->intr_enabled = 1; continue; } @@ -1943,7 +1881,7 @@ static void cyz_poll(unsigned long arg) cyz_handle_cmd(cinfo); for (port = 0; port < cinfo->nports; port++) { - info = &cy_port[port + cinfo->first_line]; + info = &cinfo->ports[port]; tty = info->tty; ch_ctrl = &(zfw_ctrl->ch_ctrl[port]); buf_ctrl = &(zfw_ctrl->buf_ctrl[port]); @@ -1953,9 +1891,9 @@ static void cyz_poll(unsigned long arg) cyz_handle_tx(info, ch_ctrl, buf_ctrl); } /* poll every 'cyz_polling_cycle' period */ - cyz_timerlist.expires = jiffies + cyz_polling_cycle; + expires = jiffies + cyz_polling_cycle; } - add_timer(&cyz_timerlist); + mod_timer(&cyz_timerlist, expires); } /* cyz_poll */ #endif /* CONFIG_CYZ_INTR */ @@ -1968,20 +1906,21 @@ static void cyz_poll(unsigned long arg) */ static int startup(struct cyclades_port *info) { + struct cyclades_card *card; unsigned long flags; int retval = 0; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; unsigned long page; card = info->card; - channel = (info->line) - (cy_card[card].first_line); + channel = info->line - card->first_line; page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); if (info->flags & ASYNC_INITIALIZED) { free_page(page); @@ -2001,24 +1940,22 @@ static int startup(struct cyclades_port *info) else info->xmit_buf = (unsigned char *)page; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); set_line_char(info); - if (!IS_CYC_Z(cy_card[card])) { + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = cy_card[card].base_addr + - (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); #ifdef CY_DEBUG_OPEN - printk("cyc startup card %d, chip %d, channel %d, " - "base_addr %lx\n", - card, chip, channel, (long)base_addr); - /**/ + printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, " + "base_addr %p\n", + card, chip, channel, base_addr); #endif - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); @@ -2034,14 +1971,14 @@ static int startup(struct cyclades_port *info) cy_writeb(base_addr + (CyMSVR2 << index), CyDTR); #ifdef CY_DEBUG_DTR - printk("cyc:startup raising DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:startup raising DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) | CyRxData); + readb(base_addr + (CySRER << index)) | CyRxData); info->flags |= ASYNC_INITIALIZED; if (info->tty) { @@ -2054,7 +1991,7 @@ static int startup(struct cyclades_port *info) info->idle_stats.recv_idle = info->idle_stats.xmit_idle = jiffies; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } else { struct FIRM_ID __iomem *firm_id; @@ -2063,24 +2000,23 @@ static int startup(struct cyclades_port *info) struct CH_CTRL __iomem *ch_ctrl; int retval; - base_addr = cy_card[card].base_addr; + base_addr = card->base_addr; firm_id = base_addr + ID_ADDRESS; - if (!ISZLOADED(cy_card[card])) { + if (!ISZLOADED(*card)) { return -ENODEV; } - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; #ifdef CY_DEBUG_OPEN - printk("cyc startup Z card %d, channel %d, base_addr %lx\n", - card, channel, (long)base_addr); - /**/ + printk(KERN_DEBUG "cyc startup Z card %d, channel %d, " + "base_addr %p\n", card, channel, base_addr); #endif - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE); #ifdef Z_WAKE @@ -2102,33 +2038,31 @@ static int startup(struct cyclades_port *info) #endif /* CONFIG_CYZ_INTR */ #endif /* Z_WAKE */ - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L); if (retval != 0) { - printk("cyc:startup(1) retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was " + "%x\n", info->line, retval); } /* Flush RX buffers before raising DTR and RTS */ - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX, - 0L); + retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L); if (retval != 0) { - printk("cyc:startup(2) retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was " + "%x\n", info->line, retval); } /* set timeout !!! */ /* set RTS and DTR !!! */ cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | + readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | C_RS_DTR); - retval = cyz_issue_cmd(&cy_card[info->card], channel, - C_CM_IOCTLM, 0L); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); if (retval != 0) { - printk("cyc:startup(3) retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was " + "%x\n", info->line, retval); } #ifdef CY_DEBUG_DTR - printk("cyc:startup raising Z DTR\n"); + printk(KERN_DEBUG "cyc:startup raising Z DTR\n"); #endif /* enable send, recv, modem !!! */ @@ -2144,51 +2078,50 @@ static int startup(struct cyclades_port *info) info->idle_stats.recv_idle = info->idle_stats.xmit_idle = jiffies; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } #ifdef CY_DEBUG_OPEN - printk(" cyc startup done\n"); + printk(KERN_DEBUG "cyc startup done\n"); #endif return 0; errout: - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); return retval; } /* startup */ static void start_xmit(struct cyclades_port *info) { + struct cyclades_card *card; unsigned long flags; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; card = info->card; - channel = (info->line) - (cy_card[card].first_line); - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = cy_card[card].base_addr + - (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), channel); cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) | CyTxRdy); - CY_UNLOCK(info, flags); + readb(base_addr + (CySRER << index)) | CyTxRdy); + spin_unlock_irqrestore(&card->card_lock, flags); } else { #ifdef CONFIG_CYZ_INTR int retval; - CY_LOCK(info, flags); - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK, - 0L); + spin_lock_irqsave(&card->card_lock, flags); + retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L); if (retval != 0) { - printk("cyc:start_xmit retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was " + "%x\n", info->line, retval); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); #else /* CONFIG_CYZ_INTR */ /* Don't have to do anything at this time */ #endif /* CONFIG_CYZ_INTR */ @@ -2201,30 +2134,30 @@ static void start_xmit(struct cyclades_port *info) */ static void shutdown(struct cyclades_port *info) { + struct cyclades_card *card; unsigned long flags; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; if (!(info->flags & ASYNC_INITIALIZED)) { return; } card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = cy_card[card].base_addr + - (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); #ifdef CY_DEBUG_OPEN - printk("cyc shutdown Y card %d, chip %d, channel %d, " - "base_addr %lx\n", - card, chip, channel, (long)base_addr); + printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, " + "channel %d, base_addr %p\n", + card, chip, channel, base_addr); #endif - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); /* Clear delta_msr_wait queue to avoid mem leaks. */ wake_up_interruptible(&info->delta_msr_wait); @@ -2240,10 +2173,10 @@ static void shutdown(struct cyclades_port *info) cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS); cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR); #ifdef CY_DEBUG_DTR - printk("cyc shutdown dropping DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc shutdown dropping DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif } cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index); @@ -2254,7 +2187,7 @@ static void shutdown(struct cyclades_port *info) set_bit(TTY_IO_ERROR, &info->tty->flags); } info->flags &= ~ASYNC_INITIALIZED; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } else { struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; @@ -2262,23 +2195,23 @@ static void shutdown(struct cyclades_port *info) struct CH_CTRL __iomem *ch_ctrl; int retval; - base_addr = cy_card[card].base_addr; + base_addr = card->base_addr; #ifdef CY_DEBUG_OPEN - printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n", - card, channel, (long)base_addr); + printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, " + "base_addr %p\n", card, channel, base_addr); #endif firm_id = base_addr + ID_ADDRESS; - if (!ISZLOADED(cy_card[card])) { + if (!ISZLOADED(*card)) { return; } - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); if (info->xmit_buf) { unsigned char *temp; @@ -2289,16 +2222,16 @@ static void shutdown(struct cyclades_port *info) if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { cy_writel(&ch_ctrl[channel].rs_control, - (uclong)(cy_readl(&ch_ctrl[channel].rs_control)& + (__u32)(readl(&ch_ctrl[channel].rs_control) & ~(C_RS_RTS | C_RS_DTR))); - retval = cyz_issue_cmd(&cy_card[info->card], channel, + retval = cyz_issue_cmd(info->card, channel, C_CM_IOCTLM, 0L); if (retval != 0) { - printk("cyc:shutdown retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR"cyc:shutdown retval on ttyC%d " + "was %x\n", info->line, retval); } #ifdef CY_DEBUG_DTR - printk("cyc:shutdown dropping Z DTR\n"); + printk(KERN_DEBUG "cyc:shutdown dropping Z DTR\n"); #endif } @@ -2307,11 +2240,11 @@ static void shutdown(struct cyclades_port *info) } info->flags &= ~ASYNC_INITIALIZED; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } #ifdef CY_DEBUG_OPEN - printk(" cyc shutdown done\n"); + printk(KERN_DEBUG "cyc shutdown done\n"); #endif } /* shutdown */ @@ -2332,7 +2265,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, int retval; void __iomem *base_addr; - cinfo = &cy_card[info->card]; + cinfo = info->card; channel = info->line - cinfo->first_line; /* @@ -2340,9 +2273,8 @@ block_til_ready(struct tty_struct *tty, struct file *filp, * until it's done, and then try again. */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&info->close_wait); - } + wait_event_interruptible(info->close_wait, + !(info->flags & ASYNC_CLOSING)); return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } @@ -2365,17 +2297,16 @@ block_til_ready(struct tty_struct *tty, struct file *filp, retval = 0; add_wait_queue(&info->open_wait, &wait); #ifdef CY_DEBUG_OPEN - printk("cyc block_til_ready before block: ttyC%d, count = %d\n", - info->line, info->count); - /**/ + printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, " + "count = %d\n", info->line, info->count); #endif - CY_LOCK(info, flags); + spin_lock_irqsave(&cinfo->card_lock, flags); if (!tty_hung_up_p(filp)) info->count--; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&cinfo->card_lock, flags); #ifdef CY_DEBUG_COUNT - printk("cyc block_til_ready: (%d): decrementing count to %d\n", - current->pid, info->count); + printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to " + "%d\n", current->pid, info->count); #endif info->blocked_open++; @@ -2386,7 +2317,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); while (1) { - CY_LOCK(info, flags); + spin_lock_irqsave(&cinfo->card_lock, flags); if ((tty->termios->c_cflag & CBAUD)) { cy_writeb(base_addr + (CyCAR << index), (u_char) channel); @@ -2395,15 +2326,14 @@ block_til_ready(struct tty_struct *tty, struct file *filp, cy_writeb(base_addr + (CyMSVR2 << index), CyDTR); #ifdef CY_DEBUG_DTR - printk("cyc:block_til_ready raising DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + - (CyMSVR1 << index)), - cy_readb(base_addr + - (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:block_til_ready raising " + "DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&cinfo->card_lock, flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || @@ -2413,26 +2343,25 @@ block_til_ready(struct tty_struct *tty, struct file *filp, break; } - CY_LOCK(info, flags); + spin_lock_irqsave(&cinfo->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || - (cy_readb(base_addr + + (readb(base_addr + (CyMSVR1 << index)) & CyDCD))) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&cinfo->card_lock, flags); break; } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&cinfo->card_lock, flags); if (signal_pending(current)) { retval = -ERESTARTSYS; break; } #ifdef CY_DEBUG_OPEN - printk("cyc block_til_ready blocking: ttyC%d, " - "count = %d\n", - info->line, info->count); - /**/ + printk(KERN_DEBUG "cyc block_til_ready blocking: " + "ttyC%d, count = %d\n", + info->line, info->count); #endif schedule(); } @@ -2446,31 +2375,30 @@ block_til_ready(struct tty_struct *tty, struct file *filp, base_addr = cinfo->base_addr; firm_id = base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)) { - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); return -EINVAL; } - zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) & - 0xfffff); + zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)& 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; while (1) { if ((tty->termios->c_cflag & CBAUD)) { cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel]. - rs_control) | (C_RS_RTS | - C_RS_DTR)); - retval = cyz_issue_cmd(&cy_card[info->card], - channel, C_CM_IOCTLM, 0L); + readl(&ch_ctrl[channel].rs_control) | + C_RS_RTS | C_RS_DTR); + retval = cyz_issue_cmd(cinfo, + channel, C_CM_IOCTLM, 0L); if (retval != 0) { - printk("cyc:block_til_ready retval on " - "ttyC%d was %x\n", + printk(KERN_ERR "cyc:block_til_ready " + "retval on ttyC%d was %x\n", info->line, retval); } #ifdef CY_DEBUG_DTR - printk("cyc:block_til_ready raising Z DTR\n"); + printk(KERN_DEBUG "cyc:block_til_ready raising " + "Z DTR\n"); #endif } @@ -2482,7 +2410,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, break; } if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || - (cy_readl(&ch_ctrl[channel].rs_status) & + (readl(&ch_ctrl[channel].rs_status) & C_RS_DCD))) { break; } @@ -2491,28 +2419,26 @@ block_til_ready(struct tty_struct *tty, struct file *filp, break; } #ifdef CY_DEBUG_OPEN - printk("cyc block_til_ready blocking: ttyC%d, " - "count = %d\n", - info->line, info->count); - /**/ + printk(KERN_DEBUG "cyc block_til_ready blocking: " + "ttyC%d, count = %d\n", + info->line, info->count); #endif schedule(); } } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) { info->count++; #ifdef CY_DEBUG_COUNT - printk("cyc:block_til_ready (%d): incrementing count to %d\n", - current->pid, info->count); + printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing " + "count to %d\n", current->pid, info->count); #endif } info->blocked_open--; #ifdef CY_DEBUG_OPEN - printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n", - info->line, info->count); - /**/ + printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, " + "count = %d\n", info->line, info->count); #endif if (retval) return retval; @@ -2527,13 +2453,20 @@ block_til_ready(struct tty_struct *tty, struct file *filp, static int cy_open(struct tty_struct *tty, struct file *filp) { struct cyclades_port *info; + unsigned int i; int retval, line; line = tty->index; if ((line < 0) || (NR_PORTS <= line)) { return -ENODEV; } - info = &cy_port[line]; + for (i = 0; i < NR_CARDS; i++) + if (line < cy_card[i].first_line + cy_card[i].nports && + line >= cy_card[i].first_line) + break; + if (i >= NR_CARDS) + return -ENODEV; + info = &cy_card[i].ports[line - cy_card[i].first_line]; if (info->line < 0) { return -ENODEV; } @@ -2542,23 +2475,23 @@ static int cy_open(struct tty_struct *tty, struct file *filp) treat it as absent from the system. This will make the user pay attention. */ - if (IS_CYC_Z(cy_card[info->card])) { - struct cyclades_card *cinfo = &cy_card[info->card]; + if (IS_CYC_Z(*info->card)) { + struct cyclades_card *cinfo = info->card; struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)) { - if (((ZE_V1 == cy_readl( - &((struct RUNTIME_9060 __iomem *) + if (((ZE_V1 == readl(&((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->mail_box_0)) && Z_FPGA_CHECK(*cinfo)) && - (ZFIRM_HLT == cy_readl( + (ZFIRM_HLT == readl( &firm_id->signature))) { - printk("cyc:Cyclades-Z Error: you need an " - "external power supply for this number " - "of ports.\n\rFirmware halted.\r\n"); + printk(KERN_ERR "cyc:Cyclades-Z Error: you " + "need an external power supply for " + "this number of ports.\nFirmware " + "halted.\n"); } else { - printk("cyc:Cyclades-Z firmware not yet " - "loaded\n"); + printk(KERN_ERR "cyc:Cyclades-Z firmware not " + "yet loaded\n"); } return -ENODEV; } @@ -2572,24 +2505,23 @@ static int cy_open(struct tty_struct *tty, struct file *filp) struct BOARD_CTRL __iomem *board_ctrl; zfw_ctrl = cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & - 0xfffff); + (readl(&firm_id->zfwctrl_addr) & + 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; /* Enable interrupts on the PLX chip */ cy_writew(cinfo->ctl_addr + 0x68, - cy_readw(cinfo->ctl_addr + - 0x68) | 0x0900); + readw(cinfo->ctl_addr + 0x68) | 0x0900); /* Enable interrupts on the FW */ retval = cyz_issue_cmd(cinfo, 0, C_CM_IRQ_ENBL, 0L); if (retval != 0) { - printk("cyc:IRQ enable retval was %x\n", - retval); + printk(KERN_ERR "cyc:IRQ enable retval " + "was %x\n", retval); } cinfo->nports = - (int)cy_readl(&board_ctrl->n_channel); + (int)readl(&board_ctrl->n_channel); cinfo->intr_enabled = 1; } } @@ -2599,7 +2531,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) return -ENODEV; } #ifdef CY_DEBUG_OTHER - printk("cyc:cy_open ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line); #endif tty->driver_data = info; info->tty = tty; @@ -2607,12 +2539,12 @@ static int cy_open(struct tty_struct *tty, struct file *filp) return -ENODEV; } #ifdef CY_DEBUG_OPEN - printk("cyc:cy_open ttyC%d, count = %d\n", info->line, info->count); - /**/ + printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line, + info->count); #endif info->count++; #ifdef CY_DEBUG_COUNT - printk("cyc:cy_open (%d): incrementing count to %d\n", + printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n", current->pid, info->count); #endif @@ -2620,8 +2552,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp) * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); + wait_event_interruptible(info->close_wait, + !(info->flags & ASYNC_CLOSING)); return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } @@ -2636,8 +2568,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp) retval = block_til_ready(tty, filp, info); if (retval) { #ifdef CY_DEBUG_OPEN - printk("cyc:cy_open returning after block_til_ready with %d\n", - retval); + printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready " + "with %d\n", retval); #endif return retval; } @@ -2645,8 +2577,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) info->throttle = 0; #ifdef CY_DEBUG_OPEN - printk(" cyc:cy_open done\n"); - /**/ + printk(KERN_DEBUG "cyc:cy_open done\n"); #endif return 0; } /* cy_open */ @@ -2656,9 +2587,10 @@ static int cy_open(struct tty_struct *tty, struct file *filp) */ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_card *card; + struct cyclades_port *info = tty->driver_data; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; unsigned long orig_jiffies; int char_time; @@ -2697,20 +2629,19 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) if (!timeout || timeout > 2 * info->timeout) timeout = 2 * info->timeout; #ifdef CY_DEBUG_WAIT_UNTIL_SENT - printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time); - printk("jiff=%lu...", jiffies); + printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...", + timeout, char_time, jiffies); #endif card = info->card; - channel = (info->line) - (cy_card[card].first_line); - if (!IS_CYC_Z(cy_card[card])) { + channel = (info->line) - (card->first_line); + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); - while (cy_readb(base_addr + (CySRER << index)) & CyTxRdy) { + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); + while (readb(base_addr + (CySRER << index)) & CyTxRdy) { #ifdef CY_DEBUG_WAIT_UNTIL_SENT - printk("Not clean (jiff=%lu)...", jiffies); + printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies); #endif if (msleep_interruptible(jiffies_to_msecs(char_time))) break; @@ -2718,13 +2649,11 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) timeout)) break; } - } else { - /* Nothing to do! */ } /* Run one more char cycle */ msleep_interruptible(jiffies_to_msecs(char_time * 5)); #ifdef CY_DEBUG_WAIT_UNTIL_SENT - printk("Clean (jiff=%lu)...done\n", jiffies); + printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies); #endif } @@ -2733,25 +2662,29 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) */ static void cy_close(struct tty_struct *tty, struct file *filp) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; unsigned long flags; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_close ttyC%d\n", info->line); + printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line); #endif if (!info || serial_paranoia_check(info, tty->name, "cy_close")) { return; } - CY_LOCK(info, flags); + card = info->card; + + spin_lock_irqsave(&card->card_lock, flags); /* If the TTY is being hung up, nothing to do */ if (tty_hung_up_p(filp)) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); return; } #ifdef CY_DEBUG_OPEN - printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count); + printk(KERN_DEBUG "cyc:cy_close ttyC%d, count = %d\n", info->line, + info->count); #endif if ((tty->count == 1) && (info->count != 1)) { /* @@ -2761,22 +2694,22 @@ static void cy_close(struct tty_struct *tty, struct file *filp) * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk("cyc:cy_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); + printk(KERN_ERR "cyc:cy_close: bad serial port count; " + "tty->count is 1, info->count is %d\n", info->count); info->count = 1; } #ifdef CY_DEBUG_COUNT - printk("cyc:cy_close at (%d): decrementing count to %d\n", + printk(KERN_DEBUG "cyc:cy_close at (%d): decrementing count to %d\n", current->pid, info->count - 1); #endif if (--info->count < 0) { #ifdef CY_DEBUG_COUNT - printk("cyc:cyc_close setting count to 0\n"); + printk(KERN_DEBUG "cyc:cyc_close setting count to 0\n"); #endif info->count = 0; } if (info->count) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); return; } info->flags |= ASYNC_CLOSING; @@ -2786,81 +2719,80 @@ static void cy_close(struct tty_struct *tty, struct file *filp) * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); if (info->closing_wait != CY_CLOSING_WAIT_NONE) { tty_wait_until_sent(tty, info->closing_wait); } - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); - if (!IS_CYC_Z(cy_card[info->card])) { - int channel = info->line - cy_card[info->card].first_line; - int index = cy_card[info->card].bus_index; - void __iomem *base_addr = cy_card[info->card].base_addr + + if (!IS_CYC_Z(*card)) { + int channel = info->line - card->first_line; + int index = card->bus_index; + void __iomem *base_addr = card->base_addr + (cy_chip_offset[channel >> 2] << index); /* Stop accepting input */ channel &= 0x03; cy_writeb(base_addr + (CyCAR << index), (u_char) channel); cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) & ~CyRxData); + readb(base_addr + (CySRER << index)) & ~CyRxData); if (info->flags & ASYNC_INITIALIZED) { /* Waiting for on-board buffers to be empty before closing the port */ - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); cy_wait_until_sent(tty, info->timeout); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); } } else { #ifdef Z_WAKE /* Waiting for on-board buffers to be empty before closing the port */ - void __iomem *base_addr = cy_card[info->card].base_addr; + void __iomem *base_addr = card->base_addr; struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS; struct ZFW_CTRL __iomem *zfw_ctrl = - base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl; - int channel = info->line - cy_card[info->card].first_line; + int channel = info->line - card->first_line; int retval; - if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) { - retval = cyz_issue_cmd(&cy_card[info->card], channel, - C_CM_IOCTLW, 0L); + if (readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) { + retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L); if (retval != 0) { - printk("cyc:cy_close retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_DEBUG "cyc:cy_close retval on " + "ttyC%d was %x\n", info->line, retval); } - CY_UNLOCK(info, flags); - interruptible_sleep_on(&info->shutdown_wait); - CY_LOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); + wait_for_completion_interruptible(&info->shutdown_wait); + spin_lock_irqsave(&card->card_lock, flags); } #endif } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); tty->closing = 0; info->event = 0; info->tty = NULL; if (info->blocked_open) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); if (info->close_delay) { msleep_interruptible(jiffies_to_msecs (info->close_delay)); } wake_up_interruptible(&info->open_wait); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); } info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); #ifdef CY_DEBUG_OTHER - printk(" cyc:cy_close done\n"); + printk(KERN_DEBUG "cyc:cy_close done\n"); #endif - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } /* cy_close */ /* This routine gets called when tty_write has put something into @@ -2878,12 +2810,12 @@ static void cy_close(struct tty_struct *tty, struct file *filp) */ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; unsigned long flags; int c, ret = 0; #ifdef CY_DEBUG_IO - printk("cyc:cy_write ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_write")) { @@ -2893,7 +2825,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) if (!info->xmit_buf) return 0; - CY_LOCK(info, flags); + spin_lock_irqsave(&info->card->card_lock, flags); while (1) { c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1), (int)(SERIAL_XMIT_SIZE - info->xmit_head))); @@ -2909,7 +2841,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) count -= c; ret += c; } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&info->card->card_lock, flags); info->idle_stats.xmit_bytes += ret; info->idle_stats.xmit_idle = jiffies; @@ -2929,11 +2861,11 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) */ static void cy_put_char(struct tty_struct *tty, unsigned char ch) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; unsigned long flags; #ifdef CY_DEBUG_IO - printk("cyc:cy_put_char ttyC%d\n", info->line); + printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_put_char")) @@ -2942,9 +2874,9 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch) if (!info->xmit_buf) return; - CY_LOCK(info, flags); + spin_lock_irqsave(&info->card->card_lock, flags); if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&info->card->card_lock, flags); return; } @@ -2953,7 +2885,7 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch) info->xmit_cnt++; info->idle_stats.xmit_bytes++; info->idle_stats.xmit_idle = jiffies; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&info->card->card_lock, flags); } /* cy_put_char */ /* @@ -2962,10 +2894,10 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch) */ static void cy_flush_chars(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; #ifdef CY_DEBUG_IO - printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_flush_chars")) @@ -2986,11 +2918,11 @@ static void cy_flush_chars(struct tty_struct *tty) */ static int cy_write_room(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; int ret; #ifdef CY_DEBUG_IO - printk("cyc:cy_write_room ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_write_room")) @@ -3003,46 +2935,49 @@ static int cy_write_room(struct tty_struct *tty) static int cy_chars_in_buffer(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, channel; + struct cyclades_card *card; + struct cyclades_port *info = tty->driver_data; + int channel; if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer")) return 0; card = info->card; - channel = (info->line) - (cy_card[card].first_line); + channel = (info->line) - (card->first_line); #ifdef Z_EXT_CHARS_IN_BUFFER if (!IS_CYC_Z(cy_card[card])) { #endif /* Z_EXT_CHARS_IN_BUFFER */ #ifdef CY_DEBUG_IO - printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */ + printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", + info->line, info->xmit_cnt); #endif return info->xmit_cnt; #ifdef Z_EXT_CHARS_IN_BUFFER } else { - static volatile struct FIRM_ID *firm_id; - static volatile struct ZFW_CTRL *zfw_ctrl; - static volatile struct CH_CTRL *ch_ctrl; - static volatile struct BUF_CTRL *buf_ctrl; + static struct FIRM_ID *firm_id; + static struct ZFW_CTRL *zfw_ctrl; + static struct CH_CTRL *ch_ctrl; + static struct BUF_CTRL *buf_ctrl; int char_count; - volatile uclong tx_put, tx_get, tx_bufsize; + __u32 tx_put, tx_get, tx_bufsize; - firm_id = cy_card[card].base_addr + ID_ADDRESS; - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + firm_id = card->base_addr + ID_ADDRESS; + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); - tx_get = cy_readl(&buf_ctrl->tx_get); - tx_put = cy_readl(&buf_ctrl->tx_put); - tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize); + tx_get = readl(&buf_ctrl->tx_get); + tx_put = readl(&buf_ctrl->tx_put); + tx_bufsize = readl(&buf_ctrl->tx_bufsize); if (tx_put >= tx_get) char_count = tx_put - tx_get; else char_count = tx_put - tx_get + tx_bufsize; #ifdef CY_DEBUG_IO - printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt + char_count); /* */ + printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", + info->line, info->xmit_cnt + char_count); #endif return info->xmit_cnt + char_count; } @@ -3055,10 +2990,10 @@ static int cy_chars_in_buffer(struct tty_struct *tty) * ------------------------------------------------------------ */ -static void cyy_baud_calc(struct cyclades_port *info, uclong baud) +static void cyy_baud_calc(struct cyclades_port *info, __u32 baud) { int co, co_val, bpr; - uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 : + __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 : 25000000); if (baud == 0) { @@ -3086,9 +3021,10 @@ static void cyy_baud_calc(struct cyclades_port *info, uclong baud) */ static void set_line_char(struct cyclades_port *info) { + struct cyclades_card *card; unsigned long flags; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; unsigned cflag, iflag; unsigned short chip_number; int baud, baud_rate = 0; @@ -3118,12 +3054,12 @@ static void set_line_char(struct cyclades_port *info) } card = info->card; - channel = (info->line) - (cy_card[card].first_line); + channel = info->line - card->first_line; chip_number = channel / 4; - if (!IS_CYC_Z(cy_card[card])) { + if (!IS_CYC_Z(*card)) { - index = cy_card[card].bus_index; + index = card->bus_index; /* baud rate */ baud = tty_get_baud_rate(info->tty); @@ -3241,10 +3177,9 @@ static void set_line_char(struct cyclades_port *info) chip = channel >> 2; channel &= 0x03; - base_addr = cy_card[card].base_addr + - (cy_chip_offset[chip] << index); + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); /* tx and rx baud rate */ @@ -3276,8 +3211,7 @@ static void set_line_char(struct cyclades_port *info) if (C_CLOCAL(info->tty)) { /* without modem intr */ cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + - (CySRER << index)) | CyMdmCh); + readb(base_addr + (CySRER << index)) | CyMdmCh); /* act on 1->0 modem transitions */ if ((cflag & CRTSCTS) && info->rflow) { cy_writeb(base_addr + (CyMCOR1 << index), @@ -3291,7 +3225,7 @@ static void set_line_char(struct cyclades_port *info) } else { /* without modem intr */ cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + + readb(base_addr + (CySRER << index)) | CyMdmCh); /* act on 1->0 modem transitions */ if ((cflag & CRTSCTS) && info->rflow) { @@ -3316,10 +3250,10 @@ static void set_line_char(struct cyclades_port *info) ~CyDTR); } #ifdef CY_DEBUG_DTR - printk("cyc:set_line_char dropping DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:set_line_char dropping DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif } else { if (info->rtsdtr_inv) { @@ -3330,17 +3264,17 @@ static void set_line_char(struct cyclades_port *info) CyDTR); } #ifdef CY_DEBUG_DTR - printk("cyc:set_line_char raising DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:set_line_char raising DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif } if (info->tty) { clear_bit(TTY_IO_ERROR, &info->tty->flags); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } else { struct FIRM_ID __iomem *firm_id; @@ -3348,16 +3282,16 @@ static void set_line_char(struct cyclades_port *info) struct BOARD_CTRL __iomem *board_ctrl; struct CH_CTRL __iomem *ch_ctrl; struct BUF_CTRL __iomem *buf_ctrl; - uclong sw_flow; + __u32 sw_flow; int retval; - firm_id = cy_card[card].base_addr + ID_ADDRESS; - if (!ISZLOADED(cy_card[card])) { + firm_id = card->base_addr + ID_ADDRESS; + if (!ISZLOADED(*card)) { return; } - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; @@ -3408,10 +3342,10 @@ static void set_line_char(struct cyclades_port *info) } if (cflag & CSTOPB) { cy_writel(&ch_ctrl->comm_data_l, - cy_readl(&ch_ctrl->comm_data_l) | C_DL_2STOP); + readl(&ch_ctrl->comm_data_l) | C_DL_2STOP); } else { cy_writel(&ch_ctrl->comm_data_l, - cy_readl(&ch_ctrl->comm_data_l) | C_DL_1STOP); + readl(&ch_ctrl->comm_data_l) | C_DL_1STOP); } if (cflag & PARENB) { if (cflag & PARODD) { @@ -3426,12 +3360,10 @@ static void set_line_char(struct cyclades_port *info) /* CTS flow control flag */ if (cflag & CRTSCTS) { cy_writel(&ch_ctrl->hw_flow, - cy_readl(&ch_ctrl-> - hw_flow) | C_RS_CTS | C_RS_RTS); + readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS); } else { - cy_writel(&ch_ctrl->hw_flow, - cy_readl(&ch_ctrl-> - hw_flow) & ~(C_RS_CTS | C_RS_RTS)); + cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) & + ~(C_RS_CTS | C_RS_RTS)); } /* As the HW flow control is done in firmware, the driver doesn't need to care about it */ @@ -3446,10 +3378,10 @@ static void set_line_char(struct cyclades_port *info) } cy_writel(&ch_ctrl->sw_flow, sw_flow); - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L); if (retval != 0) { - printk("cyc:set_line_char retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:set_line_char retval on ttyC%d " + "was %x\n", info->line, retval); } /* CD sensitivity */ @@ -3461,22 +3393,22 @@ static void set_line_char(struct cyclades_port *info) if (baud == 0) { /* baud rate is zero, turn off line */ cy_writel(&ch_ctrl->rs_control, - cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR); + readl(&ch_ctrl->rs_control) & ~C_RS_DTR); #ifdef CY_DEBUG_DTR - printk("cyc:set_line_char dropping Z DTR\n"); + printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n"); #endif } else { cy_writel(&ch_ctrl->rs_control, - cy_readl(&ch_ctrl->rs_control) | C_RS_DTR); + readl(&ch_ctrl->rs_control) | C_RS_DTR); #ifdef CY_DEBUG_DTR - printk("cyc:set_line_char raising Z DTR\n"); + printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n"); #endif } - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTLM,0L); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM,0L); if (retval != 0) { - printk("cyc:set_line_char(2) retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d " + "was %x\n", info->line, retval); } if (info->tty) { @@ -3490,14 +3422,15 @@ get_serial_info(struct cyclades_port *info, struct serial_struct __user * retinfo) { struct serial_struct tmp; - struct cyclades_card *cinfo = &cy_card[info->card]; + struct cyclades_card *cinfo = info->card; if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); tmp.type = info->type; tmp.line = info->line; - tmp.port = info->card * 0x100 + info->line - cinfo->first_line; + tmp.port = (info->card - cy_card) * 0x100 + info->line - + cinfo->first_line; tmp.irq = cinfo->irq; tmp.flags = info->flags; tmp.close_delay = info->close_delay; @@ -3566,25 +3499,25 @@ set_serial_info(struct cyclades_port *info, */ static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value) { - int card, chip, channel, index; + struct cyclades_card *card; + int chip, channel, index; unsigned char status; unsigned int result; unsigned long flags; void __iomem *base_addr; card = info->card; - channel = (info->line) - (cy_card[card].first_line); - if (!IS_CYC_Z(cy_card[card])) { + channel = (info->line) - (card->first_line); + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); - status = cy_readb(base_addr + (CySRER << index)) & + spin_lock_irqsave(&card->card_lock, flags); + status = readb(base_addr + (CySRER << index)) & (CyTxRdy | CyTxMpty); - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); result = (status ? 0 : TIOCSER_TEMT); } else { /* Not supported yet */ @@ -3595,8 +3528,9 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value) static int cy_tiocmget(struct tty_struct *tty, struct file *file) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, chip, channel, index; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; + int chip, channel, index; void __iomem *base_addr; unsigned long flags; unsigned char status; @@ -3611,19 +3545,18 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) return -ENODEV; card = info->card; - channel = (info->line) - (cy_card[card].first_line); - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); - status = cy_readb(base_addr + (CyMSVR1 << index)); - status |= cy_readb(base_addr + (CyMSVR2 << index)); - CY_UNLOCK(info, flags); + status = readb(base_addr + (CyMSVR1 << index)); + status |= readb(base_addr + (CyMSVR2 << index)); + spin_unlock_irqrestore(&card->card_lock, flags); if (info->rtsdtr_inv) { result = ((status & CyRTS) ? TIOCM_DTR : 0) | @@ -3637,19 +3570,14 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) ((status & CyDSR) ? TIOCM_DSR : 0) | ((status & CyCTS) ? TIOCM_CTS : 0); } else { - base_addr = cy_card[card].base_addr; - - if (cy_card[card].num_chips != -1) { - return -EINVAL; - } - - firm_id = cy_card[card].base_addr + ID_ADDRESS; - if (ISZLOADED(cy_card[card])) { - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + base_addr = card->base_addr; + firm_id = card->base_addr + ID_ADDRESS; + if (ISZLOADED(*card)) { + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; - lstatus = cy_readl(&ch_ctrl[channel].rs_status); + lstatus = readl(&ch_ctrl[channel].rs_status); result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) | ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) | ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) | @@ -3669,8 +3597,9 @@ static int cy_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, chip, channel, index; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; + int chip, channel, index; void __iomem *base_addr; unsigned long flags; struct FIRM_ID __iomem *firm_id; @@ -3683,16 +3612,15 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, return -ENODEV; card = info->card; - channel = (info->line) - (cy_card[card].first_line); - if (!IS_CYC_Z(cy_card[card])) { + channel = (info->line) - (card->first_line); + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); if (set & TIOCM_RTS) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -3702,10 +3630,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, cy_writeb(base_addr + (CyMSVR1 << index), CyRTS); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } if (clear & TIOCM_RTS) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -3715,10 +3643,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } if (set & TIOCM_DTR) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -3729,15 +3657,15 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, CyDTR); } #ifdef CY_DEBUG_DTR - printk("cyc:set_modem_info raising DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } if (clear & TIOCM_DTR) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -3749,68 +3677,69 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, } #ifdef CY_DEBUG_DTR - printk("cyc:set_modem_info dropping DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } } else { - base_addr = cy_card[card].base_addr; + base_addr = card->base_addr; - firm_id = cy_card[card].base_addr + ID_ADDRESS; - if (ISZLOADED(cy_card[card])) { - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + firm_id = card->base_addr + ID_ADDRESS; + if (ISZLOADED(*card)) { + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; if (set & TIOCM_RTS) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel]. - rs_control) | C_RS_RTS); - CY_UNLOCK(info, flags); + readl(&ch_ctrl[channel].rs_control) | + C_RS_RTS); + spin_unlock_irqrestore(&card->card_lock, flags); } if (clear & TIOCM_RTS) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel]. - rs_control) & ~C_RS_RTS); - CY_UNLOCK(info, flags); + readl(&ch_ctrl[channel].rs_control) & + ~C_RS_RTS); + spin_unlock_irqrestore(&card->card_lock, flags); } if (set & TIOCM_DTR) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel]. - rs_control) | C_RS_DTR); + readl(&ch_ctrl[channel].rs_control) | + C_RS_DTR); #ifdef CY_DEBUG_DTR - printk("cyc:set_modem_info raising Z DTR\n"); + printk(KERN_DEBUG "cyc:set_modem_info raising " + "Z DTR\n"); #endif - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } if (clear & TIOCM_DTR) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel]. - rs_control) & ~C_RS_DTR); + readl(&ch_ctrl[channel].rs_control) & + ~C_RS_DTR); #ifdef CY_DEBUG_DTR - printk("cyc:set_modem_info clearing Z DTR\n"); + printk(KERN_DEBUG "cyc:set_modem_info clearing " + "Z DTR\n"); #endif - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } } else { return -ENODEV; } - CY_LOCK(info, flags); - retval = cyz_issue_cmd(&cy_card[info->card], - channel, C_CM_IOCTLM, 0L); + spin_lock_irqsave(&card->card_lock, flags); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); if (retval != 0) { - printk("cyc:set_modem_info retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d " + "was %x\n", info->line, retval); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } return 0; } /* cy_tiocmset */ @@ -3820,14 +3749,17 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, */ static void cy_break(struct tty_struct *tty, int break_state) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; unsigned long flags; if (serial_paranoia_check(info, tty->name, "cy_break")) return; - CY_LOCK(info, flags); - if (!IS_CYC_Z(cy_card[info->card])) { + card = info->card; + + spin_lock_irqsave(&card->card_lock, flags); + if (!IS_CYC_Z(*card)) { /* Let the transmit ISR take care of this (since it requires stuffing characters into the output stream). */ @@ -3835,18 +3767,18 @@ static void cy_break(struct tty_struct *tty, int break_state) if (!info->breakon) { info->breakon = 1; if (!info->xmit_cnt) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); start_xmit(info); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); } } } else { if (!info->breakoff) { info->breakoff = 1; if (!info->xmit_cnt) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); start_xmit(info); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); } } } @@ -3854,24 +3786,25 @@ static void cy_break(struct tty_struct *tty, int break_state) int retval; if (break_state == -1) { - retval = cyz_issue_cmd(&cy_card[info->card], - info->line - cy_card[info->card].first_line, + retval = cyz_issue_cmd(card, + info->line - card->first_line, C_CM_SET_BREAK, 0L); if (retval != 0) { - printk("cyc:cy_break (set) retval on ttyC%d " - "was %x\n", info->line, retval); + printk(KERN_ERR "cyc:cy_break (set) retval on " + "ttyC%d was %x\n", info->line, retval); } } else { - retval = cyz_issue_cmd(&cy_card[info->card], - info->line - cy_card[info->card].first_line, + retval = cyz_issue_cmd(card, + info->line - card->first_line, C_CM_CLR_BREAK, 0L); if (retval != 0) { - printk("cyc:cy_break (clr) retval on ttyC%d " - "was %x\n", info->line, retval); + printk(KERN_DEBUG "cyc:cy_break (clr) retval " + "on ttyC%d was %x\n", info->line, + retval); } } } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } /* cy_break */ static int @@ -3889,28 +3822,27 @@ get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon) static int set_threshold(struct cyclades_port *info, unsigned long value) { + struct cyclades_card *card; void __iomem *base_addr; - int card, channel, chip, index; + int channel, chip, index; unsigned long flags; card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; + index = card->bus_index; base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + card->base_addr + (cy_chip_offset[chip] << index); info->cor3 &= ~CyREC_FIFO; info->cor3 |= value & CyREC_FIFO; - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCOR3 << index), info->cor3); cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index); - CY_UNLOCK(info, flags); - } else { - /* Nothing to do! */ + spin_unlock_irqrestore(&card->card_lock, flags); } return 0; } /* set_threshold */ @@ -3918,25 +3850,23 @@ static int set_threshold(struct cyclades_port *info, unsigned long value) static int get_threshold(struct cyclades_port *info, unsigned long __user * value) { + struct cyclades_card *card; void __iomem *base_addr; - int card, channel, chip, index; + int channel, chip, index; unsigned long tmp; card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - tmp = cy_readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO; + tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO; return put_user(tmp, value); - } else { - /* Nothing to do! */ - return 0; } + return 0; } /* get_threshold */ static int @@ -3954,49 +3884,45 @@ get_default_threshold(struct cyclades_port *info, unsigned long __user * value) static int set_timeout(struct cyclades_port *info, unsigned long value) { + struct cyclades_card *card; void __iomem *base_addr; - int card, channel, chip, index; + int channel, chip, index; unsigned long flags; card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyRTPR << index), value & 0xff); - CY_UNLOCK(info, flags); - } else { - /* Nothing to do! */ + spin_unlock_irqrestore(&card->card_lock, flags); } return 0; } /* set_timeout */ static int get_timeout(struct cyclades_port *info, unsigned long __user * value) { + struct cyclades_card *card; void __iomem *base_addr; - int card, channel, chip, index; + int channel, chip, index; unsigned long tmp; card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - tmp = cy_readb(base_addr + (CyRTPR << index)); + tmp = readb(base_addr + (CyRTPR << index)); return put_user(tmp, value); - } else { - /* Nothing to do! */ - return 0; } + return 0; } /* get_timeout */ static int set_default_timeout(struct cyclades_port *info, unsigned long value) @@ -4020,7 +3946,7 @@ static int cy_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; struct cyclades_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct __user *p_cuser; /* user space */ int ret_val = 0; @@ -4031,7 +3957,8 @@ cy_ioctl(struct tty_struct *tty, struct file *file, return -ENODEV; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */ + printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", + info->line, cmd, arg); #endif switch (cmd) { @@ -4076,14 +4003,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file, case CYGETRTSDTR_INV: ret_val = info->rtsdtr_inv; break; - case CYGETCARDINFO: - if (copy_to_user(argp, &cy_card[info->card], - sizeof(struct cyclades_card))) { - ret_val = -EFAULT; - break; - } - ret_val = 0; - break; case CYGETCD1400VER: ret_val = info->chip_rev; break; @@ -4119,34 +4038,22 @@ cy_ioctl(struct tty_struct *tty, struct file *file, * Caller should use TIOCGICOUNT to see which one it was */ case TIOCMIWAIT: - CY_LOCK(info, flags); + spin_lock_irqsave(&info->card->card_lock, flags); /* note the counters on entry */ - cprev = info->icount; - CY_UNLOCK(info, flags); - while (1) { - interruptible_sleep_on(&info->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) { - return -ERESTARTSYS; - } - - CY_LOCK(info, flags); + cnow = info->icount; + spin_unlock_irqrestore(&info->card->card_lock, flags); + ret_val = wait_event_interruptible(info->delta_msr_wait, ({ + cprev = cnow; + spin_lock_irqsave(&info->card->card_lock, flags); cnow = info->icount; /* atomic copy */ - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&info->card->card_lock, flags); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { - return -EIO; /* no change => error */ - } - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ + ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)); + })); + break; /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) @@ -4155,9 +4062,9 @@ cy_ioctl(struct tty_struct *tty, struct file *file, * RI where only 0->1 is counted. */ case TIOCGICOUNT: - CY_LOCK(info, flags); + spin_lock_irqsave(&info->card->card_lock, flags); cnow = info->icount; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&info->card->card_lock, flags); p_cuser = argp; ret_val = put_user(cnow.cts, &p_cuser->cts); if (ret_val) @@ -4199,7 +4106,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, } #ifdef CY_DEBUG_OTHER - printk(" cyc:cy_ioctl done\n"); + printk(KERN_DEBUG "cyc:cy_ioctl done\n"); #endif return ret_val; @@ -4213,10 +4120,10 @@ cy_ioctl(struct tty_struct *tty, struct file *file, */ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_set_termios ttyC%d\n", info->line); + printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line); #endif if (tty->termios->c_cflag == old_termios->c_cflag && @@ -4248,8 +4155,9 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) */ static void cy_send_xchar(struct tty_struct *tty, char ch) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, channel; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; + int channel; if (serial_paranoia_check(info, tty->name, "cy_send_xchar")) return; @@ -4260,15 +4168,13 @@ static void cy_send_xchar(struct tty_struct *tty, char ch) cy_start(tty); card = info->card; - channel = info->line - cy_card[card].first_line; + channel = info->line - card->first_line; - if (IS_CYC_Z(cy_card[card])) { + if (IS_CYC_Z(*card)) { if (ch == STOP_CHAR(tty)) - cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXOFF, - 0L); + cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L); else if (ch == START_CHAR(tty)) - cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXON, - 0L); + cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L); } } @@ -4278,15 +4184,16 @@ static void cy_send_xchar(struct tty_struct *tty, char ch) */ static void cy_throttle(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; unsigned long flags; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; #ifdef CY_DEBUG_THROTTLE char buf[64]; - printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf), + printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty), info->line); #endif @@ -4297,22 +4204,22 @@ static void cy_throttle(struct tty_struct *tty) card = info->card; if (I_IXOFF(tty)) { - if (!IS_CYC_Z(cy_card[card])) + if (!IS_CYC_Z(*card)) cy_send_xchar(tty, STOP_CHAR(tty)); else info->throttle = 1; } if (tty->termios->c_cflag & CRTSCTS) { - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = cy_card[card].base_addr + + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -4322,7 +4229,7 @@ static void cy_throttle(struct tty_struct *tty) cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } else { info->throttle = 1; } @@ -4336,16 +4243,17 @@ static void cy_throttle(struct tty_struct *tty) */ static void cy_unthrottle(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; unsigned long flags; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; #ifdef CY_DEBUG_THROTTLE char buf[64]; - printk("cyc:unthrottle %s: %d....ttyC%d\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty), info->line); + printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n", + tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty),info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) { @@ -4361,15 +4269,15 @@ static void cy_unthrottle(struct tty_struct *tty) if (tty->termios->c_cflag & CRTSCTS) { card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = cy_card[card].base_addr + + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -4379,7 +4287,7 @@ static void cy_unthrottle(struct tty_struct *tty) cy_writeb(base_addr + (CyMSVR1 << index), CyRTS); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } else { info->throttle = 0; } @@ -4392,102 +4300,96 @@ static void cy_unthrottle(struct tty_struct *tty) static void cy_stop(struct tty_struct *tty) { struct cyclades_card *cinfo; - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; void __iomem *base_addr; int chip, channel, index; unsigned long flags; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_stop ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_stop")) return; - cinfo = &cy_card[info->card]; + cinfo = info->card; channel = info->line - cinfo->first_line; if (!IS_CYC_Z(*cinfo)) { index = cinfo->bus_index; chip = channel >> 2; channel &= 0x03; - base_addr = cy_card[info->card].base_addr + - (cy_chip_offset[chip] << index); + base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&cinfo->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char)(channel & 0x0003)); /* index channel */ cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) & ~CyTxRdy); - CY_UNLOCK(info, flags); - } else { - /* Nothing to do! */ + readb(base_addr + (CySRER << index)) & ~CyTxRdy); + spin_unlock_irqrestore(&cinfo->card_lock, flags); } } /* cy_stop */ static void cy_start(struct tty_struct *tty) { struct cyclades_card *cinfo; - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; void __iomem *base_addr; int chip, channel, index; unsigned long flags; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_start ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_start")) return; - cinfo = &cy_card[info->card]; + cinfo = info->card; channel = info->line - cinfo->first_line; index = cinfo->bus_index; if (!IS_CYC_Z(*cinfo)) { chip = channel >> 2; channel &= 0x03; - base_addr = cy_card[info->card].base_addr + - (cy_chip_offset[chip] << index); + base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&cinfo->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */ cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) | CyTxRdy); - CY_UNLOCK(info, flags); - } else { - /* Nothing to do! */ + readb(base_addr + (CySRER << index)) | CyTxRdy); + spin_unlock_irqrestore(&cinfo->card_lock, flags); } } /* cy_start */ static void cy_flush_buffer(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, channel, retval; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; + int channel, retval; unsigned long flags; #ifdef CY_DEBUG_IO - printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_flush_buffer")) return; card = info->card; - channel = (info->line) - (cy_card[card].first_line); + channel = info->line - card->first_line; - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); - if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board + if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board buffers as well */ - CY_LOCK(info, flags); - retval = - cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L); + spin_lock_irqsave(&card->card_lock, flags); + retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L); if (retval != 0) { - printk("cyc: flush_buffer retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d " + "was %x\n", info->line, retval); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } tty_wakeup(tty); } /* cy_flush_buffer */ @@ -4497,10 +4399,10 @@ static void cy_flush_buffer(struct tty_struct *tty) */ static void cy_hangup(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_hangup ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_hangup")) @@ -4511,7 +4413,8 @@ static void cy_hangup(struct tty_struct *tty) info->event = 0; info->count = 0; #ifdef CY_DEBUG_COUNT - printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid); + printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n", + current->pid); #endif info->tty = NULL; info->flags &= ~ASYNC_NORMAL_ACTIVE; @@ -4526,10 +4429,107 @@ static void cy_hangup(struct tty_struct *tty) * --------------------------------------------------------------------- */ +static int __devinit cy_init_card(struct cyclades_card *cinfo) +{ + struct cyclades_port *info; + u32 mailbox; + unsigned int nports; + unsigned short chip_number; + int index, port; + + spin_lock_init(&cinfo->card_lock); + + if (IS_CYC_Z(*cinfo)) { /* Cyclades-Z */ + mailbox = readl(&((struct RUNTIME_9060 __iomem *) + cinfo->ctl_addr)->mail_box_0); + nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8; + cinfo->intr_enabled = 0; + cinfo->nports = 0; /* Will be correctly set later, after + Z FW is loaded */ + } else { + index = cinfo->bus_index; + nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips; + } + + cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL); + if (cinfo->ports == NULL) { + printk(KERN_ERR "Cyclades: cannot allocate ports\n"); + cinfo->nports = 0; + return -ENOMEM; + } + + for (port = cinfo->first_line; port < cinfo->first_line + nports; + port++) { + info = &cinfo->ports[port - cinfo->first_line]; + info->magic = CYCLADES_MAGIC; + info->card = cinfo; + info->line = port; + info->flags = STD_COM_FLAGS; + info->closing_wait = CLOSING_WAIT_DELAY; + info->close_delay = 5 * HZ / 10; + + INIT_WORK(&info->tqueue, do_softint); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_completion(&info->shutdown_wait); + init_waitqueue_head(&info->delta_msr_wait); + + if (IS_CYC_Z(*cinfo)) { + info->type = PORT_STARTECH; + if (mailbox == ZO_V1) + info->xmit_fifo_size = CYZ_FIFO_SIZE; + else + info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE; +#ifdef CONFIG_CYZ_INTR + setup_timer(&cyz_rx_full_timer[port], + cyz_rx_restart, (unsigned long)info); +#endif + } else { + info->type = PORT_CIRRUS; + info->xmit_fifo_size = CyMAX_CHAR_FIFO; + info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS; + info->cor2 = CyETC; + info->cor3 = 0x08; /* _very_ small rcv threshold */ + + chip_number = (port - cinfo->first_line) / 4; + if ((info->chip_rev = readb(cinfo->base_addr + + (cy_chip_offset[chip_number] << + index) + (CyGFRCR << index))) >= + CD1400_REV_J) { + /* It is a CD1400 rev. J or later */ + info->tbpr = baud_bpr_60[13]; /* Tx BPR */ + info->tco = baud_co_60[13]; /* Tx CO */ + info->rbpr = baud_bpr_60[13]; /* Rx BPR */ + info->rco = baud_co_60[13]; /* Rx CO */ + info->rtsdtr_inv = 1; + } else { + info->tbpr = baud_bpr_25[13]; /* Tx BPR */ + info->tco = baud_co_25[13]; /* Tx CO */ + info->rbpr = baud_bpr_25[13]; /* Rx BPR */ + info->rco = baud_co_25[13]; /* Rx CO */ + info->rtsdtr_inv = 0; + } + info->read_status_mask = CyTIMEOUT | CySPECHAR | + CyBREAK | CyPARITY | CyFRAME | CyOVERRUN; + } + + } + +#ifndef CONFIG_CYZ_INTR + if (IS_CYC_Z(*cinfo) && !timer_pending(&cyz_timerlist)) { + mod_timer(&cyz_timerlist, jiffies + 1); +#ifdef CY_PCI_DEBUG + printk(KERN_DEBUG "Cyclades-Z polling initialized\n"); +#endif + } +#endif + return 0; +} + /* initialize chips on Cyclom-Y card -- return number of valid chips (which is number of ports/4) */ -static unsigned short __init -cyy_init_card(void __iomem * true_base_addr, int index) +static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr, + int index) { unsigned int chip_number; void __iomem *base_addr; @@ -4544,7 +4544,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) base_addr = true_base_addr + (cy_chip_offset[chip_number] << index); mdelay(1); - if (cy_readb(base_addr + (CyCCR << index)) != 0x00) { + if (readb(base_addr + (CyCCR << index)) != 0x00) { /************* printk(" chip #%d at %#6lx is never idle (CCR != 0)\n", chip_number, (unsigned long)base_addr); @@ -4561,7 +4561,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) chip 4 GFRCR register appears at chip 0, there is no chip 4 and this must be a Cyclom-16Y, not a Cyclom-32Ye. */ - if (chip_number == 4 && cy_readb(true_base_addr + + if (chip_number == 4 && readb(true_base_addr + (cy_chip_offset[0] << index) + (CyGFRCR << index)) == 0) { return chip_number; @@ -4570,7 +4570,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET); mdelay(1); - if (cy_readb(base_addr + (CyGFRCR << index)) == 0x00) { + if (readb(base_addr + (CyGFRCR << index)) == 0x00) { /* printk(" chip #%d at %#6lx is not responding ", chip_number, (unsigned long)base_addr); @@ -4578,7 +4578,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) */ return chip_number; } - if ((0xf0 & (cy_readb(base_addr + (CyGFRCR << index)))) != + if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) != 0x40) { /* printk(" chip #%d at %#6lx is not valid (GFRCR == " @@ -4589,7 +4589,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) return chip_number; } cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL); - if (cy_readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) { + if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) { /* It is a CD1400 rev. J or later */ /* Impossible to reach 5ms with this chip. Changed to 2ms instead (f = 500 Hz). */ @@ -4602,7 +4602,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) /* printk(" chip #%d at %#6lx is rev 0x%2x\n", chip_number, (unsigned long)base_addr, - cy_readb(base_addr+(CyGFRCR< NR_PORTS) { - printk("Cyclom-Y/ISA found at 0x%lx ", + printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no " + "more channels are available. Change NR_PORTS " + "in cyclades.c and recompile kernel.\n", (unsigned long)cy_isa_address); - printk("but no more channels are available.\n"); - printk("Change NR_PORTS in cyclades.c and recompile " - "kernel.\n"); + iounmap(cy_isa_address); return nboard; } /* fill the next cy_card structure available */ for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == 0) + if (cy_card[j].base_addr == NULL) break; } if (j == NR_CARDS) { /* no more cy_cards available */ - printk("Cyclom-Y/ISA found at 0x%lx ", + printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no " + "more cards can be used. Change NR_CARDS in " + "cyclades.c and recompile kernel.\n", (unsigned long)cy_isa_address); - printk("but no more cards can be used .\n"); - printk("Change NR_CARDS in cyclades.c and recompile " - "kernel.\n"); + iounmap(cy_isa_address); return nboard; } /* allocate IRQ */ if (request_irq(cy_isa_irq, cyy_interrupt, IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) { - printk("Cyclom-Y/ISA found at 0x%lx ", - (unsigned long)cy_isa_address); - printk("but could not allocate IRQ#%d.\n", cy_isa_irq); + printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but " + "could not allocate IRQ#%d.\n", + (unsigned long)cy_isa_address, cy_isa_irq); + iounmap(cy_isa_address); return nboard; } @@ -4704,15 +4712,23 @@ static int __init cy_detect_isa(void) cy_card[j].bus_index = 0; cy_card[j].first_line = cy_next_channel; cy_card[j].num_chips = cy_isa_nchan / 4; + if (cy_init_card(&cy_card[j])) { + cy_card[j].base_addr = NULL; + free_irq(cy_isa_irq, &cy_card[j]); + iounmap(cy_isa_address); + continue; + } nboard++; - /* print message */ - printk("Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d, ", + printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: " + "%d channels starting from port %d\n", j + 1, (unsigned long)cy_isa_address, (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)), - cy_isa_irq); - printk("%d channels starting from port %d.\n", - cy_isa_nchan, cy_next_channel); + cy_isa_irq, cy_isa_nchan, cy_next_channel); + + for (j = cy_next_channel; + j < cy_next_channel + cy_isa_nchan; j++) + tty_register_device(cy_serial_driver, j, NULL); cy_next_channel += cy_isa_nchan; } return nboard; @@ -4721,510 +4737,310 @@ static int __init cy_detect_isa(void) #endif /* CONFIG_ISA */ } /* cy_detect_isa */ -static void plx_init(void __iomem * addr, uclong initctl) +#ifdef CONFIG_PCI +static void __devinit plx_init(void __iomem * addr, __u32 initctl) { /* Reset PLX */ - cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000); + cy_writel(addr + initctl, readl(addr + initctl) | 0x40000000); udelay(100L); - cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000); + cy_writel(addr + initctl, readl(addr + initctl) & ~0x40000000); /* Reload Config. Registers from EEPROM */ - cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000); + cy_writel(addr + initctl, readl(addr + initctl) | 0x20000000); udelay(100L); - cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000); + cy_writel(addr + initctl, readl(addr + initctl) & ~0x20000000); } -/* - * --------------------------------------------------------------------- - * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI. - * sets global variables and return the number of PCI boards found. - * --------------------------------------------------------------------- - */ -static int __init cy_detect_pci(void) +static int __devinit cy_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { -#ifdef CONFIG_PCI - - struct pci_dev *pdev = NULL; - unsigned char cyy_rev_id; - unsigned char cy_pci_irq = 0; - uclong cy_pci_phys0, cy_pci_phys2; - void __iomem *cy_pci_addr0, *cy_pci_addr2; - unsigned short i, j, cy_pci_nchan, plx_ver; - unsigned short device_id, dev_index = 0; - uclong mailbox; - uclong ZeIndex = 0; - void __iomem *Ze_addr0[NR_CARDS], *Ze_addr2[NR_CARDS]; - uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS]; - unsigned char Ze_irq[NR_CARDS]; - struct pci_dev *Ze_pdev[NR_CARDS]; - - for (i = 0; i < NR_CARDS; i++) { - /* look for a Cyclades card by vendor and device id */ - while ((device_id = cy_pci_dev_id[dev_index].device) != 0) { - if ((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES, - device_id, pdev)) == NULL) { - dev_index++; /* try next device id */ - } else { - break; /* found a board */ - } - } - - if (device_id == 0) - break; - - if (pci_enable_device(pdev)) - continue; - - /* read PCI configuration area */ - cy_pci_irq = pdev->irq; - cy_pci_phys0 = pci_resource_start(pdev, 0); - cy_pci_phys2 = pci_resource_start(pdev, 2); - pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id); + void __iomem *addr0 = NULL, *addr2 = NULL; + char *card_name = NULL; + u32 mailbox; + unsigned int device_id, nchan = 0, card_no, i; + unsigned char plx_ver; + int retval, irq; + + retval = pci_enable_device(pdev); + if (retval) { + dev_err(&pdev->dev, "cannot enable device\n"); + goto err; + } - device_id &= ~PCI_DEVICE_ID_MASK; + /* read PCI configuration area */ + irq = pdev->irq; + device_id = pdev->device & ~PCI_DEVICE_ID_MASK; - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || - device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { -#ifdef CY_PCI_DEBUG - printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ", - pdev->bus->number, pdev->devfn); - printk("rev_id=%d) IRQ%d\n", - cyy_rev_id, (int)cy_pci_irq); - printk("Cyclom-Y/PCI:found winaddr=0x%lx " - "ctladdr=0x%lx\n", - (ulong)cy_pci_phys2, (ulong)cy_pci_phys0); +#if defined(__alpha__) + if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ + dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low " + "addresses on Alpha systems.\n"); + retval = -EIO; + goto err_dis; + } #endif + if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) { + dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low " + "addresses\n"); + retval = -EIO; + goto err_dis; + } - if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { - printk(" Warning: PCI I/O bit incorrectly " - "set. Ignoring it...\n"); - pdev->resource[2].flags &= ~IORESOURCE_IO; - } + if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { + dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring " + "it...\n"); + pdev->resource[2].flags &= ~IORESOURCE_IO; + } - /* Although we don't use this I/O region, we should - request it from the kernel anyway, to avoid problems - with other drivers accessing it. */ - if (pci_request_regions(pdev, "Cyclom-Y") != 0) { - printk(KERN_ERR "cyclades: failed to reserve " - "PCI resources\n"); - continue; - } -#if defined(__alpha__) - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ - printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ", - pdev->bus->number, pdev->devfn); - printk("rev_id=%d) IRQ%d\n", - cyy_rev_id, (int)cy_pci_irq); - printk("Cyclom-Y/PCI:found winaddr=0x%lx " - "ctladdr=0x%lx\n", - (ulong)cy_pci_phys2, - (ulong)cy_pci_phys0); - printk("Cyclom-Y/PCI not supported for low " - "addresses in Alpha systems.\n"); - i--; - continue; - } -#endif - cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Yctl); - cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ywin); + retval = pci_request_regions(pdev, "cyclades"); + if (retval) { + dev_err(&pdev->dev, "failed to reserve resources\n"); + goto err_dis; + } -#ifdef CY_PCI_DEBUG - printk("Cyclom-Y/PCI: relocate winaddr=0x%lx " - "ctladdr=0x%lx\n", - (u_long)cy_pci_addr2, (u_long)cy_pci_addr0); -#endif - cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP * - cyy_init_card(cy_pci_addr2, 1)); - if (cy_pci_nchan == 0) { - printk("Cyclom-Y PCI host card with "); - printk("no Serial-Modules at 0x%lx.\n", - (ulong) cy_pci_phys2); - i--; - continue; - } - if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) { - printk("Cyclom-Y/PCI found at 0x%lx ", - (ulong) cy_pci_phys2); - printk("but no channels are available.\n"); - printk("Change NR_PORTS in cyclades.c and " - "recompile kernel.\n"); - return i; - } - /* fill the next cy_card structure available */ - for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == 0) - break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - printk("Cyclom-Y/PCI found at 0x%lx ", - (ulong) cy_pci_phys2); - printk("but no more cards can be used.\n"); - printk("Change NR_CARDS in cyclades.c and " - "recompile kernel.\n"); - return i; - } + retval = -EIO; + if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || + device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { + card_name = "Cyclom-Y"; - /* allocate IRQ */ - if (request_irq(cy_pci_irq, cyy_interrupt, - IRQF_SHARED, "Cyclom-Y", &cy_card[j])) { - printk("Cyclom-Y/PCI found at 0x%lx ", - (ulong) cy_pci_phys2); - printk("but could not allocate IRQ%d.\n", - cy_pci_irq); - return i; - } + addr0 = pci_iomap(pdev, 0, CyPCI_Yctl); + if (addr0 == NULL) { + dev_err(&pdev->dev, "can't remap ctl region\n"); + goto err_reg; + } + addr2 = pci_iomap(pdev, 2, CyPCI_Ywin); + if (addr2 == NULL) { + dev_err(&pdev->dev, "can't remap base region\n"); + goto err_unmap; + } - /* set cy_card */ - cy_card[j].base_phys = (ulong) cy_pci_phys2; - cy_card[j].ctl_phys = (ulong) cy_pci_phys0; - cy_card[j].base_addr = cy_pci_addr2; - cy_card[j].ctl_addr = cy_pci_addr0; - cy_card[j].irq = (int)cy_pci_irq; - cy_card[j].bus_index = 1; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = cy_pci_nchan / 4; - cy_card[j].pdev = pdev; - - /* enable interrupts in the PCI interface */ - plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f; - switch (plx_ver) { - case PLX_9050: - - cy_writeb(cy_pci_addr0 + 0x4c, 0x43); - break; + nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1); + if (nchan == 0) { + dev_err(&pdev->dev, "Cyclom-Y PCI host card with no " + "Serial-Modules\n"); + return -EIO; + } + } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { + struct RUNTIME_9060 __iomem *ctl_addr; - case PLX_9060: - case PLX_9080: - default: /* Old boards, use PLX_9060 */ - - plx_init(cy_pci_addr0, 0x6c); - /* For some yet unknown reason, once the PLX9060 reloads - the EEPROM, the IRQ is lost and, thus, we have to - re-write it to the PCI config. registers. - This will remain here until we find a permanent - fix. */ - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, - cy_pci_irq); - - cy_writew(cy_pci_addr0 + 0x68, - cy_readw(cy_pci_addr0 + - 0x68) | 0x0900); - break; - } + ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl); + if (addr0 == NULL) { + dev_err(&pdev->dev, "can't remap ctl region\n"); + goto err_reg; + } - /* print message */ - printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ", - j + 1, (ulong)cy_pci_phys2, - (ulong) (cy_pci_phys2 + CyPCI_Ywin - 1), - (int)cy_pci_irq); - printk("%d channels starting from port %d.\n", - cy_pci_nchan, cy_next_channel); - - cy_next_channel += cy_pci_nchan; - } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) { - /* print message */ - printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ", - pdev->bus->number, pdev->devfn); - printk("rev_id=%d) IRQ%d\n", - cyy_rev_id, (int)cy_pci_irq); - printk("Cyclades-Z/PCI: found winaddr=0x%lx " - "ctladdr=0x%lx\n", - (ulong)cy_pci_phys2, (ulong)cy_pci_phys0); - printk("Cyclades-Z/PCI not supported for low " - "addresses\n"); - break; - } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { -#ifdef CY_PCI_DEBUG - printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ", - pdev->bus->number, pdev->devfn); - printk("rev_id=%d) IRQ%d\n", - cyy_rev_id, (int)cy_pci_irq); - printk("Cyclades-Z/PCI: found winaddr=0x%lx " - "ctladdr=0x%lx\n", - (ulong) cy_pci_phys2, (ulong) cy_pci_phys0); -#endif - cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Zctl); - - /* Disable interrupts on the PLX before resetting it */ - cy_writew(cy_pci_addr0 + 0x68, - cy_readw(cy_pci_addr0 + 0x68) & ~0x0900); - - plx_init(cy_pci_addr0, 0x6c); - /* For some yet unknown reason, once the PLX9060 reloads - the EEPROM, the IRQ is lost and, thus, we have to - re-write it to the PCI config. registers. - This will remain here until we find a permanent - fix. */ - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, - cy_pci_irq); - - mailbox = - (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *) - cy_pci_addr0)->mail_box_0); - - if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { - printk(" Warning: PCI I/O bit incorrectly " - "set. Ignoring it...\n"); - pdev->resource[2].flags &= ~IORESOURCE_IO; - } + /* Disable interrupts on the PLX before resetting it */ + cy_writew(addr0 + 0x68, + readw(addr0 + 0x68) & ~0x0900); + + plx_init(addr0, 0x6c); + /* For some yet unknown reason, once the PLX9060 reloads + the EEPROM, the IRQ is lost and, thus, we have to + re-write it to the PCI config. registers. + This will remain here until we find a permanent + fix. */ + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq); + + mailbox = (u32)readl(&ctl_addr->mail_box_0); + + addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ? + CyPCI_Ze_win : CyPCI_Zwin); + if (addr2 == NULL) { + dev_err(&pdev->dev, "can't remap base region\n"); + goto err_unmap; + } - /* Although we don't use this I/O region, we should - request it from the kernel anyway, to avoid problems - with other drivers accessing it. */ - if (pci_request_regions(pdev, "Cyclades-Z") != 0) { - printk(KERN_ERR "cyclades: failed to reserve " - "PCI resources\n"); - continue; - } + if (mailbox == ZE_V1) { + card_name = "Cyclades-Ze"; - if (mailbox == ZE_V1) { - cy_pci_addr2 = ioremap(cy_pci_phys2, - CyPCI_Ze_win); - if (ZeIndex == NR_CARDS) { - printk("Cyclades-Ze/PCI found at " - "0x%lx but no more cards can " - "be used.\nChange NR_CARDS in " - "cyclades.c and recompile " - "kernel.\n", - (ulong)cy_pci_phys2); - } else { - Ze_phys0[ZeIndex] = cy_pci_phys0; - Ze_phys2[ZeIndex] = cy_pci_phys2; - Ze_addr0[ZeIndex] = cy_pci_addr0; - Ze_addr2[ZeIndex] = cy_pci_addr2; - Ze_irq[ZeIndex] = cy_pci_irq; - Ze_pdev[ZeIndex] = pdev; - ZeIndex++; - } - i--; - continue; - } else { - cy_pci_addr2 = ioremap(cy_pci_phys2,CyPCI_Zwin); - } + readl(&ctl_addr->mail_box_0); + nchan = ZE_V1_NPORTS; + } else { + card_name = "Cyclades-8Zo"; #ifdef CY_PCI_DEBUG - printk("Cyclades-Z/PCI: relocate winaddr=0x%lx " - "ctladdr=0x%lx\n", - (ulong) cy_pci_addr2, (ulong) cy_pci_addr0); if (mailbox == ZO_V1) { - cy_writel(&((struct RUNTIME_9060 *) - (cy_pci_addr0))->loc_addr_base, - WIN_CREG); - PAUSE; - printk("Cyclades-8Zo/PCI: FPGA id %lx, ver " - "%lx\n", (ulong) (0xff & - cy_readl(&((struct CUSTOM_REG *) - (cy_pci_addr2))->fpga_id)), - (ulong)(0xff & - cy_readl(&((struct CUSTOM_REG *) - (cy_pci_addr2))-> - fpga_version))); - cy_writel(&((struct RUNTIME_9060 *) - (cy_pci_addr0))->loc_addr_base, - WIN_RAM); + cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); + dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA " + "id %lx, ver %lx\n", (ulong)(0xff & + readl(&((struct CUSTOM_REG *)addr2)-> + fpga_id)), (ulong)(0xff & + readl(&((struct CUSTOM_REG *)addr2)-> + fpga_version))); + cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); } else { - printk("Cyclades-Z/PCI: New Cyclades-Z board. " - "FPGA not loaded\n"); + dev_info(&pdev->dev, "Cyclades-Z/PCI: New " + "Cyclades-Z board. FPGA not loaded\n"); } #endif /* The following clears the firmware id word. This ensures that the driver will not attempt to talk to the board until it has been properly initialized. */ - PAUSE; if ((mailbox == ZO_V1) || (mailbox == ZO_V2)) - cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L); + cy_writel(addr2 + ID_ADDRESS, 0L); /* This must be a Cyclades-8Zo/PCI. The extendable version will have a different device_id and will be allocated its maximum number of ports. */ - cy_pci_nchan = 8; - - if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) { - printk("Cyclades-8Zo/PCI found at 0x%lx but" - "no channels are available.\nChange " - "NR_PORTS in cyclades.c and recompile " - "kernel.\n", (ulong)cy_pci_phys2); - return i; - } - - /* fill the next cy_card structure available */ - for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == 0) - break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - printk("Cyclades-8Zo/PCI found at 0x%lx but" - "no more cards can be used.\nChange " - "NR_CARDS in cyclades.c and recompile " - "kernel.\n", (ulong)cy_pci_phys2); - return i; - } -#ifdef CONFIG_CYZ_INTR - /* allocate IRQ only if board has an IRQ */ - if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) { - if (request_irq(cy_pci_irq, cyz_interrupt, - IRQF_SHARED, "Cyclades-Z", - &cy_card[j])) { - printk("Cyclom-8Zo/PCI found at 0x%lx " - "but could not allocate " - "IRQ%d.\n", (ulong)cy_pci_phys2, - cy_pci_irq); - return i; - } - } -#endif /* CONFIG_CYZ_INTR */ - - /* set cy_card */ - cy_card[j].base_phys = cy_pci_phys2; - cy_card[j].ctl_phys = cy_pci_phys0; - cy_card[j].base_addr = cy_pci_addr2; - cy_card[j].ctl_addr = cy_pci_addr0; - cy_card[j].irq = (int)cy_pci_irq; - cy_card[j].bus_index = 1; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = -1; - cy_card[j].pdev = pdev; - - /* print message */ -#ifdef CONFIG_CYZ_INTR - /* don't report IRQ if board is no IRQ */ - if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) - printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, " - "IRQ%d, ", j + 1, (ulong)cy_pci_phys2, - (ulong) (cy_pci_phys2 + CyPCI_Zwin - 1), - (int)cy_pci_irq); - else -#endif /* CONFIG_CYZ_INTR */ - printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ", - j + 1, (ulong)cy_pci_phys2, - (ulong)(cy_pci_phys2 + CyPCI_Zwin - 1)); - - printk("%d channels starting from port %d.\n", - cy_pci_nchan, cy_next_channel); - cy_next_channel += cy_pci_nchan; + nchan = 8; } } - for (; ZeIndex != 0 && i < NR_CARDS; i++) { - cy_pci_phys0 = Ze_phys0[0]; - cy_pci_phys2 = Ze_phys2[0]; - cy_pci_addr0 = Ze_addr0[0]; - cy_pci_addr2 = Ze_addr2[0]; - cy_pci_irq = Ze_irq[0]; - pdev = Ze_pdev[0]; - for (j = 0; j < ZeIndex - 1; j++) { - Ze_phys0[j] = Ze_phys0[j + 1]; - Ze_phys2[j] = Ze_phys2[j + 1]; - Ze_addr0[j] = Ze_addr0[j + 1]; - Ze_addr2[j] = Ze_addr2[j + 1]; - Ze_irq[j] = Ze_irq[j + 1]; - Ze_pdev[j] = Ze_pdev[j + 1]; - } - ZeIndex--; - mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *) - cy_pci_addr0)->mail_box_0); -#ifdef CY_PCI_DEBUG - printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n", - (ulong)cy_pci_addr2, (ulong)cy_pci_addr0); - printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not " - "loaded\n"); -#endif - PAUSE; - /* This must be the new Cyclades-Ze/PCI. */ - cy_pci_nchan = ZE_V1_NPORTS; - - if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) { - printk("Cyclades-Ze/PCI found at 0x%lx but no channels " - "are available.\nChange NR_PORTS in cyclades.c " - "and recompile kernel.\n", - (ulong) cy_pci_phys2); - return i; - } + if ((cy_next_channel + nchan) > NR_PORTS) { + dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " + "channels are available. Change NR_PORTS in " + "cyclades.c and recompile kernel.\n"); + goto err_unmap; + } + /* fill the next cy_card structure available */ + for (card_no = 0; card_no < NR_CARDS; card_no++) { + if (cy_card[card_no].base_addr == NULL) + break; + } + if (card_no == NR_CARDS) { /* no more cy_cards available */ + dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " + "more cards can be used. Change NR_CARDS in " + "cyclades.c and recompile kernel.\n"); + goto err_unmap; + } - /* fill the next cy_card structure available */ - for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == 0) - break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - printk("Cyclades-Ze/PCI found at 0x%lx but no more " - "cards can be used.\nChange NR_CARDS in " - "cyclades.c and recompile kernel.\n", - (ulong) cy_pci_phys2); - return i; + if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || + device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { + /* allocate IRQ */ + retval = request_irq(irq, cyy_interrupt, + IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]); + if (retval) { + dev_err(&pdev->dev, "could not allocate IRQ\n"); + goto err_unmap; } + cy_card[card_no].num_chips = nchan / 4; + } else { #ifdef CONFIG_CYZ_INTR /* allocate IRQ only if board has an IRQ */ - if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) { - if (request_irq(cy_pci_irq, cyz_interrupt, + if (irq != 0 && irq != 255) { + retval = request_irq(irq, cyz_interrupt, IRQF_SHARED, "Cyclades-Z", - &cy_card[j])) { - printk("Cyclom-Ze/PCI found at 0x%lx ", - (ulong) cy_pci_phys2); - printk("but could not allocate IRQ%d.\n", - cy_pci_irq); - return i; + &cy_card[card_no]); + if (retval) { + dev_err(&pdev->dev, "could not allocate IRQ\n"); + goto err_unmap; } } #endif /* CONFIG_CYZ_INTR */ + cy_card[card_no].num_chips = -1; + } - /* set cy_card */ - cy_card[j].base_phys = cy_pci_phys2; - cy_card[j].ctl_phys = cy_pci_phys0; - cy_card[j].base_addr = cy_pci_addr2; - cy_card[j].ctl_addr = cy_pci_addr0; - cy_card[j].irq = (int)cy_pci_irq; - cy_card[j].bus_index = 1; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = -1; - cy_card[j].pdev = pdev; + /* set cy_card */ + cy_card[card_no].base_addr = addr2; + cy_card[card_no].ctl_addr = addr0; + cy_card[card_no].irq = irq; + cy_card[card_no].bus_index = 1; + cy_card[card_no].first_line = cy_next_channel; + retval = cy_init_card(&cy_card[card_no]); + if (retval) + goto err_null; - /* print message */ -#ifdef CONFIG_CYZ_INTR - /* don't report IRQ if board is no IRQ */ - if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) - printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ", - j + 1, (ulong) cy_pci_phys2, - (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1), - (int)cy_pci_irq); - else -#endif /* CONFIG_CYZ_INTR */ - printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ", - j + 1, (ulong) cy_pci_phys2, - (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1)); + pci_set_drvdata(pdev, &cy_card[card_no]); - printk("%d channels starting from port %d.\n", - cy_pci_nchan, cy_next_channel); - cy_next_channel += cy_pci_nchan; - } - if (ZeIndex != 0) { - printk("Cyclades-Ze/PCI found at 0x%x but no more cards can be " - "used.\nChange NR_CARDS in cyclades.c and recompile " - "kernel.\n", (unsigned int)Ze_phys2[0]); + if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || + device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { + /* enable interrupts in the PCI interface */ + plx_ver = readb(addr2 + CyPLX_VER) & 0x0f; + switch (plx_ver) { + case PLX_9050: + + cy_writeb(addr0 + 0x4c, 0x43); + break; + + case PLX_9060: + case PLX_9080: + default: /* Old boards, use PLX_9060 */ + + plx_init(addr0, 0x6c); + /* For some yet unknown reason, once the PLX9060 reloads + the EEPROM, the IRQ is lost and, thus, we have to + re-write it to the PCI config. registers. + This will remain here until we find a permanent + fix. */ + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq); + + cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900); + break; + } } - return i; -#else + + dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from " + "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel); + for (i = cy_next_channel; i < cy_next_channel + nchan; i++) + tty_register_device(cy_serial_driver, i, &pdev->dev); + cy_next_channel += nchan; + return 0; -#endif /* ifdef CONFIG_PCI */ -} /* cy_detect_pci */ +err_null: + cy_card[card_no].base_addr = NULL; + free_irq(irq, &cy_card[card_no]); +err_unmap: + pci_iounmap(pdev, addr0); + if (addr2) + pci_iounmap(pdev, addr2); +err_reg: + pci_release_regions(pdev); +err_dis: + pci_disable_device(pdev); +err: + return retval; +} -/* - * This routine prints out the appropriate serial driver version number - * and identifies which options were configured into this driver. - */ -static inline void show_version(void) +static void __devexit cy_pci_remove(struct pci_dev *pdev) { - printk("Cyclades driver " CY_VERSION "\n"); - printk(" built %s %s\n", __DATE__, __TIME__); -} /* show_version */ + struct cyclades_card *cinfo = pci_get_drvdata(pdev); + unsigned int i; + + /* non-Z with old PLX */ + if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) == + PLX_9050) + cy_writeb(cinfo->ctl_addr + 0x4c, 0); + else +#ifndef CONFIG_CYZ_INTR + if (!IS_CYC_Z(*cinfo)) +#endif + cy_writew(cinfo->ctl_addr + 0x68, + readw(cinfo->ctl_addr + 0x68) & ~0x0900); + + pci_iounmap(pdev, cinfo->base_addr); + if (cinfo->ctl_addr) + pci_iounmap(pdev, cinfo->ctl_addr); + if (cinfo->irq +#ifndef CONFIG_CYZ_INTR + && !IS_CYC_Z(*cinfo) +#endif /* CONFIG_CYZ_INTR */ + ) + free_irq(cinfo->irq, cinfo); + pci_release_regions(pdev); + + cinfo->base_addr = NULL; + for (i = cinfo->first_line; i < cinfo->first_line + + cinfo->nports; i++) + tty_unregister_device(cy_serial_driver, i); + cinfo->nports = 0; + kfree(cinfo->ports); +} + +static struct pci_driver cy_pci_driver = { + .name = "cyclades", + .id_table = cy_pci_dev_id, + .probe = cy_pci_probe, + .remove = __devexit_p(cy_pci_remove) +}; +#endif static int cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, int *eof, void *data) { struct cyclades_port *info; - int i; + unsigned int i, j; int len = 0; off_t begin = 0; off_t pos = 0; @@ -5238,33 +5054,34 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, len += size; /* Output one line for each known port */ - for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) { - info = &cy_port[i]; - - if (info->count) - size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu " - "%8lu %9lu %6ld\n", info->line, - (cur_jifs - info->idle_stats.in_use) / HZ, - info->idle_stats.xmit_bytes, - (cur_jifs - info->idle_stats.xmit_idle) / HZ, - info->idle_stats.recv_bytes, - (cur_jifs - info->idle_stats.recv_idle) / HZ, - info->idle_stats.overruns, - (long)info->tty->ldisc.num); - else - size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu " - "%8lu %9lu %6ld\n", - info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); - len += size; - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; + for (i = 0; i < NR_CARDS; i++) + for (j = 0; j < cy_card[i].nports; j++) { + info = &cy_card[i].ports[j]; + + if (info->count) + size = sprintf(buf + len, "%3d %8lu %10lu %8lu " + "%10lu %8lu %9lu %6ld\n", info->line, + (cur_jifs - info->idle_stats.in_use) / + HZ, info->idle_stats.xmit_bytes, + (cur_jifs - info->idle_stats.xmit_idle)/ + HZ, info->idle_stats.recv_bytes, + (cur_jifs - info->idle_stats.recv_idle)/ + HZ, info->idle_stats.overruns, + (long)info->tty->ldisc.num); + else + size = sprintf(buf + len, "%3d %8lu %10lu %8lu " + "%10lu %8lu %9lu %6ld\n", + info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); + len += size; + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto done; } - if (pos > offset + length) - goto done; - } *eof = 1; done: *start = buf + (offset - begin); /* Start of wanted data */ @@ -5319,18 +5136,15 @@ static const struct tty_operations cy_ops = { static int __init cy_init(void) { - struct cyclades_port *info; - struct cyclades_card *cinfo; - int number_z_boards = 0; - int board, port, i, index; - unsigned long mailbox; - unsigned short chip_number; - int nports; + unsigned int nboards; + int retval = -ENOMEM; cy_serial_driver = alloc_tty_driver(NR_PORTS); if (!cy_serial_driver) - return -ENOMEM; - show_version(); + goto err; + + printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n", + __DATE__, __TIME__); /* Initialize the tty_driver structure */ @@ -5344,15 +5158,13 @@ static int __init cy_init(void) cy_serial_driver->init_termios = tty_std_termios; cy_serial_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - cy_serial_driver->flags = TTY_DRIVER_REAL_RAW; + cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(cy_serial_driver, &cy_ops); - if (tty_register_driver(cy_serial_driver)) - panic("Couldn't register Cyclades serial driver\n"); - - for (i = 0; i < NR_CARDS; i++) { - /* base_addr=0 indicates board not found */ - cy_card[i].base_addr = NULL; + retval = tty_register_driver(cy_serial_driver); + if (retval) { + printk(KERN_ERR "Couldn't register Cyclades serial driver\n"); + goto err_frtty; } /* the code below is responsible to find the boards. Each different @@ -5363,223 +5175,68 @@ static int __init cy_init(void) the cy_next_channel. */ /* look for isa boards */ - cy_isa_nboard = cy_detect_isa(); + nboards = cy_detect_isa(); +#ifdef CONFIG_PCI /* look for pci boards */ - cy_pci_nboard = cy_detect_pci(); - - cy_nboard = cy_isa_nboard + cy_pci_nboard; - - /* invalidate remaining cy_card structures */ - for (i = 0; i < NR_CARDS; i++) { - if (cy_card[i].base_addr == 0) { - cy_card[i].first_line = -1; - cy_card[i].ctl_addr = NULL; - cy_card[i].irq = 0; - cy_card[i].bus_index = 0; - cy_card[i].first_line = 0; - cy_card[i].num_chips = 0; - } - } - /* invalidate remaining cy_port structures */ - for (i = cy_next_channel; i < NR_PORTS; i++) { - cy_port[i].line = -1; - cy_port[i].magic = -1; - } - - /* initialize per-port data structures for each valid board found */ - for (board = 0; board < cy_nboard; board++) { - cinfo = &cy_card[board]; - if (cinfo->num_chips == -1) { /* Cyclades-Z */ - number_z_boards++; - mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *) - cy_card[board].ctl_addr)-> - mail_box_0); - nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8; - cinfo->intr_enabled = 0; - cinfo->nports = 0; /* Will be correctly set later, after - Z FW is loaded */ - spin_lock_init(&cinfo->card_lock); - for (port = cinfo->first_line; - port < cinfo->first_line + nports; port++) { - info = &cy_port[port]; - info->magic = CYCLADES_MAGIC; - info->type = PORT_STARTECH; - info->card = board; - info->line = port; - info->chip_rev = 0; - info->flags = STD_COM_FLAGS; - info->tty = NULL; - if (mailbox == ZO_V1) - info->xmit_fifo_size = CYZ_FIFO_SIZE; - else - info->xmit_fifo_size = - 4 * CYZ_FIFO_SIZE; - info->cor1 = 0; - info->cor2 = 0; - info->cor3 = 0; - info->cor4 = 0; - info->cor5 = 0; - info->tbpr = 0; - info->tco = 0; - info->rbpr = 0; - info->rco = 0; - info->custom_divisor = 0; - info->close_delay = 5 * HZ / 10; - info->closing_wait = CLOSING_WAIT_DELAY; - info->icount.cts = info->icount.dsr = - info->icount.rng = info->icount.dcd = 0; - info->icount.rx = info->icount.tx = 0; - info->icount.frame = info->icount.parity = 0; - info->icount.overrun = info->icount.brk = 0; - info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - info->default_threshold = 0; - info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - init_waitqueue_head(&info->shutdown_wait); - init_waitqueue_head(&info->delta_msr_wait); - /* info->session */ - /* info->pgrp */ - info->read_status_mask = 0; - /* info->timeout */ - /* Bentson's vars */ - info->jiffies[0] = 0; - info->jiffies[1] = 0; - info->jiffies[2] = 0; - info->rflush_count = 0; -#ifdef CONFIG_CYZ_INTR - init_timer(&cyz_rx_full_timer[port]); - cyz_rx_full_timer[port].function = NULL; + retval = pci_register_driver(&cy_pci_driver); + if (retval && !nboards) + goto err_unr; #endif - } - continue; - } else { /* Cyclom-Y of some kind */ - index = cinfo->bus_index; - spin_lock_init(&cinfo->card_lock); - cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips; - for (port = cinfo->first_line; - port < cinfo->first_line + cinfo->nports; port++) { - info = &cy_port[port]; - info->magic = CYCLADES_MAGIC; - info->type = PORT_CIRRUS; - info->card = board; - info->line = port; - info->flags = STD_COM_FLAGS; - info->tty = NULL; - info->xmit_fifo_size = CyMAX_CHAR_FIFO; - info->cor1 = - CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS; - info->cor2 = CyETC; - info->cor3 = 0x08; /* _very_ small rcv threshold */ - info->cor4 = 0; - info->cor5 = 0; - info->custom_divisor = 0; - info->close_delay = 5 * HZ / 10; - info->closing_wait = CLOSING_WAIT_DELAY; - info->icount.cts = info->icount.dsr = - info->icount.rng = info->icount.dcd = 0; - info->icount.rx = info->icount.tx = 0; - info->icount.frame = info->icount.parity = 0; - info->icount.overrun = info->icount.brk = 0; - chip_number = (port - cinfo->first_line) / 4; - if ((info->chip_rev = - cy_readb(cinfo->base_addr + - (cy_chip_offset[chip_number] << - index) + (CyGFRCR << index))) >= - CD1400_REV_J) { - /* It is a CD1400 rev. J or later */ - info->tbpr = baud_bpr_60[13]; /* Tx BPR */ - info->tco = baud_co_60[13]; /* Tx CO */ - info->rbpr = baud_bpr_60[13]; /* Rx BPR */ - info->rco = baud_co_60[13]; /* Rx CO */ - info->rflow = 0; - info->rtsdtr_inv = 1; - } else { - info->tbpr = baud_bpr_25[13]; /* Tx BPR */ - info->tco = baud_co_25[13]; /* Tx CO */ - info->rbpr = baud_bpr_25[13]; /* Rx BPR */ - info->rco = baud_co_25[13]; /* Rx CO */ - info->rflow = 0; - info->rtsdtr_inv = 0; - } - info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - info->default_threshold = 0; - info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - init_waitqueue_head(&info->shutdown_wait); - init_waitqueue_head(&info->delta_msr_wait); - /* info->session */ - /* info->pgrp */ - info->read_status_mask = - CyTIMEOUT | CySPECHAR | CyBREAK - | CyPARITY | CyFRAME | CyOVERRUN; - /* info->timeout */ - } - } - } - -#ifndef CONFIG_CYZ_INTR - if (number_z_boards && !cyz_timeron) { - cyz_timeron++; - cyz_timerlist.expires = jiffies + 1; - add_timer(&cyz_timerlist); -#ifdef CY_PCI_DEBUG - printk("Cyclades-Z polling initialized\n"); -#endif - } -#endif /* CONFIG_CYZ_INTR */ return 0; - +err_unr: + tty_unregister_driver(cy_serial_driver); +err_frtty: + put_tty_driver(cy_serial_driver); +err: + return retval; } /* cy_init */ static void __exit cy_cleanup_module(void) { + struct cyclades_card *card; int i, e1; #ifndef CONFIG_CYZ_INTR - if (cyz_timeron){ - cyz_timeron = 0; - del_timer(&cyz_timerlist); - } + del_timer_sync(&cyz_timerlist); #endif /* CONFIG_CYZ_INTR */ if ((e1 = tty_unregister_driver(cy_serial_driver))) - printk("cyc: failed to unregister Cyclades serial driver(%d)\n", - e1); + printk(KERN_ERR "failed to unregister Cyclades serial " + "driver(%d)\n", e1); - put_tty_driver(cy_serial_driver); +#ifdef CONFIG_PCI + pci_unregister_driver(&cy_pci_driver); +#endif for (i = 0; i < NR_CARDS; i++) { - if (cy_card[i].base_addr) { - iounmap(cy_card[i].base_addr); - if (cy_card[i].ctl_addr) - iounmap(cy_card[i].ctl_addr); - if (cy_card[i].irq + card = &cy_card[i]; + if (card->base_addr) { + /* clear interrupt */ + cy_writeb(card->base_addr + Cy_ClrIntr, 0); + iounmap(card->base_addr); + if (card->ctl_addr) + iounmap(card->ctl_addr); + if (card->irq #ifndef CONFIG_CYZ_INTR - && cy_card[i].num_chips != -1 /* not a Z card */ + && !IS_CYC_Z(*card) #endif /* CONFIG_CYZ_INTR */ ) - free_irq(cy_card[i].irq, &cy_card[i]); -#ifdef CONFIG_PCI - if (cy_card[i].pdev) - pci_release_regions(cy_card[i].pdev); -#endif + free_irq(card->irq, card); + for (e1 = card->first_line; + e1 < card->first_line + + card->nports; e1++) + tty_unregister_device(cy_serial_driver, e1); + kfree(card->ports); } } + + put_tty_driver(cy_serial_driver); } /* cy_cleanup_module */ module_init(cy_init); module_exit(cy_cleanup_module); MODULE_LICENSE("GPL"); +MODULE_VERSION(CY_VERSION); diff --git a/trunk/drivers/char/digi.h b/trunk/drivers/char/digi.h deleted file mode 100644 index 19df0e879b1b..000000000000 --- a/trunk/drivers/char/digi.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Definitions for DigiBoard ditty(1) command. */ - -#if !defined(TIOCMODG) -#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */ -#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */ -#endif - -#if !defined(TIOCMSET) -#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */ -#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */ -#endif - -#if !defined(TIOCMBIC) -#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */ -#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */ -#endif - -#if !defined(TIOCSDTR) -#define TIOCSDTR (('e'<<8) | 0) /* set DTR */ -#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */ -#endif - -/************************************************************************ - * Ioctl command arguments for DIGI parameters. - ************************************************************************/ -#define DIGI_GETA (('e'<<8) | 94) /* Read params */ - -#define DIGI_SETA (('e'<<8) | 95) /* Set params */ -#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */ -#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */ - -#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */ - /* control characters */ -#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */ - /* control characters */ -#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */ - /* flow control chars */ -#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */ - /* flow control chars */ - -struct digiflow_struct { - unsigned char startc; /* flow cntl start char */ - unsigned char stopc; /* flow cntl stop char */ -}; - -typedef struct digiflow_struct digiflow_t; - - -/************************************************************************ - * Values for digi_flags - ************************************************************************/ -#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */ -#define DIGI_FAST 0x0002 /* Fast baud rates */ -#define RTSPACE 0x0004 /* RTS input flow control */ -#define CTSPACE 0x0008 /* CTS output flow control */ -#define DSRPACE 0x0010 /* DSR output flow control */ -#define DCDPACE 0x0020 /* DCD output flow control */ -#define DTRPACE 0x0040 /* DTR input flow control */ -#define DIGI_FORCEDCD 0x0100 /* Force carrier */ -#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */ -#define DIGI_AIXON 0x0400 /* Aux flow control in fep */ - - -/************************************************************************ - * Structure used with ioctl commands for DIGI parameters. - ************************************************************************/ -struct digi_struct { - unsigned short digi_flags; /* Flags (see above) */ -}; - -typedef struct digi_struct digi_t; diff --git a/trunk/drivers/char/drm/README.drm b/trunk/drivers/char/drm/README.drm index 6441e01e587c..af74cd79a279 100644 --- a/trunk/drivers/char/drm/README.drm +++ b/trunk/drivers/char/drm/README.drm @@ -1,6 +1,6 @@ ************************************************************ * For the very latest on DRI development, please see: * -* http://dri.sourceforge.net/ * +* http://dri.freedesktop.org/ * ************************************************************ The Direct Rendering Manager (drm) is a device-independent kernel-level @@ -26,21 +26,19 @@ ways: Documentation on the DRI is available from: - http://precisioninsight.com/piinsights.html + http://dri.freedesktop.org/wiki/Documentation + http://sourceforge.net/project/showfiles.php?group_id=387 + http://dri.sourceforge.net/doc/ For specific information about kernel-level support, see: The Direct Rendering Manager, Kernel Support for the Direct Rendering Infrastructure - http://precisioninsight.com/dr/drm.html + http://dri.sourceforge.net/doc/drm_low_level.html Hardware Locking for the Direct Rendering Infrastructure - http://precisioninsight.com/dr/locking.html + http://dri.sourceforge.net/doc/hardware_locking_low_level.html A Security Analysis of the Direct Rendering Infrastructure - http://precisioninsight.com/dr/security.html + http://dri.sourceforge.net/doc/security_low_level.html -************************************************************ -* For the very latest on DRI development, please see: * -* http://dri.sourceforge.net/ * -************************************************************ diff --git a/trunk/drivers/char/drm/ati_pcigart.c b/trunk/drivers/char/drm/ati_pcigart.c index bd7be09ea53d..5b91bc04ea4e 100644 --- a/trunk/drivers/char/drm/ati_pcigart.c +++ b/trunk/drivers/char/drm/ati_pcigart.c @@ -33,59 +33,44 @@ #include "drmP.h" -#if PAGE_SIZE == 65536 -# define ATI_PCIGART_TABLE_ORDER 0 -# define ATI_PCIGART_TABLE_PAGES (1 << 0) -#elif PAGE_SIZE == 16384 -# define ATI_PCIGART_TABLE_ORDER 1 -# define ATI_PCIGART_TABLE_PAGES (1 << 1) -#elif PAGE_SIZE == 8192 -# define ATI_PCIGART_TABLE_ORDER 2 -# define ATI_PCIGART_TABLE_PAGES (1 << 2) -#elif PAGE_SIZE == 4096 -# define ATI_PCIGART_TABLE_ORDER 3 -# define ATI_PCIGART_TABLE_PAGES (1 << 3) -#else -# error - PAGE_SIZE not 64K, 16K, 8K or 4K -#endif - -# define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */ # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ -static void *drm_ati_alloc_pcigart_table(void) +static void *drm_ati_alloc_pcigart_table(int order) { unsigned long address; struct page *page; int i; - DRM_DEBUG("%s\n", __FUNCTION__); + + DRM_DEBUG("%s: alloc %d order\n", __FUNCTION__, order); address = __get_free_pages(GFP_KERNEL | __GFP_COMP, - ATI_PCIGART_TABLE_ORDER); + order); if (address == 0UL) { return NULL; } page = virt_to_page(address); - for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) + for (i = 0; i < order; i++, page++) SetPageReserved(page); DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address); return (void *)address; } -static void drm_ati_free_pcigart_table(void *address) +static void drm_ati_free_pcigart_table(void *address, int order) { struct page *page; int i; + int num_pages = 1 << order; DRM_DEBUG("%s\n", __FUNCTION__); page = virt_to_page((unsigned long)address); - for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) + for (i = 0; i < num_pages; i++, page++) ClearPageReserved(page); - free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER); + free_pages((unsigned long)address, order); } int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) @@ -93,6 +78,8 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) drm_sg_mem_t *entry = dev->sg; unsigned long pages; int i; + int order; + int num_pages, max_pages; /* we need to support large memory configurations */ if (!entry) { @@ -100,15 +87,19 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) return 0; } + order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE); + num_pages = 1 << order; + if (gart_info->bus_addr) { if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { pci_unmap_single(dev->pdev, gart_info->bus_addr, - ATI_PCIGART_TABLE_PAGES * PAGE_SIZE, + num_pages * PAGE_SIZE, PCI_DMA_TODEVICE); } - pages = (entry->pages <= ATI_MAX_PCIGART_PAGES) - ? entry->pages : ATI_MAX_PCIGART_PAGES; + max_pages = (gart_info->table_size / sizeof(u32)); + pages = (entry->pages <= max_pages) + ? entry->pages : max_pages; for (i = 0; i < pages; i++) { if (!entry->busaddr[i]) @@ -123,13 +114,12 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) if (gart_info->gart_table_location == DRM_ATI_GART_MAIN && gart_info->addr) { - drm_ati_free_pcigart_table(gart_info->addr); + drm_ati_free_pcigart_table(gart_info->addr, order); gart_info->addr = NULL; } return 1; } - EXPORT_SYMBOL(drm_ati_pcigart_cleanup); int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) @@ -139,6 +129,9 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) unsigned long pages; u32 *pci_gart, page_base, bus_address = 0; int i, j, ret = 0; + int order; + int max_pages; + int num_pages; if (!entry) { DRM_ERROR("no scatter/gather memory!\n"); @@ -148,7 +141,10 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); - address = drm_ati_alloc_pcigart_table(); + order = drm_order((gart_info->table_size + + (PAGE_SIZE-1)) / PAGE_SIZE); + num_pages = 1 << order; + address = drm_ati_alloc_pcigart_table(order); if (!address) { DRM_ERROR("cannot allocate PCI GART page!\n"); goto done; @@ -160,11 +156,13 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) } bus_address = pci_map_single(dev->pdev, address, - ATI_PCIGART_TABLE_PAGES * - PAGE_SIZE, PCI_DMA_TODEVICE); + num_pages * PAGE_SIZE, + PCI_DMA_TODEVICE); if (bus_address == 0) { DRM_ERROR("unable to map PCIGART pages!\n"); - drm_ati_free_pcigart_table(address); + order = drm_order((gart_info->table_size + + (PAGE_SIZE-1)) / PAGE_SIZE); + drm_ati_free_pcigart_table(address, order); address = NULL; goto done; } @@ -177,10 +175,11 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) pci_gart = (u32 *) address; - pages = (entry->pages <= ATI_MAX_PCIGART_PAGES) - ? entry->pages : ATI_MAX_PCIGART_PAGES; + max_pages = (gart_info->table_size / sizeof(u32)); + pages = (entry->pages <= max_pages) + ? entry->pages : max_pages; - memset(pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32)); + memset(pci_gart, 0, max_pages * sizeof(u32)); for (i = 0; i < pages; i++) { /* we need to support large memory configurations */ @@ -198,10 +197,18 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) page_base = (u32) entry->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { - if (gart_info->is_pcie) + switch(gart_info->gart_reg_if) { + case DRM_ATI_GART_IGP: + *pci_gart = cpu_to_le32((page_base) | 0xc); + break; + case DRM_ATI_GART_PCIE: *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); - else + break; + default: + case DRM_ATI_GART_PCI: *pci_gart = cpu_to_le32(page_base); + break; + } pci_gart++; page_base += ATI_PCIGART_PAGE_SIZE; } @@ -220,5 +227,4 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) gart_info->bus_addr = bus_address; return ret; } - EXPORT_SYMBOL(drm_ati_pcigart_init); diff --git a/trunk/drivers/char/drm/drm.h b/trunk/drivers/char/drm/drm.h index 8db9041e306c..089198491f16 100644 --- a/trunk/drivers/char/drm/drm.h +++ b/trunk/drivers/char/drm/drm.h @@ -654,11 +654,13 @@ typedef struct drm_set_version { /** * Device specific ioctls should only be in their respective headers - * The device specific ioctl range is from 0x40 to 0x79. + * The device specific ioctl range is from 0x40 to 0x99. + * Generic IOCTLS restart at 0xA0. * * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and * drmCommandReadWrite(). */ #define DRM_COMMAND_BASE 0x40 +#define DRM_COMMAND_END 0xA0 #endif diff --git a/trunk/drivers/char/drm/drmP.h b/trunk/drivers/char/drm/drmP.h index 85d99e21e188..d494315752a2 100644 --- a/trunk/drivers/char/drm/drmP.h +++ b/trunk/drivers/char/drm/drmP.h @@ -414,6 +414,10 @@ typedef struct drm_lock_data { struct file *filp; /**< File descr of lock holder (0=kernel) */ wait_queue_head_t lock_queue; /**< Queue of blocked processes */ unsigned long lock_time; /**< Time of last lock in jiffies */ + spinlock_t spinlock; + uint32_t kernel_waiters; + uint32_t user_waiters; + int idle_has_lock; } drm_lock_data_t; /** @@ -515,12 +519,17 @@ typedef struct drm_vbl_sig { #define DRM_ATI_GART_MAIN 1 #define DRM_ATI_GART_FB 2 +#define DRM_ATI_GART_PCI 1 +#define DRM_ATI_GART_PCIE 2 +#define DRM_ATI_GART_IGP 3 + typedef struct ati_pcigart_info { int gart_table_location; - int is_pcie; + int gart_reg_if; void *addr; dma_addr_t bus_addr; drm_local_map_t mapping; + int table_size; } drm_ati_pcigart_info; /* @@ -590,6 +599,8 @@ struct drm_driver { void (*reclaim_buffers) (struct drm_device * dev, struct file * filp); void (*reclaim_buffers_locked) (struct drm_device *dev, struct file *filp); + void (*reclaim_buffers_idlelocked) (struct drm_device *dev, + struct file * filp); unsigned long (*get_map_ofs) (drm_map_t * map); unsigned long (*get_reg_ofs) (struct drm_device * dev); void (*set_version) (struct drm_device * dev, drm_set_version_t * sv); @@ -764,7 +775,7 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev, } #ifdef __alpha__ -#define drm_get_pci_domain(dev) dev->hose->bus->number +#define drm_get_pci_domain(dev) dev->hose->index #else #define drm_get_pci_domain(dev) 0 #endif @@ -915,9 +926,18 @@ extern int drm_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_unlock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context); -extern int drm_lock_free(drm_device_t * dev, - __volatile__ unsigned int *lock, unsigned int context); +extern int drm_lock_take(drm_lock_data_t *lock_data, unsigned int context); +extern int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context); +extern void drm_idlelock_take(drm_lock_data_t *lock_data); +extern void drm_idlelock_release(drm_lock_data_t *lock_data); + +/* + * These are exported to drivers so that they can implement fencing using + * DMA quiscent + idle. DMA quiescent usually requires the hardware lock. + */ + +extern int drm_i_have_hw_lock(struct file *filp); +extern int drm_kernel_take_hw_lock(struct file *filp); /* Buffer management support (drm_bufs.h) */ extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request); diff --git a/trunk/drivers/char/drm/drm_bufs.c b/trunk/drivers/char/drm/drm_bufs.c index a6828cc14e58..c11345856ffe 100644 --- a/trunk/drivers/char/drm/drm_bufs.c +++ b/trunk/drivers/char/drm/drm_bufs.c @@ -57,7 +57,8 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, list_for_each(list, &dev->maplist->head) { drm_map_list_t *entry = list_entry(list, drm_map_list_t, head); if (entry->map && map->type == entry->map->type && - entry->map->offset == map->offset) { + ((entry->map->offset == map->offset) || + (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) { return entry; } } @@ -180,8 +181,20 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, if (map->type == _DRM_REGISTERS) map->handle = ioremap(map->offset, map->size); break; - case _DRM_SHM: + list = drm_find_matching_map(dev, map); + if (list != NULL) { + if(list->map->size != map->size) { + DRM_DEBUG("Matching maps of type %d with " + "mismatched sizes, (%ld vs %ld)\n", + map->type, map->size, list->map->size); + list->map->size = map->size; + } + + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + *maplist = list; + return 0; + } map->handle = vmalloc_user(map->size); DRM_DEBUG("%lu %d %p\n", map->size, drm_order(map->size), map->handle); @@ -200,15 +213,45 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */ } break; - case _DRM_AGP: - if (drm_core_has_AGP(dev)) { + case _DRM_AGP: { + drm_agp_mem_t *entry; + int valid = 0; + + if (!drm_core_has_AGP(dev)) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; + } #ifdef __alpha__ - map->offset += dev->hose->mem_space->start; + map->offset += dev->hose->mem_space->start; #endif - map->offset += dev->agp->base; - map->mtrr = dev->agp->agp_mtrr; /* for getmap */ + /* Note: dev->agp->base may actually be 0 when the DRM + * is not in control of AGP space. But if user space is + * it should already have added the AGP base itself. + */ + map->offset += dev->agp->base; + map->mtrr = dev->agp->agp_mtrr; /* for getmap */ + + /* This assumes the DRM is in total control of AGP space. + * It's not always the case as AGP can be in the control + * of user space (i.e. i810 driver). So this loop will get + * skipped and we double check that dev->agp->memory is + * actually set as well as being invalid before EPERM'ing + */ + for (entry = dev->agp->memory; entry; entry = entry->next) { + if ((map->offset >= entry->bound) && + (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) { + valid = 1; + break; + } } + if (dev->agp->memory && !valid) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EPERM; + } + DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size); + break; + } case _DRM_SCATTER_GATHER: if (!dev->sg) { drm_free(map, sizeof(*map), DRM_MEM_MAPS); @@ -267,7 +310,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, *maplist = list; return 0; -} + } int drm_addmap(drm_device_t * dev, unsigned int offset, unsigned int size, drm_map_type_t type, @@ -519,6 +562,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) { drm_device_dma_t *dma = dev->dma; drm_buf_entry_t *entry; + drm_agp_mem_t *agp_entry; drm_buf_t *buf; unsigned long offset; unsigned long agp_offset; @@ -529,7 +573,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) int page_order; int total; int byte_count; - int i; + int i, valid; drm_buf_t **temp_buflist; if (!dma) @@ -560,6 +604,19 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) if (dev->queue_count) return -EBUSY; /* Not while in use */ + /* Make sure buffers are located in AGP memory that we own */ + valid = 0; + for (agp_entry = dev->agp->memory; agp_entry; agp_entry = agp_entry->next) { + if ((agp_offset >= agp_entry->bound) && + (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { + valid = 1; + break; + } + } + if (dev->agp->memory && !valid) { + DRM_DEBUG("zone invalid\n"); + return -EINVAL; + } spin_lock(&dev->count_lock); if (dev->buf_use) { spin_unlock(&dev->count_lock); diff --git a/trunk/drivers/char/drm/drm_drv.c b/trunk/drivers/char/drm/drm_drv.c index f5b9b2480c14..8e77b7ed0f44 100644 --- a/trunk/drivers/char/drm/drm_drv.c +++ b/trunk/drivers/char/drm/drm_drv.c @@ -15,8 +15,6 @@ * #define DRIVER_DESC "Matrox G200/G400" * #define DRIVER_DATE "20001127" * - * #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls ) - * * #define drm_x mga_##x * \endcode */ @@ -120,7 +118,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, }; -#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) +#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) /** * Take down the DRM device. @@ -496,11 +494,14 @@ int drm_ioctl(struct inode *inode, struct file *filp, (long)old_encode_dev(priv->head->device), priv->authenticated); - if (nr < DRIVER_IOCTL_COUNT) - ioctl = &drm_ioctls[nr]; - else if ((nr >= DRM_COMMAND_BASE) - && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) + if ((nr >= DRM_CORE_IOCTL_COUNT) && + ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END))) + goto err_i1; + if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && + (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; + else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) + ioctl = &drm_ioctls[nr]; else goto err_i1; diff --git a/trunk/drivers/char/drm/drm_fops.c b/trunk/drivers/char/drm/drm_fops.c index 898f47dafec0..3b159cab3bc8 100644 --- a/trunk/drivers/char/drm/drm_fops.c +++ b/trunk/drivers/char/drm/drm_fops.c @@ -46,6 +46,7 @@ static int drm_setup(drm_device_t * dev) drm_local_map_t *map; int i; int ret; + u32 sareapage; if (dev->driver->firstopen) { ret = dev->driver->firstopen(dev); @@ -56,7 +57,8 @@ static int drm_setup(drm_device_t * dev) dev->magicfree.next = NULL; /* prebuild the SAREA */ - i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); + sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE); + i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); if (i != 0) return i; @@ -84,7 +86,7 @@ static int drm_setup(drm_device_t * dev) INIT_LIST_HEAD(&dev->ctxlist->head); dev->vmalist = NULL; - dev->sigdata.lock = dev->lock.hw_lock = NULL; + dev->sigdata.lock = NULL; init_waitqueue_head(&dev->lock.lock_queue); dev->queue_count = 0; dev->queue_reserved = 0; @@ -354,58 +356,56 @@ int drm_release(struct inode *inode, struct file *filp) current->pid, (long)old_encode_dev(priv->head->device), dev->open_count); - if (priv->lock_count && dev->lock.hw_lock && - _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && - dev->lock.filp == filp) { - DRM_DEBUG("File %p released, freeing lock for context %d\n", - filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - - if (dev->driver->reclaim_buffers_locked) + if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { + if (drm_i_have_hw_lock(filp)) { dev->driver->reclaim_buffers_locked(dev, filp); - - drm_lock_free(dev, &dev->lock.hw_lock->lock, - _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - - /* FIXME: may require heavy-handed reset of - hardware at this point, possibly - processed via a callback to the X - server. */ - } else if (dev->driver->reclaim_buffers_locked && priv->lock_count - && dev->lock.hw_lock) { - /* The lock is required to reclaim buffers */ - DECLARE_WAITQUEUE(entry, current); - - add_wait_queue(&dev->lock.lock_queue, &entry); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - if (!dev->lock.hw_lock) { - /* Device has been unregistered */ - retcode = -EINTR; - break; + } else { + unsigned long _end=jiffies + 3*DRM_HZ; + int locked = 0; + + drm_idlelock_take(&dev->lock); + + /* + * Wait for a while. + */ + + do{ + spin_lock(&dev->lock.spinlock); + locked = dev->lock.idle_has_lock; + spin_unlock(&dev->lock.spinlock); + if (locked) + break; + schedule(); + } while (!time_after_eq(jiffies, _end)); + + if (!locked) { + DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" + "\tdriver to use reclaim_buffers_idlelocked() instead.\n" + "\tI will go on reclaiming the buffers anyway.\n"); } - if (drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - dev->lock.filp = filp; - dev->lock.lock_time = jiffies; - atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); - break; /* Got lock */ - } - /* Contention */ - schedule(); - if (signal_pending(current)) { - retcode = -ERESTARTSYS; - break; - } - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&dev->lock.lock_queue, &entry); - if (!retcode) { + dev->driver->reclaim_buffers_locked(dev, filp); - drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT); + drm_idlelock_release(&dev->lock); } } + if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) { + + drm_idlelock_take(&dev->lock); + dev->driver->reclaim_buffers_idlelocked(dev, filp); + drm_idlelock_release(&dev->lock); + + } + + if (drm_i_have_hw_lock(filp)) { + DRM_DEBUG("File %p released, freeing lock for context %d\n", + filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + + drm_lock_free(&dev->lock, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + } + + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && !dev->driver->reclaim_buffers_locked) { dev->driver->reclaim_buffers(dev, filp); diff --git a/trunk/drivers/char/drm/drm_hashtab.c b/trunk/drivers/char/drm/drm_hashtab.c index a0b2d6802ae4..31acb621dcce 100644 --- a/trunk/drivers/char/drm/drm_hashtab.c +++ b/trunk/drivers/char/drm/drm_hashtab.c @@ -43,7 +43,16 @@ int drm_ht_create(drm_open_hash_t *ht, unsigned int order) ht->size = 1 << order; ht->order = order; ht->fill = 0; - ht->table = vmalloc(ht->size*sizeof(*ht->table)); + ht->table = NULL; + ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > PAGE_SIZE); + if (!ht->use_vmalloc) { + ht->table = drm_calloc(ht->size, sizeof(*ht->table), + DRM_MEM_HASHTAB); + } + if (!ht->table) { + ht->use_vmalloc = 1; + ht->table = vmalloc(ht->size*sizeof(*ht->table)); + } if (!ht->table) { DRM_ERROR("Out of memory for hash table\n"); return -ENOMEM; @@ -183,7 +192,11 @@ int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item) void drm_ht_remove(drm_open_hash_t *ht) { if (ht->table) { - vfree(ht->table); + if (ht->use_vmalloc) + vfree(ht->table); + else + drm_free(ht->table, ht->size * sizeof(*ht->table), + DRM_MEM_HASHTAB); ht->table = NULL; } } diff --git a/trunk/drivers/char/drm/drm_hashtab.h b/trunk/drivers/char/drm/drm_hashtab.h index 40afec05bff8..613091c970af 100644 --- a/trunk/drivers/char/drm/drm_hashtab.h +++ b/trunk/drivers/char/drm/drm_hashtab.h @@ -47,6 +47,7 @@ typedef struct drm_open_hash{ unsigned int order; unsigned int fill; struct hlist_head *table; + int use_vmalloc; } drm_open_hash_t; diff --git a/trunk/drivers/char/drm/drm_irq.c b/trunk/drivers/char/drm/drm_irq.c index 9d00c51fe2c4..2e75331fd83e 100644 --- a/trunk/drivers/char/drm/drm_irq.c +++ b/trunk/drivers/char/drm/drm_irq.c @@ -424,7 +424,7 @@ static void drm_locked_tasklet_func(unsigned long data) spin_lock_irqsave(&dev->tasklet_lock, irqflags); if (!dev->locked_tasklet_func || - !drm_lock_take(&dev->lock.hw_lock->lock, + !drm_lock_take(&dev->lock, DRM_KERNEL_CONTEXT)) { spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); return; @@ -435,7 +435,7 @@ static void drm_locked_tasklet_func(unsigned long data) dev->locked_tasklet_func(dev); - drm_lock_free(dev, &dev->lock.hw_lock->lock, + drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT); dev->locked_tasklet_func = NULL; diff --git a/trunk/drivers/char/drm/drm_lock.c b/trunk/drivers/char/drm/drm_lock.c index e9993ba461a2..befd1af19dfe 100644 --- a/trunk/drivers/char/drm/drm_lock.c +++ b/trunk/drivers/char/drm/drm_lock.c @@ -35,9 +35,6 @@ #include "drmP.h" -static int drm_lock_transfer(drm_device_t * dev, - __volatile__ unsigned int *lock, - unsigned int context); static int drm_notifier(void *priv); /** @@ -80,6 +77,9 @@ int drm_lock(struct inode *inode, struct file *filp, return -EINVAL; add_wait_queue(&dev->lock.lock_queue, &entry); + spin_lock(&dev->lock.spinlock); + dev->lock.user_waiters++; + spin_unlock(&dev->lock.spinlock); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); if (!dev->lock.hw_lock) { @@ -87,7 +87,7 @@ int drm_lock(struct inode *inode, struct file *filp, ret = -EINTR; break; } - if (drm_lock_take(&dev->lock.hw_lock->lock, lock.context)) { + if (drm_lock_take(&dev->lock, lock.context)) { dev->lock.filp = filp; dev->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); @@ -101,12 +101,14 @@ int drm_lock(struct inode *inode, struct file *filp, break; } } + spin_lock(&dev->lock.spinlock); + dev->lock.user_waiters--; + spin_unlock(&dev->lock.spinlock); __set_current_state(TASK_RUNNING); remove_wait_queue(&dev->lock.lock_queue, &entry); - DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); - if (ret) - return ret; + DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); + if (ret) return ret; sigemptyset(&dev->sigmask); sigaddset(&dev->sigmask, SIGSTOP); @@ -127,14 +129,12 @@ int drm_lock(struct inode *inode, struct file *filp, } } - /* dev->driver->kernel_context_switch isn't used by any of the x86 - * drivers but is used by the Sparc driver. - */ if (dev->driver->kernel_context_switch && dev->last_context != lock.context) { dev->driver->kernel_context_switch(dev, dev->last_context, lock.context); } + return 0; } @@ -184,12 +184,8 @@ int drm_unlock(struct inode *inode, struct file *filp, if (dev->driver->kernel_context_switch_unlock) dev->driver->kernel_context_switch_unlock(dev); else { - drm_lock_transfer(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT); - - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); + if (drm_lock_free(&dev->lock,lock.context)) { + /* FIXME: Should really bail out here. */ } } @@ -206,18 +202,26 @@ int drm_unlock(struct inode *inode, struct file *filp, * * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction. */ -int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) +int drm_lock_take(drm_lock_data_t *lock_data, + unsigned int context) { unsigned int old, new, prev; + volatile unsigned int *lock = &lock_data->hw_lock->lock; + spin_lock(&lock_data->spinlock); do { old = *lock; if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT; - else - new = context | _DRM_LOCK_HELD; + else { + new = context | _DRM_LOCK_HELD | + ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ? + _DRM_LOCK_CONT : 0); + } prev = cmpxchg(lock, old, new); } while (prev != old); + spin_unlock(&lock_data->spinlock); + if (_DRM_LOCKING_CONTEXT(old) == context) { if (old & _DRM_LOCK_HELD) { if (context != DRM_KERNEL_CONTEXT) { @@ -227,7 +231,8 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) return 0; } } - if (new == (context | _DRM_LOCK_HELD)) { + + if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) { /* Have lock */ return 1; } @@ -246,13 +251,13 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) * Resets the lock file pointer. * Marks the lock as held by the given context, via the \p cmpxchg instruction. */ -static int drm_lock_transfer(drm_device_t * dev, - __volatile__ unsigned int *lock, +static int drm_lock_transfer(drm_lock_data_t *lock_data, unsigned int context) { unsigned int old, new, prev; + volatile unsigned int *lock = &lock_data->hw_lock->lock; - dev->lock.filp = NULL; + lock_data->filp = NULL; do { old = *lock; new = context | _DRM_LOCK_HELD; @@ -272,23 +277,32 @@ static int drm_lock_transfer(drm_device_t * dev, * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task * waiting on the lock queue. */ -int drm_lock_free(drm_device_t * dev, - __volatile__ unsigned int *lock, unsigned int context) +int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context) { unsigned int old, new, prev; + volatile unsigned int *lock = &lock_data->hw_lock->lock; + + spin_lock(&lock_data->spinlock); + if (lock_data->kernel_waiters != 0) { + drm_lock_transfer(lock_data, 0); + lock_data->idle_has_lock = 1; + spin_unlock(&lock_data->spinlock); + return 1; + } + spin_unlock(&lock_data->spinlock); - dev->lock.filp = NULL; do { old = *lock; - new = 0; + new = _DRM_LOCKING_CONTEXT(old); prev = cmpxchg(lock, old, new); } while (prev != old); + if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { DRM_ERROR("%d freed heavyweight lock held by %d\n", context, _DRM_LOCKING_CONTEXT(old)); return 1; } - wake_up_interruptible(&dev->lock.lock_queue); + wake_up_interruptible(&lock_data->lock_queue); return 0; } @@ -322,3 +336,67 @@ static int drm_notifier(void *priv) } while (prev != old); return 0; } + +/** + * This function returns immediately and takes the hw lock + * with the kernel context if it is free, otherwise it gets the highest priority when and if + * it is eventually released. + * + * This guarantees that the kernel will _eventually_ have the lock _unless_ it is held + * by a blocked process. (In the latter case an explicit wait for the hardware lock would cause + * a deadlock, which is why the "idlelock" was invented). + * + * This should be sufficient to wait for GPU idle without + * having to worry about starvation. + */ + +void drm_idlelock_take(drm_lock_data_t *lock_data) +{ + int ret = 0; + + spin_lock(&lock_data->spinlock); + lock_data->kernel_waiters++; + if (!lock_data->idle_has_lock) { + + spin_unlock(&lock_data->spinlock); + ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT); + spin_lock(&lock_data->spinlock); + + if (ret == 1) + lock_data->idle_has_lock = 1; + } + spin_unlock(&lock_data->spinlock); +} +EXPORT_SYMBOL(drm_idlelock_take); + +void drm_idlelock_release(drm_lock_data_t *lock_data) +{ + unsigned int old, prev; + volatile unsigned int *lock = &lock_data->hw_lock->lock; + + spin_lock(&lock_data->spinlock); + if (--lock_data->kernel_waiters == 0) { + if (lock_data->idle_has_lock) { + do { + old = *lock; + prev = cmpxchg(lock, old, DRM_KERNEL_CONTEXT); + } while (prev != old); + wake_up_interruptible(&lock_data->lock_queue); + lock_data->idle_has_lock = 0; + } + } + spin_unlock(&lock_data->spinlock); +} +EXPORT_SYMBOL(drm_idlelock_release); + + +int drm_i_have_hw_lock(struct file *filp) +{ + DRM_DEVICE; + + return (priv->lock_count && dev->lock.hw_lock && + _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && + dev->lock.filp == filp); +} + +EXPORT_SYMBOL(drm_i_have_hw_lock); diff --git a/trunk/drivers/char/drm/drm_mm.c b/trunk/drivers/char/drm/drm_mm.c index 9b46b85027d0..2ec1d9f26264 100644 --- a/trunk/drivers/char/drm/drm_mm.c +++ b/trunk/drivers/char/drm/drm_mm.c @@ -274,7 +274,6 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) return drm_mm_create_tail_node(mm, start, size); } -EXPORT_SYMBOL(drm_mm_init); void drm_mm_takedown(drm_mm_t * mm) { @@ -295,4 +294,3 @@ void drm_mm_takedown(drm_mm_t * mm) drm_free(entry, sizeof(*entry), DRM_MEM_MM); } -EXPORT_SYMBOL(drm_mm_takedown); diff --git a/trunk/drivers/char/drm/drm_os_linux.h b/trunk/drivers/char/drm/drm_os_linux.h index 2908b72daa6e..0fe7b4497927 100644 --- a/trunk/drivers/char/drm/drm_os_linux.h +++ b/trunk/drivers/char/drm/drm_os_linux.h @@ -70,9 +70,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size) #endif -/** Task queue handler arguments */ -#define DRM_TASKQUEUE_ARGS void *arg - /** For data going into the kernel through the ioctl argument */ #define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \ if ( copy_from_user(&arg1, arg2, arg3) ) \ diff --git a/trunk/drivers/char/drm/drm_pciids.h b/trunk/drivers/char/drm/drm_pciids.h index ad54b845978b..31cdde83713b 100644 --- a/trunk/drivers/char/drm/drm_pciids.h +++ b/trunk/drivers/char/drm/drm_pciids.h @@ -102,6 +102,7 @@ {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \ {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ + {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ @@ -230,10 +231,10 @@ {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \ + {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \ {0, 0, 0} #define i810_PCI_IDS \ @@ -296,5 +297,6 @@ {0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2a02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0, 0, 0} diff --git a/trunk/drivers/char/drm/drm_proc.c b/trunk/drivers/char/drm/drm_proc.c index 7fd0da712142..b204498d1a28 100644 --- a/trunk/drivers/char/drm/drm_proc.c +++ b/trunk/drivers/char/drm/drm_proc.c @@ -72,7 +72,7 @@ static struct drm_proc_list { #endif }; -#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0])) +#define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list) /** * Initialize the DRI proc filesystem for a device. diff --git a/trunk/drivers/char/drm/drm_stub.c b/trunk/drivers/char/drm/drm_stub.c index 120d10256feb..19408adcc775 100644 --- a/trunk/drivers/char/drm/drm_stub.c +++ b/trunk/drivers/char/drm/drm_stub.c @@ -62,6 +62,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, spin_lock_init(&dev->count_lock); spin_lock_init(&dev->drw_lock); spin_lock_init(&dev->tasklet_lock); + spin_lock_init(&dev->lock.spinlock); init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); diff --git a/trunk/drivers/char/drm/drm_vm.c b/trunk/drivers/char/drm/drm_vm.c index 54a632848955..35540cfb43dd 100644 --- a/trunk/drivers/char/drm/drm_vm.c +++ b/trunk/drivers/char/drm/drm_vm.c @@ -41,6 +41,30 @@ static void drm_vm_open(struct vm_area_struct *vma); static void drm_vm_close(struct vm_area_struct *vma); +static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) +{ + pgprot_t tmp = vm_get_page_prot(vma->vm_flags); + +#if defined(__i386__) || defined(__x86_64__) + if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) { + pgprot_val(tmp) |= _PAGE_PCD; + pgprot_val(tmp) &= ~_PAGE_PWT; + } +#elif defined(__powerpc__) + pgprot_val(tmp) |= _PAGE_NO_CACHE; + if (map_type == _DRM_REGISTERS) + pgprot_val(tmp) |= _PAGE_GUARDED; +#endif +#if defined(__ia64__) + if (efi_range_is_wc(vma->vm_start, vma->vm_end - + vma->vm_start)) + tmp = pgprot_writecombine(tmp); + else + tmp = pgprot_noncached(tmp); +#endif + return tmp; +} + /** * \c nopage method for AGP virtual memory. * @@ -151,8 +175,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, offset = address - vma->vm_start; i = (unsigned long)map->handle + offset; - page = (map->type == _DRM_CONSISTENT) ? - virt_to_page((void *)i) : vmalloc_to_page((void *)i); + page = vmalloc_to_page((void *)i); if (!page) return NOPAGE_SIGBUS; get_page(page); @@ -389,7 +412,7 @@ static struct vm_operations_struct drm_vm_sg_ops = { * Create a new drm_vma_entry structure as the \p vma private data entry and * add it to drm_device::vmalist. */ -static void drm_vm_open(struct vm_area_struct *vma) +static void drm_vm_open_locked(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->head->dev; @@ -401,15 +424,23 @@ static void drm_vm_open(struct vm_area_struct *vma) vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); if (vma_entry) { - mutex_lock(&dev->struct_mutex); vma_entry->vma = vma; vma_entry->next = dev->vmalist; vma_entry->pid = current->pid; dev->vmalist = vma_entry; - mutex_unlock(&dev->struct_mutex); } } +static void drm_vm_open(struct vm_area_struct *vma) +{ + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->head->dev; + + mutex_lock(&dev->struct_mutex); + drm_vm_open_locked(vma); + mutex_unlock(&dev->struct_mutex); +} + /** * \c close method for all virtual memory types. * @@ -460,7 +491,6 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) drm_device_dma_t *dma; unsigned long length = vma->vm_end - vma->vm_start; - lock_kernel(); dev = priv->head->dev; dma = dev->dma; DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", @@ -468,10 +498,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) /* Length must match exact page count */ if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { - unlock_kernel(); return -EINVAL; } - unlock_kernel(); if (!capable(CAP_SYS_ADMIN) && (dma->flags & _DRM_DMA_USE_PCI_RO)) { @@ -494,7 +522,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) vma->vm_flags |= VM_RESERVED; /* Don't swap */ vma->vm_file = filp; /* Needed for drm_vm_open() */ - drm_vm_open(vma); + drm_vm_open_locked(vma); return 0; } @@ -529,7 +557,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs); * according to the mapping type and remaps the pages. Finally sets the file * pointer and calls vm_open(). */ -int drm_mmap(struct file *filp, struct vm_area_struct *vma) +static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; @@ -565,7 +593,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) return -EPERM; /* Check for valid size. */ - if (map->size != vma->vm_end - vma->vm_start) + if (map->size < vma->vm_end - vma->vm_start) return -EINVAL; if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) { @@ -600,37 +628,16 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) /* fall through to _DRM_FRAME_BUFFER... */ case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: -#if defined(__i386__) || defined(__x86_64__) - if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { - pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; - pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; - } -#elif defined(__powerpc__) - pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; - if (map->type == _DRM_REGISTERS) - pgprot_val(vma->vm_page_prot) |= _PAGE_GUARDED; -#endif - vma->vm_flags |= VM_IO; /* not in core dump */ -#if defined(__ia64__) - if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) - vma->vm_page_prot = - pgprot_writecombine(vma->vm_page_prot); - else - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); -#endif offset = dev->driver->get_reg_ofs(dev); + vma->vm_flags |= VM_IO; /* not in core dump */ + vma->vm_page_prot = drm_io_prot(map->type, vma); #ifdef __sparc__ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +#endif if (io_remap_pfn_range(vma, vma->vm_start, (map->offset + offset) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) -#else - if (io_remap_pfn_range(vma, vma->vm_start, - (map->offset + offset) >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) -#endif return -EAGAIN; DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," " offset = 0x%lx\n", @@ -638,10 +645,15 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_start, vma->vm_end, map->offset + offset); vma->vm_ops = &drm_vm_ops; break; - case _DRM_SHM: case _DRM_CONSISTENT: - /* Consistent memory is really like shared memory. It's only - * allocate in a different way */ + /* Consistent memory is really like shared memory. But + * it's allocated in a different way, so avoid nopage */ + if (remap_pfn_range(vma, vma->vm_start, + page_to_pfn(virt_to_page(map->handle)), + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; + /* fall through to _DRM_SHM */ + case _DRM_SHM: vma->vm_ops = &drm_vm_shm_ops; vma->vm_private_data = (void *)map; /* Don't let this area swap. Change when @@ -659,8 +671,20 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_flags |= VM_RESERVED; /* Don't swap */ vma->vm_file = filp; /* Needed for drm_vm_open() */ - drm_vm_open(vma); + drm_vm_open_locked(vma); return 0; } +int drm_mmap(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_mmap_locked(filp, vma); + mutex_unlock(&dev->struct_mutex); + + return ret; +} EXPORT_SYMBOL(drm_mmap); diff --git a/trunk/drivers/char/drm/i915_dma.c b/trunk/drivers/char/drm/i915_dma.c index 9354ce3b0093..1ba15d9a171a 100644 --- a/trunk/drivers/char/drm/i915_dma.c +++ b/trunk/drivers/char/drm/i915_dma.c @@ -34,7 +34,8 @@ #define IS_I965G(dev) (dev->pci_device == 0x2972 || \ dev->pci_device == 0x2982 || \ dev->pci_device == 0x2992 || \ - dev->pci_device == 0x29A2) + dev->pci_device == 0x29A2 || \ + dev->pci_device == 0x2A02) /* Really want an OS-independent resettable timer. Would like to have * this loop run for (eg) 3 sec, but have the timer reset every time diff --git a/trunk/drivers/char/drm/r128_cce.c b/trunk/drivers/char/drm/r128_cce.c index db5a60450e68..1014602c43a7 100644 --- a/trunk/drivers/char/drm/r128_cce.c +++ b/trunk/drivers/char/drm/r128_cce.c @@ -560,9 +560,10 @@ static int r128_do_init_cce(drm_device_t * dev, drm_r128_init_t * init) if (dev_priv->is_pci) { #endif dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; + dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE; dev_priv->gart_info.addr = NULL; dev_priv->gart_info.bus_addr = 0; - dev_priv->gart_info.is_pcie = 0; + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) { DRM_ERROR("failed to init PCI GART!\n"); dev->dev_private = (void *)dev_priv; diff --git a/trunk/drivers/char/drm/r128_drv.h b/trunk/drivers/char/drm/r128_drv.h index f1efb49de8df..9086835686dc 100644 --- a/trunk/drivers/char/drm/r128_drv.h +++ b/trunk/drivers/char/drm/r128_drv.h @@ -383,6 +383,8 @@ extern long r128_compat_ioctl(struct file *filp, unsigned int cmd, #define R128_PERFORMANCE_BOXES 0 +#define R128_PCIGART_TABLE_SIZE 32768 + #define R128_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) #define R128_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) #define R128_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) diff --git a/trunk/drivers/char/drm/radeon_cp.c b/trunk/drivers/char/drm/radeon_cp.c index 5ed965688293..68338389d836 100644 --- a/trunk/drivers/char/drm/radeon_cp.c +++ b/trunk/drivers/char/drm/radeon_cp.c @@ -830,6 +830,15 @@ static int RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) return RADEON_READ(RADEON_PCIE_DATA); } +static u32 RADEON_READ_IGPGART(drm_radeon_private_t *dev_priv, int addr) +{ + u32 ret; + RADEON_WRITE(RADEON_IGPGART_INDEX, addr & 0x7f); + ret = RADEON_READ(RADEON_IGPGART_DATA); + RADEON_WRITE(RADEON_IGPGART_INDEX, 0x7f); + return ret; +} + #if RADEON_FIFO_DEBUG static void radeon_status(drm_radeon_private_t * dev_priv) { @@ -1267,7 +1276,44 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv) } } -/* Enable or disable PCI-E GART on the chip */ +/* Enable or disable IGP GART on the chip */ +static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on) +{ + u32 temp, tmp; + + tmp = RADEON_READ(RADEON_AIC_CNTL); + if (on) { + DRM_DEBUG("programming igpgart %08X %08lX %08X\n", + dev_priv->gart_vm_start, + (long)dev_priv->gart_info.bus_addr, + dev_priv->gart_size); + + RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_18, 0x1000); + RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, 0x1); + RADEON_WRITE_IGPGART(RADEON_IGPGART_CTRL, 0x42040800); + RADEON_WRITE_IGPGART(RADEON_IGPGART_BASE_ADDR, + dev_priv->gart_info.bus_addr); + + temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_UNK_39); + RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_39, temp); + + RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start); + dev_priv->gart_size = 32*1024*1024; + RADEON_WRITE(RADEON_MC_AGP_LOCATION, + (((dev_priv->gart_vm_start - 1 + + dev_priv->gart_size) & 0xffff0000) | + (dev_priv->gart_vm_start >> 16))); + + temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_ENABLE); + RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, temp); + + RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); + RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1); + RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); + RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0); + } +} + static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on) { u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); @@ -1302,6 +1348,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) { u32 tmp; + if (dev_priv->flags & RADEON_IS_IGPGART) { + radeon_set_igpgart(dev_priv, on); + return; + } + if (dev_priv->flags & RADEON_IS_PCIE) { radeon_set_pciegart(dev_priv, on); return; @@ -1560,8 +1611,8 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) if (dev_priv->flags & RADEON_IS_AGP) { base = dev->agp->base; /* Check if valid */ - if ((base + dev_priv->gart_size) > dev_priv->fb_location && - base < (dev_priv->fb_location + dev_priv->fb_size)) { + if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location && + base < (dev_priv->fb_location + dev_priv->fb_size - 1)) { DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n", dev->agp->base); base = 0; @@ -1571,8 +1622,8 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) /* If not or if AGP is at 0 (Macs), try to put it elsewhere */ if (base == 0) { base = dev_priv->fb_location + dev_priv->fb_size; - if (((base + dev_priv->gart_size) & 0xfffffffful) - < base) + if (base < dev_priv->fb_location || + ((base + dev_priv->gart_size) & 0xfffffffful) < base) base = dev_priv->fb_location - dev_priv->gart_size; } @@ -1620,20 +1671,22 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) #endif { /* if we have an offset set from userspace */ - if (dev_priv->pcigart_offset) { + if (dev_priv->pcigart_offset_set) { dev_priv->gart_info.bus_addr = dev_priv->pcigart_offset + dev_priv->fb_location; dev_priv->gart_info.mapping.offset = dev_priv->gart_info.bus_addr; dev_priv->gart_info.mapping.size = - RADEON_PCIGART_TABLE_SIZE; + dev_priv->gart_info.table_size; drm_core_ioremap(&dev_priv->gart_info.mapping, dev); dev_priv->gart_info.addr = dev_priv->gart_info.mapping.handle; - dev_priv->gart_info.is_pcie = - !!(dev_priv->flags & RADEON_IS_PCIE); + if (dev_priv->flags & RADEON_IS_PCIE) + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE; + else + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; dev_priv->gart_info.gart_table_location = DRM_ATI_GART_FB; @@ -1641,6 +1694,10 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) dev_priv->gart_info.addr, dev_priv->pcigart_offset); } else { + if (dev_priv->flags & RADEON_IS_IGPGART) + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP; + else + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; dev_priv->gart_info.addr = NULL; @@ -1714,7 +1771,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev) if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) { drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); - dev_priv->gart_info.addr = NULL; + dev_priv->gart_info.addr = 0; } } /* only clear to the start of flags */ @@ -2222,6 +2279,8 @@ int radeon_driver_firstopen(struct drm_device *dev) drm_local_map_t *map; drm_radeon_private_t *dev_priv = dev->dev_private; + dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; + ret = drm_addmap(dev, drm_get_resource_start(dev, 2), drm_get_resource_len(dev, 2), _DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio); diff --git a/trunk/drivers/char/drm/radeon_drm.h b/trunk/drivers/char/drm/radeon_drm.h index 8d6350dd5360..66c4b6fed04f 100644 --- a/trunk/drivers/char/drm/radeon_drm.h +++ b/trunk/drivers/char/drm/radeon_drm.h @@ -707,6 +707,7 @@ typedef struct drm_radeon_setparam { #define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */ #define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */ #define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */ +#define RADEON_SETPARAM_PCIGART_TABLE_SIZE 5 /* PCI GART Table Size */ /* 1.14: Clients can allocate/free a surface */ diff --git a/trunk/drivers/char/drm/radeon_drv.h b/trunk/drivers/char/drm/radeon_drv.h index 8b105f1460a7..54f49ef4bef0 100644 --- a/trunk/drivers/char/drm/radeon_drv.h +++ b/trunk/drivers/char/drm/radeon_drv.h @@ -95,9 +95,11 @@ * 1.24- Add general-purpose packet for manipulating scratch registers (r300) * 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL, * new packet type) + * 1.26- Add support for variable size PCI(E) gart aperture + * 1.27- Add support for IGP GART */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 25 +#define DRIVER_MINOR 27 #define DRIVER_PATCHLEVEL 0 /* @@ -143,6 +145,7 @@ enum radeon_chip_flags { RADEON_IS_PCIE = 0x00200000UL, RADEON_NEW_MEMMAP = 0x00400000UL, RADEON_IS_PCI = 0x00800000UL, + RADEON_IS_IGPGART = 0x01000000UL, }; #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ @@ -240,7 +243,6 @@ typedef struct drm_radeon_private { int do_boxes; int page_flipping; - int current_page; u32 color_fmt; unsigned int front_offset; @@ -280,6 +282,7 @@ typedef struct drm_radeon_private { struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES]; unsigned long pcigart_offset; + unsigned int pcigart_offset_set; drm_ati_pcigart_info gart_info; u32 scratch_ages[5]; @@ -432,6 +435,15 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, #define RADEON_PCIE_TX_GART_END_LO 0x16 #define RADEON_PCIE_TX_GART_END_HI 0x17 +#define RADEON_IGPGART_INDEX 0x168 +#define RADEON_IGPGART_DATA 0x16c +#define RADEON_IGPGART_UNK_18 0x18 +#define RADEON_IGPGART_CTRL 0x2b +#define RADEON_IGPGART_BASE_ADDR 0x2c +#define RADEON_IGPGART_FLUSH 0x2e +#define RADEON_IGPGART_ENABLE 0x38 +#define RADEON_IGPGART_UNK_39 0x39 + #define RADEON_MPP_TB_CONFIG 0x01c0 #define RADEON_MEM_CNTL 0x0140 #define RADEON_MEM_SDRAM_MODE_REG 0x0158 @@ -964,6 +976,14 @@ do { \ RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) ); \ } while (0) +#define RADEON_WRITE_IGPGART( addr, val ) \ +do { \ + RADEON_WRITE( RADEON_IGPGART_INDEX, \ + ((addr) & 0x7f) | (1 << 8)); \ + RADEON_WRITE( RADEON_IGPGART_DATA, (val) ); \ + RADEON_WRITE( RADEON_IGPGART_INDEX, 0x7f ); \ +} while (0) + #define RADEON_WRITE_PCIE( addr, val ) \ do { \ RADEON_WRITE8( RADEON_PCIE_INDEX, \ diff --git a/trunk/drivers/char/drm/radeon_state.c b/trunk/drivers/char/drm/radeon_state.c index 938eccb78cc0..98c5f1d3a8e7 100644 --- a/trunk/drivers/char/drm/radeon_state.c +++ b/trunk/drivers/char/drm/radeon_state.c @@ -773,7 +773,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv, RADEON_GMC_SRC_DATATYPE_COLOR | RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS); - if (dev_priv->page_flipping && dev_priv->current_page == 1) { + if (dev_priv->sarea_priv->pfCurrentPage == 1) { OUT_RING(dev_priv->front_pitch_offset); } else { OUT_RING(dev_priv->back_pitch_offset); @@ -861,7 +861,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev, dev_priv->stats.clears++; - if (dev_priv->page_flipping && dev_priv->current_page == 1) { + if (dev_priv->sarea_priv->pfCurrentPage == 1) { unsigned int tmp = flags; flags &= ~(RADEON_FRONT | RADEON_BACK); @@ -1382,7 +1382,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev) /* Make this work even if front & back are flipped: */ OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); - if (dev_priv->current_page == 0) { + if (dev_priv->sarea_priv->pfCurrentPage == 0) { OUT_RING(dev_priv->back_pitch_offset); OUT_RING(dev_priv->front_pitch_offset); } else { @@ -1416,12 +1416,12 @@ static void radeon_cp_dispatch_flip(drm_device_t * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle; - int offset = (dev_priv->current_page == 1) + int offset = (dev_priv->sarea_priv->pfCurrentPage == 1) ? dev_priv->front_offset : dev_priv->back_offset; RING_LOCALS; - DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", + DRM_DEBUG("%s: pfCurrentPage=%d\n", __FUNCTION__, - dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage); + dev_priv->sarea_priv->pfCurrentPage); /* Do some trivial performance monitoring... */ @@ -1449,8 +1449,8 @@ static void radeon_cp_dispatch_flip(drm_device_t * dev) * performing the swapbuffer ioctl. */ dev_priv->sarea_priv->last_frame++; - dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page = - 1 - dev_priv->current_page; + dev_priv->sarea_priv->pfCurrentPage = + 1 - dev_priv->sarea_priv->pfCurrentPage; BEGIN_RING(2); @@ -2152,24 +2152,10 @@ static int radeon_do_init_pageflip(drm_device_t * dev) ADVANCE_RING(); dev_priv->page_flipping = 1; - dev_priv->current_page = 0; - dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page; - return 0; -} - -/* Called whenever a client dies, from drm_release. - * NOTE: Lock isn't necessarily held when this is called! - */ -static int radeon_do_cleanup_pageflip(drm_device_t * dev) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - DRM_DEBUG("\n"); - - if (dev_priv->current_page != 0) - radeon_cp_dispatch_flip(dev); + if (dev_priv->sarea_priv->pfCurrentPage != 1) + dev_priv->sarea_priv->pfCurrentPage = 0; - dev_priv->page_flipping = 0; return 0; } @@ -3145,10 +3131,16 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS) break; case RADEON_SETPARAM_PCIGART_LOCATION: dev_priv->pcigart_offset = sp.value; + dev_priv->pcigart_offset_set = 1; break; case RADEON_SETPARAM_NEW_MEMMAP: dev_priv->new_memmap = sp.value; break; + case RADEON_SETPARAM_PCIGART_TABLE_SIZE: + dev_priv->gart_info.table_size = sp.value; + if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE) + dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; + break; default: DRM_DEBUG("Invalid parameter %d\n", sp.param); return DRM_ERR(EINVAL); @@ -3168,9 +3160,7 @@ void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp) { if (dev->dev_private) { drm_radeon_private_t *dev_priv = dev->dev_private; - if (dev_priv->page_flipping) { - radeon_do_cleanup_pageflip(dev); - } + dev_priv->page_flipping = 0; radeon_mem_release(filp, dev_priv->gart_heap); radeon_mem_release(filp, dev_priv->fb_heap); radeon_surfaces_release(filp, dev_priv); @@ -3179,6 +3169,14 @@ void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp) void radeon_driver_lastclose(drm_device_t * dev) { + if (dev->dev_private) { + drm_radeon_private_t *dev_priv = dev->dev_private; + + if (dev_priv->sarea_priv && + dev_priv->sarea_priv->pfCurrentPage != 0) + radeon_cp_dispatch_flip(dev); + } + radeon_do_release(dev); } diff --git a/trunk/drivers/char/drm/sis_drv.c b/trunk/drivers/char/drm/sis_drv.c index 3d5b3218b6ff..690e0af8e7c2 100644 --- a/trunk/drivers/char/drm/sis_drv.c +++ b/trunk/drivers/char/drm/sis_drv.c @@ -71,7 +71,7 @@ static struct drm_driver driver = { .context_dtor = NULL, .dma_quiescent = sis_idle, .reclaim_buffers = NULL, - .reclaim_buffers_locked = sis_reclaim_buffers_locked, + .reclaim_buffers_idlelocked = sis_reclaim_buffers_locked, .lastclose = sis_lastclose, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, diff --git a/trunk/drivers/char/drm/via_dma.c b/trunk/drivers/char/drm/via_dma.c index c0539c6299cf..13a9c5ca4593 100644 --- a/trunk/drivers/char/drm/via_dma.c +++ b/trunk/drivers/char/drm/via_dma.c @@ -252,7 +252,7 @@ static int via_dma_init(DRM_IOCTL_ARGS) break; case VIA_DMA_INITIALIZED: retcode = (dev_priv->ring.virtual_start != NULL) ? - 0 : DRM_ERR(EFAULT); + 0 : DRM_ERR(EFAULT); break; default: retcode = DRM_ERR(EINVAL); @@ -432,56 +432,34 @@ static int via_hook_segment(drm_via_private_t * dev_priv, { int paused, count; volatile uint32_t *paused_at = dev_priv->last_pause_ptr; + uint32_t reader,ptr; + paused = 0; via_flush_write_combine(); - while (!*(via_get_dma(dev_priv) - 1)) ; - *dev_priv->last_pause_ptr = pause_addr_lo; + (void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1); + *paused_at = pause_addr_lo; via_flush_write_combine(); - - /* - * The below statement is inserted to really force the flush. - * Not sure it is needed. - */ - - while (!*dev_priv->last_pause_ptr) ; + (void) *paused_at; + reader = *(dev_priv->hw_addr_ptr); + ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; - while (!*dev_priv->last_pause_ptr) ; - paused = 0; - count = 20; - - while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--) ; - if ((count <= 8) && (count >= 0)) { - uint32_t rgtr, ptr; - rgtr = *(dev_priv->hw_addr_ptr); - ptr = ((volatile char *)dev_priv->last_pause_ptr - - dev_priv->dma_ptr) + dev_priv->dma_offset + - (uint32_t) dev_priv->agpAddr + 4 - CMDBUF_ALIGNMENT_SIZE; - if (rgtr <= ptr) { - DRM_ERROR - ("Command regulator\npaused at count %d, address %x, " - "while current pause address is %x.\n" - "Please mail this message to " - "\n", count, - rgtr, ptr); - } + if ((ptr - reader) <= dev_priv->dma_diff ) { + count = 10000000; + while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--); } if (paused && !no_pci_fire) { - uint32_t rgtr, ptr; - uint32_t ptr_low; + reader = *(dev_priv->hw_addr_ptr); + if ((ptr - reader) == dev_priv->dma_diff) { - count = 1000000; - while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) - && count--) ; + /* + * There is a concern that these writes may stall the PCI bus + * if the GPU is not idle. However, idling the GPU first + * doesn't make a difference. + */ - rgtr = *(dev_priv->hw_addr_ptr); - ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + - dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; - - ptr_low = (ptr > 3 * CMDBUF_ALIGNMENT_SIZE) ? - ptr - 3 * CMDBUF_ALIGNMENT_SIZE : 0; - if (rgtr <= ptr && rgtr >= ptr_low) { VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); @@ -494,6 +472,9 @@ static int via_hook_segment(drm_via_private_t * dev_priv, static int via_wait_idle(drm_via_private_t * dev_priv) { int count = 10000000; + + while (!(VIA_READ(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && count--); + while (count-- && (VIA_READ(VIA_REG_STATUS) & (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY))) ; @@ -537,6 +518,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) uint32_t end_addr, end_addr_lo; uint32_t command; uint32_t agp_base; + uint32_t ptr; + uint32_t reader; + int count; dev_priv->dma_low = 0; @@ -554,7 +538,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) &pause_addr_hi, &pause_addr_lo, 1) - 1; via_flush_write_combine(); - while (!*dev_priv->last_pause_ptr) ; + (void) *(volatile uint32_t *)dev_priv->last_pause_ptr; VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); VIA_WRITE(VIA_REG_TRANSPACE, command); @@ -566,6 +550,24 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) DRM_WRITEMEMORYBARRIER(); VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); VIA_READ(VIA_REG_TRANSPACE); + + dev_priv->dma_diff = 0; + + count = 10000000; + while (!(VIA_READ(0x41c) & 0x80000000) && count--); + + reader = *(dev_priv->hw_addr_ptr); + ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) + + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; + + /* + * This is the difference between where we tell the + * command reader to pause and where it actually pauses. + * This differs between hw implementation so we need to + * detect it. + */ + + dev_priv->dma_diff = ptr - reader; } static void via_pad_cache(drm_via_private_t * dev_priv, int qwords) @@ -592,7 +594,6 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) uint32_t pause_addr_lo, pause_addr_hi; uint32_t jump_addr_lo, jump_addr_hi; volatile uint32_t *last_pause_ptr; - uint32_t dma_low_save1, dma_low_save2; agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, @@ -619,31 +620,11 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) &pause_addr_lo, 0); *last_pause_ptr = pause_addr_lo; - dma_low_save1 = dev_priv->dma_low; - - /* - * Now, set a trap that will pause the regulator if it tries to rerun the old - * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause - * and reissues the jump command over PCI, while the regulator has already taken the jump - * and actually paused at the current buffer end). - * There appears to be no other way to detect this condition, since the hw_addr_pointer - * does not seem to get updated immediately when a jump occurs. - */ - last_pause_ptr = - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, - &pause_addr_lo, 0) - 1; - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, - &pause_addr_lo, 0); - *last_pause_ptr = pause_addr_lo; - - dma_low_save2 = dev_priv->dma_low; - dev_priv->dma_low = dma_low_save1; - via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0); - dev_priv->dma_low = dma_low_save2; - via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0); + via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0); } + static void via_cmdbuf_rewind(drm_via_private_t * dev_priv) { via_cmdbuf_jump(dev_priv); diff --git a/trunk/drivers/char/drm/via_drv.c b/trunk/drivers/char/drm/via_drv.c index bb9dde8b1911..2d4957ab256a 100644 --- a/trunk/drivers/char/drm/via_drv.c +++ b/trunk/drivers/char/drm/via_drv.c @@ -52,7 +52,8 @@ static struct drm_driver driver = { .dma_quiescent = via_driver_dma_quiescent, .dri_library_name = dri_library_name, .reclaim_buffers = drm_core_reclaim_buffers, - .reclaim_buffers_locked = via_reclaim_buffers_locked, + .reclaim_buffers_locked = NULL, + .reclaim_buffers_idlelocked = via_reclaim_buffers_locked, .lastclose = via_lastclose, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, diff --git a/trunk/drivers/char/drm/via_drv.h b/trunk/drivers/char/drm/via_drv.h index 8b8778d4a423..b46ca8e6306d 100644 --- a/trunk/drivers/char/drm/via_drv.h +++ b/trunk/drivers/char/drm/via_drv.h @@ -29,11 +29,11 @@ #define DRIVER_NAME "via" #define DRIVER_DESC "VIA Unichrome / Pro" -#define DRIVER_DATE "20061227" +#define DRIVER_DATE "20070202" #define DRIVER_MAJOR 2 #define DRIVER_MINOR 11 -#define DRIVER_PATCHLEVEL 0 +#define DRIVER_PATCHLEVEL 1 #include "via_verifier.h" @@ -93,6 +93,7 @@ typedef struct drm_via_private { unsigned long vram_offset; unsigned long agp_offset; drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; + uint32_t dma_diff; } drm_via_private_t; enum via_family { diff --git a/trunk/drivers/char/drm/via_mm.h b/trunk/drivers/char/drm/via_mm.h deleted file mode 100644 index d57efda57c76..000000000000 --- a/trunk/drivers/char/drm/via_mm.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. - * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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 _via_drm_mm_h_ -#define _via_drm_mm_h_ - -typedef struct { - unsigned int context; - unsigned int size; - unsigned long offset; - unsigned long free; -} drm_via_mm_t; - -typedef struct { - unsigned int size; - unsigned long handle; - void *virtual; -} drm_via_dma_t; - -#endif diff --git a/trunk/drivers/char/ds1620.c b/trunk/drivers/char/ds1620.c index 3d7efc26aad6..334ad5bbe6b6 100644 --- a/trunk/drivers/char/ds1620.c +++ b/trunk/drivers/char/ds1620.c @@ -4,7 +4,6 @@ */ #include #include -#include #include #include #include diff --git a/trunk/drivers/char/dsp56k.c b/trunk/drivers/char/dsp56k.c index db984e481d4c..9b8278e1f4f8 100644 --- a/trunk/drivers/char/dsp56k.c +++ b/trunk/drivers/char/dsp56k.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/char/dtlk.c b/trunk/drivers/char/dtlk.c index d8dbdb916232..abde6ddefe69 100644 --- a/trunk/drivers/char/dtlk.c +++ b/trunk/drivers/char/dtlk.c @@ -62,7 +62,6 @@ #include /* for __init, module_{init,exit} */ #include /* for POLLIN, etc. */ #include /* local header file for DoubleTalk values */ -#include #ifdef TRACING #define TRACE_TEXT(str) printk(str); @@ -325,16 +324,22 @@ static int dtlk_release(struct inode *inode, struct file *file) static int __init dtlk_init(void) { + int err; + dtlk_port_lpc = 0; dtlk_port_tts = 0; dtlk_busy = 0; dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops); - if (dtlk_major == 0) { + if (dtlk_major < 0) { printk(KERN_ERR "DoubleTalk PC - cannot register device\n"); - return 0; + return dtlk_major; + } + err = dtlk_dev_probe(); + if (err) { + unregister_chrdev(dtlk_major, "dtlk"); + return err; } - if (dtlk_dev_probe() == 0) - printk(", MAJOR %d\n", dtlk_major); + printk(", MAJOR %d\n", dtlk_major); init_waitqueue_head(&dtlk_process_list); diff --git a/trunk/drivers/char/ec3104_keyb.c b/trunk/drivers/char/ec3104_keyb.c index 77f58ed6d59a..020011495d91 100644 --- a/trunk/drivers/char/ec3104_keyb.c +++ b/trunk/drivers/char/ec3104_keyb.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/char/epca.c b/trunk/drivers/char/epca.c index de5be30484ad..c6c56fb8ba50 100644 --- a/trunk/drivers/char/epca.c +++ b/trunk/drivers/char/epca.c @@ -949,7 +949,7 @@ static int block_til_ready(struct tty_struct *tty, } /* End forever while */ - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&ch->open_wait, &wait); if (!tty_hung_up_p(filp)) ch->count++; diff --git a/trunk/drivers/char/genrtc.c b/trunk/drivers/char/genrtc.c index 23b25ada65ea..49f914e79216 100644 --- a/trunk/drivers/char/genrtc.c +++ b/trunk/drivers/char/genrtc.c @@ -207,7 +207,7 @@ static ssize_t gen_rtc_read(struct file *file, char __user *buf, sizeof(unsigned long); } out: - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&gen_rtc_wait, &wait); return retval; diff --git a/trunk/drivers/char/hangcheck-timer.c b/trunk/drivers/char/hangcheck-timer.c index ae76a9ffe89f..f0e7263dfcde 100644 --- a/trunk/drivers/char/hangcheck-timer.c +++ b/trunk/drivers/char/hangcheck-timer.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/char/hvc_console.c b/trunk/drivers/char/hvc_console.c index 0f9ed7b46a6d..322bc5f7d86b 100644 --- a/trunk/drivers/char/hvc_console.c +++ b/trunk/drivers/char/hvc_console.c @@ -111,7 +111,7 @@ static int last_hvc = -1; * lock held. If successful, this function increments the kobject reference * count against the target hvc_struct so it should be released when finished. */ -struct hvc_struct *hvc_get_by_index(int index) +static struct hvc_struct *hvc_get_by_index(int index) { struct hvc_struct *hp; unsigned long flags; @@ -150,7 +150,8 @@ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = * hvc_console_setup() finds adapters. */ -void hvc_console_print(struct console *co, const char *b, unsigned count) +static void hvc_console_print(struct console *co, const char *b, + unsigned count) { char c[N_OUTBUF] __ALIGNED__; unsigned i = 0, n = 0; @@ -208,7 +209,7 @@ static int __init hvc_console_setup(struct console *co, char *options) return 0; } -struct console hvc_con_driver = { +static struct console hvc_con_driver = { .name = "hvc", .write = hvc_console_print, .device = hvc_console_device, @@ -278,7 +279,6 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) return 0; } -EXPORT_SYMBOL(hvc_instantiate); /* Wake the sleeping khvcd */ static void hvc_kick(void) @@ -792,7 +792,6 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, return hp; } -EXPORT_SYMBOL(hvc_alloc); int __devexit hvc_remove(struct hvc_struct *hp) { @@ -828,11 +827,10 @@ int __devexit hvc_remove(struct hvc_struct *hp) tty_hangup(tty); return 0; } -EXPORT_SYMBOL(hvc_remove); /* Driver initialization. Follow console initialization. This is where the TTY * interfaces start to become available. */ -int __init hvc_init(void) +static int __init hvc_init(void) { struct tty_driver *drv; diff --git a/trunk/drivers/char/hvc_iseries.c b/trunk/drivers/char/hvc_iseries.c index ec420fe8a908..b37f1d5a5be6 100644 --- a/trunk/drivers/char/hvc_iseries.c +++ b/trunk/drivers/char/hvc_iseries.c @@ -579,7 +579,7 @@ static int hvc_find_vtys(void) if (!vtermno) continue; - if (!device_is_compatible(vty, "IBM,iSeries-vty")) + if (!of_device_is_compatible(vty, "IBM,iSeries-vty")) continue; if (num_found == 0) diff --git a/trunk/drivers/char/hvc_vio.c b/trunk/drivers/char/hvc_vio.c index 94a542e20efb..79711aa4b41d 100644 --- a/trunk/drivers/char/hvc_vio.c +++ b/trunk/drivers/char/hvc_vio.c @@ -157,7 +157,7 @@ static int hvc_find_vtys(void) if (!vtermno) continue; - if (device_is_compatible(vty, "hvterm1")) { + if (of_device_is_compatible(vty, "hvterm1")) { hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops); ++num_found; } diff --git a/trunk/drivers/char/hw_random/intel-rng.c b/trunk/drivers/char/hw_random/intel-rng.c index cc1046e6ee02..4ae9811d1a6c 100644 --- a/trunk/drivers/char/hw_random/intel-rng.c +++ b/trunk/drivers/char/hw_random/intel-rng.c @@ -24,10 +24,11 @@ * warranty of any kind, whether express or implied. */ -#include +#include #include +#include #include -#include +#include #include @@ -217,30 +218,117 @@ static struct hwrng intel_rng = { .data_read = intel_rng_data_read, }; +struct intel_rng_hw { + struct pci_dev *dev; + void __iomem *mem; + u8 bios_cntl_off; + u8 bios_cntl_val; + u8 fwh_dec_en1_off; + u8 fwh_dec_en1_val; +}; -#ifdef CONFIG_SMP -static char __initdata waitflag; +static int __init intel_rng_hw_init(void *_intel_rng_hw) +{ + struct intel_rng_hw *intel_rng_hw = _intel_rng_hw; + u8 mfc, dvc; + + /* interrupts disabled in stop_machine_run call */ + + if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK)) + pci_write_config_byte(intel_rng_hw->dev, + intel_rng_hw->fwh_dec_en1_off, + intel_rng_hw->fwh_dec_en1_val | + FWH_F8_EN_MASK); + if (!(intel_rng_hw->bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK)) + pci_write_config_byte(intel_rng_hw->dev, + intel_rng_hw->bios_cntl_off, + intel_rng_hw->bios_cntl_val | + BIOS_CNTL_WRITE_ENABLE_MASK); + + writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem); + writeb(INTEL_FWH_READ_ID_CMD, intel_rng_hw->mem); + mfc = readb(intel_rng_hw->mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS); + dvc = readb(intel_rng_hw->mem + INTEL_FWH_DEVICE_CODE_ADDRESS); + writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem); + + if (!(intel_rng_hw->bios_cntl_val & + (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))) + pci_write_config_byte(intel_rng_hw->dev, + intel_rng_hw->bios_cntl_off, + intel_rng_hw->bios_cntl_val); + if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK)) + pci_write_config_byte(intel_rng_hw->dev, + intel_rng_hw->fwh_dec_en1_off, + intel_rng_hw->fwh_dec_en1_val); -static void __init intel_init_wait(void *unused) + if (mfc != INTEL_FWH_MANUFACTURER_CODE || + (dvc != INTEL_FWH_DEVICE_CODE_8M && + dvc != INTEL_FWH_DEVICE_CODE_4M)) { + printk(KERN_ERR PFX "FWH not detected\n"); + return -ENODEV; + } + + return 0; +} + +static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw, + struct pci_dev *dev) { - while (waitflag) - cpu_relax(); + intel_rng_hw->bios_cntl_val = 0xff; + intel_rng_hw->fwh_dec_en1_val = 0xff; + intel_rng_hw->dev = dev; + + /* Check for Intel 82802 */ + if (dev->device < 0x2640) { + intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD; + intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_OLD; + } else { + intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW; + intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_NEW; + } + + pci_read_config_byte(dev, intel_rng_hw->fwh_dec_en1_off, + &intel_rng_hw->fwh_dec_en1_val); + pci_read_config_byte(dev, intel_rng_hw->bios_cntl_off, + &intel_rng_hw->bios_cntl_val); + + if ((intel_rng_hw->bios_cntl_val & + (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)) + == BIOS_CNTL_LOCK_ENABLE_MASK) { + static __initdata /*const*/ char warning[] = + KERN_WARNING PFX "Firmware space is locked read-only. " + KERN_WARNING PFX "If you can't or\n don't want to " + KERN_WARNING PFX "disable this in firmware setup, and " + KERN_WARNING PFX "if\n you are certain that your " + KERN_WARNING PFX "system has a functional\n RNG, try" + KERN_WARNING PFX "using the 'no_fwh_detect' option.\n"; + + if (no_fwh_detect) + return -ENODEV; + printk(warning); + return -EBUSY; + } + + intel_rng_hw->mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN); + if (intel_rng_hw->mem == NULL) + return -EBUSY; + + return 0; } -#endif + static int __init mod_init(void) { int err = -ENODEV; - unsigned i; + int i; struct pci_dev *dev = NULL; - void __iomem *mem; - unsigned long flags; - u8 bios_cntl_off, fwh_dec_en1_off; - u8 bios_cntl_val = 0xff, fwh_dec_en1_val = 0xff; - u8 hw_status, mfc, dvc; + void __iomem *mem = mem; + u8 hw_status; + struct intel_rng_hw *intel_rng_hw; for (i = 0; !dev && pci_tbl[i].vendor; ++i) - dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, NULL); + dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, + NULL); if (!dev) goto out; /* Device not found. */ @@ -250,39 +338,18 @@ static int __init mod_init(void) goto fwh_done; } - /* Check for Intel 82802 */ - if (dev->device < 0x2640) { - fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD; - bios_cntl_off = BIOS_CNTL_REG_OLD; - } else { - fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW; - bios_cntl_off = BIOS_CNTL_REG_NEW; - } - - pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val); - pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val); - - if ((bios_cntl_val & - (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)) - == BIOS_CNTL_LOCK_ENABLE_MASK) { - static __initdata /*const*/ char warning[] = - KERN_WARNING PFX "Firmware space is locked read-only. If you can't or\n" - KERN_WARNING PFX "don't want to disable this in firmware setup, and if\n" - KERN_WARNING PFX "you are certain that your system has a functional\n" - KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n"; - + intel_rng_hw = kmalloc(sizeof(*intel_rng_hw), GFP_KERNEL); + if (!intel_rng_hw) { pci_dev_put(dev); - if (no_fwh_detect) - goto fwh_done; - printk(warning); - err = -EBUSY; goto out; } - mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN); - if (mem == NULL) { + err = intel_init_hw_struct(intel_rng_hw, dev); + if (err) { pci_dev_put(dev); - err = -EBUSY; + kfree(intel_rng_hw); + if (err == -ENODEV) + goto fwh_done; goto out; } @@ -290,59 +357,18 @@ static int __init mod_init(void) * Since the BIOS code/data is going to disappear from its normal * location with the Read ID command, all activity on the system * must be stopped until the state is back to normal. + * + * Use stop_machine_run because IPIs can be blocked by disabling + * interrupts. */ -#ifdef CONFIG_SMP - set_mb(waitflag, 1); - if (smp_call_function(intel_init_wait, NULL, 1, 0) != 0) { - set_mb(waitflag, 0); - pci_dev_put(dev); - printk(KERN_ERR PFX "cannot run on all processors\n"); - err = -EAGAIN; - goto err_unmap; - } -#endif - local_irq_save(flags); - - if (!(fwh_dec_en1_val & FWH_F8_EN_MASK)) - pci_write_config_byte(dev, - fwh_dec_en1_off, - fwh_dec_en1_val | FWH_F8_EN_MASK); - if (!(bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK)) - pci_write_config_byte(dev, - bios_cntl_off, - bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK); - - writeb(INTEL_FWH_RESET_CMD, mem); - writeb(INTEL_FWH_READ_ID_CMD, mem); - mfc = readb(mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS); - dvc = readb(mem + INTEL_FWH_DEVICE_CODE_ADDRESS); - writeb(INTEL_FWH_RESET_CMD, mem); - - if (!(bios_cntl_val & - (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))) - pci_write_config_byte(dev, bios_cntl_off, bios_cntl_val); - if (!(fwh_dec_en1_val & FWH_F8_EN_MASK)) - pci_write_config_byte(dev, fwh_dec_en1_off, fwh_dec_en1_val); - - local_irq_restore(flags); -#ifdef CONFIG_SMP - /* Tell other CPUs to resume. */ - set_mb(waitflag, 0); -#endif - - iounmap(mem); + err = stop_machine_run(intel_rng_hw_init, intel_rng_hw, NR_CPUS); pci_dev_put(dev); - - if (mfc != INTEL_FWH_MANUFACTURER_CODE || - (dvc != INTEL_FWH_DEVICE_CODE_8M && - dvc != INTEL_FWH_DEVICE_CODE_4M)) { - printk(KERN_ERR PFX "FWH not detected\n"); - err = -ENODEV; + iounmap(intel_rng_hw->mem); + kfree(intel_rng_hw); + if (err) goto out; - } fwh_done: - err = -ENOMEM; mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); if (!mem) @@ -352,22 +378,21 @@ static int __init mod_init(void) /* Check for Random Number Generator */ err = -ENODEV; hw_status = hwstatus_get(mem); - if ((hw_status & INTEL_RNG_PRESENT) == 0) - goto err_unmap; + if ((hw_status & INTEL_RNG_PRESENT) == 0) { + iounmap(mem); + goto out; + } printk(KERN_INFO "Intel 82802 RNG detected\n"); err = hwrng_register(&intel_rng); if (err) { printk(KERN_ERR PFX "RNG registering failed (%d)\n", err); - goto err_unmap; + iounmap(mem); } out: return err; -err_unmap: - iounmap(mem); - goto out; } static void __exit mod_exit(void) diff --git a/trunk/drivers/char/i8k.c b/trunk/drivers/char/i8k.c index 353d9f3cf8d7..0289705967de 100644 --- a/trunk/drivers/char/i8k.c +++ b/trunk/drivers/char/i8k.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/char/ip27-rtc.c b/trunk/drivers/char/ip27-rtc.c index a48da02aad2f..932264a657d0 100644 --- a/trunk/drivers/char/ip27-rtc.c +++ b/trunk/drivers/char/ip27-rtc.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/char/ipmi/ipmi_si_intf.c b/trunk/drivers/char/ipmi/ipmi_si_intf.c index e22146546add..6c5d15de3317 100644 --- a/trunk/drivers/char/ipmi/ipmi_si_intf.c +++ b/trunk/drivers/char/ipmi/ipmi_si_intf.c @@ -9,6 +9,7 @@ * source@mvista.com * * Copyright 2002 MontaVista Software Inc. + * Copyright 2006 IBM Corp., Christian Krafft * * 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 @@ -64,6 +65,11 @@ #include #include +#ifdef CONFIG_PPC_OF +#include +#include +#endif + #define PFX "ipmi_si: " /* Measure times between events in the driver. */ @@ -76,6 +82,12 @@ #define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a short timeout */ +/* Bit for BMC global enables. */ +#define IPMI_BMC_RCV_MSG_INTR 0x01 +#define IPMI_BMC_EVT_MSG_INTR 0x02 +#define IPMI_BMC_EVT_MSG_BUFF 0x04 +#define IPMI_BMC_SYS_LOG 0x08 + enum si_intf_state { SI_NORMAL, SI_GETTING_FLAGS, @@ -84,7 +96,9 @@ enum si_intf_state { SI_CLEARING_FLAGS_THEN_SET_IRQ, SI_GETTING_MESSAGES, SI_ENABLE_INTERRUPTS1, - SI_ENABLE_INTERRUPTS2 + SI_ENABLE_INTERRUPTS2, + SI_DISABLE_INTERRUPTS1, + SI_DISABLE_INTERRUPTS2 /* FIXME - add watchdog stuff. */ }; @@ -333,6 +347,17 @@ static void start_enable_irq(struct smi_info *smi_info) smi_info->si_state = SI_ENABLE_INTERRUPTS1; } +static void start_disable_irq(struct smi_info *smi_info) +{ + unsigned char msg[2]; + + msg[0] = (IPMI_NETFN_APP_REQUEST << 2); + msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; + + smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); + smi_info->si_state = SI_DISABLE_INTERRUPTS1; +} + static void start_clear_flags(struct smi_info *smi_info) { unsigned char msg[3]; @@ -353,7 +378,7 @@ static void start_clear_flags(struct smi_info *smi_info) static inline void disable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { - disable_irq_nosync(smi_info->irq); + start_disable_irq(smi_info); smi_info->interrupt_disabled = 1; } } @@ -361,7 +386,7 @@ static inline void disable_si_irq(struct smi_info *smi_info) static inline void enable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (smi_info->interrupt_disabled)) { - enable_irq(smi_info->irq); + start_enable_irq(smi_info); smi_info->interrupt_disabled = 0; } } @@ -583,7 +608,9 @@ static void handle_transaction_done(struct smi_info *smi_info) } else { msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; - msg[2] = msg[3] | 1; /* enable msg queue int */ + msg[2] = (msg[3] | + IPMI_BMC_RCV_MSG_INTR | + IPMI_BMC_EVT_MSG_INTR); smi_info->handlers->start_transaction( smi_info->si_sm, msg, 3); smi_info->si_state = SI_ENABLE_INTERRUPTS2; @@ -605,6 +632,45 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->si_state = SI_NORMAL; break; } + + case SI_DISABLE_INTERRUPTS1: + { + unsigned char msg[4]; + + /* We got the flags from the SMI, now handle them. */ + smi_info->handlers->get_result(smi_info->si_sm, msg, 4); + if (msg[2] != 0) { + printk(KERN_WARNING + "ipmi_si: Could not disable interrupts" + ", failed get.\n"); + smi_info->si_state = SI_NORMAL; + } else { + msg[0] = (IPMI_NETFN_APP_REQUEST << 2); + msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; + msg[2] = (msg[3] & + ~(IPMI_BMC_RCV_MSG_INTR | + IPMI_BMC_EVT_MSG_INTR)); + smi_info->handlers->start_transaction( + smi_info->si_sm, msg, 3); + smi_info->si_state = SI_DISABLE_INTERRUPTS2; + } + break; + } + + case SI_DISABLE_INTERRUPTS2: + { + unsigned char msg[4]; + + /* We got the flags from the SMI, now handle them. */ + smi_info->handlers->get_result(smi_info->si_sm, msg, 4); + if (msg[2] != 0) { + printk(KERN_WARNING + "ipmi_si: Could not disable interrupts" + ", failed set.\n"); + } + smi_info->si_state = SI_NORMAL; + break; + } } } @@ -858,9 +924,6 @@ static void smi_timeout(unsigned long data) struct timeval t; #endif - if (atomic_read(&smi_info->stop_operation)) - return; - spin_lock_irqsave(&(smi_info->si_lock), flags); #ifdef DEBUG_TIMING do_gettimeofday(&t); @@ -916,15 +979,11 @@ static irqreturn_t si_irq_handler(int irq, void *data) smi_info->interrupts++; spin_unlock(&smi_info->count_lock); - if (atomic_read(&smi_info->stop_operation)) - goto out; - #ifdef DEBUG_TIMING do_gettimeofday(&t); printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif smi_event_handler(smi_info, 0); - out: spin_unlock_irqrestore(&(smi_info->si_lock), flags); return IRQ_HANDLED; } @@ -1006,6 +1065,7 @@ static DEFINE_MUTEX(smi_infos_lock); static int smi_num; /* Used to sequence the SMIs */ #define DEFAULT_REGSPACING 1 +#define DEFAULT_REGSIZE 1 static int si_trydefaults = 1; static char *si_type[SI_MAX_PARMS]; @@ -1111,7 +1171,7 @@ static int std_irq_setup(struct smi_info *info) if (info->si_type == SI_BT) { rv = request_irq(info->irq, si_bt_irq_handler, - IRQF_DISABLED, + IRQF_SHARED | IRQF_DISABLED, DEVICE_NAME, info); if (!rv) @@ -1121,7 +1181,7 @@ static int std_irq_setup(struct smi_info *info) } else rv = request_irq(info->irq, si_irq_handler, - IRQF_DISABLED, + IRQF_SHARED | IRQF_DISABLED, DEVICE_NAME, info); if (rv) { @@ -1701,15 +1761,11 @@ static u32 ipmi_acpi_gpe(void *context) smi_info->interrupts++; spin_unlock(&smi_info->count_lock); - if (atomic_read(&smi_info->stop_operation)) - goto out; - #ifdef DEBUG_TIMING do_gettimeofday(&t); printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif smi_event_handler(smi_info, 0); - out: spin_unlock_irqrestore(&(smi_info->si_lock), flags); return ACPI_INTERRUPT_HANDLED; @@ -2133,12 +2189,15 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, info->irq_setup = std_irq_setup; info->dev = &pdev->dev; + pci_set_drvdata(pdev, info); return try_smi_init(info); } static void __devexit ipmi_pci_remove(struct pci_dev *pdev) { + struct smi_info *info = pci_get_drvdata(pdev); + cleanup_one_si(info); } #ifdef CONFIG_PM @@ -2172,6 +2231,99 @@ static struct pci_driver ipmi_pci_driver = { #endif /* CONFIG_PCI */ +#ifdef CONFIG_PPC_OF +static int __devinit ipmi_of_probe(struct of_device *dev, + const struct of_device_id *match) +{ + struct smi_info *info; + struct resource resource; + const int *regsize, *regspacing, *regshift; + struct device_node *np = dev->node; + int ret; + int proplen; + + dev_info(&dev->dev, PFX "probing via device tree\n"); + + ret = of_address_to_resource(np, 0, &resource); + if (ret) { + dev_warn(&dev->dev, PFX "invalid address from OF\n"); + return ret; + } + + regsize = get_property(np, "reg-size", &proplen); + if (regsize && proplen != 4) { + dev_warn(&dev->dev, PFX "invalid regsize from OF\n"); + return -EINVAL; + } + + regspacing = get_property(np, "reg-spacing", &proplen); + if (regspacing && proplen != 4) { + dev_warn(&dev->dev, PFX "invalid regspacing from OF\n"); + return -EINVAL; + } + + regshift = get_property(np, "reg-shift", &proplen); + if (regshift && proplen != 4) { + dev_warn(&dev->dev, PFX "invalid regshift from OF\n"); + return -EINVAL; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + + if (!info) { + dev_err(&dev->dev, + PFX "could not allocate memory for OF probe\n"); + return -ENOMEM; + } + + info->si_type = (enum si_type) match->data; + info->addr_source = "device-tree"; + info->io_setup = mem_setup; + info->irq_setup = std_irq_setup; + + info->io.addr_type = IPMI_MEM_ADDR_SPACE; + info->io.addr_data = resource.start; + + info->io.regsize = regsize ? *regsize : DEFAULT_REGSIZE; + info->io.regspacing = regspacing ? *regspacing : DEFAULT_REGSPACING; + info->io.regshift = regshift ? *regshift : 0; + + info->irq = irq_of_parse_and_map(dev->node, 0); + info->dev = &dev->dev; + + dev_dbg(&dev->dev, "addr 0x%lx regsize %ld spacing %ld irq %x\n", + info->io.addr_data, info->io.regsize, info->io.regspacing, + info->irq); + + dev->dev.driver_data = (void*) info; + + return try_smi_init(info); +} + +static int __devexit ipmi_of_remove(struct of_device *dev) +{ + cleanup_one_si(dev->dev.driver_data); + return 0; +} + +static struct of_device_id ipmi_match[] = +{ + { .type = "ipmi", .compatible = "ipmi-kcs", .data = (void *)(unsigned long) SI_KCS }, + { .type = "ipmi", .compatible = "ipmi-smic", .data = (void *)(unsigned long) SI_SMIC }, + { .type = "ipmi", .compatible = "ipmi-bt", .data = (void *)(unsigned long) SI_BT }, + {}, +}; + +static struct of_platform_driver ipmi_of_platform_driver = +{ + .name = "ipmi", + .match_table = ipmi_match, + .probe = ipmi_of_probe, + .remove = __devexit_p(ipmi_of_remove), +}; +#endif /* CONFIG_PPC_OF */ + + static int try_get_dev_id(struct smi_info *smi_info) { unsigned char msg[2]; @@ -2801,6 +2953,10 @@ static __devinit int init_ipmi_si(void) } #endif +#ifdef CONFIG_PPC_OF + of_register_platform_driver(&ipmi_of_platform_driver); +#endif + if (si_trydefaults) { mutex_lock(&smi_infos_lock); if (list_empty(&smi_infos)) { @@ -2838,28 +2994,33 @@ static void cleanup_one_si(struct smi_info *to_clean) list_del(&to_clean->link); - /* Tell the timer and interrupt handlers that we are shutting - down. */ - spin_lock_irqsave(&(to_clean->si_lock), flags); - spin_lock(&(to_clean->msg_lock)); - + /* Tell the driver that we are shutting down. */ atomic_inc(&to_clean->stop_operation); - if (to_clean->irq_cleanup) - to_clean->irq_cleanup(to_clean); - - spin_unlock(&(to_clean->msg_lock)); - spin_unlock_irqrestore(&(to_clean->si_lock), flags); - - /* Wait until we know that we are out of any interrupt - handlers might have been running before we freed the - interrupt. */ - synchronize_sched(); - + /* Make sure the timer and thread are stopped and will not run + again. */ wait_for_timer_and_thread(to_clean); - /* Interrupts and timeouts are stopped, now make sure the - interface is in a clean state. */ + /* Timeouts are stopped, now make sure the interrupts are off + for the device. A little tricky with locks to make sure + there are no races. */ + spin_lock_irqsave(&to_clean->si_lock, flags); + while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { + spin_unlock_irqrestore(&to_clean->si_lock, flags); + poll(to_clean); + schedule_timeout_uninterruptible(1); + spin_lock_irqsave(&to_clean->si_lock, flags); + } + disable_si_irq(to_clean); + spin_unlock_irqrestore(&to_clean->si_lock, flags); + while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { + poll(to_clean); + schedule_timeout_uninterruptible(1); + } + + /* Clean up interrupts and make sure that everything is done. */ + if (to_clean->irq_cleanup) + to_clean->irq_cleanup(to_clean); while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); schedule_timeout_uninterruptible(1); @@ -2898,6 +3059,10 @@ static __exit void cleanup_ipmi_si(void) pci_unregister_driver(&ipmi_pci_driver); #endif +#ifdef CONFIG_PPC_OF + of_unregister_platform_driver(&ipmi_of_platform_driver); +#endif + mutex_lock(&smi_infos_lock); list_for_each_entry_safe(e, tmp_e, &smi_infos, link) cleanup_one_si(e); diff --git a/trunk/drivers/char/ipmi/ipmi_watchdog.c b/trunk/drivers/char/ipmi/ipmi_watchdog.c index 6b634e8d9519..147c12047cf3 100644 --- a/trunk/drivers/char/ipmi/ipmi_watchdog.c +++ b/trunk/drivers/char/ipmi/ipmi_watchdog.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -49,9 +50,18 @@ #include #include #include +#include #include -#ifdef CONFIG_X86_LOCAL_APIC -#include + +#ifdef CONFIG_X86 +/* This is ugly, but I've determined that x86 is the only architecture + that can reasonably support the IPMI NMI watchdog timeout at this + time. If another architecture adds this capability somehow, it + will have to be a somewhat different mechanism and I have no idea + how it will work. So in the unlikely event that another + architecture supports this, we can figure out a good generic + mechanism for it at that time. */ +#define HAVE_DIE_NMI_POST #endif #define PFX "IPMI Watchdog: " @@ -317,6 +327,11 @@ static unsigned char ipmi_version_minor; /* If a pretimeout occurs, this is used to allow only one panic to happen. */ static atomic_t preop_panic_excl = ATOMIC_INIT(-1); +#ifdef HAVE_DIE_NMI_POST +static int testing_nmi; +static int nmi_handler_registered; +#endif + static int ipmi_heartbeat(void); static void panic_halt_ipmi_heartbeat(void); @@ -358,6 +373,10 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, int hbnow = 0; + /* These can be cleared as we are setting the timeout. */ + ipmi_start_timer_on_heartbeat = 0; + pretimeout_since_last_heartbeat = 0; + data[0] = 0; WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); @@ -432,13 +451,12 @@ static int ipmi_set_timeout(int do_heartbeat) wait_for_completion(&set_timeout_wait); + mutex_unlock(&set_timeout_lock); + if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) || ((send_heartbeat_now) && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) - { rv = ipmi_heartbeat(); - } - mutex_unlock(&set_timeout_lock); out: return rv; @@ -518,12 +536,10 @@ static int ipmi_heartbeat(void) int rv; struct ipmi_system_interface_addr addr; - if (ipmi_ignore_heartbeat) { + if (ipmi_ignore_heartbeat) return 0; - } if (ipmi_start_timer_on_heartbeat) { - ipmi_start_timer_on_heartbeat = 0; ipmi_watchdog_state = action_val; return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); } else if (pretimeout_since_last_heartbeat) { @@ -531,7 +547,6 @@ static int ipmi_heartbeat(void) We don't want to set the action, though, we want to leave that alone (thus it can't be combined with the above operation. */ - pretimeout_since_last_heartbeat = 0; return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); } @@ -919,6 +934,45 @@ static void ipmi_register_watchdog(int ipmi_intf) printk(KERN_CRIT PFX "Unable to register misc device\n"); } +#ifdef HAVE_DIE_NMI_POST + if (nmi_handler_registered) { + int old_pretimeout = pretimeout; + int old_timeout = timeout; + int old_preop_val = preop_val; + + /* Set the pretimeout to go off in a second and give + ourselves plenty of time to stop the timer. */ + ipmi_watchdog_state = WDOG_TIMEOUT_RESET; + preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */ + pretimeout = 99; + timeout = 100; + + testing_nmi = 1; + + rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); + if (rv) { + printk(KERN_WARNING PFX "Error starting timer to" + " test NMI: 0x%x. The NMI pretimeout will" + " likely not work\n", rv); + rv = 0; + goto out_restore; + } + + msleep(1500); + + if (testing_nmi != 2) { + printk(KERN_WARNING PFX "IPMI NMI didn't seem to" + " occur. The NMI pretimeout will" + " likely not work\n"); + } + out_restore: + testing_nmi = 0; + preop_val = old_preop_val; + pretimeout = old_pretimeout; + timeout = old_timeout; + } +#endif + out: up_write(®ister_sem); @@ -928,6 +982,10 @@ static void ipmi_register_watchdog(int ipmi_intf) ipmi_watchdog_state = action_val; ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); printk(KERN_INFO PFX "Starting now!\n"); + } else { + /* Stop the timer now. */ + ipmi_watchdog_state = WDOG_TIMEOUT_NONE; + ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); } } @@ -964,17 +1022,28 @@ static void ipmi_unregister_watchdog(int ipmi_intf) up_write(®ister_sem); } -#ifdef HAVE_NMI_HANDLER +#ifdef HAVE_DIE_NMI_POST static int -ipmi_nmi(void *dev_id, int cpu, int handled) +ipmi_nmi(struct notifier_block *self, unsigned long val, void *data) { + if (val != DIE_NMI_POST) + return NOTIFY_OK; + + if (testing_nmi) { + testing_nmi = 2; + return NOTIFY_STOP; + } + /* If we are not expecting a timeout, ignore it. */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) - return NOTIFY_DONE; + return NOTIFY_OK; + + if (preaction_val != WDOG_PRETIMEOUT_NMI) + return NOTIFY_OK; /* If no one else handled the NMI, we assume it was the IPMI watchdog. */ - if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) { + if (preop_val == WDOG_PREOP_PANIC) { /* On some machines, the heartbeat will give an error and not work unless we re-enable the timer. So do so. */ @@ -983,18 +1052,12 @@ ipmi_nmi(void *dev_id, int cpu, int handled) panic(PFX "pre-timeout"); } - return NOTIFY_DONE; + return NOTIFY_STOP; } -static struct nmi_handler ipmi_nmi_handler = -{ - .link = LIST_HEAD_INIT(ipmi_nmi_handler.link), - .dev_name = "ipmi_watchdog", - .dev_id = NULL, - .handler = ipmi_nmi, - .priority = 0, /* Call us last. */ +static struct notifier_block ipmi_nmi_handler = { + .notifier_call = ipmi_nmi }; -int nmi_handler_registered; #endif static int wdog_reboot_handler(struct notifier_block *this, @@ -1111,7 +1174,7 @@ static int preaction_op(const char *inval, char *outval) preaction_val = WDOG_PRETIMEOUT_NONE; else if (strcmp(inval, "pre_smi") == 0) preaction_val = WDOG_PRETIMEOUT_SMI; -#ifdef HAVE_NMI_HANDLER +#ifdef HAVE_DIE_NMI_POST else if (strcmp(inval, "pre_nmi") == 0) preaction_val = WDOG_PRETIMEOUT_NMI; #endif @@ -1145,7 +1208,7 @@ static int preop_op(const char *inval, char *outval) static void check_parms(void) { -#ifdef HAVE_NMI_HANDLER +#ifdef HAVE_DIE_NMI_POST int do_nmi = 0; int rv; @@ -1158,20 +1221,9 @@ static void check_parms(void) preop_op("preop_none", NULL); do_nmi = 0; } -#ifdef CONFIG_X86_LOCAL_APIC - if (nmi_watchdog == NMI_IO_APIC) { - printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC" - " mode (value is %d), that is incompatible" - " with using NMI in the IPMI watchdog." - " Disabling IPMI nmi pretimeout.\n", - nmi_watchdog); - preaction_val = WDOG_PRETIMEOUT_NONE; - do_nmi = 0; - } -#endif } if (do_nmi && !nmi_handler_registered) { - rv = request_nmi(&ipmi_nmi_handler); + rv = register_die_notifier(&ipmi_nmi_handler); if (rv) { printk(KERN_WARNING PFX "Can't register nmi handler\n"); @@ -1179,7 +1231,7 @@ static void check_parms(void) } else nmi_handler_registered = 1; } else if (!do_nmi && nmi_handler_registered) { - release_nmi(&ipmi_nmi_handler); + unregister_die_notifier(&ipmi_nmi_handler); nmi_handler_registered = 0; } #endif @@ -1215,9 +1267,9 @@ static int __init ipmi_wdog_init(void) rv = ipmi_smi_watcher_register(&smi_watcher); if (rv) { -#ifdef HAVE_NMI_HANDLER - if (preaction_val == WDOG_PRETIMEOUT_NMI) - release_nmi(&ipmi_nmi_handler); +#ifdef HAVE_DIE_NMI_POST + if (nmi_handler_registered) + unregister_die_notifier(&ipmi_nmi_handler); #endif atomic_notifier_chain_unregister(&panic_notifier_list, &wdog_panic_notifier); @@ -1236,9 +1288,9 @@ static void __exit ipmi_wdog_exit(void) ipmi_smi_watcher_unregister(&smi_watcher); ipmi_unregister_watchdog(watchdog_ifnum); -#ifdef HAVE_NMI_HANDLER +#ifdef HAVE_DIE_NMI_POST if (nmi_handler_registered) - release_nmi(&ipmi_nmi_handler); + unregister_die_notifier(&ipmi_nmi_handler); #endif atomic_notifier_chain_unregister(&panic_notifier_list, diff --git a/trunk/drivers/char/isicom.c b/trunk/drivers/char/isicom.c index 43ab9edc76f5..761f77740d67 100644 --- a/trunk/drivers/char/isicom.c +++ b/trunk/drivers/char/isicom.c @@ -137,11 +137,10 @@ #define InterruptTheCard(base) outw(0, (base) + 0xc) #define ClearInterrupt(base) inw((base) + 0x0a) +#define pr_dbg(str...) pr_debug("ISICOM: " str) #ifdef DEBUG -#define pr_dbg(str...) printk(KERN_DEBUG "ISICOM: " str) #define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c)) #else -#define pr_dbg(str...) do { } while (0) #define isicom_paranoia_check(a, b, c) 0 #endif diff --git a/trunk/drivers/char/keyboard.c b/trunk/drivers/char/keyboard.c index c06e86ad1dab..1b094509b1d2 100644 --- a/trunk/drivers/char/keyboard.c +++ b/trunk/drivers/char/keyboard.c @@ -109,7 +109,7 @@ struct kbd_struct kbd_table[MAX_NR_CONSOLES]; static struct kbd_struct *kbd = kbd_table; struct vt_spawn_console vt_spawn_con = { - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), .pid = NULL, .sig = 0, }; diff --git a/trunk/drivers/char/lp.c b/trunk/drivers/char/lp.c index b51d08be0bcf..62051f8b0910 100644 --- a/trunk/drivers/char/lp.c +++ b/trunk/drivers/char/lp.c @@ -118,7 +118,6 @@ #include #include #include -#include #include #include #include @@ -139,9 +138,6 @@ /* if you have more than 8 printers, remember to increase LP_NO */ #define LP_NO 8 -/* ROUND_UP macro from fs/select.c */ -#define ROUND_UP(x,y) (((x)+(y)-1)/(y)) - static struct lp_struct lp_table[LP_NO]; static unsigned int lp_count = 0; @@ -652,7 +648,7 @@ static int lp_ioctl(struct inode *inode, struct file *file, (par_timeout.tv_usec < 0)) { return -EINVAL; } - to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ); + to_jiffies = DIV_ROUND_UP(par_timeout.tv_usec, 1000000/HZ); to_jiffies += par_timeout.tv_sec * (long) HZ; if (to_jiffies <= 0) { return -EINVAL; @@ -803,7 +799,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), NULL, + class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev, "lp%d", nr); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, diff --git a/trunk/drivers/char/mem.c b/trunk/drivers/char/mem.c index 5f066963f171..cc9a9d0df979 100644 --- a/trunk/drivers/char/mem.c +++ b/trunk/drivers/char/mem.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -552,7 +551,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, return virtr + wrote; } -#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) +#ifdef CONFIG_DEVPORT static ssize_t read_port(struct file * file, char __user * buf, size_t count, loff_t *ppos) { @@ -835,7 +834,7 @@ static const struct file_operations null_fops = { .splice_write = splice_write_null, }; -#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) +#ifdef CONFIG_DEVPORT static const struct file_operations port_fops = { .llseek = memory_lseek, .read = read_port, @@ -913,7 +912,7 @@ static int memory_open(struct inode * inode, struct file * filp) case 3: filp->f_op = &null_fops; break; -#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) +#ifdef CONFIG_DEVPORT case 4: filp->f_op = &port_fops; break; @@ -960,7 +959,7 @@ static const struct { {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, {3, "null", S_IRUGO | S_IWUGO, &null_fops}, -#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) +#ifdef CONFIG_DEVPORT {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, #endif {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, diff --git a/trunk/drivers/char/misc.c b/trunk/drivers/char/misc.c index 7e975f606924..4e6fb9651a16 100644 --- a/trunk/drivers/char/misc.c +++ b/trunk/drivers/char/misc.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -53,7 +54,7 @@ * Head entry for the doubly linked miscdevice list */ static LIST_HEAD(misc_list); -static DECLARE_MUTEX(misc_sem); +static DEFINE_MUTEX(misc_mtx); /* * Assigned numbers, used for dynamic minors @@ -69,7 +70,7 @@ static void *misc_seq_start(struct seq_file *seq, loff_t *pos) struct miscdevice *p; loff_t off = 0; - down(&misc_sem); + mutex_lock(&misc_mtx); list_for_each_entry(p, &misc_list, list) { if (*pos == off++) return p; @@ -89,7 +90,7 @@ static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void misc_seq_stop(struct seq_file *seq, void *v) { - up(&misc_sem); + mutex_unlock(&misc_mtx); } static int misc_seq_show(struct seq_file *seq, void *v) @@ -129,7 +130,7 @@ static int misc_open(struct inode * inode, struct file * file) int err = -ENODEV; const struct file_operations *old_fops, *new_fops = NULL; - down(&misc_sem); + mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { @@ -139,9 +140,9 @@ static int misc_open(struct inode * inode, struct file * file) } if (!new_fops) { - up(&misc_sem); + mutex_unlock(&misc_mtx); request_module("char-major-%d-%d", MISC_MAJOR, minor); - down(&misc_sem); + mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { @@ -165,7 +166,7 @@ static int misc_open(struct inode * inode, struct file * file) } fops_put(old_fops); fail: - up(&misc_sem); + mutex_unlock(&misc_mtx); return err; } @@ -201,10 +202,10 @@ int misc_register(struct miscdevice * misc) INIT_LIST_HEAD(&misc->list); - down(&misc_sem); + mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { - up(&misc_sem); + mutex_unlock(&misc_mtx); return -EBUSY; } } @@ -215,7 +216,7 @@ int misc_register(struct miscdevice * misc) if ( (misc_minors[i>>3] & (1 << (i&7))) == 0) break; if (i<0) { - up(&misc_sem); + mutex_unlock(&misc_mtx); return -EBUSY; } misc->minor = i; @@ -238,7 +239,7 @@ int misc_register(struct miscdevice * misc) */ list_add(&misc->list, &misc_list); out: - up(&misc_sem); + mutex_unlock(&misc_mtx); return err; } @@ -259,13 +260,13 @@ int misc_deregister(struct miscdevice * misc) if (list_empty(&misc->list)) return -EINVAL; - down(&misc_sem); + mutex_lock(&misc_mtx); list_del(&misc->list); device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); } - up(&misc_sem); + mutex_unlock(&misc_mtx); return 0; } diff --git a/trunk/drivers/char/moxa.c b/trunk/drivers/char/moxa.c index 7dbaee8d9402..e0d35c20c04f 100644 --- a/trunk/drivers/char/moxa.c +++ b/trunk/drivers/char/moxa.c @@ -1582,7 +1582,7 @@ int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port) if(copy_from_user(&dltmp, argp, sizeof(struct dl_str))) return -EFAULT; - if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS) + if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS || dltmp.len < 0) return -EINVAL; switch(cmd) @@ -2529,6 +2529,8 @@ static int moxaloadbios(int cardno, unsigned char __user *tmp, int len) void __iomem *baseAddr; int i; + if(len < 0 || len > sizeof(moxaBuff)) + return -EINVAL; if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; baseAddr = moxa_boards[cardno].basemem; @@ -2576,7 +2578,7 @@ static int moxaload320b(int cardno, unsigned char __user *tmp, int len) void __iomem *baseAddr; int i; - if(len > sizeof(moxaBuff)) + if(len < 0 || len > sizeof(moxaBuff)) return -EINVAL; if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; @@ -2596,6 +2598,8 @@ static int moxaloadcode(int cardno, unsigned char __user *tmp, int len) void __iomem *baseAddr, *ofsAddr; int retval, port, i; + if(len < 0 || len > sizeof(moxaBuff)) + return -EINVAL; if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; baseAddr = moxa_boards[cardno].basemem; diff --git a/trunk/drivers/char/mxser.c b/trunk/drivers/char/mxser.c index 80a01150b86c..5953a45d7e96 100644 --- a/trunk/drivers/char/mxser.c +++ b/trunk/drivers/char/mxser.c @@ -54,7 +54,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/char/mxser_new.c b/trunk/drivers/char/mxser_new.c index f7603b6aeb87..6cde448cd5b2 100644 --- a/trunk/drivers/char/mxser_new.c +++ b/trunk/drivers/char/mxser_new.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/char/n_r3964.c b/trunk/drivers/char/n_r3964.c index 65f2d3a96b85..14557a4822c0 100644 --- a/trunk/drivers/char/n_r3964.c +++ b/trunk/drivers/char/n_r3964.c @@ -1088,13 +1088,13 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, /* block until there is a message: */ add_wait_queue(&pInfo->read_wait, &wait); repeat: - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); pMsg = remove_msg(pInfo, pClient); if (!pMsg && !signal_pending(current)) { schedule(); goto repeat; } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&pInfo->read_wait, &wait); } diff --git a/trunk/drivers/char/ppdev.c b/trunk/drivers/char/ppdev.c index 4abd1eff61d6..84ac64fc48a1 100644 --- a/trunk/drivers/char/ppdev.c +++ b/trunk/drivers/char/ppdev.c @@ -66,7 +66,6 @@ #include #include #include -#include #include #include @@ -752,7 +751,7 @@ static const struct file_operations pp_fops = { static void pp_attach(struct parport *port) { - device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number), + device_create(ppdev_class, port->dev, MKDEV(PP_MAJOR, port->number), "parport%d", port->number); } diff --git a/trunk/drivers/char/riscom8.c b/trunk/drivers/char/riscom8.c index 70145254fb9d..3494e3fc44bf 100644 --- a/trunk/drivers/char/riscom8.c +++ b/trunk/drivers/char/riscom8.c @@ -980,7 +980,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, } schedule(); } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&port->open_wait, &wait); if (!tty_hung_up_p(filp)) port->count++; diff --git a/trunk/drivers/char/rocket.c b/trunk/drivers/char/rocket.c index 76357c855ce3..61a63da420c2 100644 --- a/trunk/drivers/char/rocket.c +++ b/trunk/drivers/char/rocket.c @@ -65,10 +65,6 @@ /****** Kernel includes ******/ -#ifdef MODVERSIONS -#include -#endif - #include #include #include @@ -85,6 +81,7 @@ #include #include #include +#include #include #include #include @@ -93,7 +90,6 @@ #include #include #include -#include #include /****** RocketPort includes ******/ @@ -702,7 +698,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) } } spin_lock_init(&info->slock); - sema_init(&info->write_sem, 1); + mutex_init(&info->write_mtx); rp_table[line] = info; if (pci_dev) tty_register_device(rocket_driver, line, &pci_dev->dev); @@ -947,7 +943,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, #endif schedule(); /* Don't hold spinlock here, will hang PC */ } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); spin_lock_irqsave(&info->slock, flags); @@ -1602,7 +1598,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout) if (signal_pending(current)) break; } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); #endif @@ -1661,8 +1657,11 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch) if (rocket_paranoia_check(info, "rp_put_char")) return; - /* Grab the port write semaphore, locking out other processes that try to write to this port */ - down(&info->write_sem); + /* + * Grab the port write mutex, locking out other processes that try to + * write to this port + */ + mutex_lock(&info->write_mtx); #ifdef ROCKET_DEBUG_WRITE printk(KERN_INFO "rp_put_char %c...", ch); @@ -1684,12 +1683,12 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch) info->xmit_fifo_room--; } spin_unlock_irqrestore(&info->slock, flags); - up(&info->write_sem); + mutex_unlock(&info->write_mtx); } /* * Exception handler - write routine, called when user app writes to the device. - * A per port write semaphore is used to protect from another process writing to + * A per port write mutex is used to protect from another process writing to * this port at the same time. This other process could be running on the other CPU * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out). * Spinlocks protect the info xmit members. @@ -1706,7 +1705,7 @@ static int rp_write(struct tty_struct *tty, if (count <= 0 || rocket_paranoia_check(info, "rp_write")) return 0; - down_interruptible(&info->write_sem); + mutex_lock_interruptible(&info->write_mtx); #ifdef ROCKET_DEBUG_WRITE printk(KERN_INFO "rp_write %d chars...", count); @@ -1777,7 +1776,7 @@ static int rp_write(struct tty_struct *tty, wake_up_interruptible(&tty->poll_wait); #endif } - up(&info->write_sem); + mutex_unlock(&info->write_mtx); return retval; } @@ -1852,6 +1851,12 @@ static void rp_flush_buffer(struct tty_struct *tty) #ifdef CONFIG_PCI +static struct pci_device_id __devinitdata rocket_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) }, + { } +}; +MODULE_DEVICE_TABLE(pci, rocket_pci_ids); + /* * Called when a PCI card is found. Retrieves and stores model information, * init's aiopic and serial port hardware. diff --git a/trunk/drivers/char/rocket_int.h b/trunk/drivers/char/rocket_int.h index 3a8bcc85bc14..89b4d7b10d12 100644 --- a/trunk/drivers/char/rocket_int.h +++ b/trunk/drivers/char/rocket_int.h @@ -15,6 +15,8 @@ #define ROCKET_TYPE_MODEMIII 3 #define ROCKET_TYPE_PC104 4 +#include + #include #include @@ -1171,7 +1173,7 @@ struct r_port { struct wait_queue *close_wait; #endif spinlock_t slock; - struct semaphore write_sem; + struct mutex write_mtx; }; #define RPORT_MAGIC 0x525001 diff --git a/trunk/drivers/char/rtc.c b/trunk/drivers/char/rtc.c index c7dac9b13351..20380a2c4dee 100644 --- a/trunk/drivers/char/rtc.c +++ b/trunk/drivers/char/rtc.c @@ -388,7 +388,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf, if (!retval) retval = count; out: - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&rtc_wait, &wait); return retval; diff --git a/trunk/drivers/char/selection.c b/trunk/drivers/char/selection.c index 74cff839c857..a69f094d1ed3 100644 --- a/trunk/drivers/char/selection.c +++ b/trunk/drivers/char/selection.c @@ -299,7 +299,7 @@ int paste_selection(struct tty_struct *tty) pasted += count; } remove_wait_queue(&vc->paste_wait, &wait); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); tty_ldisc_deref(ld); return 0; diff --git a/trunk/drivers/char/serial167.c b/trunk/drivers/char/serial167.c index 5fd314adc1f2..c585b4738f86 100644 --- a/trunk/drivers/char/serial167.c +++ b/trunk/drivers/char/serial167.c @@ -1892,7 +1892,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, #endif schedule(); } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) { info->count++; diff --git a/trunk/drivers/char/synclink.c b/trunk/drivers/char/synclink.c index ce4db6f52362..f02a0795983f 100644 --- a/trunk/drivers/char/synclink.c +++ b/trunk/drivers/char/synclink.c @@ -4010,8 +4010,13 @@ static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info) for ( i=0; inum_tx_holding_buffers; ++i) { info->tx_holding_buffers[i].buffer = kmalloc(info->max_frame_size, GFP_KERNEL); - if ( info->tx_holding_buffers[i].buffer == NULL ) + if (info->tx_holding_buffers[i].buffer == NULL) { + for (--i; i >= 0; i--) { + kfree(info->tx_holding_buffers[i].buffer); + info->tx_holding_buffers[i].buffer = NULL; + } return -ENOMEM; + } } return 0; diff --git a/trunk/drivers/char/synclink_gt.c b/trunk/drivers/char/synclink_gt.c index 0a367cd4121f..2a7736b5f2f7 100644 --- a/trunk/drivers/char/synclink_gt.c +++ b/trunk/drivers/char/synclink_gt.c @@ -3415,6 +3415,9 @@ static void device_init(int adapter_num, struct pci_dev *pdev) } } } + + for (i=0; i < port_count; ++i) + tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev)); } static int __devinit init_one(struct pci_dev *dev, @@ -3466,6 +3469,8 @@ static void slgt_cleanup(void) printk("unload %s %s\n", driver_name, driver_version); if (serial_driver) { + for (info=slgt_device_list ; info != NULL ; info=info->next_device) + tty_unregister_device(serial_driver, info->line); if ((rc = tty_unregister_driver(serial_driver))) DBGERR(("tty_unregister_driver error=%d\n", rc)); put_tty_driver(serial_driver); @@ -3506,23 +3511,10 @@ static int __init slgt_init(void) printk("%s %s\n", driver_name, driver_version); - slgt_device_count = 0; - if ((rc = pci_register_driver(&pci_driver)) < 0) { - printk("%s pci_register_driver error=%d\n", driver_name, rc); - return rc; - } - pci_registered = 1; - - if (!slgt_device_list) { - printk("%s no devices found\n",driver_name); - pci_unregister_driver(&pci_driver); - return -ENODEV; - } - serial_driver = alloc_tty_driver(MAX_DEVICES); if (!serial_driver) { - rc = -ENOMEM; - goto error; + printk("%s can't allocate tty driver\n", driver_name); + return -ENOMEM; } /* Initialize the tty_driver structure */ @@ -3539,7 +3531,7 @@ static int __init slgt_init(void) B9600 | CS8 | CREAD | HUPCL | CLOCAL; serial_driver->init_termios.c_ispeed = 9600; serial_driver->init_termios.c_ospeed = 9600; - serial_driver->flags = TTY_DRIVER_REAL_RAW; + serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(serial_driver, &ops); if ((rc = tty_register_driver(serial_driver)) < 0) { DBGERR(("%s can't register serial driver\n", driver_name)); @@ -3552,6 +3544,16 @@ static int __init slgt_init(void) driver_name, driver_version, serial_driver->major); + slgt_device_count = 0; + if ((rc = pci_register_driver(&pci_driver)) < 0) { + printk("%s pci_register_driver error=%d\n", driver_name, rc); + goto error; + } + pci_registered = 1; + + if (!slgt_device_list) + printk("%s no devices found\n",driver_name); + return 0; error: diff --git a/trunk/drivers/char/sysrq.c b/trunk/drivers/char/sysrq.c index 1d8c4ae61551..39cc318011ea 100644 --- a/trunk/drivers/char/sysrq.c +++ b/trunk/drivers/char/sysrq.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/char/tipar.c b/trunk/drivers/char/tipar.c index 47fb20f69695..35b40b996534 100644 --- a/trunk/drivers/char/tipar.c +++ b/trunk/drivers/char/tipar.c @@ -442,7 +442,7 @@ tipar_register(int nr, struct parport *port) } class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR, - TIPAR_MINOR + nr), NULL, "par%d", nr); + TIPAR_MINOR + nr), port->dev, "par%d", nr); /* Display informations */ pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq == diff --git a/trunk/drivers/char/tpm/tpm.c b/trunk/drivers/char/tpm/tpm.c index e5a254a434f8..9bb542913b86 100644 --- a/trunk/drivers/char/tpm/tpm.c +++ b/trunk/drivers/char/tpm/tpm.c @@ -24,7 +24,9 @@ */ #include +#include #include + #include "tpm.h" enum tpm_const { @@ -328,10 +330,10 @@ static void timeout_work(struct work_struct *work) { struct tpm_chip *chip = container_of(work, struct tpm_chip, work); - down(&chip->buffer_mutex); + mutex_lock(&chip->buffer_mutex); atomic_set(&chip->data_pending, 0); memset(chip->data_buffer, 0, TPM_BUFSIZE); - up(&chip->buffer_mutex); + mutex_unlock(&chip->buffer_mutex); } /* @@ -380,7 +382,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, return -E2BIG; } - down(&chip->tpm_mutex); + mutex_lock(&chip->tpm_mutex); if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) { dev_err(chip->dev, @@ -419,7 +421,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: - up(&chip->tpm_mutex); + mutex_unlock(&chip->tpm_mutex); return rc; } @@ -942,12 +944,12 @@ int tpm_release(struct inode *inode, struct file *file) { struct tpm_chip *chip = file->private_data; + flush_scheduled_work(); spin_lock(&driver_lock); file->private_data = NULL; - chip->num_opens--; del_singleshot_timer_sync(&chip->user_read_timer); - flush_scheduled_work(); atomic_set(&chip->data_pending, 0); + chip->num_opens--; put_device(chip->dev); kfree(chip->data_buffer); spin_unlock(&driver_lock); @@ -966,14 +968,14 @@ ssize_t tpm_write(struct file *file, const char __user *buf, while (atomic_read(&chip->data_pending) != 0) msleep(TPM_TIMEOUT); - down(&chip->buffer_mutex); + mutex_lock(&chip->buffer_mutex); if (in_size > TPM_BUFSIZE) in_size = TPM_BUFSIZE; if (copy_from_user (chip->data_buffer, (void __user *) buf, in_size)) { - up(&chip->buffer_mutex); + mutex_unlock(&chip->buffer_mutex); return -EFAULT; } @@ -981,7 +983,7 @@ ssize_t tpm_write(struct file *file, const char __user *buf, out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); atomic_set(&chip->data_pending, out_size); - up(&chip->buffer_mutex); + mutex_unlock(&chip->buffer_mutex); /* Set a timeout by which the reader must come claim the result */ mod_timer(&chip->user_read_timer, jiffies + (60 * HZ)); @@ -1004,10 +1006,10 @@ ssize_t tpm_read(struct file *file, char __user *buf, if (size < ret_size) ret_size = size; - down(&chip->buffer_mutex); + mutex_lock(&chip->buffer_mutex); if (copy_to_user(buf, chip->data_buffer, ret_size)) ret_size = -EFAULT; - up(&chip->buffer_mutex); + mutex_unlock(&chip->buffer_mutex); } return ret_size; @@ -1097,11 +1099,16 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend /* Driver specific per-device data */ chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); + + if (chip == NULL || devname == NULL) { + kfree(chip); + kfree(devname); return NULL; + } - init_MUTEX(&chip->buffer_mutex); - init_MUTEX(&chip->tpm_mutex); + mutex_init(&chip->buffer_mutex); + mutex_init(&chip->tpm_mutex); INIT_LIST_HEAD(&chip->list); INIT_WORK(&chip->work, timeout_work); @@ -1124,7 +1131,6 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend set_bit(chip->dev_num, dev_mask); - devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); chip->vendor.miscdev.name = devname; diff --git a/trunk/drivers/char/tpm/tpm.h b/trunk/drivers/char/tpm/tpm.h index 9f273f032b0f..b2e2b002a1bb 100644 --- a/trunk/drivers/char/tpm/tpm.h +++ b/trunk/drivers/char/tpm/tpm.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -94,11 +95,11 @@ struct tpm_chip { /* Data passed to and from the tpm via the read/write calls */ u8 *data_buffer; atomic_t data_pending; - struct semaphore buffer_mutex; + struct mutex buffer_mutex; struct timer_list user_read_timer; /* user needs to claim result */ struct work_struct work; - struct semaphore tpm_mutex; /* tpm is processing */ + struct mutex tpm_mutex; /* tpm is processing */ struct tpm_vendor_specific vendor; diff --git a/trunk/drivers/char/tpm/tpm_atmel.h b/trunk/drivers/char/tpm/tpm_atmel.h index 3c852009196e..c912d8691cbd 100644 --- a/trunk/drivers/char/tpm/tpm_atmel.h +++ b/trunk/drivers/char/tpm/tpm_atmel.h @@ -47,12 +47,12 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) if (!dn) return NULL; - if (!device_is_compatible(dn, "AT97SC3201")) { + if (!of_device_is_compatible(dn, "AT97SC3201")) { of_node_put(dn); return NULL; } - reg = get_property(dn, "reg", ®len); + reg = of_get_property(dn, "reg", ®len); naddrc = of_n_addr_cells(dn); nsizec = of_n_size_cells(dn); diff --git a/trunk/drivers/char/tpm/tpm_infineon.c b/trunk/drivers/char/tpm/tpm_infineon.c index 1353b5a6bae8..967002a5a1e5 100644 --- a/trunk/drivers/char/tpm/tpm_infineon.c +++ b/trunk/drivers/char/tpm/tpm_infineon.c @@ -30,12 +30,60 @@ #define TPM_MAX_TRIES 5000 #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 -/* These values will be filled after PnP-call */ -static int TPM_INF_DATA; -static int TPM_INF_ADDR; -static int TPM_INF_BASE; -static int TPM_INF_ADDR_LEN; -static int TPM_INF_PORT_LEN; +#define TPM_INF_IO_PORT 0x0 +#define TPM_INF_IO_MEM 0x1 + +#define TPM_INF_ADDR 0x0 +#define TPM_INF_DATA 0x1 + +struct tpm_inf_dev { + int iotype; + + void __iomem *mem_base; /* MMIO ioremap'd addr */ + unsigned long map_base; /* phys MMIO base */ + unsigned long map_size; /* MMIO region size */ + unsigned int index_off; /* index register offset */ + + unsigned int data_regs; /* Data registers */ + unsigned int data_size; + + unsigned int config_port; /* IO Port config index reg */ + unsigned int config_size; +}; + +static struct tpm_inf_dev tpm_dev; + +static inline void tpm_data_out(unsigned char data, unsigned char offset) +{ + if (tpm_dev.iotype == TPM_INF_IO_PORT) + outb(data, tpm_dev.data_regs + offset); + else + writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset); +} + +static inline unsigned char tpm_data_in(unsigned char offset) +{ + if (tpm_dev.iotype == TPM_INF_IO_PORT) + return inb(tpm_dev.data_regs + offset); + else + return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset); +} + +static inline void tpm_config_out(unsigned char data, unsigned char offset) +{ + if (tpm_dev.iotype == TPM_INF_IO_PORT) + outb(data, tpm_dev.config_port + offset); + else + writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset); +} + +static inline unsigned char tpm_config_in(unsigned char offset) +{ + if (tpm_dev.iotype == TPM_INF_IO_PORT) + return inb(tpm_dev.config_port + offset); + else + return readb(tpm_dev.mem_base + tpm_dev.index_off + offset); +} /* TPM header definitions */ enum infineon_tpm_header { @@ -105,7 +153,7 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo) if (clear_wrfifo) { for (i = 0; i < 4096; i++) { - status = inb(chip->vendor.base + WRFIFO); + status = tpm_data_in(WRFIFO); if (status == 0xff) { if (check == 5) break; @@ -125,8 +173,8 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo) */ i = 0; do { - status = inb(chip->vendor.base + RDFIFO); - status = inb(chip->vendor.base + STAT); + status = tpm_data_in(RDFIFO); + status = tpm_data_in(STAT); i++; if (i == TPM_MAX_TRIES) return -EIO; @@ -139,7 +187,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) int status; int i; for (i = 0; i < TPM_MAX_TRIES; i++) { - status = inb(chip->vendor.base + STAT); + status = tpm_data_in(STAT); /* check the status-register if wait_for_bit is set */ if (status & 1 << wait_for_bit) break; @@ -158,7 +206,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) { wait(chip, STAT_XFE); - outb(sendbyte, chip->vendor.base + WRFIFO); + tpm_data_out(sendbyte, WRFIFO); } /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more @@ -205,7 +253,7 @@ static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count) ret = wait(chip, STAT_RDA); if (ret) return -EIO; - buf[i] = inb(chip->vendor.base + RDFIFO); + buf[i] = tpm_data_in(RDFIFO); } if (buf[0] != TPM_VL_VER) { @@ -220,7 +268,7 @@ static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count) for (i = 0; i < size; i++) { wait(chip, STAT_RDA); - buf[i] = inb(chip->vendor.base + RDFIFO); + buf[i] = tpm_data_in(RDFIFO); } if ((size == 0x6D00) && (buf[1] == 0x80)) { @@ -269,7 +317,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) u8 count_high, count_low, count_4, count_3, count_2, count_1; /* Disabling Reset, LP and IRQC */ - outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD); + tpm_data_out(RESET_LP_IRQC_DISABLE, CMD); ret = empty_fifo(chip, 1); if (ret) { @@ -320,7 +368,7 @@ static void tpm_inf_cancel(struct tpm_chip *chip) static u8 tpm_inf_status(struct tpm_chip *chip) { - return inb(chip->vendor.base + STAT); + return tpm_data_in(STAT); } static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); @@ -381,51 +429,88 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, /* read IO-ports through PnP */ if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) { - TPM_INF_ADDR = pnp_port_start(dev, 0); - TPM_INF_ADDR_LEN = pnp_port_len(dev, 0); - TPM_INF_DATA = (TPM_INF_ADDR + 1); - TPM_INF_BASE = pnp_port_start(dev, 1); - TPM_INF_PORT_LEN = pnp_port_len(dev, 1); - if ((TPM_INF_PORT_LEN < 4) || (TPM_INF_ADDR_LEN < 2)) { + + tpm_dev.iotype = TPM_INF_IO_PORT; + + tpm_dev.config_port = pnp_port_start(dev, 0); + tpm_dev.config_size = pnp_port_len(dev, 0); + tpm_dev.data_regs = pnp_port_start(dev, 1); + tpm_dev.data_size = pnp_port_len(dev, 1); + if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) { rc = -EINVAL; goto err_last; } dev_info(&dev->dev, "Found %s with ID %s\n", dev->name, dev_id->id); - if (!((TPM_INF_BASE >> 8) & 0xff)) { + if (!((tpm_dev.data_regs >> 8) & 0xff)) { rc = -EINVAL; goto err_last; } /* publish my base address and request region */ - if (request_region - (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { + if (request_region(tpm_dev.data_regs, tpm_dev.data_size, + "tpm_infineon0") == NULL) { rc = -EINVAL; goto err_last; } - if (request_region - (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) { + if (request_region(tpm_dev.config_port, tpm_dev.config_size, + "tpm_infineon0") == NULL) { + release_region(tpm_dev.data_regs, tpm_dev.data_size); rc = -EINVAL; goto err_last; } + } else if (pnp_mem_valid(dev, 0) && + !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) { + + tpm_dev.iotype = TPM_INF_IO_MEM; + + tpm_dev.map_base = pnp_mem_start(dev, 0); + tpm_dev.map_size = pnp_mem_len(dev, 0); + + dev_info(&dev->dev, "Found %s with ID %s\n", + dev->name, dev_id->id); + + /* publish my base address and request region */ + if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size, + "tpm_infineon0") == NULL) { + rc = -EINVAL; + goto err_last; + } + + tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size); + if (tpm_dev.mem_base == NULL) { + release_mem_region(tpm_dev.map_base, tpm_dev.map_size); + rc = -EINVAL; + goto err_last; + } + + /* + * The only known MMIO based Infineon TPM system provides + * a single large mem region with the device config + * registers at the default TPM_ADDR. The data registers + * seem like they could be placed anywhere within the MMIO + * region, but lets just put them at zero offset. + */ + tpm_dev.index_off = TPM_ADDR; + tpm_dev.data_regs = 0x0; } else { rc = -EINVAL; goto err_last; } /* query chip for its vendor, its version number a.s.o. */ - outb(ENABLE_REGISTER_PAIR, TPM_INF_ADDR); - outb(IDVENL, TPM_INF_ADDR); - vendorid[1] = inb(TPM_INF_DATA); - outb(IDVENH, TPM_INF_ADDR); - vendorid[0] = inb(TPM_INF_DATA); - outb(IDPDL, TPM_INF_ADDR); - productid[1] = inb(TPM_INF_DATA); - outb(IDPDH, TPM_INF_ADDR); - productid[0] = inb(TPM_INF_DATA); - outb(CHIP_ID1, TPM_INF_ADDR); - version[1] = inb(TPM_INF_DATA); - outb(CHIP_ID2, TPM_INF_ADDR); - version[0] = inb(TPM_INF_DATA); + tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR); + tpm_config_out(IDVENL, TPM_INF_ADDR); + vendorid[1] = tpm_config_in(TPM_INF_DATA); + tpm_config_out(IDVENH, TPM_INF_ADDR); + vendorid[0] = tpm_config_in(TPM_INF_DATA); + tpm_config_out(IDPDL, TPM_INF_ADDR); + productid[1] = tpm_config_in(TPM_INF_DATA); + tpm_config_out(IDPDH, TPM_INF_ADDR); + productid[0] = tpm_config_in(TPM_INF_DATA); + tpm_config_out(CHIP_ID1, TPM_INF_ADDR); + version[1] = tpm_config_in(TPM_INF_DATA); + tpm_config_out(CHIP_ID2, TPM_INF_ADDR); + version[0] = tpm_config_in(TPM_INF_DATA); switch ((productid[0] << 8) | productid[1]) { case 6: @@ -442,51 +527,54 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { /* configure TPM with IO-ports */ - outb(IOLIMH, TPM_INF_ADDR); - outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA); - outb(IOLIML, TPM_INF_ADDR); - outb((TPM_INF_BASE & 0xff), TPM_INF_DATA); + tpm_config_out(IOLIMH, TPM_INF_ADDR); + tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA); + tpm_config_out(IOLIML, TPM_INF_ADDR); + tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA); /* control if IO-ports are set correctly */ - outb(IOLIMH, TPM_INF_ADDR); - ioh = inb(TPM_INF_DATA); - outb(IOLIML, TPM_INF_ADDR); - iol = inb(TPM_INF_DATA); + tpm_config_out(IOLIMH, TPM_INF_ADDR); + ioh = tpm_config_in(TPM_INF_DATA); + tpm_config_out(IOLIML, TPM_INF_ADDR); + iol = tpm_config_in(TPM_INF_DATA); - if ((ioh << 8 | iol) != TPM_INF_BASE) { + if ((ioh << 8 | iol) != tpm_dev.data_regs) { dev_err(&dev->dev, - "Could not set IO-ports to 0x%x\n", - TPM_INF_BASE); + "Could not set IO-data registers to 0x%x\n", + tpm_dev.data_regs); rc = -EIO; goto err_release_region; } /* activate register */ - outb(TPM_DAR, TPM_INF_ADDR); - outb(0x01, TPM_INF_DATA); - outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); + tpm_config_out(TPM_DAR, TPM_INF_ADDR); + tpm_config_out(0x01, TPM_INF_DATA); + tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); /* disable RESET, LP and IRQC */ - outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD); + tpm_data_out(RESET_LP_IRQC_DISABLE, CMD); /* Finally, we're done, print some infos */ dev_info(&dev->dev, "TPM found: " - "config base 0x%x, " - "io base 0x%x, " + "config base 0x%lx, " + "data base 0x%lx, " "chip version 0x%02x%02x, " "vendor id 0x%x%x (Infineon), " "product id 0x%02x%02x" "%s\n", - TPM_INF_ADDR, - TPM_INF_BASE, + tpm_dev.iotype == TPM_INF_IO_PORT ? + tpm_dev.config_port : + tpm_dev.map_base + tpm_dev.index_off, + tpm_dev.iotype == TPM_INF_IO_PORT ? + tpm_dev.data_regs : + tpm_dev.map_base + tpm_dev.data_regs, version[0], version[1], vendorid[0], vendorid[1], productid[0], productid[1], chipname); - if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) { + if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) goto err_release_region; - } - chip->vendor.base = TPM_INF_BASE; + return 0; } else { rc = -ENODEV; @@ -494,8 +582,13 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, } err_release_region: - release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); - release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); + if (tpm_dev.iotype == TPM_INF_IO_PORT) { + release_region(tpm_dev.data_regs, tpm_dev.data_size); + release_region(tpm_dev.config_port, tpm_dev.config_size); + } else { + iounmap(tpm_dev.mem_base); + release_mem_region(tpm_dev.map_base, tpm_dev.map_size); + } err_last: return rc; @@ -506,8 +599,14 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) struct tpm_chip *chip = pnp_get_drvdata(dev); if (chip) { - release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); - release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); + if (tpm_dev.iotype == TPM_INF_IO_PORT) { + release_region(tpm_dev.data_regs, tpm_dev.data_size); + release_region(tpm_dev.config_port, + tpm_dev.config_size); + } else { + iounmap(tpm_dev.mem_base); + release_mem_region(tpm_dev.map_base, tpm_dev.map_size); + } tpm_remove_hardware(chip->dev); } } @@ -539,5 +638,5 @@ module_exit(cleanup_inf); MODULE_AUTHOR("Marcel Selhorst "); MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); -MODULE_VERSION("1.8"); +MODULE_VERSION("1.9"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/char/tty_io.c b/trunk/drivers/char/tty_io.c index 7a32df594907..7710a6a77d97 100644 --- a/trunk/drivers/char/tty_io.c +++ b/trunk/drivers/char/tty_io.c @@ -141,8 +141,6 @@ static DECLARE_MUTEX(allocated_ptys_lock); static int ptmx_open(struct inode *, struct file *); #endif -extern void disable_early_printk(void); - static void initialize_tty_struct(struct tty_struct *tty); static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); @@ -155,8 +153,8 @@ int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int tty_fasync(int fd, struct file * filp, int on); static void release_tty(struct tty_struct *tty, int idx); -static struct pid *__proc_set_tty(struct task_struct *tsk, - struct tty_struct *tty); +static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); +static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); /** * alloc_tty_struct - allocate a tty object @@ -1534,10 +1532,9 @@ void disassociate_ctty(int on_exit) } spin_lock_irq(¤t->sighand->siglock); - tty_pgrp = current->signal->tty_old_pgrp; + put_pid(current->signal->tty_old_pgrp); current->signal->tty_old_pgrp = NULL; spin_unlock_irq(¤t->sighand->siglock); - put_pid(tty_pgrp); mutex_lock(&tty_mutex); /* It is possible that do_tty_hangup has free'd this tty */ @@ -1562,6 +1559,18 @@ void disassociate_ctty(int on_exit) unlock_kernel(); } +/** + * + * no_tty - Ensure the current process does not have a controlling tty + */ +void no_tty(void) +{ + struct task_struct *tsk = current; + if (tsk->signal->leader) + disassociate_ctty(0); + proc_clear_tty(tsk); +} + /** * stop_tty - propogate flow control @@ -2508,7 +2517,6 @@ static int tty_open(struct inode * inode, struct file * filp) int index; dev_t device = inode->i_rdev; unsigned short saved_flags = filp->f_flags; - struct pid *old_pgrp; nonseekable_open(inode, filp); @@ -2602,17 +2610,15 @@ static int tty_open(struct inode * inode, struct file * filp) goto retry_open; } - old_pgrp = NULL; mutex_lock(&tty_mutex); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && !current->signal->tty && tty->session == NULL) - old_pgrp = __proc_set_tty(current, tty); + __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); mutex_unlock(&tty_mutex); - put_pid(old_pgrp); return 0; } @@ -3287,9 +3293,7 @@ int tty_ioctl(struct inode * inode, struct file * file, case TIOCNOTTY: if (current->signal->tty != tty) return -ENOTTY; - if (current->signal->leader) - disassociate_ctty(0); - proc_clear_tty(current); + no_tty(); return 0; case TIOCSCTTY: return tiocsctty(tty, arg); @@ -3720,11 +3724,10 @@ int tty_register_driver(struct tty_driver *driver) if (driver->flags & TTY_DRIVER_INSTALLED) return 0; - if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { - p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); + if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) { + p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); if (!p) return -ENOMEM; - memset(p, 0, driver->num * 3 * sizeof(void *)); } if (!driver->major) { @@ -3767,7 +3770,9 @@ int tty_register_driver(struct tty_driver *driver) if (!driver->put_char) driver->put_char = tty_default_put_char; + mutex_lock(&tty_mutex); list_add(&driver->tty_drivers, &tty_drivers); + mutex_unlock(&tty_mutex); if ( !(driver->flags & TTY_DRIVER_DYNAMIC_DEV) ) { for(i = 0; i < driver->num; i++) @@ -3793,8 +3798,9 @@ int tty_unregister_driver(struct tty_driver *driver) unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), driver->num); - + mutex_lock(&tty_mutex); list_del(&driver->tty_drivers); + mutex_unlock(&tty_mutex); /* * Free the termios and termios_locked structures because @@ -3837,11 +3843,9 @@ void proc_clear_tty(struct task_struct *p) p->signal->tty = NULL; spin_unlock_irq(&p->sighand->siglock); } -EXPORT_SYMBOL(proc_clear_tty); -static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) +static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) { - struct pid *old_pgrp; if (tty) { /* We should not have a session or pgrp to here but.... */ put_pid(tty->session); @@ -3849,21 +3853,16 @@ static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tt tty->session = get_pid(task_session(tsk)); tty->pgrp = get_pid(task_pgrp(tsk)); } - old_pgrp = tsk->signal->tty_old_pgrp; + put_pid(tsk->signal->tty_old_pgrp); tsk->signal->tty = tty; tsk->signal->tty_old_pgrp = NULL; - return old_pgrp; } -void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) +static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) { - struct pid *old_pgrp; - spin_lock_irq(&tsk->sighand->siglock); - old_pgrp = __proc_set_tty(tsk, tty); + __proc_set_tty(tsk, tty); spin_unlock_irq(&tsk->sighand->siglock); - - put_pid(old_pgrp); } struct tty_struct *get_current_tty(void) @@ -3898,9 +3897,6 @@ void __init console_init(void) * set up the console device so that later boot sequences can * inform about problems etc.. */ -#ifdef CONFIG_EARLY_PRINTK - disable_early_printk(); -#endif call = __con_initcall_start; while (call < __con_initcall_end) { (*call)(); diff --git a/trunk/drivers/char/vc_screen.c b/trunk/drivers/char/vc_screen.c index 791930320a13..83aeedda200c 100644 --- a/trunk/drivers/char/vc_screen.c +++ b/trunk/drivers/char/vc_screen.c @@ -28,12 +28,13 @@ #include #include #include +#include #include #include #include #include -#include #include + #include #include #include @@ -70,11 +71,11 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) { int size; - down(&con_buf_sem); + mutex_lock(&con_buf_mtx); size = vcs_size(file->f_path.dentry->d_inode); switch (orig) { default: - up(&con_buf_sem); + mutex_unlock(&con_buf_mtx); return -EINVAL; case 2: offset += size; @@ -85,11 +86,11 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) break; } if (offset < 0 || offset > size) { - up(&con_buf_sem); + mutex_unlock(&con_buf_mtx); return -EINVAL; } file->f_pos = offset; - up(&con_buf_sem); + mutex_unlock(&con_buf_mtx); return file->f_pos; } @@ -106,7 +107,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) unsigned short *org = NULL; ssize_t ret; - down(&con_buf_sem); + mutex_lock(&con_buf_mtx); pos = *ppos; @@ -263,7 +264,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) ret = read; unlock_out: release_console_sem(); - up(&con_buf_sem); + mutex_unlock(&con_buf_mtx); return ret; } @@ -280,7 +281,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) u16 *org0 = NULL, *org = NULL; size_t ret; - down(&con_buf_sem); + mutex_lock(&con_buf_mtx); pos = *ppos; @@ -450,7 +451,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) unlock_out: release_console_sem(); - up(&con_buf_sem); + mutex_unlock(&con_buf_mtx); return ret; } diff --git a/trunk/drivers/char/vt.c b/trunk/drivers/char/vt.c index 1bbb45b937fd..bbd9fc412877 100644 --- a/trunk/drivers/char/vt.c +++ b/trunk/drivers/char/vt.c @@ -86,6 +86,7 @@ #include #include #include +#include #include #include #include @@ -157,6 +158,8 @@ static void blank_screen_t(unsigned long dummy); static void set_palette(struct vc_data *vc); static int printable; /* Is console ready for printing? */ +static int default_utf8; +module_param(default_utf8, int, S_IRUGO | S_IWUSR); /* * ignore_poke: don't unblank the screen when things are typed. This is @@ -348,10 +351,12 @@ void update_region(struct vc_data *vc, unsigned long start, int count) /* Structure of attributes is hardware-dependent */ -static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) +static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, + u8 _underline, u8 _reverse, u8 _italic) { if (vc->vc_sw->con_build_attr) - return vc->vc_sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse); + return vc->vc_sw->con_build_attr(vc, _color, _intensity, + _blink, _underline, _reverse, _italic); #ifndef VT_BUF_VRAM_ONLY /* @@ -368,10 +373,13 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 u8 a = vc->vc_color; if (!vc->vc_can_do_color) return _intensity | + (_italic ? 2 : 0) | (_underline ? 4 : 0) | (_reverse ? 8 : 0) | (_blink ? 0x80 : 0); - if (_underline) + if (_italic) + a = (a & 0xF0) | vc->vc_itcolor; + else if (_underline) a = (a & 0xf0) | vc->vc_ulcolor; else if (_intensity == 0) a = (a & 0xf0) | vc->vc_ulcolor; @@ -392,8 +400,10 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 static void update_attr(struct vc_data *vc) { - vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm); - vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm) << 8) | ' '; + vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, + vc->vc_blink, vc->vc_underline, + vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic); + vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' '; } /* Note: inverting the screen twice should revert to the original state */ @@ -934,6 +944,10 @@ int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; +module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR); +module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR); +module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR); + /* * gotoxy() must verify all boundaries, because the arguments * might also be negative. If the given position is out of @@ -1132,6 +1146,7 @@ static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar posi static void default_attr(struct vc_data *vc) { vc->vc_intensity = 1; + vc->vc_italic = 0; vc->vc_underline = 0; vc->vc_reverse = 0; vc->vc_blink = 0; @@ -1154,6 +1169,9 @@ static void csi_m(struct vc_data *vc) case 2: vc->vc_intensity = 0; break; + case 3: + vc->vc_italic = 1; + break; case 4: vc->vc_underline = 1; break; @@ -1194,6 +1212,9 @@ static void csi_m(struct vc_data *vc) case 22: vc->vc_intensity = 1; break; + case 23: + vc->vc_italic = 0; + break; case 24: vc->vc_underline = 0; break; @@ -1454,6 +1475,7 @@ static void save_cur(struct vc_data *vc) vc->vc_saved_x = vc->vc_x; vc->vc_saved_y = vc->vc_y; vc->vc_s_intensity = vc->vc_intensity; + vc->vc_s_italic = vc->vc_italic; vc->vc_s_underline = vc->vc_underline; vc->vc_s_blink = vc->vc_blink; vc->vc_s_reverse = vc->vc_reverse; @@ -1468,6 +1490,7 @@ static void restore_cur(struct vc_data *vc) { gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y); vc->vc_intensity = vc->vc_s_intensity; + vc->vc_italic = vc->vc_s_italic; vc->vc_underline = vc->vc_s_underline; vc->vc_blink = vc->vc_s_blink; vc->vc_reverse = vc->vc_s_reverse; @@ -1497,7 +1520,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) vc->vc_charset = 0; vc->vc_need_wrap = 0; vc->vc_report_mouse = 0; - vc->vc_utf = 0; + vc->vc_utf = default_utf8; vc->vc_utf_count = 0; vc->vc_disp_ctrl = 0; @@ -1930,7 +1953,47 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) * kernel memory allocation is available. */ char con_buf[CON_BUF_SIZE]; -DECLARE_MUTEX(con_buf_sem); +DEFINE_MUTEX(con_buf_mtx); + +/* is_double_width() is based on the wcwidth() implementation by + * Markus Kuhn -- 2003-05-20 (Unicode 4.0) + * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c + */ +struct interval { + uint32_t first; + uint32_t last; +}; + +static int bisearch(uint32_t ucs, const struct interval *table, int max) +{ + int min = 0; + int mid; + + if (ucs < table[0].first || ucs > table[max].last) + return 0; + while (max >= min) { + mid = (min + max) / 2; + if (ucs > table[mid].last) + min = mid + 1; + else if (ucs < table[mid].first) + max = mid - 1; + else + return 1; + } + return 0; +} + +static int is_double_width(uint32_t ucs) +{ + static const struct interval double_width[] = { + { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E }, + { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF }, + { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 }, { 0xFFE0, 0xFFE6 }, + { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD } + }; + return bisearch(ucs, double_width, + sizeof(double_width) / sizeof(*double_width) - 1); +} /* acquires console_sem */ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) @@ -1948,6 +2011,10 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co unsigned int currcons; unsigned long draw_from = 0, draw_to = 0; struct vc_data *vc; + unsigned char vc_attr; + uint8_t rescan; + uint8_t inverse; + uint8_t width; u16 himask, charmask; const unsigned char *orig_buf = NULL; int orig_count; @@ -1983,7 +2050,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co /* At this point 'buf' is guaranteed to be a kernel buffer * and therefore no access to userspace (and therefore sleeping) - * will be needed. The con_buf_sem serializes all tty based + * will be needed. The con_buf_mtx serializes all tty based * console rendering and vcs write/read operations. We hold * the console spinlock during the entire write. */ @@ -2010,53 +2077,86 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co buf++; n++; count--; + rescan = 0; + inverse = 0; + width = 1; /* Do no translation at all in control states */ if (vc->vc_state != ESnormal) { tc = c; } else if (vc->vc_utf && !vc->vc_disp_ctrl) { - /* Combine UTF-8 into Unicode */ - /* Malformed sequences as sequences of replacement glyphs */ + /* Combine UTF-8 into Unicode in vc_utf_char. + * vc_utf_count is the number of continuation bytes still + * expected to arrive. + * vc_npar is the number of continuation bytes arrived so + * far + */ rescan_last_byte: - if(c > 0x7f) { + if ((c & 0xc0) == 0x80) { + /* Continuation byte received */ + static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff }; if (vc->vc_utf_count) { - if ((c & 0xc0) == 0x80) { - vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); - if (--vc->vc_utf_count) { - vc->vc_npar++; - continue; - } - tc = c = vc->vc_utf_char; - } else - goto replacement_glyph; - } else { - vc->vc_npar = 0; - if ((c & 0xe0) == 0xc0) { - vc->vc_utf_count = 1; - vc->vc_utf_char = (c & 0x1f); - } else if ((c & 0xf0) == 0xe0) { - vc->vc_utf_count = 2; - vc->vc_utf_char = (c & 0x0f); - } else if ((c & 0xf8) == 0xf0) { - vc->vc_utf_count = 3; - vc->vc_utf_char = (c & 0x07); - } else if ((c & 0xfc) == 0xf8) { - vc->vc_utf_count = 4; - vc->vc_utf_char = (c & 0x03); - } else if ((c & 0xfe) == 0xfc) { - vc->vc_utf_count = 5; - vc->vc_utf_char = (c & 0x01); - } else - goto replacement_glyph; + vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); + vc->vc_npar++; + if (--vc->vc_utf_count) { + /* Still need some bytes */ continue; - } + } + /* Got a whole character */ + c = vc->vc_utf_char; + /* Reject overlong sequences */ + if (c <= utf8_length_changes[vc->vc_npar - 1] || + c > utf8_length_changes[vc->vc_npar]) + c = 0xfffd; + } else { + /* Unexpected continuation byte */ + vc->vc_utf_count = 0; + c = 0xfffd; + } } else { - if (vc->vc_utf_count) - goto replacement_glyph; - tc = c; + /* Single ASCII byte or first byte of a sequence received */ + if (vc->vc_utf_count) { + /* Continuation byte expected */ + rescan = 1; + vc->vc_utf_count = 0; + c = 0xfffd; + } else if (c > 0x7f) { + /* First byte of a multibyte sequence received */ + vc->vc_npar = 0; + if ((c & 0xe0) == 0xc0) { + vc->vc_utf_count = 1; + vc->vc_utf_char = (c & 0x1f); + } else if ((c & 0xf0) == 0xe0) { + vc->vc_utf_count = 2; + vc->vc_utf_char = (c & 0x0f); + } else if ((c & 0xf8) == 0xf0) { + vc->vc_utf_count = 3; + vc->vc_utf_char = (c & 0x07); + } else if ((c & 0xfc) == 0xf8) { + vc->vc_utf_count = 4; + vc->vc_utf_char = (c & 0x03); + } else if ((c & 0xfe) == 0xfc) { + vc->vc_utf_count = 5; + vc->vc_utf_char = (c & 0x01); + } else { + /* 254 and 255 are invalid */ + c = 0xfffd; + } + if (vc->vc_utf_count) { + /* Still need some bytes */ + continue; + } + } + /* Nothing to do if an ASCII byte was received */ } + /* End of UTF-8 decoding. */ + /* c is the received character, or U+FFFD for invalid sequences. */ + /* Replace invalid Unicode code points with U+FFFD too */ + if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) + c = 0xfffd; + tc = c; } else { /* no utf or alternate charset mode */ - tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; + tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; } /* If the original code was a control character we @@ -2076,56 +2176,80 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co && (c != 128+27); if (vc->vc_state == ESnormal && ok) { + if (vc->vc_utf && !vc->vc_disp_ctrl) { + if (is_double_width(c)) + width = 2; + } /* Now try to find out how to display it */ tc = conv_uni_to_pc(vc, tc); if (tc & ~charmask) { - if ( tc == -4 ) { - /* If we got -4 (not found) then see if we have - defined a replacement character (U+FFFD) */ -replacement_glyph: - tc = conv_uni_to_pc(vc, 0xfffd); - if (!(tc & ~charmask)) - goto display_glyph; - } else if ( tc != -3 ) - continue; /* nothing to display */ - /* no hash table or no replacement -- - * hope for the best */ - if ( c & ~charmask ) - tc = '?'; - else - tc = c; + if (tc == -1 || tc == -2) { + continue; /* nothing to display */ + } + /* Glyph not found */ + if (!(vc->vc_utf && !vc->vc_disp_ctrl) && !(c & ~charmask)) { + /* In legacy mode use the glyph we get by a 1:1 mapping. + This would make absolutely no sense with Unicode in mind. */ + tc = c; + } else { + /* Display U+FFFD. If it's not found, display an inverse question mark. */ + tc = conv_uni_to_pc(vc, 0xfffd); + if (tc < 0) { + inverse = 1; + tc = conv_uni_to_pc(vc, '?'); + if (tc < 0) tc = '?'; + } + } } -display_glyph: - if (vc->vc_need_wrap || vc->vc_decim) - FLUSH - if (vc->vc_need_wrap) { - cr(vc); - lf(vc); - } - if (vc->vc_decim) - insert_char(vc, 1); - scr_writew(himask ? - ((vc->vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : - (vc->vc_attr << 8) + tc, - (u16 *) vc->vc_pos); - if (DO_UPDATE(vc) && draw_x < 0) { - draw_x = vc->vc_x; - draw_from = vc->vc_pos; - } - if (vc->vc_x == vc->vc_cols - 1) { - vc->vc_need_wrap = vc->vc_decawm; - draw_to = vc->vc_pos + 2; + if (!inverse) { + vc_attr = vc->vc_attr; } else { - vc->vc_x++; - draw_to = (vc->vc_pos += 2); + /* invert vc_attr */ + if (!vc->vc_can_do_color) { + vc_attr = (vc->vc_attr) ^ 0x08; + } else if (vc->vc_hi_font_mask == 0x100) { + vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4); + } else { + vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4); + } } - if (vc->vc_utf_count) { - if (vc->vc_npar) { - vc->vc_npar--; - goto display_glyph; + + while (1) { + if (vc->vc_need_wrap || vc->vc_decim) + FLUSH + if (vc->vc_need_wrap) { + cr(vc); + lf(vc); + } + if (vc->vc_decim) + insert_char(vc, 1); + scr_writew(himask ? + ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : + (vc_attr << 8) + tc, + (u16 *) vc->vc_pos); + if (DO_UPDATE(vc) && draw_x < 0) { + draw_x = vc->vc_x; + draw_from = vc->vc_pos; + } + if (vc->vc_x == vc->vc_cols - 1) { + vc->vc_need_wrap = vc->vc_decawm; + draw_to = vc->vc_pos + 2; + } else { + vc->vc_x++; + draw_to = (vc->vc_pos += 2); } - vc->vc_utf_count = 0; + + if (!--width) break; + + tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */ + if (tc < 0) tc = ' '; + } + + if (rescan) { + rescan = 0; + inverse = 0; + width = 1; c = orig; goto rescan_last_byte; } @@ -2581,6 +2705,11 @@ static void con_close(struct tty_struct *tty, struct file *filp) mutex_unlock(&tty_mutex); } +static int default_italic_color = 2; // green (ASCII) +static int default_underline_color = 3; // cyan (ASCII) +module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR); +module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR); + static void vc_init(struct vc_data *vc, unsigned int rows, unsigned int cols, int do_clear) { @@ -2600,7 +2729,8 @@ static void vc_init(struct vc_data *vc, unsigned int rows, vc->vc_palette[k++] = default_blu[j] ; } vc->vc_def_color = 0x07; /* white */ - vc->vc_ulcolor = 0x0f; /* bold white */ + vc->vc_ulcolor = default_underline_color; + vc->vc_itcolor = default_italic_color; vc->vc_halfcolor = 0x08; /* grey */ init_waitqueue_head(&vc->paste_wait); reset_terminal(vc, do_clear); diff --git a/trunk/drivers/char/vt_ioctl.c b/trunk/drivers/char/vt_ioctl.c index c9f2dd620e87..c6f6f4209739 100644 --- a/trunk/drivers/char/vt_ioctl.c +++ b/trunk/drivers/char/vt_ioctl.c @@ -1061,7 +1061,7 @@ int vt_waitactive(int vt) schedule(); } remove_wait_queue(&vt_activate_queue, &wait); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); return retval; } diff --git a/trunk/drivers/char/watchdog/omap_wdt.c b/trunk/drivers/char/watchdog/omap_wdt.c index 84074a697dce..b36fa8de2131 100644 --- a/trunk/drivers/char/watchdog/omap_wdt.c +++ b/trunk/drivers/char/watchdog/omap_wdt.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/cpufreq/cpufreq_ondemand.c b/trunk/drivers/cpufreq/cpufreq_ondemand.c index 8d053f500fc2..8532bb79e5fc 100644 --- a/trunk/drivers/cpufreq/cpufreq_ondemand.c +++ b/trunk/drivers/cpufreq/cpufreq_ondemand.c @@ -470,7 +470,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) dbs_info->enable = 1; ondemand_powersave_bias_init(); dbs_info->sample_type = DBS_NORMAL_SAMPLE; - INIT_DELAYED_WORK(&dbs_info->work, do_dbs_timer); + INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer); queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work, delay); } diff --git a/trunk/drivers/edac/i82875p_edac.c b/trunk/drivers/edac/i82875p_edac.c index 161fe09a6d38..2800b3e614a9 100644 --- a/trunk/drivers/edac/i82875p_edac.c +++ b/trunk/drivers/edac/i82875p_edac.c @@ -261,10 +261,6 @@ static void i82875p_check(struct mem_ctl_info *mci) i82875p_process_error_info(mci, &info, 1); } -#ifdef CONFIG_PROC_FS -extern int pci_proc_attach_device(struct pci_dev *); -#endif - /* Return 0 on success or 1 on failure. */ static int i82875p_setup_overfl_dev(struct pci_dev *pdev, struct pci_dev **ovrfl_pdev, void __iomem **ovrfl_window) @@ -287,17 +283,12 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev, if (dev == NULL) return 1; + + pci_bus_add_device(dev); } *ovrfl_pdev = dev; -#ifdef CONFIG_PROC_FS - if ((dev->procent == NULL) && pci_proc_attach_device(dev)) { - i82875p_printk(KERN_ERR, "%s(): Failed to attach overflow " - "device\n", __func__); - return 1; - } -#endif /* CONFIG_PROC_FS */ if (pci_enable_device(dev)) { i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow " "device\n", __func__); diff --git a/trunk/drivers/eisa/virtual_root.c b/trunk/drivers/eisa/virtual_root.c index 9b4fcac03ad5..3074879f231f 100644 --- a/trunk/drivers/eisa/virtual_root.c +++ b/trunk/drivers/eisa/virtual_root.c @@ -47,7 +47,7 @@ static void virtual_eisa_release (struct device *dev) /* nothing really to do here */ } -static int virtual_eisa_root_init (void) +static int __init virtual_eisa_root_init (void) { int r; diff --git a/trunk/drivers/hid/hid-core.c b/trunk/drivers/hid/hid-core.c index 62e21cc73938..6ec04e79f685 100644 --- a/trunk/drivers/hid/hid-core.c +++ b/trunk/drivers/hid/hid-core.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/hwmon/Kconfig b/trunk/drivers/hwmon/Kconfig index 6d105a1d41b1..3ba3a5221c41 100644 --- a/trunk/drivers/hwmon/Kconfig +++ b/trunk/drivers/hwmon/Kconfig @@ -2,9 +2,7 @@ # Hardware monitoring chip drivers configuration # -menu "Hardware Monitoring support" - -config HWMON +menuconfig HWMON tristate "Hardware Monitoring support" default y help @@ -23,13 +21,15 @@ config HWMON This support can also be built as a module. If so, the module will be called hwmon. +if HWMON + config HWMON_VID tristate default n config SENSORS_ABITUGURU tristate "Abit uGuru" - depends on HWMON && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get support for the Abit uGuru chips sensor part. The voltage and frequency control parts of the Abit @@ -39,9 +39,19 @@ config SENSORS_ABITUGURU This driver can also be built as a module. If so, the module will be called abituguru. +config SENSORS_AD7418 + tristate "Analog Devices AD7416, AD7417 and AD7418" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Analog Devices + AD7416, AD7417 and AD7418 temperature monitoring chips. + + This driver can also be built as a module. If so, the module + will be called ad7418. + config SENSORS_ADM1021 tristate "Analog Devices ADM1021 and compatibles" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for Analog Devices ADM1021 and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, @@ -53,7 +63,7 @@ config SENSORS_ADM1021 config SENSORS_ADM1025 tristate "Analog Devices ADM1025 and compatibles" - depends on HWMON && I2C + depends on I2C select HWMON_VID help If you say yes here you get support for Analog Devices ADM1025 @@ -64,7 +74,7 @@ config SENSORS_ADM1025 config SENSORS_ADM1026 tristate "Analog Devices ADM1026 and compatibles" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for Analog Devices ADM1026 @@ -75,7 +85,7 @@ config SENSORS_ADM1026 config SENSORS_ADM1029 tristate "Analog Devices ADM1029" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes here you get support for Analog Devices ADM1029 sensor chip. @@ -86,7 +96,7 @@ config SENSORS_ADM1029 config SENSORS_ADM1031 tristate "Analog Devices ADM1031 and compatibles" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes here you get support for Analog Devices ADM1031 and ADM1030 sensor chips. @@ -96,7 +106,7 @@ config SENSORS_ADM1031 config SENSORS_ADM9240 tristate "Analog Devices ADM9240 and compatibles" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for Analog Devices ADM9240, @@ -107,7 +117,7 @@ config SENSORS_ADM9240 config SENSORS_K8TEMP tristate "AMD Athlon64/FX or Opteron temperature sensor" - depends on HWMON && X86 && PCI && EXPERIMENTAL + depends on X86 && PCI && EXPERIMENTAL help If you say yes here you get support for the temperature sensor(s) inside your CPU. Supported is whole AMD K8 @@ -119,7 +129,7 @@ config SENSORS_K8TEMP config SENSORS_AMS tristate "Apple Motion Sensor driver" - depends on HWMON && PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL + depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL help Support for the motion sensor included in PowerBooks. Includes implementations for PMU and I2C. @@ -144,7 +154,7 @@ config SENSORS_AMS_I2C config SENSORS_ASB100 tristate "Asus ASB100 Bach" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for the ASB100 Bach sensor @@ -155,7 +165,7 @@ config SENSORS_ASB100 config SENSORS_ATXP1 tristate "Attansic ATXP1 VID controller" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for the Attansic ATXP1 VID @@ -169,7 +179,7 @@ config SENSORS_ATXP1 config SENSORS_DS1621 tristate "Dallas Semiconductor DS1621 and DS1625" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for Dallas Semiconductor DS1621 and DS1625 sensor chips. @@ -179,7 +189,7 @@ config SENSORS_DS1621 config SENSORS_F71805F tristate "Fintek F71805F/FG and F71872F/FG" - depends on HWMON && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get support for hardware monitoring features of the Fintek F71805F/FG and F71872F/FG Super-I/O @@ -190,7 +200,7 @@ config SENSORS_F71805F config SENSORS_FSCHER tristate "FSC Hermes" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for Fujitsu Siemens Computers Hermes sensor chips. @@ -200,7 +210,7 @@ config SENSORS_FSCHER config SENSORS_FSCPOS tristate "FSC Poseidon" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for Fujitsu Siemens Computers Poseidon sensor chips. @@ -210,7 +220,7 @@ config SENSORS_FSCPOS config SENSORS_GL518SM tristate "Genesys Logic GL518SM" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for Genesys Logic GL518SM sensor chips. @@ -220,7 +230,7 @@ config SENSORS_GL518SM config SENSORS_GL520SM tristate "Genesys Logic GL520SM" - depends on HWMON && I2C + depends on I2C select HWMON_VID help If you say yes here you get support for Genesys Logic GL520SM @@ -229,9 +239,17 @@ config SENSORS_GL520SM This driver can also be built as a module. If so, the module will be called gl520sm. +config SENSORS_CORETEMP + tristate "Intel Core (2) Duo/Solo temperature sensor" + depends on X86 && EXPERIMENTAL + help + If you say yes here you get support for the temperature + sensor inside your CPU. Supported all are all known variants + of Intel Core family. + config SENSORS_IT87 tristate "ITE IT87xx and compatibles" - depends on HWMON && I2C + depends on I2C select I2C_ISA select HWMON_VID help @@ -243,7 +261,7 @@ config SENSORS_IT87 config SENSORS_LM63 tristate "National Semiconductor LM63" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for the National Semiconductor LM63 remote diode digital temperature sensor with integrated fan @@ -255,7 +273,7 @@ config SENSORS_LM63 config SENSORS_LM70 tristate "National Semiconductor LM70" - depends on HWMON && SPI_MASTER && EXPERIMENTAL + depends on SPI_MASTER && EXPERIMENTAL help If you say yes here you get support for the National Semiconductor LM70 digital temperature sensor chip. @@ -265,7 +283,7 @@ config SENSORS_LM70 config SENSORS_LM75 tristate "National Semiconductor LM75 and compatibles" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for National Semiconductor LM75 sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in @@ -280,7 +298,7 @@ config SENSORS_LM75 config SENSORS_LM77 tristate "National Semiconductor LM77" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for National Semiconductor LM77 sensor chips. @@ -290,8 +308,7 @@ config SENSORS_LM77 config SENSORS_LM78 tristate "National Semiconductor LM78 and compatibles" - depends on HWMON && I2C - select I2C_ISA + depends on I2C select HWMON_VID help If you say yes here you get support for National Semiconductor LM78, @@ -302,7 +319,7 @@ config SENSORS_LM78 config SENSORS_LM80 tristate "National Semiconductor LM80" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes here you get support for National Semiconductor LM80 sensor chips. @@ -312,7 +329,7 @@ config SENSORS_LM80 config SENSORS_LM83 tristate "National Semiconductor LM83 and compatibles" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for National Semiconductor LM82 and LM83 sensor chips. @@ -322,7 +339,7 @@ config SENSORS_LM83 config SENSORS_LM85 tristate "National Semiconductor LM85 and compatibles" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for National Semiconductor LM85 @@ -333,7 +350,7 @@ config SENSORS_LM85 config SENSORS_LM87 tristate "National Semiconductor LM87" - depends on HWMON && I2C + depends on I2C select HWMON_VID help If you say yes here you get support for National Semiconductor LM87 @@ -344,7 +361,7 @@ config SENSORS_LM87 config SENSORS_LM90 tristate "National Semiconductor LM90 and compatibles" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for National Semiconductor LM90, LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and @@ -358,7 +375,7 @@ config SENSORS_LM90 config SENSORS_LM92 tristate "National Semiconductor LM92 and compatibles" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for National Semiconductor LM92 and Maxim MAX6635 sensor chips. @@ -368,16 +385,26 @@ config SENSORS_LM92 config SENSORS_MAX1619 tristate "Maxim MAX1619 sensor chip" - depends on HWMON && I2C + depends on I2C help If you say yes here you get support for MAX1619 sensor chip. This driver can also be built as a module. If so, the module will be called max1619. +config SENSORS_MAX6650 + tristate "Maxim MAX6650 sensor chip" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the MAX6650 / MAX6651 + sensor chips. + + This driver can also be built as a module. If so, the module + will be called max6650. + config SENSORS_PC87360 tristate "National Semiconductor PC87360 family" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL select I2C_ISA select HWMON_VID help @@ -392,7 +419,7 @@ config SENSORS_PC87360 config SENSORS_PC87427 tristate "National Semiconductor PC87427" - depends on HWMON && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get access to the hardware monitoring functions of the National Semiconductor PC87427 Super-I/O chip. @@ -405,7 +432,7 @@ config SENSORS_PC87427 config SENSORS_SIS5595 tristate "Silicon Integrated Systems Corp. SiS5595" - depends on HWMON && I2C && PCI && EXPERIMENTAL + depends on I2C && PCI && EXPERIMENTAL select I2C_ISA help If you say yes here you get support for the integrated sensors in @@ -416,28 +443,28 @@ config SENSORS_SIS5595 config SENSORS_SMSC47M1 tristate "SMSC LPC47M10x and compatibles" - depends on HWMON && I2C - select I2C_ISA help If you say yes here you get support for the integrated fan monitoring and control capabilities of the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x, LPC47M14x, LPC47M15x, - LPC47M192 and LPC47M997 chips. + LPC47M192, LPC47M292 and LPC47M997 chips. - The temperature and voltage sensor features of the LPC47M192 - and LPC47M997 are supported by another driver, select also - "SMSC LPC47M192 and compatibles" below for those. + The temperature and voltage sensor features of the LPC47M15x, + LPC47M192, LPC47M292 and LPC47M997 are supported by another + driver, select also "SMSC LPC47M192 and compatibles" below for + those. This driver can also be built as a module. If so, the module will be called smsc47m1. config SENSORS_SMSC47M192 tristate "SMSC LPC47M192 and compatibles" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for the temperature and - voltage sensors of the SMSC LPC47M192 and LPC47M997 chips. + voltage sensors of the SMSC LPC47M192, LPC47M15x, LPC47M292 + and LPC47M997 chips. The fan monitoring and control capabilities of these chips are supported by another driver, select @@ -449,8 +476,7 @@ config SENSORS_SMSC47M192 config SENSORS_SMSC47B397 tristate "SMSC LPC47B397-NC" - depends on HWMON && I2C && EXPERIMENTAL - select I2C_ISA + depends on EXPERIMENTAL help If you say yes here you get support for the SMSC LPC47B397-NC sensor chip. @@ -460,7 +486,7 @@ config SENSORS_SMSC47B397 config SENSORS_VIA686A tristate "VIA686A" - depends on HWMON && I2C && PCI + depends on I2C && PCI select I2C_ISA help If you say yes here you get support for the integrated sensors in @@ -471,7 +497,7 @@ config SENSORS_VIA686A config SENSORS_VT1211 tristate "VIA VT1211" - depends on HWMON && EXPERIMENTAL + depends on EXPERIMENTAL select HWMON_VID help If you say yes here then you get support for hardware monitoring @@ -482,7 +508,7 @@ config SENSORS_VT1211 config SENSORS_VT8231 tristate "VIA VT8231" - depends on HWMON && I2C && PCI && EXPERIMENTAL + depends on I2C && PCI && EXPERIMENTAL select HWMON_VID select I2C_ISA help @@ -494,8 +520,7 @@ config SENSORS_VT8231 config SENSORS_W83781D tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F" - depends on HWMON && I2C - select I2C_ISA + depends on I2C select HWMON_VID help If you say yes here you get support for the Winbond W8378x series @@ -507,7 +532,7 @@ config SENSORS_W83781D config SENSORS_W83791D tristate "Winbond W83791D" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for the Winbond W83791D chip. @@ -517,7 +542,7 @@ config SENSORS_W83791D config SENSORS_W83792D tristate "Winbond W83792D" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes here you get support for the Winbond W83792D chip. @@ -526,7 +551,7 @@ config SENSORS_W83792D config SENSORS_W83793 tristate "Winbond W83793" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for the Winbond W83793 @@ -537,7 +562,7 @@ config SENSORS_W83793 config SENSORS_W83L785TS tristate "Winbond W83L785TS-S" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes here you get support for the Winbond W83L785TS-S sensor chip, which is used on the Asus A7N8X, among other @@ -548,8 +573,6 @@ config SENSORS_W83L785TS config SENSORS_W83627HF tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF" - depends on HWMON && I2C - select I2C_ISA select HWMON_VID help If you say yes here you get support for the Winbond W836X7 series @@ -561,7 +584,7 @@ config SENSORS_W83627HF config SENSORS_W83627EHF tristate "Winbond W83627EHF" - depends on HWMON && I2C && EXPERIMENTAL + depends on I2C && EXPERIMENTAL select I2C_ISA help If you say yes here you get preliminary support for the hardware @@ -577,7 +600,7 @@ config SENSORS_W83627EHF config SENSORS_HDAPS tristate "IBM Hard Drive Active Protection System (hdaps)" - depends on HWMON && INPUT && X86 + depends on INPUT && X86 default n help This driver provides support for the IBM Hard Drive Active Protection @@ -594,9 +617,32 @@ config SENSORS_HDAPS Say Y here if you have an applicable laptop and want to experience the awesome power of hdaps. +config SENSORS_APPLESMC + tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" + depends on HWMON && INPUT && X86 + select NEW_LEDS + select LEDS_CLASS + default n + help + This driver provides support for the Apple System Management + Controller, which provides an accelerometer (Apple Sudden Motion + Sensor), light sensors, temperature sensors, keyboard backlight + control and fan control. + + Only Intel-based Apple's computers are supported (MacBook Pro, + MacBook, MacMini). + + Data from the different sensors, keyboard backlight control and fan + control are accessible via sysfs. + + This driver also provides an absolute input class device, allowing + the laptop to act as a pinball machine-esque joystick. + + Say Y here if you have an applicable laptop and want to experience + the awesome power of applesmc. + config HWMON_DEBUG_CHIP bool "Hardware Monitoring Chip debugging messages" - depends on HWMON default n help Say Y here if you want the I2C chip drivers to produce a bunch of @@ -604,4 +650,4 @@ config HWMON_DEBUG_CHIP a problem with I2C support and want to see more of what is going on. -endmenu +endif # HWMON diff --git a/trunk/drivers/hwmon/Makefile b/trunk/drivers/hwmon/Makefile index 4165c27a2f25..cfaf338919dd 100644 --- a/trunk/drivers/hwmon/Makefile +++ b/trunk/drivers/hwmon/Makefile @@ -14,14 +14,17 @@ obj-$(CONFIG_SENSORS_W83781D) += w83781d.o obj-$(CONFIG_SENSORS_W83791D) += w83791d.o obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o +obj-$(CONFIG_SENSORS_AD7418) += ad7418.o obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o +obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o obj-$(CONFIG_SENSORS_AMS) += ams/ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o +obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_F71805F) += f71805f.o obj-$(CONFIG_SENSORS_FSCHER) += fscher.o @@ -43,6 +46,7 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o obj-$(CONFIG_SENSORS_LM90) += lm90.o obj-$(CONFIG_SENSORS_LM92) += lm92.o obj-$(CONFIG_SENSORS_MAX1619) += max1619.o +obj-$(CONFIG_SENSORS_MAX6650) += max6650.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o diff --git a/trunk/drivers/hwmon/ad7418.c b/trunk/drivers/hwmon/ad7418.c new file mode 100644 index 000000000000..cc8b624a1e51 --- /dev/null +++ b/trunk/drivers/hwmon/ad7418.c @@ -0,0 +1,373 @@ +/* + * An hwmon driver for the Analog Devices AD7416/17/18 + * Copyright (C) 2006-07 Tower Technologies + * + * Author: Alessandro Zummo + * + * Based on lm75.c + * Copyright (C) 1998-99 Frodo Looijaard + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lm75.h" + +#define DRV_VERSION "0.3" + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x28, I2C_CLIENT_END }; +/* Insmod parameters */ +I2C_CLIENT_INSMOD_3(ad7416, ad7417, ad7418); + +/* AD7418 registers */ +#define AD7418_REG_TEMP_IN 0x00 +#define AD7418_REG_CONF 0x01 +#define AD7418_REG_TEMP_HYST 0x02 +#define AD7418_REG_TEMP_OS 0x03 +#define AD7418_REG_ADC 0x04 +#define AD7418_REG_CONF2 0x05 + +#define AD7418_REG_ADC_CH(x) ((x) << 5) +#define AD7418_CH_TEMP AD7418_REG_ADC_CH(0) + +static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN, + AD7418_REG_TEMP_HYST, + AD7418_REG_TEMP_OS }; + +struct ad7418_data { + struct i2c_client client; + struct class_device *class_dev; + struct attribute_group attrs; + enum chips type; + struct mutex lock; + int adc_max; /* number of ADC channels */ + char valid; + unsigned long last_updated; /* In jiffies */ + s16 temp[3]; /* Register values */ + u16 in[4]; +}; + +static int ad7418_attach_adapter(struct i2c_adapter *adapter); +static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind); +static int ad7418_detach_client(struct i2c_client *client); + +static struct i2c_driver ad7418_driver = { + .driver = { + .name = "ad7418", + }, + .attach_adapter = ad7418_attach_adapter, + .detach_client = ad7418_detach_client, +}; + +/* All registers are word-sized, except for the configuration registers. + * AD7418 uses a high-byte first convention. Do NOT use those functions to + * access the configuration registers CONF and CONF2, as they are byte-sized. + */ +static inline int ad7418_read(struct i2c_client *client, u8 reg) +{ + return swab16(i2c_smbus_read_word_data(client, reg)); +} + +static inline int ad7418_write(struct i2c_client *client, u8 reg, u16 value) +{ + return i2c_smbus_write_word_data(client, reg, swab16(value)); +} + +static void ad7418_init_client(struct i2c_client *client) +{ + struct ad7418_data *data = i2c_get_clientdata(client); + + int reg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF); + if (reg < 0) { + dev_err(&client->dev, "cannot read configuration register\n"); + } else { + dev_info(&client->dev, "configuring for mode 1\n"); + i2c_smbus_write_byte_data(client, AD7418_REG_CONF, reg & 0xfe); + + if (data->type == ad7417 || data->type == ad7418) + i2c_smbus_write_byte_data(client, + AD7418_REG_CONF2, 0x00); + } +} + +static struct ad7418_data *ad7418_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ad7418_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + u8 cfg; + int i, ch; + + /* read config register and clear channel bits */ + cfg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF); + cfg &= 0x1F; + + i2c_smbus_write_byte_data(client, AD7418_REG_CONF, + cfg | AD7418_CH_TEMP); + udelay(30); + + for (i = 0; i < 3; i++) { + data->temp[i] = ad7418_read(client, AD7418_REG_TEMP[i]); + } + + for (i = 0, ch = 4; i < data->adc_max; i++, ch--) { + i2c_smbus_write_byte_data(client, + AD7418_REG_CONF, + cfg | AD7418_REG_ADC_CH(ch)); + + udelay(15); + data->in[data->adc_max - 1 - i] = + ad7418_read(client, AD7418_REG_ADC); + } + + /* restore old configuration value */ + ad7418_write(client, AD7418_REG_CONF, cfg); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->lock); + + return data; +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct ad7418_data *data = ad7418_update_device(dev); + return sprintf(buf, "%d\n", + LM75_TEMP_FROM_REG(data->temp[attr->index])); +} + +static ssize_t show_adc(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct ad7418_data *data = ad7418_update_device(dev); + + return sprintf(buf, "%d\n", + ((data->in[attr->index] >> 6) * 2500 + 512) / 1024); +} + +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct ad7418_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->lock); + data->temp[attr->index] = LM75_TEMP_TO_REG(temp); + ad7418_write(client, AD7418_REG_TEMP[attr->index], data->temp[attr->index]); + mutex_unlock(&data->lock); + return count; +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, + show_temp, set_temp, 1); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + show_temp, set_temp, 2); + +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 0); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 1); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 2); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 3); + +static int ad7418_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, ad7418_detect); +} + +static struct attribute *ad7416_attributes[] = { + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL +}; + +static struct attribute *ad7417_attributes[] = { + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + NULL +}; + +static struct attribute *ad7418_attributes[] = { + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + NULL +}; + +static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct ad7418_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + if (!(data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + client = &data->client; + client->addr = address; + client->adapter = adapter; + client->driver = &ad7418_driver; + + i2c_set_clientdata(client, data); + + mutex_init(&data->lock); + + /* AD7418 has a curious behaviour on registers 6 and 7. They + * both always read 0xC071 and are not documented on the datasheet. + * We use them to detect the chip. + */ + if (kind <= 0) { + int reg, reg6, reg7; + + /* the AD7416 lies within this address range, but I have + * no means to check. + */ + if (address >= 0x48 && address <= 0x4f) { + /* XXX add tests for AD7416 here */ + /* data->type = ad7416; */ + } + /* here we might have AD7417 or AD7418 */ + else if (address >= 0x28 && address <= 0x2f) { + reg6 = i2c_smbus_read_word_data(client, 0x06); + reg7 = i2c_smbus_read_word_data(client, 0x07); + + if (address == 0x28 && reg6 == 0xC071 && reg7 == 0xC071) + data->type = ad7418; + + /* XXX add tests for AD7417 here */ + + + /* both AD7417 and AD7418 have bits 0-5 of + * the CONF2 register at 0 + */ + reg = i2c_smbus_read_byte_data(client, + AD7418_REG_CONF2); + if (reg & 0x3F) + data->type = any_chip; /* detection failed */ + } + } else { + dev_dbg(&adapter->dev, "detection forced\n"); + } + + if (kind > 0) + data->type = kind; + else if (kind < 0 && data->type == any_chip) { + err = -ENODEV; + goto exit_free; + } + + switch (data->type) { + case any_chip: + case ad7416: + data->adc_max = 0; + data->attrs.attrs = ad7416_attributes; + strlcpy(client->name, "ad7416", I2C_NAME_SIZE); + break; + + case ad7417: + data->adc_max = 4; + data->attrs.attrs = ad7417_attributes; + strlcpy(client->name, "ad7417", I2C_NAME_SIZE); + break; + + case ad7418: + data->adc_max = 1; + data->attrs.attrs = ad7418_attributes; + strlcpy(client->name, "ad7418", I2C_NAME_SIZE); + break; + } + + if ((err = i2c_attach_client(client))) + goto exit_free; + + dev_info(&client->dev, "%s chip found\n", client->name); + + /* Initialize the AD7418 chip */ + ad7418_init_client(client); + + /* Register sysfs hooks */ + if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) + goto exit_detach; + + data->class_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove; + } + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &data->attrs); +exit_detach: + i2c_detach_client(client); +exit_free: + kfree(data); +exit: + return err; +} + +static int ad7418_detach_client(struct i2c_client *client) +{ + struct ad7418_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &data->attrs); + i2c_detach_client(client); + kfree(data); + return 0; +} + +static int __init ad7418_init(void) +{ + return i2c_add_driver(&ad7418_driver); +} + +static void __exit ad7418_exit(void) +{ + i2c_del_driver(&ad7418_driver); +} + +MODULE_AUTHOR("Alessandro Zummo "); +MODULE_DESCRIPTION("AD7416/17/18 driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(ad7418_init); +module_exit(ad7418_exit); diff --git a/trunk/drivers/hwmon/ams/ams-core.c b/trunk/drivers/hwmon/ams/ams-core.c index f5ebad561412..6db973739725 100644 --- a/trunk/drivers/hwmon/ams/ams-core.c +++ b/trunk/drivers/hwmon/ams/ams-core.c @@ -144,7 +144,7 @@ int ams_sensor_attach(void) const u32 *prop; /* Get orientation */ - prop = get_property(ams_info.of_node, "orientation", NULL); + prop = of_get_property(ams_info.of_node, "orientation", NULL); if (!prop) return -ENODEV; ams_info.orient1 = *prop; @@ -208,20 +208,17 @@ int __init ams_init(void) #ifdef CONFIG_SENSORS_AMS_I2C np = of_find_node_by_name(NULL, "accelerometer"); - if (np && device_is_compatible(np, "AAPL,accelerometer_1")) + if (np && of_device_is_compatible(np, "AAPL,accelerometer_1")) /* Found I2C motion sensor */ return ams_i2c_init(np); #endif #ifdef CONFIG_SENSORS_AMS_PMU np = of_find_node_by_name(NULL, "sms"); - if (np && device_is_compatible(np, "sms")) + if (np && of_device_is_compatible(np, "sms")) /* Found PMU motion sensor */ return ams_pmu_init(np); #endif - - printk(KERN_ERR "ams: No motion sensor found.\n"); - return -ENODEV; } diff --git a/trunk/drivers/hwmon/ams/ams-i2c.c b/trunk/drivers/hwmon/ams/ams-i2c.c index 485d333bcb3e..957760536a4c 100644 --- a/trunk/drivers/hwmon/ams/ams-i2c.c +++ b/trunk/drivers/hwmon/ams/ams-i2c.c @@ -85,17 +85,17 @@ static int ams_i2c_write(u8 reg, u8 value) static int ams_i2c_cmd(enum ams_i2c_cmd cmd) { s32 result; - int remaining = HZ / 20; + int count = 3; ams_i2c_write(AMS_COMMAND, cmd); - mdelay(5); + msleep(5); - while (remaining) { + while (count--) { result = ams_i2c_read(AMS_COMMAND); if (result == 0 || result & 0x80) return 0; - remaining = schedule_timeout(remaining); + schedule_timeout_uninterruptible(HZ / 20); } return -1; @@ -276,7 +276,7 @@ int __init ams_i2c_init(struct device_node *np) ams_info.bustype = BUS_I2C; /* look for bus either using "reg" or by path */ - prop = get_property(ams_info.of_node, "reg", NULL); + prop = of_get_property(ams_info.of_node, "reg", NULL); if (!prop) { result = -ENODEV; diff --git a/trunk/drivers/hwmon/ams/ams-pmu.c b/trunk/drivers/hwmon/ams/ams-pmu.c index 1b01c215bfe7..9463e9768f6f 100644 --- a/trunk/drivers/hwmon/ams/ams-pmu.c +++ b/trunk/drivers/hwmon/ams/ams-pmu.c @@ -160,7 +160,7 @@ int __init ams_pmu_init(struct device_node *np) ams_info.bustype = BUS_HOST; /* Get PMU command, should be 0x4e, but we can never know */ - prop = get_property(ams_info.of_node, "reg", NULL); + prop = of_get_property(ams_info.of_node, "reg", NULL); if (!prop) { result = -ENODEV; goto exit; diff --git a/trunk/drivers/hwmon/applesmc.c b/trunk/drivers/hwmon/applesmc.c new file mode 100644 index 000000000000..3215f9c87f32 --- /dev/null +++ b/trunk/drivers/hwmon/applesmc.c @@ -0,0 +1,1339 @@ +/* + * drivers/hwmon/applesmc.c - driver for Apple's SMC (accelerometer, temperature + * sensors, fan control, keyboard backlight control) used in Intel-based Apple + * computers. + * + * Copyright (C) 2007 Nicolas Boichat + * + * Based on hdaps.c driver: + * Copyright (C) 2005 Robert Love + * Copyright (C) 2005 Jesper Juhl + * + * Fan control based on smcFanControl: + * Copyright (C) 2006 Hendrik Holtmann + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* data port used by Apple SMC */ +#define APPLESMC_DATA_PORT 0x300 +/* command/status port used by Apple SMC */ +#define APPLESMC_CMD_PORT 0x304 + +#define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */ + +#define APPLESMC_MAX_DATA_LENGTH 32 + +#define APPLESMC_STATUS_MASK 0x0f +#define APPLESMC_READ_CMD 0x10 +#define APPLESMC_WRITE_CMD 0x11 +#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12 +#define APPLESMC_GET_KEY_TYPE_CMD 0x13 + +#define KEY_COUNT_KEY "#KEY" /* r-o ui32 */ + +#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6 bytes) */ +#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */ +#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */ + +#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */ + +#define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */ +#define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */ +#define MOTION_SENSOR_Z_KEY "MO_Z" /* r-o sp78 (2 bytes) */ +#define MOTION_SENSOR_KEY "MOCN" /* r/w ui16 */ + +#define FANS_COUNT "FNum" /* r-o ui8 */ +#define FANS_MANUAL "FS! " /* r-w ui16 */ +#define FAN_ACTUAL_SPEED "F0Ac" /* r-o fpe2 (2 bytes) */ +#define FAN_MIN_SPEED "F0Mn" /* r-o fpe2 (2 bytes) */ +#define FAN_MAX_SPEED "F0Mx" /* r-o fpe2 (2 bytes) */ +#define FAN_SAFE_SPEED "F0Sf" /* r-o fpe2 (2 bytes) */ +#define FAN_TARGET_SPEED "F0Tg" /* r-w fpe2 (2 bytes) */ +#define FAN_POSITION "F0ID" /* r-o char[16] */ + +/* + * Temperature sensors keys (sp78 - 2 bytes). + * First set for Macbook(Pro), second for Macmini. + */ +static const char* temperature_sensors_sets[][13] = { + { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H", + "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL }, + { "TC0D", "TC0P", NULL } +}; + +/* List of keys used to read/write fan speeds */ +static const char* fan_speed_keys[] = { + FAN_ACTUAL_SPEED, + FAN_MIN_SPEED, + FAN_MAX_SPEED, + FAN_SAFE_SPEED, + FAN_TARGET_SPEED +}; + +#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */ +#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */ + +#define APPLESMC_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */ +#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */ +#define APPLESMC_INPUT_FLAT 4 + +#define SENSOR_X 0 +#define SENSOR_Y 1 +#define SENSOR_Z 2 + +/* Structure to be passed to DMI_MATCH function */ +struct dmi_match_data { +/* Indicates whether this computer has an accelerometer. */ + int accelerometer; +/* Indicates whether this computer has light sensors and keyboard backlight. */ + int light; +/* Indicates which temperature sensors set to use. */ + int temperature_set; +}; + +static const int debug; +static struct platform_device *pdev; +static s16 rest_x; +static s16 rest_y; +static struct timer_list applesmc_timer; +static struct input_dev *applesmc_idev; +static struct class_device *hwmon_class_dev; + +/* Indicates whether this computer has an accelerometer. */ +static unsigned int applesmc_accelerometer; + +/* Indicates whether this computer has light sensors and keyboard backlight. */ +static unsigned int applesmc_light; + +/* Indicates which temperature sensors set to use. */ +static unsigned int applesmc_temperature_set; + +static struct mutex applesmc_lock; + +/* + * Last index written to key_at_index sysfs file, and value to use for all other + * key_at_index_* sysfs files. + */ +static unsigned int key_at_index; + +static struct workqueue_struct *applesmc_led_wq; + +/* + * __wait_status - Wait up to 2ms for the status port to get a certain value + * (masked with 0x0f), returning zero if the value is obtained. Callers must + * hold applesmc_lock. + */ +static int __wait_status(u8 val) +{ + unsigned int i; + + val = val & APPLESMC_STATUS_MASK; + + for (i = 0; i < 200; i++) { + if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) { + if (debug) + printk(KERN_DEBUG + "Waited %d us for status %x\n", + i*10, val); + return 0; + } + udelay(10); + } + + printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n", + val, inb(APPLESMC_CMD_PORT)); + + return -EIO; +} + +/* + * applesmc_read_key - reads len bytes from a given key, and put them in buffer. + * Returns zero on success or a negative error on failure. Callers must + * hold applesmc_lock. + */ +static int applesmc_read_key(const char* key, u8* buffer, u8 len) +{ + int i; + + if (len > APPLESMC_MAX_DATA_LENGTH) { + printk(KERN_ERR "applesmc_read_key: cannot read more than " + "%d bytes\n", APPLESMC_MAX_DATA_LENGTH); + return -EINVAL; + } + + outb(APPLESMC_READ_CMD, APPLESMC_CMD_PORT); + if (__wait_status(0x0c)) + return -EIO; + + for (i = 0; i < 4; i++) { + outb(key[i], APPLESMC_DATA_PORT); + if (__wait_status(0x04)) + return -EIO; + } + if (debug) + printk(KERN_DEBUG "<%s", key); + + outb(len, APPLESMC_DATA_PORT); + if (debug) + printk(KERN_DEBUG ">%x", len); + + for (i = 0; i < len; i++) { + if (__wait_status(0x05)) + return -EIO; + buffer[i] = inb(APPLESMC_DATA_PORT); + if (debug) + printk(KERN_DEBUG "<%x", buffer[i]); + } + if (debug) + printk(KERN_DEBUG "\n"); + + return 0; +} + +/* + * applesmc_write_key - writes len bytes from buffer to a given key. + * Returns zero on success or a negative error on failure. Callers must + * hold applesmc_lock. + */ +static int applesmc_write_key(const char* key, u8* buffer, u8 len) +{ + int i; + + if (len > APPLESMC_MAX_DATA_LENGTH) { + printk(KERN_ERR "applesmc_write_key: cannot write more than " + "%d bytes\n", APPLESMC_MAX_DATA_LENGTH); + return -EINVAL; + } + + outb(APPLESMC_WRITE_CMD, APPLESMC_CMD_PORT); + if (__wait_status(0x0c)) + return -EIO; + + for (i = 0; i < 4; i++) { + outb(key[i], APPLESMC_DATA_PORT); + if (__wait_status(0x04)) + return -EIO; + } + + outb(len, APPLESMC_DATA_PORT); + + for (i = 0; i < len; i++) { + if (__wait_status(0x04)) + return -EIO; + outb(buffer[i], APPLESMC_DATA_PORT); + } + + return 0; +} + +/* + * applesmc_get_key_at_index - get key at index, and put the result in key + * (char[6]). Returns zero on success or a negative error on failure. Callers + * must hold applesmc_lock. + */ +static int applesmc_get_key_at_index(int index, char* key) +{ + int i; + u8 readkey[4]; + readkey[0] = index >> 24; + readkey[1] = index >> 16; + readkey[2] = index >> 8; + readkey[3] = index; + + outb(APPLESMC_GET_KEY_BY_INDEX_CMD, APPLESMC_CMD_PORT); + if (__wait_status(0x0c)) + return -EIO; + + for (i = 0; i < 4; i++) { + outb(readkey[i], APPLESMC_DATA_PORT); + if (__wait_status(0x04)) + return -EIO; + } + + outb(4, APPLESMC_DATA_PORT); + + for (i = 0; i < 4; i++) { + if (__wait_status(0x05)) + return -EIO; + key[i] = inb(APPLESMC_DATA_PORT); + } + key[4] = 0; + + return 0; +} + +/* + * applesmc_get_key_type - get key type, and put the result in type (char[6]). + * Returns zero on success or a negative error on failure. Callers must + * hold applesmc_lock. + */ +static int applesmc_get_key_type(char* key, char* type) +{ + int i; + + outb(APPLESMC_GET_KEY_TYPE_CMD, APPLESMC_CMD_PORT); + if (__wait_status(0x0c)) + return -EIO; + + for (i = 0; i < 4; i++) { + outb(key[i], APPLESMC_DATA_PORT); + if (__wait_status(0x04)) + return -EIO; + } + + outb(5, APPLESMC_DATA_PORT); + + for (i = 0; i < 6; i++) { + if (__wait_status(0x05)) + return -EIO; + type[i] = inb(APPLESMC_DATA_PORT); + } + type[5] = 0; + + return 0; +} + +/* + * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must + * hold applesmc_lock. + */ +static int applesmc_read_motion_sensor(int index, s16* value) +{ + u8 buffer[2]; + int ret; + + switch (index) { + case SENSOR_X: + ret = applesmc_read_key(MOTION_SENSOR_X_KEY, buffer, 2); + break; + case SENSOR_Y: + ret = applesmc_read_key(MOTION_SENSOR_Y_KEY, buffer, 2); + break; + case SENSOR_Z: + ret = applesmc_read_key(MOTION_SENSOR_Z_KEY, buffer, 2); + break; + default: + ret = -EINVAL; + } + + *value = ((s16)buffer[0] << 8) | buffer[1]; + + return ret; +} + +/* + * applesmc_device_init - initialize the accelerometer. Returns zero on success + * and negative error code on failure. Can sleep. + */ +static int applesmc_device_init(void) +{ + int total, ret = -ENXIO; + u8 buffer[2]; + + if (!applesmc_accelerometer) + return 0; + + mutex_lock(&applesmc_lock); + + for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) { + if (debug) + printk(KERN_DEBUG "applesmc try %d\n", total); + if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) && + (buffer[0] != 0x00 || buffer[1] != 0x00)) { + if (total == INIT_TIMEOUT_MSECS) { + printk(KERN_DEBUG "applesmc: device has" + " already been initialized" + " (0x%02x, 0x%02x).\n", + buffer[0], buffer[1]); + } else { + printk(KERN_DEBUG "applesmc: device" + " successfully initialized" + " (0x%02x, 0x%02x).\n", + buffer[0], buffer[1]); + } + ret = 0; + goto out; + } + buffer[0] = 0xe0; + buffer[1] = 0x00; + applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2); + msleep(INIT_WAIT_MSECS); + } + + printk(KERN_WARNING "applesmc: failed to init the device\n"); + +out: + mutex_unlock(&applesmc_lock); + return ret; +} + +/* + * applesmc_get_fan_count - get the number of fans. Callers must NOT hold + * applesmc_lock. + */ +static int applesmc_get_fan_count(void) +{ + int ret; + u8 buffer[1]; + + mutex_lock(&applesmc_lock); + + ret = applesmc_read_key(FANS_COUNT, buffer, 1); + + mutex_unlock(&applesmc_lock); + if (ret) + return ret; + else + return buffer[0]; +} + +/* Device model stuff */ +static int applesmc_probe(struct platform_device *dev) +{ + int ret; + + ret = applesmc_device_init(); + if (ret) + return ret; + + printk(KERN_INFO "applesmc: device successfully initialized.\n"); + return 0; +} + +static int applesmc_resume(struct platform_device *dev) +{ + return applesmc_device_init(); +} + +static struct platform_driver applesmc_driver = { + .probe = applesmc_probe, + .resume = applesmc_resume, + .driver = { + .name = "applesmc", + .owner = THIS_MODULE, + }, +}; + +/* + * applesmc_calibrate - Set our "resting" values. Callers must + * hold applesmc_lock. + */ +static void applesmc_calibrate(void) +{ + applesmc_read_motion_sensor(SENSOR_X, &rest_x); + applesmc_read_motion_sensor(SENSOR_Y, &rest_y); + rest_x = -rest_x; +} + +static int applesmc_idev_open(struct input_dev *dev) +{ + add_timer(&applesmc_timer); + + return 0; +} + +static void applesmc_idev_close(struct input_dev *dev) +{ + del_timer_sync(&applesmc_timer); +} + +static void applesmc_idev_poll(unsigned long unused) +{ + s16 x, y; + + /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ + if (!mutex_trylock(&applesmc_lock)) { + mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD); + return; + } + + if (applesmc_read_motion_sensor(SENSOR_X, &x)) + goto out; + if (applesmc_read_motion_sensor(SENSOR_Y, &y)) + goto out; + + x = -x; + input_report_abs(applesmc_idev, ABS_X, x - rest_x); + input_report_abs(applesmc_idev, ABS_Y, y - rest_y); + input_sync(applesmc_idev); + +out: + mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD); + + mutex_unlock(&applesmc_lock); +} + +/* Sysfs Files */ + +static ssize_t applesmc_position_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + s16 x, y, z; + + mutex_lock(&applesmc_lock); + + ret = applesmc_read_motion_sensor(SENSOR_X, &x); + if (ret) + goto out; + ret = applesmc_read_motion_sensor(SENSOR_Y, &y); + if (ret) + goto out; + ret = applesmc_read_motion_sensor(SENSOR_Z, &z); + if (ret) + goto out; + +out: + mutex_unlock(&applesmc_lock); + if (ret) + return ret; + else + return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z); +} + +static ssize_t applesmc_light_show(struct device *dev, + struct device_attribute *attr, char *sysfsbuf) +{ + int ret; + u8 left = 0, right = 0; + u8 buffer[6]; + + mutex_lock(&applesmc_lock); + + ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, 6); + left = buffer[2]; + if (ret) + goto out; + ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, 6); + right = buffer[2]; + +out: + mutex_unlock(&applesmc_lock); + if (ret) + return ret; + else + return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right); +} + +/* Displays degree Celsius * 1000 */ +static ssize_t applesmc_show_temperature(struct device *dev, + struct device_attribute *devattr, char *sysfsbuf) +{ + int ret; + u8 buffer[2]; + unsigned int temp; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + const char* key = + temperature_sensors_sets[applesmc_temperature_set][attr->index]; + + mutex_lock(&applesmc_lock); + + ret = applesmc_read_key(key, buffer, 2); + temp = buffer[0]*1000; + temp += (buffer[1] >> 6) * 250; + + mutex_unlock(&applesmc_lock); + + if (ret) + return ret; + else + return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp); +} + +static ssize_t applesmc_show_fan_speed(struct device *dev, + struct device_attribute *attr, char *sysfsbuf) +{ + int ret; + unsigned int speed = 0; + char newkey[5]; + u8 buffer[2]; + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + + newkey[0] = fan_speed_keys[sensor_attr->nr][0]; + newkey[1] = '0' + sensor_attr->index; + newkey[2] = fan_speed_keys[sensor_attr->nr][2]; + newkey[3] = fan_speed_keys[sensor_attr->nr][3]; + newkey[4] = 0; + + mutex_lock(&applesmc_lock); + + ret = applesmc_read_key(newkey, buffer, 2); + speed = ((buffer[0] << 8 | buffer[1]) >> 2); + + mutex_unlock(&applesmc_lock); + if (ret) + return ret; + else + return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed); +} + +static ssize_t applesmc_store_fan_speed(struct device *dev, + struct device_attribute *attr, + const char *sysfsbuf, size_t count) +{ + int ret; + u32 speed; + char newkey[5]; + u8 buffer[2]; + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + + speed = simple_strtoul(sysfsbuf, NULL, 10); + + if (speed > 0x4000) /* Bigger than a 14-bit value */ + return -EINVAL; + + newkey[0] = fan_speed_keys[sensor_attr->nr][0]; + newkey[1] = '0' + sensor_attr->index; + newkey[2] = fan_speed_keys[sensor_attr->nr][2]; + newkey[3] = fan_speed_keys[sensor_attr->nr][3]; + newkey[4] = 0; + + mutex_lock(&applesmc_lock); + + buffer[0] = (speed >> 6) & 0xff; + buffer[1] = (speed << 2) & 0xff; + ret = applesmc_write_key(newkey, buffer, 2); + + mutex_unlock(&applesmc_lock); + if (ret) + return ret; + else + return count; +} + +static ssize_t applesmc_show_fan_manual(struct device *dev, + struct device_attribute *devattr, char *sysfsbuf) +{ + int ret; + u16 manual = 0; + u8 buffer[2]; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + mutex_lock(&applesmc_lock); + + ret = applesmc_read_key(FANS_MANUAL, buffer, 2); + manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01; + + mutex_unlock(&applesmc_lock); + if (ret) + return ret; + else + return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual); +} + +static ssize_t applesmc_store_fan_manual(struct device *dev, + struct device_attribute *devattr, + const char *sysfsbuf, size_t count) +{ + int ret; + u8 buffer[2]; + u32 input; + u16 val; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + input = simple_strtoul(sysfsbuf, NULL, 10); + + mutex_lock(&applesmc_lock); + + ret = applesmc_read_key(FANS_MANUAL, buffer, 2); + val = (buffer[0] << 8 | buffer[1]); + if (ret) + goto out; + + if (input) + val = val | (0x01 << attr->index); + else + val = val & ~(0x01 << attr->index); + + buffer[0] = (val >> 8) & 0xFF; + buffer[1] = val & 0xFF; + + ret = applesmc_write_key(FANS_MANUAL, buffer, 2); + +out: + mutex_unlock(&applesmc_lock); + if (ret) + return ret; + else + return count; +} + +static ssize_t applesmc_show_fan_position(struct device *dev, + struct device_attribute *attr, char *sysfsbuf) +{ + int ret; + char newkey[5]; + u8 buffer[17]; + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + + newkey[0] = FAN_POSITION[0]; + newkey[1] = '0' + sensor_attr->index; + newkey[2] = FAN_POSITION[2]; + newkey[3] = FAN_POSITION[3]; + newkey[4] = 0; + + mutex_lock(&applesmc_lock); + + ret = applesmc_read_key(newkey, buffer, 16); + buffer[16] = 0; + + mutex_unlock(&applesmc_lock); + if (ret) + return ret; + else + return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4); +} + +static ssize_t applesmc_calibrate_show(struct device *dev, + struct device_attribute *attr, char *sysfsbuf) +{ + return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y); +} + +static ssize_t applesmc_calibrate_store(struct device *dev, + struct device_attribute *attr, const char *sysfsbuf, size_t count) +{ + mutex_lock(&applesmc_lock); + applesmc_calibrate(); + mutex_unlock(&applesmc_lock); + + return count; +} + +/* Store the next backlight value to be written by the work */ +static unsigned int backlight_value; + +static void applesmc_backlight_set(struct work_struct *work) +{ + u8 buffer[2]; + + mutex_lock(&applesmc_lock); + buffer[0] = backlight_value; + buffer[1] = 0x00; + applesmc_write_key(BACKLIGHT_KEY, buffer, 2); + mutex_unlock(&applesmc_lock); +} +static DECLARE_WORK(backlight_work, &applesmc_backlight_set); + +static void applesmc_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + int ret; + + backlight_value = value; + ret = queue_work(applesmc_led_wq, &backlight_work); + + if (debug && (!ret)) + printk(KERN_DEBUG "applesmc: work was already on the queue.\n"); +} + +static ssize_t applesmc_key_count_show(struct device *dev, + struct device_attribute *attr, char *sysfsbuf) +{ + int ret; + u8 buffer[4]; + u32 count; + + mutex_lock(&applesmc_lock); + + ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4); + count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) + + ((u32)buffer[2]<<8) + buffer[3]; + + mutex_unlock(&applesmc_lock); + if (ret) + return ret; + else + return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count); +} + +static ssize_t applesmc_key_at_index_read_show(struct device *dev, + struct device_attribute *attr, char *sysfsbuf) +{ + char key[5]; + char info[6]; + int ret; + + mutex_lock(&applesmc_lock); + + ret = applesmc_get_key_at_index(key_at_index, key); + + if (ret || !key[0]) { + mutex_unlock(&applesmc_lock); + + return -EINVAL; + } + + ret = applesmc_get_key_type(key, info); + + if (ret) { + mutex_unlock(&applesmc_lock); + + return ret; + } + + /* + * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than + * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf. + */ + ret = applesmc_read_key(key, sysfsbuf, info[0]); + + mutex_unlock(&applesmc_lock); + + if (!ret) { + return info[0]; + } + else { + return ret; + } +} + +static ssize_t applesmc_key_at_index_data_length_show(struct device *dev, + struct device_attribute *attr, char *sysfsbuf) +{ + char key[5]; + char info[6]; + int ret; + + mutex_lock(&applesmc_lock); + + ret = applesmc_get_key_at_index(key_at_index, key); + + if (ret || !key[0]) { + mutex_unlock(&applesmc_lock); + + return -EINVAL; + } + + ret = applesmc_get_key_type(key, info); + + mutex_unlock(&applesmc_lock); + + if (!ret) + return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]); + else + return ret; +} + +static ssize_t applesmc_key_at_index_type_show(struct device *dev, + struct device_attribute *attr, char *sysfsbuf) +{ + char key[5]; + char info[6]; + int ret; + + mutex_lock(&applesmc_lock); + + ret = applesmc_get_key_at_index(key_at_index, key); + + if (ret || !key[0]) { + mutex_unlock(&applesmc_lock); + + return -EINVAL; + } + + ret = applesmc_get_key_type(key, info); + + mutex_unlock(&applesmc_lock); + + if (!ret) + return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1); + else + return ret; +} + +static ssize_t applesmc_key_at_index_name_show(struct device *dev, + struct device_attribute *attr, char *sysfsbuf) +{ + char key[5]; + int ret; + + mutex_lock(&applesmc_lock); + + ret = applesmc_get_key_at_index(key_at_index, key); + + mutex_unlock(&applesmc_lock); + + if (!ret && key[0]) + return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key); + else + return -EINVAL; +} + +static ssize_t applesmc_key_at_index_show(struct device *dev, + struct device_attribute *attr, char *sysfsbuf) +{ + return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index); +} + +static ssize_t applesmc_key_at_index_store(struct device *dev, + struct device_attribute *attr, const char *sysfsbuf, size_t count) +{ + mutex_lock(&applesmc_lock); + + key_at_index = simple_strtoul(sysfsbuf, NULL, 10); + + mutex_unlock(&applesmc_lock); + + return count; +} + +static struct led_classdev applesmc_backlight = { + .name = "smc:kbd_backlight", + .default_trigger = "nand-disk", + .brightness_set = applesmc_brightness_set, +}; + +static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL); +static DEVICE_ATTR(calibrate, 0644, + applesmc_calibrate_show, applesmc_calibrate_store); + +static struct attribute *accelerometer_attributes[] = { + &dev_attr_position.attr, + &dev_attr_calibrate.attr, + NULL +}; + +static const struct attribute_group accelerometer_attributes_group = + { .attrs = accelerometer_attributes }; + +static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL); + +static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL); +static DEVICE_ATTR(key_at_index, 0644, + applesmc_key_at_index_show, applesmc_key_at_index_store); +static DEVICE_ATTR(key_at_index_name, 0444, + applesmc_key_at_index_name_show, NULL); +static DEVICE_ATTR(key_at_index_type, 0444, + applesmc_key_at_index_type_show, NULL); +static DEVICE_ATTR(key_at_index_data_length, 0444, + applesmc_key_at_index_data_length_show, NULL); +static DEVICE_ATTR(key_at_index_data, 0444, + applesmc_key_at_index_read_show, NULL); + +static struct attribute *key_enumeration_attributes[] = { + &dev_attr_key_count.attr, + &dev_attr_key_at_index.attr, + &dev_attr_key_at_index_name.attr, + &dev_attr_key_at_index_type.attr, + &dev_attr_key_at_index_data_length.attr, + &dev_attr_key_at_index_data.attr, + NULL +}; + +static const struct attribute_group key_enumeration_group = + { .attrs = key_enumeration_attributes }; + +/* + * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries. + * - show actual speed + * - show/store minimum speed + * - show maximum speed + * - show safe speed + * - show/store target speed + * - show/store manual mode + */ +#define sysfs_fan_speeds_offset(offset) \ +static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \ + applesmc_show_fan_speed, NULL, 0, offset-1); \ +\ +static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \ + applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \ +\ +static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \ + applesmc_show_fan_speed, NULL, 2, offset-1); \ +\ +static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \ + applesmc_show_fan_speed, NULL, 3, offset-1); \ +\ +static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \ + applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \ +\ +static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \ + applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \ +\ +static SENSOR_DEVICE_ATTR(fan##offset##_position, S_IRUGO, \ + applesmc_show_fan_position, NULL, offset-1); \ +\ +static struct attribute *fan##offset##_attributes[] = { \ + &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \ + &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \ + &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \ + &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \ + &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \ + &sensor_dev_attr_fan##offset##_position.dev_attr.attr, \ + NULL \ +}; + +/* + * Create the needed functions for each fan using the macro defined above + * (2 fans are supported) + */ +sysfs_fan_speeds_offset(1); +sysfs_fan_speeds_offset(2); + +static const struct attribute_group fan_attribute_groups[] = { + { .attrs = fan1_attributes }, + { .attrs = fan2_attributes } +}; + +/* + * Temperature sensors sysfs entries. + */ +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, + applesmc_show_temperature, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, + applesmc_show_temperature, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, + applesmc_show_temperature, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, + applesmc_show_temperature, NULL, 3); +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, + applesmc_show_temperature, NULL, 4); +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, + applesmc_show_temperature, NULL, 5); +static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, + applesmc_show_temperature, NULL, 6); +static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, + applesmc_show_temperature, NULL, 7); +static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, + applesmc_show_temperature, NULL, 8); +static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, + applesmc_show_temperature, NULL, 9); +static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO, + applesmc_show_temperature, NULL, 10); +static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO, + applesmc_show_temperature, NULL, 11); + +static struct attribute *temperature_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_temp7_input.dev_attr.attr, + &sensor_dev_attr_temp8_input.dev_attr.attr, + &sensor_dev_attr_temp9_input.dev_attr.attr, + &sensor_dev_attr_temp10_input.dev_attr.attr, + &sensor_dev_attr_temp11_input.dev_attr.attr, + &sensor_dev_attr_temp12_input.dev_attr.attr, + NULL +}; + +static const struct attribute_group temperature_attributes_group = + { .attrs = temperature_attributes }; + +/* Module stuff */ + +/* + * applesmc_dmi_match - found a match. return one, short-circuiting the hunt. + */ +static int applesmc_dmi_match(struct dmi_system_id *id) +{ + int i = 0; + struct dmi_match_data* dmi_data = id->driver_data; + printk(KERN_INFO "applesmc: %s detected:\n", id->ident); + applesmc_accelerometer = dmi_data->accelerometer; + printk(KERN_INFO "applesmc: - Model %s accelerometer\n", + applesmc_accelerometer ? "with" : "without"); + applesmc_light = dmi_data->light; + printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n", + applesmc_light ? "with" : "without"); + + applesmc_temperature_set = dmi_data->temperature_set; + while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL) + i++; + printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i); + return 1; +} + +/* Create accelerometer ressources */ +static int applesmc_create_accelerometer(void) +{ + int ret; + + ret = sysfs_create_group(&pdev->dev.kobj, + &accelerometer_attributes_group); + if (ret) + goto out; + + applesmc_idev = input_allocate_device(); + if (!applesmc_idev) { + ret = -ENOMEM; + goto out_sysfs; + } + + /* initial calibrate for the input device */ + applesmc_calibrate(); + + /* initialize the input class */ + applesmc_idev->name = "applesmc"; + applesmc_idev->id.bustype = BUS_HOST; + applesmc_idev->cdev.dev = &pdev->dev; + applesmc_idev->evbit[0] = BIT(EV_ABS); + applesmc_idev->open = applesmc_idev_open; + applesmc_idev->close = applesmc_idev_close; + input_set_abs_params(applesmc_idev, ABS_X, + -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT); + input_set_abs_params(applesmc_idev, ABS_Y, + -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT); + + ret = input_register_device(applesmc_idev); + if (ret) + goto out_idev; + + /* start up our timer for the input device */ + init_timer(&applesmc_timer); + applesmc_timer.function = applesmc_idev_poll; + applesmc_timer.expires = jiffies + APPLESMC_POLL_PERIOD; + + return 0; + +out_idev: + input_free_device(applesmc_idev); + +out_sysfs: + sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); + +out: + printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret); + return ret; +} + +/* Release all ressources used by the accelerometer */ +static void applesmc_release_accelerometer(void) +{ + del_timer_sync(&applesmc_timer); + input_unregister_device(applesmc_idev); + sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); +} + +static __initdata struct dmi_match_data applesmc_dmi_data[] = { +/* MacBook Pro: accelerometer, backlight and temperature set 0 */ + { .accelerometer = 1, .light = 1, .temperature_set = 0 }, +/* MacBook: accelerometer and temperature set 0 */ + { .accelerometer = 1, .light = 0, .temperature_set = 0 }, +/* MacBook: temperature set 1 */ + { .accelerometer = 0, .light = 0, .temperature_set = 1 } +}; + +/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1". + * So we need to put "Apple MacBook Pro" before "Apple MacBook". */ +static __initdata struct dmi_system_id applesmc_whitelist[] = { + { applesmc_dmi_match, "Apple MacBook Pro", { + DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), + DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") }, + (void*)&applesmc_dmi_data[0]}, + { applesmc_dmi_match, "Apple MacBook", { + DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), + DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") }, + (void*)&applesmc_dmi_data[1]}, + { applesmc_dmi_match, "Apple Macmini", { + DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), + DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") }, + (void*)&applesmc_dmi_data[2]}, + { .ident = NULL } +}; + +static int __init applesmc_init(void) +{ + int ret; + int count; + int i; + + mutex_init(&applesmc_lock); + + if (!dmi_check_system(applesmc_whitelist)) { + printk(KERN_WARNING "applesmc: supported laptop not found!\n"); + ret = -ENODEV; + goto out; + } + + if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS, + "applesmc")) { + ret = -ENXIO; + goto out; + } + + ret = platform_driver_register(&applesmc_driver); + if (ret) + goto out_region; + + pdev = platform_device_register_simple("applesmc", -1, NULL, 0); + if (IS_ERR(pdev)) { + ret = PTR_ERR(pdev); + goto out_driver; + } + + /* Create key enumeration sysfs files */ + ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group); + if (ret) + goto out_device; + + /* create fan files */ + count = applesmc_get_fan_count(); + if (count < 0) { + printk(KERN_ERR "applesmc: Cannot get the number of fans.\n"); + } else { + printk(KERN_INFO "applesmc: %d fans found.\n", count); + + switch (count) { + default: + printk(KERN_WARNING "applesmc: More than 2 fans found," + " but at most 2 fans are supported" + " by the driver.\n"); + case 2: + ret = sysfs_create_group(&pdev->dev.kobj, + &fan_attribute_groups[1]); + if (ret) + goto out_key_enumeration; + case 1: + ret = sysfs_create_group(&pdev->dev.kobj, + &fan_attribute_groups[0]); + if (ret) + goto out_fan_1; + case 0: + ; + } + } + + for (i = 0; + temperature_sensors_sets[applesmc_temperature_set][i] != NULL; + i++) { + if (temperature_attributes[i] == NULL) { + printk(KERN_ERR "applesmc: More temperature sensors " + "in temperature_sensors_sets (at least %i)" + "than available sysfs files in " + "temperature_attributes (%i), please report " + "this bug.\n", i, i-1); + goto out_temperature; + } + ret = sysfs_create_file(&pdev->dev.kobj, + temperature_attributes[i]); + if (ret) + goto out_temperature; + } + + if (applesmc_accelerometer) { + ret = applesmc_create_accelerometer(); + if (ret) + goto out_temperature; + } + + if (applesmc_light) { + /* Add light sensor file */ + ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr); + if (ret) + goto out_accelerometer; + + /* Create the workqueue */ + applesmc_led_wq = create_singlethread_workqueue("applesmc-led"); + if (!applesmc_led_wq) { + ret = -ENOMEM; + goto out_light_sysfs; + } + + /* register as a led device */ + ret = led_classdev_register(&pdev->dev, &applesmc_backlight); + if (ret < 0) + goto out_light_wq; + } + + hwmon_class_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(hwmon_class_dev)) { + ret = PTR_ERR(hwmon_class_dev); + goto out_light_ledclass; + } + + printk(KERN_INFO "applesmc: driver successfully loaded.\n"); + + return 0; + +out_light_ledclass: + if (applesmc_light) + led_classdev_unregister(&applesmc_backlight); +out_light_wq: + if (applesmc_light) + destroy_workqueue(applesmc_led_wq); +out_light_sysfs: + if (applesmc_light) + sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr); +out_accelerometer: + if (applesmc_accelerometer) + applesmc_release_accelerometer(); +out_temperature: + sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group); + sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]); +out_fan_1: + sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]); +out_key_enumeration: + sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group); +out_device: + platform_device_unregister(pdev); +out_driver: + platform_driver_unregister(&applesmc_driver); +out_region: + release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS); +out: + printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret); + return ret; +} + +static void __exit applesmc_exit(void) +{ + hwmon_device_unregister(hwmon_class_dev); + if (applesmc_light) { + led_classdev_unregister(&applesmc_backlight); + destroy_workqueue(applesmc_led_wq); + sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr); + } + if (applesmc_accelerometer) + applesmc_release_accelerometer(); + sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group); + sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]); + sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]); + sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group); + platform_device_unregister(pdev); + platform_driver_unregister(&applesmc_driver); + release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS); + + printk(KERN_INFO "applesmc: driver unloaded.\n"); +} + +module_init(applesmc_init); +module_exit(applesmc_exit); + +MODULE_AUTHOR("Nicolas Boichat"); +MODULE_DESCRIPTION("Apple SMC"); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/hwmon/coretemp.c b/trunk/drivers/hwmon/coretemp.c new file mode 100644 index 000000000000..03b1f650d1c4 --- /dev/null +++ b/trunk/drivers/hwmon/coretemp.c @@ -0,0 +1,406 @@ +/* + * coretemp.c - Linux kernel module for hardware monitoring + * + * Copyright (C) 2007 Rudolf Marek + * + * Inspired from many hwmon drivers + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "coretemp" + +typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW; + +/* + * Functions declaration + */ + +static struct coretemp_data *coretemp_update_device(struct device *dev); + +struct coretemp_data { + struct class_device *class_dev; + struct mutex update_lock; + const char *name; + u32 id; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + int temp; + int tjmax; + u8 alarm; +}; + +static struct coretemp_data *coretemp_update_device(struct device *dev); + +/* + * Sysfs stuff + */ + +static ssize_t show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + int ret; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct coretemp_data *data = dev_get_drvdata(dev); + + if (attr->index == SHOW_NAME) + ret = sprintf(buf, "%s\n", data->name); + else /* show label */ + ret = sprintf(buf, "Core %d\n", data->id); + return ret; +} + +static ssize_t show_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct coretemp_data *data = coretemp_update_device(dev); + /* read the Out-of-spec log, never clear */ + return sprintf(buf, "%d\n", data->alarm); +} + +static ssize_t show_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct coretemp_data *data = coretemp_update_device(dev); + int err; + + if (attr->index == SHOW_TEMP) + err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN; + else + err = sprintf(buf, "%d\n", data->tjmax); + + return err; +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, + SHOW_TEMP); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, + SHOW_TJMAX); +static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL); +static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL); +static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME); + +static struct attribute *coretemp_attributes[] = { + &sensor_dev_attr_name.dev_attr.attr, + &sensor_dev_attr_temp1_label.dev_attr.attr, + &dev_attr_temp1_crit_alarm.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + NULL +}; + +static const struct attribute_group coretemp_group = { + .attrs = coretemp_attributes, +}; + +static struct coretemp_data *coretemp_update_device(struct device *dev) +{ + struct coretemp_data *data = dev_get_drvdata(dev); + + mutex_lock(&data->update_lock); + + if (!data->valid || time_after(jiffies, data->last_updated + HZ)) { + u32 eax, edx; + + data->valid = 0; + rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx); + data->alarm = (eax >> 5) & 1; + /* update only if data has been valid */ + if (eax & 0x80000000) { + data->temp = data->tjmax - (((eax >> 16) + & 0x7f) * 1000); + data->valid = 1; + } else { + dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax); + } + data->last_updated = jiffies; + } + + mutex_unlock(&data->update_lock); + return data; +} + +static int __devinit coretemp_probe(struct platform_device *pdev) +{ + struct coretemp_data *data; + struct cpuinfo_x86 *c = &(cpu_data)[pdev->id]; + int err; + u32 eax, edx; + + if (!(data = kzalloc(sizeof(struct coretemp_data), GFP_KERNEL))) { + err = -ENOMEM; + dev_err(&pdev->dev, "Out of memory\n"); + goto exit; + } + + data->id = pdev->id; + data->name = "coretemp"; + mutex_init(&data->update_lock); + /* Tjmax default is 100 degrees C */ + data->tjmax = 100000; + + /* test if we can access the THERM_STATUS MSR */ + err = rdmsr_safe_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx); + if (err) { + dev_err(&pdev->dev, + "Unable to access THERM_STATUS MSR, giving up\n"); + goto exit_free; + } + + /* Some processors have Tjmax 85 following magic should detect it + Intel won't disclose the information without signed NDA, but + individuals cannot sign it. Catch(ed) 22. + */ + + if (((c->x86_model == 0xf) && (c->x86_mask > 3)) || + (c->x86_model == 0xe)) { + err = rdmsr_safe_on_cpu(data->id, 0xee, &eax, &edx); + if (err) { + dev_warn(&pdev->dev, + "Unable to access MSR 0xEE, Tjmax left at %d " + "degrees C\n", data->tjmax/1000); + } else if (eax & 0x40000000) { + data->tjmax = 85000; + } + } + + platform_set_drvdata(pdev, data); + + if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group))) + goto exit_free; + + data->class_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + dev_err(&pdev->dev, "Class registration failed (%d)\n", + err); + goto exit_class; + } + + return 0; + +exit_class: + sysfs_remove_group(&pdev->dev.kobj, &coretemp_group); +exit_free: + kfree(data); +exit: + return err; +} + +static int __devexit coretemp_remove(struct platform_device *pdev) +{ + struct coretemp_data *data = platform_get_drvdata(pdev); + + hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&pdev->dev.kobj, &coretemp_group); + platform_set_drvdata(pdev, NULL); + kfree(data); + return 0; +} + +static struct platform_driver coretemp_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, + .probe = coretemp_probe, + .remove = __devexit_p(coretemp_remove), +}; + +struct pdev_entry { + struct list_head list; + struct platform_device *pdev; + unsigned int cpu; +}; + +static LIST_HEAD(pdev_list); +static DEFINE_MUTEX(pdev_list_mutex); + +static int __cpuinit coretemp_device_add(unsigned int cpu) +{ + int err; + struct platform_device *pdev; + struct pdev_entry *pdev_entry; + + pdev = platform_device_alloc(DRVNAME, cpu); + if (!pdev) { + err = -ENOMEM; + printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + goto exit; + } + + pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL); + if (!pdev_entry) { + err = -ENOMEM; + goto exit_device_put; + } + + err = platform_device_add(pdev); + if (err) { + printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", + err); + goto exit_device_free; + } + + pdev_entry->pdev = pdev; + pdev_entry->cpu = cpu; + mutex_lock(&pdev_list_mutex); + list_add_tail(&pdev_entry->list, &pdev_list); + mutex_unlock(&pdev_list_mutex); + + return 0; + +exit_device_free: + kfree(pdev_entry); +exit_device_put: + platform_device_put(pdev); +exit: + return err; +} + +#ifdef CONFIG_HOTPLUG_CPU +void coretemp_device_remove(unsigned int cpu) +{ + struct pdev_entry *p, *n; + mutex_lock(&pdev_list_mutex); + list_for_each_entry_safe(p, n, &pdev_list, list) { + if (p->cpu == cpu) { + platform_device_unregister(p->pdev); + list_del(&p->list); + kfree(p); + } + } + mutex_unlock(&pdev_list_mutex); +} + +static int coretemp_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long) hcpu; + + switch (action) { + case CPU_ONLINE: + coretemp_device_add(cpu); + break; + case CPU_DEAD: + coretemp_device_remove(cpu); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata coretemp_cpu_notifier = { + .notifier_call = coretemp_cpu_callback, +}; +#endif /* !CONFIG_HOTPLUG_CPU */ + +static int __init coretemp_init(void) +{ + int i, err = -ENODEV; + struct pdev_entry *p, *n; + + printk(KERN_NOTICE DRVNAME ": This driver uses undocumented features " + "of Core CPU. Temperature might be wrong!\n"); + + /* quick check if we run Intel */ + if (cpu_data[0].x86_vendor != X86_VENDOR_INTEL) + goto exit; + + err = platform_driver_register(&coretemp_driver); + if (err) + goto exit; + + for_each_online_cpu(i) { + struct cpuinfo_x86 *c = &(cpu_data)[i]; + + /* check if family 6, models e, f */ + if ((c->cpuid_level < 0) || (c->x86 != 0x6) || + !((c->x86_model == 0xe) || (c->x86_model == 0xf))) { + + /* supported CPU not found, but report the unknown + family 6 CPU */ + if ((c->x86 == 0x6) && (c->x86_model > 0xf)) + printk(KERN_WARNING DRVNAME ": Unknown CPU " + "model %x\n", c->x86_model); + continue; + } + + err = coretemp_device_add(i); + if (err) + goto exit_devices_unreg; + } + if (list_empty(&pdev_list)) { + err = -ENODEV; + goto exit_driver_unreg; + } + +#ifdef CONFIG_HOTPLUG_CPU + register_hotcpu_notifier(&coretemp_cpu_notifier); +#endif + return 0; + +exit_devices_unreg: + mutex_lock(&pdev_list_mutex); + list_for_each_entry_safe(p, n, &pdev_list, list) { + platform_device_unregister(p->pdev); + list_del(&p->list); + kfree(p); + } + mutex_unlock(&pdev_list_mutex); +exit_driver_unreg: + platform_driver_unregister(&coretemp_driver); +exit: + return err; +} + +static void __exit coretemp_exit(void) +{ + struct pdev_entry *p, *n; +#ifdef CONFIG_HOTPLUG_CPU + unregister_hotcpu_notifier(&coretemp_cpu_notifier); +#endif + mutex_lock(&pdev_list_mutex); + list_for_each_entry_safe(p, n, &pdev_list, list) { + platform_device_unregister(p->pdev); + list_del(&p->list); + kfree(p); + } + mutex_unlock(&pdev_list_mutex); + platform_driver_unregister(&coretemp_driver); +} + +MODULE_AUTHOR("Rudolf Marek "); +MODULE_DESCRIPTION("Intel Core temperature monitor"); +MODULE_LICENSE("GPL"); + +module_init(coretemp_init) +module_exit(coretemp_exit) diff --git a/trunk/drivers/hwmon/f71805f.c b/trunk/drivers/hwmon/f71805f.c index 7c2973487122..cdbe309b8fc4 100644 --- a/trunk/drivers/hwmon/f71805f.c +++ b/trunk/drivers/hwmon/f71805f.c @@ -35,6 +35,7 @@ #include #include #include +#include #include static struct platform_device *pdev; @@ -1140,6 +1141,13 @@ static int __devinit f71805f_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start + ADDR_REG_OFFSET, 2, DRVNAME)) { + err = -EBUSY; + dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n", + (unsigned long)(res->start + ADDR_REG_OFFSET), + (unsigned long)(res->start + ADDR_REG_OFFSET + 1)); + goto exit_free; + } data->addr = res->start; data->name = names[sio_data->kind]; mutex_init(&data->update_lock); @@ -1165,7 +1173,7 @@ static int __devinit f71805f_probe(struct platform_device *pdev) /* Register sysfs interface files */ if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group))) - goto exit_free; + goto exit_release_region; if (data->has_in & (1 << 4)) { /* in4 */ if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group_optin[0]))) @@ -1219,6 +1227,8 @@ static int __devinit f71805f_probe(struct platform_device *pdev) for (i = 0; i < 4; i++) sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]); sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); +exit_release_region: + release_region(res->start + ADDR_REG_OFFSET, 2); exit_free: platform_set_drvdata(pdev, NULL); kfree(data); @@ -1229,6 +1239,7 @@ static int __devinit f71805f_probe(struct platform_device *pdev) static int __devexit f71805f_remove(struct platform_device *pdev) { struct f71805f_data *data = platform_get_drvdata(pdev); + struct resource *res; int i; platform_set_drvdata(pdev, NULL); @@ -1239,6 +1250,9 @@ static int __devexit f71805f_remove(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); kfree(data); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start + ADDR_REG_OFFSET, 2); + return 0; } diff --git a/trunk/drivers/hwmon/hdaps.c b/trunk/drivers/hwmon/hdaps.c index bf759ea545ac..f82fa2d23f95 100644 --- a/trunk/drivers/hwmon/hdaps.c +++ b/trunk/drivers/hwmon/hdaps.c @@ -30,10 +30,12 @@ #include #include #include +#include #include #include #include #include + #include #define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */ @@ -71,10 +73,10 @@ static u8 km_activity; static int rest_x; static int rest_y; -static DECLARE_MUTEX(hdaps_sem); +static DEFINE_MUTEX(hdaps_mtx); /* - * __get_latch - Get the value from a given port. Callers must hold hdaps_sem. + * __get_latch - Get the value from a given port. Callers must hold hdaps_mtx. */ static inline u8 __get_latch(u16 port) { @@ -83,7 +85,7 @@ static inline u8 __get_latch(u16 port) /* * __check_latch - Check a port latch for a given value. Returns zero if the - * port contains the given value. Callers must hold hdaps_sem. + * port contains the given value. Callers must hold hdaps_mtx. */ static inline int __check_latch(u16 port, u8 val) { @@ -94,7 +96,7 @@ static inline int __check_latch(u16 port, u8 val) /* * __wait_latch - Wait up to 100us for a port latch to get a certain value, - * returning zero if the value is obtained. Callers must hold hdaps_sem. + * returning zero if the value is obtained. Callers must hold hdaps_mtx. */ static int __wait_latch(u16 port, u8 val) { @@ -111,7 +113,7 @@ static int __wait_latch(u16 port, u8 val) /* * __device_refresh - request a refresh from the accelerometer. Does not wait - * for refresh to complete. Callers must hold hdaps_sem. + * for refresh to complete. Callers must hold hdaps_mtx. */ static void __device_refresh(void) { @@ -125,7 +127,7 @@ static void __device_refresh(void) /* * __device_refresh_sync - request a synchronous refresh from the * accelerometer. We wait for the refresh to complete. Returns zero if - * successful and nonzero on error. Callers must hold hdaps_sem. + * successful and nonzero on error. Callers must hold hdaps_mtx. */ static int __device_refresh_sync(void) { @@ -135,7 +137,7 @@ static int __device_refresh_sync(void) /* * __device_complete - indicate to the accelerometer that we are done reading - * data, and then initiate an async refresh. Callers must hold hdaps_sem. + * data, and then initiate an async refresh. Callers must hold hdaps_mtx. */ static inline void __device_complete(void) { @@ -153,7 +155,7 @@ static int hdaps_readb_one(unsigned int port, u8 *val) { int ret; - down(&hdaps_sem); + mutex_lock(&hdaps_mtx); /* do a sync refresh -- we need to be sure that we read fresh data */ ret = __device_refresh_sync(); @@ -164,7 +166,7 @@ static int hdaps_readb_one(unsigned int port, u8 *val) __device_complete(); out: - up(&hdaps_sem); + mutex_unlock(&hdaps_mtx); return ret; } @@ -199,9 +201,9 @@ static int hdaps_read_pair(unsigned int port1, unsigned int port2, { int ret; - down(&hdaps_sem); + mutex_lock(&hdaps_mtx); ret = __hdaps_read_pair(port1, port2, val1, val2); - up(&hdaps_sem); + mutex_unlock(&hdaps_mtx); return ret; } @@ -214,7 +216,7 @@ static int hdaps_device_init(void) { int total, ret = -ENXIO; - down(&hdaps_sem); + mutex_lock(&hdaps_mtx); outb(0x13, 0x1610); outb(0x01, 0x161f); @@ -280,7 +282,7 @@ static int hdaps_device_init(void) } out: - up(&hdaps_sem); + mutex_unlock(&hdaps_mtx); return ret; } @@ -314,7 +316,7 @@ static struct platform_driver hdaps_driver = { }; /* - * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_sem. + * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_mtx. */ static void hdaps_calibrate(void) { @@ -326,7 +328,7 @@ static void hdaps_mousedev_poll(unsigned long unused) int x, y; /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ - if (down_trylock(&hdaps_sem)) { + if (mutex_trylock(&hdaps_mtx)) { mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD); return; } @@ -341,7 +343,7 @@ static void hdaps_mousedev_poll(unsigned long unused) mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD); out: - up(&hdaps_sem); + mutex_unlock(&hdaps_mtx); } @@ -421,9 +423,9 @@ static ssize_t hdaps_calibrate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - down(&hdaps_sem); + mutex_lock(&hdaps_mtx); hdaps_calibrate(); - up(&hdaps_sem); + mutex_unlock(&hdaps_mtx); return count; } diff --git a/trunk/drivers/hwmon/hwmon-vid.c b/trunk/drivers/hwmon/hwmon-vid.c index b80f6ed5acfc..5aab23b93e24 100644 --- a/trunk/drivers/hwmon/hwmon-vid.c +++ b/trunk/drivers/hwmon/hwmon-vid.c @@ -166,16 +166,16 @@ static struct vrm_model vrm_models[] = { {X86_VENDOR_INTEL, 0x6, 0xE, ANY, 14}, /* Intel Core (65 nm) */ {X86_VENDOR_INTEL, 0x6, 0xF, ANY, 110}, /* Intel Conroe */ {X86_VENDOR_INTEL, 0x6, ANY, ANY, 82}, /* any P6 */ - {X86_VENDOR_INTEL, 0x7, ANY, ANY, 0}, /* Itanium */ {X86_VENDOR_INTEL, 0xF, 0x0, ANY, 90}, /* P4 */ {X86_VENDOR_INTEL, 0xF, 0x1, ANY, 90}, /* P4 Willamette */ {X86_VENDOR_INTEL, 0xF, 0x2, ANY, 90}, /* P4 Northwood */ {X86_VENDOR_INTEL, 0xF, ANY, ANY, 100}, /* Prescott and above assume VRD 10 */ - {X86_VENDOR_INTEL, 0x10, ANY, ANY, 0}, /* Itanium 2 */ {X86_VENDOR_CENTAUR, 0x6, 0x7, ANY, 85}, /* Eden ESP/Ezra */ {X86_VENDOR_CENTAUR, 0x6, 0x8, 0x7, 85}, /* Ezra T */ {X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nemiah */ - {X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M */ + {X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M, Eden-N */ + {X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0}, /* No information */ + {X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7, Esther */ {X86_VENDOR_UNKNOWN, ANY, ANY, ANY, 0} /* stop here */ }; diff --git a/trunk/drivers/hwmon/lm75.c b/trunk/drivers/hwmon/lm75.c index 7c65b8bb6d72..a40166ffad12 100644 --- a/trunk/drivers/hwmon/lm75.c +++ b/trunk/drivers/hwmon/lm75.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "lm75.h" @@ -39,10 +40,12 @@ I2C_CLIENT_INSMOD_1(lm75); /* Many LM75 constants specified below */ /* The LM75 registers */ -#define LM75_REG_TEMP 0x00 #define LM75_REG_CONF 0x01 -#define LM75_REG_TEMP_HYST 0x02 -#define LM75_REG_TEMP_OS 0x03 +static const u8 LM75_REG_TEMP[3] = { + 0x00, /* input */ + 0x03, /* max */ + 0x02, /* hyst */ +}; /* Each client has this additional data */ struct lm75_data { @@ -51,9 +54,10 @@ struct lm75_data { struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - u16 temp_input; /* Register values */ - u16 temp_max; - u16 temp_hyst; + u16 temp[3]; /* Register values, + 0 = input + 1 = max + 2 = hyst */ }; static int lm75_attach_adapter(struct i2c_adapter *adapter); @@ -75,35 +79,36 @@ static struct i2c_driver lm75_driver = { .detach_client = lm75_detach_client, }; -#define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm75_data *data = lm75_update_device(dev); \ - return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ +static ssize_t show_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct lm75_data *data = lm75_update_device(dev); + return sprintf(buf, "%d\n", + LM75_TEMP_FROM_REG(data->temp[attr->index])); } -show(temp_max); -show(temp_hyst); -show(temp_input); - -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm75_data *data = i2c_get_clientdata(client); \ - int temp = simple_strtoul(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->value = LM75_TEMP_TO_REG(temp); \ - lm75_write_value(client, reg, data->value); \ - mutex_unlock(&data->update_lock); \ - return count; \ + +static ssize_t set_temp(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct lm75_data *data = i2c_get_clientdata(client); + int nr = attr->index; + unsigned long temp = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->temp[nr] = LM75_TEMP_TO_REG(temp); + lm75_write_value(client, LM75_REG_TEMP[nr], data->temp[nr]); + mutex_unlock(&data->update_lock); + return count; } -set(temp_max, LM75_REG_TEMP_OS); -set(temp_hyst, LM75_REG_TEMP_HYST); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + show_temp, set_temp, 1); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, + show_temp, set_temp, 2); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); static int lm75_attach_adapter(struct i2c_adapter *adapter) { @@ -113,9 +118,9 @@ static int lm75_attach_adapter(struct i2c_adapter *adapter) } static struct attribute *lm75_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_max_hyst.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, NULL }; @@ -283,11 +288,12 @@ static struct lm75_data *lm75_update_device(struct device *dev) if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { + int i; dev_dbg(&client->dev, "Starting lm75 update\n"); - data->temp_input = lm75_read_value(client, LM75_REG_TEMP); - data->temp_max = lm75_read_value(client, LM75_REG_TEMP_OS); - data->temp_hyst = lm75_read_value(client, LM75_REG_TEMP_HYST); + for (i = 0; i < ARRAY_SIZE(data->temp); i++) + data->temp[i] = lm75_read_value(client, + LM75_REG_TEMP[i]); data->last_updated = jiffies; data->valid = 1; } diff --git a/trunk/drivers/hwmon/lm78.c b/trunk/drivers/hwmon/lm78.c index 886786c33916..9fb572f03ba5 100644 --- a/trunk/drivers/hwmon/lm78.c +++ b/trunk/drivers/hwmon/lm78.c @@ -2,6 +2,7 @@ lm78.c - Part of lm_sensors, Linux kernel modules for hardware monitoring Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (c) 2007 Jean Delvare 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 @@ -23,13 +24,18 @@ #include #include #include -#include +#include +#include #include #include +#include #include #include #include +/* ISA device, if found */ +static struct platform_device *pdev; + /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, @@ -121,12 +127,8 @@ static inline int TEMP_FROM_REG(s8 val) a bit - except if there could be more than one SMBus. Groan. No solution for this yet. */ -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* For each registered chip, we need to keep some data in memory. - The structure is dynamically allocated. */ +/* For ISA chips, we abuse the i2c_client addr and name fields. We also use + the driver field to differentiate between I2C and ISA chips. */ struct lm78_data { struct i2c_client client; struct class_device *class_dev; @@ -152,14 +154,16 @@ struct lm78_data { static int lm78_attach_adapter(struct i2c_adapter *adapter); -static int lm78_isa_attach_adapter(struct i2c_adapter *adapter); static int lm78_detect(struct i2c_adapter *adapter, int address, int kind); static int lm78_detach_client(struct i2c_client *client); -static int lm78_read_value(struct i2c_client *client, u8 reg); -static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value); +static int __devinit lm78_isa_probe(struct platform_device *pdev); +static int __devexit lm78_isa_remove(struct platform_device *pdev); + +static int lm78_read_value(struct lm78_data *data, u8 reg); +static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value); static struct lm78_data *lm78_update_device(struct device *dev); -static void lm78_init_client(struct i2c_client *client); +static void lm78_init_device(struct lm78_data *data); static struct i2c_driver lm78_driver = { @@ -171,95 +175,78 @@ static struct i2c_driver lm78_driver = { .detach_client = lm78_detach_client, }; -static struct i2c_driver lm78_isa_driver = { +static struct platform_driver lm78_isa_driver = { .driver = { .owner = THIS_MODULE, - .name = "lm78-isa", + .name = "lm78", }, - .attach_adapter = lm78_isa_attach_adapter, - .detach_client = lm78_detach_client, + .probe = lm78_isa_probe, + .remove = lm78_isa_remove, }; /* 7 Voltages */ -static ssize_t show_in(struct device *dev, char *buf, int nr) +static ssize_t show_in(struct device *dev, struct device_attribute *da, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index])); } -static ssize_t show_in_min(struct device *dev, char *buf, int nr) +static ssize_t show_in_min(struct device *dev, struct device_attribute *da, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index])); } -static ssize_t show_in_max(struct device *dev, char *buf, int nr) +static ssize_t show_in_max(struct device *dev, struct device_attribute *da, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index])); } -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_min(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct lm78_data *data = dev_get_drvdata(dev); unsigned long val = simple_strtoul(buf, NULL, 10); + int nr = attr->index; mutex_lock(&data->update_lock); data->in_min[nr] = IN_TO_REG(val); - lm78_write_value(client, LM78_REG_IN_MIN(nr), data->in_min[nr]); + lm78_write_value(data, LM78_REG_IN_MIN(nr), data->in_min[nr]); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_in_max(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct lm78_data *data = dev_get_drvdata(dev); unsigned long val = simple_strtoul(buf, NULL, 10); + int nr = attr->index; mutex_lock(&data->update_lock); data->in_max[nr] = IN_TO_REG(val); - lm78_write_value(client, LM78_REG_IN_MAX(nr), data->in_max[nr]); + lm78_write_value(data, LM78_REG_IN_MAX(nr), data->in_max[nr]); mutex_unlock(&data->update_lock); return count; } #define show_in_offset(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset, NULL); \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in, NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset); show_in_offset(0); show_in_offset(1); @@ -270,46 +257,49 @@ show_in_offset(5); show_in_offset(6); /* Temperature */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *da, + char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); } -static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp_over(struct device *dev, struct device_attribute *da, + char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); } -static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_temp_over(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); + struct lm78_data *data = dev_get_drvdata(dev); long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp_over = TEMP_TO_REG(val); - lm78_write_value(client, LM78_REG_TEMP_OVER, data->temp_over); + lm78_write_value(data, LM78_REG_TEMP_OVER, data->temp_over); mutex_unlock(&data->update_lock); return count; } -static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da, + char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); } -static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); + struct lm78_data *data = dev_get_drvdata(dev); long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp_hyst = TEMP_TO_REG(val); - lm78_write_value(client, LM78_REG_TEMP_HYST, data->temp_hyst); + lm78_write_value(data, LM78_REG_TEMP_HYST, data->temp_hyst); mutex_unlock(&data->update_lock); return count; } @@ -321,49 +311,59 @@ static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_hyst, set_temp_hyst); /* 3 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) +static ssize_t show_fan(struct device *dev, struct device_attribute *da, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm78_data *data = lm78_update_device(dev); + int nr = attr->index; return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr])) ); } -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +static ssize_t show_fan_min(struct device *dev, struct device_attribute *da, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm78_data *data = lm78_update_device(dev); + int nr = attr->index; return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); } -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_min(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct lm78_data *data = dev_get_drvdata(dev); + int nr = attr->index; unsigned long val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); + lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; } -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +static ssize_t show_fan_div(struct device *dev, struct device_attribute *da, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index])); } /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct lm78_data *data = dev_get_drvdata(dev); + int nr = attr->index; unsigned long val = simple_strtoul(buf, NULL, 10); unsigned long min; u8 reg; @@ -378,13 +378,13 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, case 4: data->fan_div[nr] = 2; break; case 8: data->fan_div[nr] = 3; break; default: - dev_err(&client->dev, "fan_div value %ld not " + dev_err(dev, "fan_div value %ld not " "supported. Choose one of 1, 2, 4 or 8!\n", val); mutex_unlock(&data->update_lock); return -EINVAL; } - reg = lm78_read_value(client, LM78_REG_VID_FANDIV); + reg = lm78_read_value(data, LM78_REG_VID_FANDIV); switch (nr) { case 0: reg = (reg & 0xcf) | (data->fan_div[nr] << 4); @@ -393,63 +393,36 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, reg = (reg & 0x3f) | (data->fan_div[nr] << 6); break; } - lm78_write_value(client, LM78_REG_VID_FANDIV, reg); + lm78_write_value(data, LM78_REG_VID_FANDIV, reg); data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); + lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; } -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); - -static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - return set_fan_div(dev, buf, count, 0) ; -} - -static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - return set_fan_div(dev, buf, count, 1) ; -} +#define show_fan_offset(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1); show_fan_offset(1); show_fan_offset(2); show_fan_offset(3); /* Fan 3 divisor is locked in H/W */ -static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, - show_fan_1_div, set_fan_1_div); -static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, - show_fan_2_div, set_fan_2_div); -static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL); +static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, + show_fan_div, set_fan_div, 0); +static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, + show_fan_div, set_fan_div, 1); +static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2); /* VID */ -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vid(struct device *dev, struct device_attribute *da, + char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, 82)); @@ -457,7 +430,8 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); /* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *da, + char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%u\n", data->alarms); @@ -475,45 +449,40 @@ static int lm78_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, lm78_detect); } -static int lm78_isa_attach_adapter(struct i2c_adapter *adapter) -{ - return lm78_detect(adapter, isa_address, -1); -} - static struct attribute *lm78_attributes[] = { - &dev_attr_in0_input.attr, - &dev_attr_in0_min.attr, - &dev_attr_in0_max.attr, - &dev_attr_in1_input.attr, - &dev_attr_in1_min.attr, - &dev_attr_in1_max.attr, - &dev_attr_in2_input.attr, - &dev_attr_in2_min.attr, - &dev_attr_in2_max.attr, - &dev_attr_in3_input.attr, - &dev_attr_in3_min.attr, - &dev_attr_in3_max.attr, - &dev_attr_in4_input.attr, - &dev_attr_in4_min.attr, - &dev_attr_in4_max.attr, - &dev_attr_in5_input.attr, - &dev_attr_in5_min.attr, - &dev_attr_in5_max.attr, - &dev_attr_in6_input.attr, - &dev_attr_in6_min.attr, - &dev_attr_in6_max.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, &dev_attr_temp1_input.attr, &dev_attr_temp1_max.attr, &dev_attr_temp1_max_hyst.attr, - &dev_attr_fan1_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan1_div.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan2_div.attr, - &dev_attr_fan3_input.attr, - &dev_attr_fan3_min.attr, - &dev_attr_fan3_div.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan3_div.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_cpu0_vid.attr, @@ -524,6 +493,17 @@ static const struct attribute_group lm78_group = { .attrs = lm78_attributes, }; +/* I2C devices get this name attribute automatically, but for ISA devices + we must create it by ourselves. */ +static ssize_t show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct lm78_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->client.name); +} +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + /* This function is called by i2c_probe */ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) { @@ -531,54 +511,10 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) struct i2c_client *new_client; struct lm78_data *data; const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - if (!is_isa && - !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { err = -ENODEV; - goto ERROR0; - } - - /* Reserve the ISA region */ - if (is_isa) - if (!request_region(address, LM78_EXTENT, - lm78_isa_driver.driver.name)) { - err = -EBUSY; - goto ERROR0; - } - - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (kind < 0) { - if (is_isa) { - -#define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like - chips. But only if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i) { - err = -ENODEV; - goto ERROR1; - } - if (inb_p(address + 3) != i) { - err = -ENODEV; - goto ERROR1; - } - if (inb_p(address + 7) != i) { - err = -ENODEV; - goto ERROR1; - } -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - err = -ENODEV; - goto ERROR1; - } - } + goto ERROR1; } /* OK. For now, we presume we have a valid client. We now create the @@ -591,22 +527,19 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) } new_client = &data->client; - if (is_isa) - mutex_init(&data->lock); i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; - new_client->driver = is_isa ? &lm78_isa_driver : &lm78_driver; - new_client->flags = 0; + new_client->driver = &lm78_driver; /* Now, we do the remaining detection. */ if (kind < 0) { - if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80) { + if (lm78_read_value(data, LM78_REG_CONFIG) & 0x80) { err = -ENODEV; goto ERROR2; } - if (!is_isa && (lm78_read_value( - new_client, LM78_REG_I2C_ADDR) != address)) { + if (lm78_read_value(data, LM78_REG_I2C_ADDR) != + address) { err = -ENODEV; goto ERROR2; } @@ -614,7 +547,7 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) /* Determine the chip type. */ if (kind <= 0) { - i = lm78_read_value(new_client, LM78_REG_CHIPID); + i = lm78_read_value(data, LM78_REG_CHIPID); if (i == 0x00 || i == 0x20 /* LM78 */ || i == 0x40) /* LM78-J */ kind = lm78; @@ -641,21 +574,12 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) strlcpy(new_client->name, client_name, I2C_NAME_SIZE); data->type = kind; - data->valid = 0; - mutex_init(&data->update_lock); - /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) goto ERROR2; /* Initialize the LM78 chip */ - lm78_init_client(new_client); - - /* A few vars need to be filled upon startup */ - for (i = 0; i < 3; i++) { - data->fan_min[i] = lm78_read_value(new_client, - LM78_REG_FAN_MIN(i)); - } + lm78_init_device(data); /* Register sysfs hooks */ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group))) @@ -676,9 +600,6 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) ERROR2: kfree(data); ERROR1: - if (is_isa) - release_region(address, LM78_EXTENT); -ERROR0: return err; } @@ -693,9 +614,77 @@ static int lm78_detach_client(struct i2c_client *client) if ((err = i2c_detach_client(client))) return err; - if(i2c_is_isa_client(client)) - release_region(client->addr, LM78_EXTENT); + kfree(data); + + return 0; +} + +static int __devinit lm78_isa_probe(struct platform_device *pdev) +{ + int err; + struct lm78_data *data; + struct resource *res; + const char *name; + + /* Reserve the ISA region */ + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, LM78_EXTENT, "lm78")) { + err = -EBUSY; + goto exit; + } + + if (!(data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release_region; + } + mutex_init(&data->lock); + data->client.addr = res->start; + i2c_set_clientdata(&data->client, data); + platform_set_drvdata(pdev, data); + + if (lm78_read_value(data, LM78_REG_CHIPID) & 0x80) { + data->type = lm79; + name = "lm79"; + } else { + data->type = lm78; + name = "lm78"; + } + strlcpy(data->client.name, name, I2C_NAME_SIZE); + + /* Initialize the LM78 chip */ + lm78_init_device(data); + + /* Register sysfs hooks */ + if ((err = sysfs_create_group(&pdev->dev.kobj, &lm78_group)) + || (err = device_create_file(&pdev->dev, &dev_attr_name))) + goto exit_remove_files; + + data->class_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove_files; + } + + return 0; + + exit_remove_files: + sysfs_remove_group(&pdev->dev.kobj, &lm78_group); + device_remove_file(&pdev->dev, &dev_attr_name); + kfree(data); + exit_release_region: + release_region(res->start, LM78_EXTENT); + exit: + return err; +} + +static int __devexit lm78_isa_remove(struct platform_device *pdev) +{ + struct lm78_data *data = platform_get_drvdata(pdev); + hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&pdev->dev.kobj, &lm78_group); + device_remove_file(&pdev->dev, &dev_attr_name); + release_region(data->client.addr, LM78_EXTENT); kfree(data); return 0; @@ -706,11 +695,12 @@ static int lm78_detach_client(struct i2c_client *client) separately. We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, would slow down the LM78 access and should not be necessary. */ -static int lm78_read_value(struct i2c_client *client, u8 reg) +static int lm78_read_value(struct lm78_data *data, u8 reg) { - int res; - if (i2c_is_isa_client(client)) { - struct lm78_data *data = i2c_get_clientdata(client); + struct i2c_client *client = &data->client; + + if (!client->driver) { /* ISA device */ + int res; mutex_lock(&data->lock); outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); res = inb_p(client->addr + LM78_DATA_REG_OFFSET); @@ -727,10 +717,11 @@ static int lm78_read_value(struct i2c_client *client, u8 reg) would slow down the LM78 access and should not be necessary. There are some ugly typecasts here, but the good new is - they should nowhere else be necessary! */ -static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) +static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value) { - if (i2c_is_isa_client(client)) { - struct lm78_data *data = i2c_get_clientdata(client); + struct i2c_client *client = &data->client; + + if (!client->driver) { /* ISA device */ mutex_lock(&data->lock); outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); outb_p(value, client->addr + LM78_DATA_REG_OFFSET); @@ -740,20 +731,29 @@ static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) return i2c_smbus_write_byte_data(client, reg, value); } -static void lm78_init_client(struct i2c_client *client) +static void lm78_init_device(struct lm78_data *data) { - u8 config = lm78_read_value(client, LM78_REG_CONFIG); + u8 config; + int i; /* Start monitoring */ - if (!(config & 0x01)) - lm78_write_value(client, LM78_REG_CONFIG, + config = lm78_read_value(data, LM78_REG_CONFIG); + if ((config & 0x09) != 0x01) + lm78_write_value(data, LM78_REG_CONFIG, (config & 0xf7) | 0x01); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 3; i++) { + data->fan_min[i] = lm78_read_value(data, + LM78_REG_FAN_MIN(i)); + } + + mutex_init(&data->update_lock); } static struct lm78_data *lm78_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); + struct lm78_data *data = dev_get_drvdata(dev); int i; mutex_lock(&data->update_lock); @@ -761,39 +761,39 @@ static struct lm78_data *lm78_update_device(struct device *dev) if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { - dev_dbg(&client->dev, "Starting lm78 update\n"); + dev_dbg(dev, "Starting lm78 update\n"); for (i = 0; i <= 6; i++) { data->in[i] = - lm78_read_value(client, LM78_REG_IN(i)); + lm78_read_value(data, LM78_REG_IN(i)); data->in_min[i] = - lm78_read_value(client, LM78_REG_IN_MIN(i)); + lm78_read_value(data, LM78_REG_IN_MIN(i)); data->in_max[i] = - lm78_read_value(client, LM78_REG_IN_MAX(i)); + lm78_read_value(data, LM78_REG_IN_MAX(i)); } for (i = 0; i < 3; i++) { data->fan[i] = - lm78_read_value(client, LM78_REG_FAN(i)); + lm78_read_value(data, LM78_REG_FAN(i)); data->fan_min[i] = - lm78_read_value(client, LM78_REG_FAN_MIN(i)); + lm78_read_value(data, LM78_REG_FAN_MIN(i)); } - data->temp = lm78_read_value(client, LM78_REG_TEMP); + data->temp = lm78_read_value(data, LM78_REG_TEMP); data->temp_over = - lm78_read_value(client, LM78_REG_TEMP_OVER); + lm78_read_value(data, LM78_REG_TEMP_OVER); data->temp_hyst = - lm78_read_value(client, LM78_REG_TEMP_HYST); - i = lm78_read_value(client, LM78_REG_VID_FANDIV); + lm78_read_value(data, LM78_REG_TEMP_HYST); + i = lm78_read_value(data, LM78_REG_VID_FANDIV); data->vid = i & 0x0f; if (data->type == lm79) data->vid |= - (lm78_read_value(client, LM78_REG_CHIPID) & + (lm78_read_value(data, LM78_REG_CHIPID) & 0x01) << 4; else data->vid |= 0x10; data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = i >> 6; - data->alarms = lm78_read_value(client, LM78_REG_ALARM1) + - (lm78_read_value(client, LM78_REG_ALARM2) << 8); + data->alarms = lm78_read_value(data, LM78_REG_ALARM1) + + (lm78_read_value(data, LM78_REG_ALARM2) << 8); data->last_updated = jiffies; data->valid = 1; @@ -805,26 +805,154 @@ static struct lm78_data *lm78_update_device(struct device *dev) return data; } +/* return 1 if a supported chip is found, 0 otherwise */ +static int __init lm78_isa_found(unsigned short address) +{ + int val, save, found = 0; + + if (!request_region(address, LM78_EXTENT, "lm78")) + return 0; + +#define REALLY_SLOW_IO + /* We need the timeouts for at least some LM78-like + chips. But only if we read 'undefined' registers. */ + val = inb_p(address + 1); + if (inb_p(address + 2) != val + || inb_p(address + 3) != val + || inb_p(address + 7) != val) + goto release; +#undef REALLY_SLOW_IO + + /* We should be able to change the 7 LSB of the address port. The + MSB (busy flag) should be clear initially, set after the write. */ + save = inb_p(address + LM78_ADDR_REG_OFFSET); + if (save & 0x80) + goto release; + val = ~save & 0x7f; + outb_p(val, address + LM78_ADDR_REG_OFFSET); + if (inb_p(address + LM78_ADDR_REG_OFFSET) != (val | 0x80)) { + outb_p(save, address + LM78_ADDR_REG_OFFSET); + goto release; + } + + /* We found a device, now see if it could be an LM78 */ + outb_p(LM78_REG_CONFIG, address + LM78_ADDR_REG_OFFSET); + val = inb_p(address + LM78_DATA_REG_OFFSET); + if (val & 0x80) + goto release; + outb_p(LM78_REG_I2C_ADDR, address + LM78_ADDR_REG_OFFSET); + val = inb_p(address + LM78_DATA_REG_OFFSET); + if (val < 0x03 || val > 0x77) /* Not a valid I2C address */ + goto release; + + /* The busy flag should be clear again */ + if (inb_p(address + LM78_ADDR_REG_OFFSET) & 0x80) + goto release; + + /* Explicitly prevent the misdetection of Winbond chips */ + outb_p(0x4f, address + LM78_ADDR_REG_OFFSET); + val = inb_p(address + LM78_DATA_REG_OFFSET); + if (val == 0xa3 || val == 0x5c) + goto release; + + /* Explicitly prevent the misdetection of ITE chips */ + outb_p(0x58, address + LM78_ADDR_REG_OFFSET); + val = inb_p(address + LM78_DATA_REG_OFFSET); + if (val == 0x90) + goto release; + + /* Determine the chip type */ + outb_p(LM78_REG_CHIPID, address + LM78_ADDR_REG_OFFSET); + val = inb_p(address + LM78_DATA_REG_OFFSET); + if (val == 0x00 /* LM78 */ + || val == 0x40 /* LM78-J */ + || (val & 0xfe) == 0xc0) /* LM79 */ + found = 1; + + if (found) + pr_info("lm78: Found an %s chip at %#x\n", + val & 0x80 ? "LM79" : "LM78", (int)address); + + release: + release_region(address, LM78_EXTENT); + return found; +} + +static int __init lm78_isa_device_add(unsigned short address) +{ + struct resource res = { + .start = address, + .end = address + LM78_EXTENT, + .name = "lm78", + .flags = IORESOURCE_IO, + }; + int err; + + pdev = platform_device_alloc("lm78", address); + if (!pdev) { + err = -ENOMEM; + printk(KERN_ERR "lm78: Device allocation failed\n"); + goto exit; + } + + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR "lm78: Device resource addition failed " + "(%d)\n", err); + goto exit_device_put; + } + + err = platform_device_add(pdev); + if (err) { + printk(KERN_ERR "lm78: Device addition failed (%d)\n", + err); + goto exit_device_put; + } + + return 0; + + exit_device_put: + platform_device_put(pdev); + exit: + pdev = NULL; + return err; +} + static int __init sm_lm78_init(void) { int res; res = i2c_add_driver(&lm78_driver); if (res) - return res; + goto exit; - /* Don't exit if this one fails, we still want the I2C variants - to work! */ - if (i2c_isa_add_driver(&lm78_isa_driver)) - isa_address = 0; + if (lm78_isa_found(isa_address)) { + res = platform_driver_register(&lm78_isa_driver); + if (res) + goto exit_unreg_i2c_driver; + + /* Sets global pdev as a side effect */ + res = lm78_isa_device_add(isa_address); + if (res) + goto exit_unreg_isa_driver; + } return 0; + + exit_unreg_isa_driver: + platform_driver_unregister(&lm78_isa_driver); + exit_unreg_i2c_driver: + i2c_del_driver(&lm78_driver); + exit: + return res; } static void __exit sm_lm78_exit(void) { - if (isa_address) - i2c_isa_del_driver(&lm78_isa_driver); + if (pdev) { + platform_device_unregister(pdev); + platform_driver_unregister(&lm78_isa_driver); + } i2c_del_driver(&lm78_driver); } diff --git a/trunk/drivers/hwmon/lm87.c b/trunk/drivers/hwmon/lm87.c index 3ce825489e34..988ae1c4aada 100644 --- a/trunk/drivers/hwmon/lm87.c +++ b/trunk/drivers/hwmon/lm87.c @@ -747,6 +747,7 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) } if (!(data->channel & CHAN_NO_VID)) { + data->vrm = vid_which_vrm(); if ((err = device_create_file(&new_client->dev, &dev_attr_cpu0_vid)) || (err = device_create_file(&new_client->dev, @@ -779,7 +780,6 @@ static void lm87_init_client(struct i2c_client *client) u8 config; data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE); - data->vrm = vid_which_vrm(); config = lm87_read_value(client, LM87_REG_CONFIG); if (!(config & 0x01)) { diff --git a/trunk/drivers/hwmon/max6650.c b/trunk/drivers/hwmon/max6650.c new file mode 100644 index 000000000000..8415664f33c2 --- /dev/null +++ b/trunk/drivers/hwmon/max6650.c @@ -0,0 +1,693 @@ +/* + * max6650.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring. + * + * (C) 2007 by Hans J. Koch + * + * based on code written by John Morris + * Copyright (c) 2003 Spirent Communications + * and Claus Gindhart + * + * This module has only been tested with the MAX6650 chip. It should + * also work with the MAX6651. It does not distinguish max6650 and max6651 + * chips. + * + * Tha datasheet was last seen at: + * + * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan. There are four disjoint possibilities, by pin config. + */ + +static unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b, I2C_CLIENT_END}; + +/* + * Insmod parameters + */ + +/* fan_voltage: 5=5V fan, 12=12V fan, 0=don't change */ +static int fan_voltage; +/* prescaler: Possible values are 1, 2, 4, 8, 16 or 0 for don't change */ +static int prescaler; +/* clock: The clock frequency of the chip the driver should assume */ +static int clock = 254000; + +module_param(fan_voltage, int, S_IRUGO); +module_param(prescaler, int, S_IRUGO); +module_param(clock, int, S_IRUGO); + +I2C_CLIENT_INSMOD_1(max6650); + +/* + * MAX 6650/6651 registers + */ + +#define MAX6650_REG_SPEED 0x00 +#define MAX6650_REG_CONFIG 0x02 +#define MAX6650_REG_GPIO_DEF 0x04 +#define MAX6650_REG_DAC 0x06 +#define MAX6650_REG_ALARM_EN 0x08 +#define MAX6650_REG_ALARM 0x0A +#define MAX6650_REG_TACH0 0x0C +#define MAX6650_REG_TACH1 0x0E +#define MAX6650_REG_TACH2 0x10 +#define MAX6650_REG_TACH3 0x12 +#define MAX6650_REG_GPIO_STAT 0x14 +#define MAX6650_REG_COUNT 0x16 + +/* + * Config register bits + */ + +#define MAX6650_CFG_V12 0x08 +#define MAX6650_CFG_PRESCALER_MASK 0x07 +#define MAX6650_CFG_PRESCALER_2 0x01 +#define MAX6650_CFG_PRESCALER_4 0x02 +#define MAX6650_CFG_PRESCALER_8 0x03 +#define MAX6650_CFG_PRESCALER_16 0x04 +#define MAX6650_CFG_MODE_MASK 0x30 +#define MAX6650_CFG_MODE_ON 0x00 +#define MAX6650_CFG_MODE_OFF 0x10 +#define MAX6650_CFG_MODE_CLOSED_LOOP 0x20 +#define MAX6650_CFG_MODE_OPEN_LOOP 0x30 +#define MAX6650_COUNT_MASK 0x03 + +/* Minimum and maximum values of the FAN-RPM */ +#define FAN_RPM_MIN 240 +#define FAN_RPM_MAX 30000 + +#define DIV_FROM_REG(reg) (1 << (reg & 7)) + +static int max6650_attach_adapter(struct i2c_adapter *adapter); +static int max6650_detect(struct i2c_adapter *adapter, int address, int kind); +static int max6650_init_client(struct i2c_client *client); +static int max6650_detach_client(struct i2c_client *client); +static struct max6650_data *max6650_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver max6650_driver = { + .driver = { + .name = "max6650", + }, + .attach_adapter = max6650_attach_adapter, + .detach_client = max6650_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct max6650_data +{ + struct i2c_client client; + struct class_device *class_dev; + struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* register values */ + u8 speed; + u8 config; + u8 tach[4]; + u8 count; + u8 dac; +}; + +static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct max6650_data *data = max6650_update_device(dev); + int rpm; + + /* + * Calculation details: + * + * Each tachometer counts over an interval given by the "count" + * register (0.25, 0.5, 1 or 2 seconds). This module assumes + * that the fans produce two pulses per revolution (this seems + * to be the most common). + */ + + rpm = ((data->tach[attr->index] * 120) / DIV_FROM_REG(data->count)); + return sprintf(buf, "%d\n", rpm); +} + +/* + * Set the fan speed to the specified RPM (or read back the RPM setting). + * This works in closed loop mode only. Use pwm1 for open loop speed setting. + * + * The MAX6650/1 will automatically control fan speed when in closed loop + * mode. + * + * Assumptions: + * + * 1) The MAX6650/1 internal 254kHz clock frequency is set correctly. Use + * the clock module parameter if you need to fine tune this. + * + * 2) The prescaler (low three bits of the config register) has already + * been set to an appropriate value. Use the prescaler module parameter + * if your BIOS doesn't initialize the chip properly. + * + * The relevant equations are given on pages 21 and 22 of the datasheet. + * + * From the datasheet, the relevant equation when in regulation is: + * + * [fCLK / (128 x (KTACH + 1))] = 2 x FanSpeed / KSCALE + * + * where: + * + * fCLK is the oscillator frequency (either the 254kHz internal + * oscillator or the externally applied clock) + * + * KTACH is the value in the speed register + * + * FanSpeed is the speed of the fan in rps + * + * KSCALE is the prescaler value (1, 2, 4, 8, or 16) + * + * When reading, we need to solve for FanSpeed. When writing, we need to + * solve for KTACH. + * + * Note: this tachometer is completely separate from the tachometers + * used to measure the fan speeds. Only one fan's speed (fan1) is + * controlled. + */ + +static ssize_t get_target(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct max6650_data *data = max6650_update_device(dev); + int kscale, ktach, rpm; + + /* + * Use the datasheet equation: + * + * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)] + * + * then multiply by 60 to give rpm. + */ + + kscale = DIV_FROM_REG(data->config); + ktach = data->speed; + rpm = 60 * kscale * clock / (256 * (ktach + 1)); + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t set_target(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max6650_data *data = i2c_get_clientdata(client); + int rpm = simple_strtoul(buf, NULL, 10); + int kscale, ktach; + + rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX); + + /* + * Divide the required speed by 60 to get from rpm to rps, then + * use the datasheet equation: + * + * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1 + */ + + mutex_lock(&data->update_lock); + + kscale = DIV_FROM_REG(data->config); + ktach = ((clock * kscale) / (256 * rpm / 60)) - 1; + if (ktach < 0) + ktach = 0; + if (ktach > 255) + ktach = 255; + data->speed = ktach; + + i2c_smbus_write_byte_data(client, MAX6650_REG_SPEED, data->speed); + + mutex_unlock(&data->update_lock); + + return count; +} + +/* + * Get/set the fan speed in open loop mode using pwm1 sysfs file. + * Speed is given as a relative value from 0 to 255, where 255 is maximum + * speed. Note that this is done by writing directly to the chip's DAC, + * it won't change the closed loop speed set by fan1_target. + * Also note that due to rounding errors it is possible that you don't read + * back exactly the value you have set. + */ + +static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + int pwm; + struct max6650_data *data = max6650_update_device(dev); + + /* Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans. + Lower DAC values mean higher speeds. */ + if (data->config & MAX6650_CFG_V12) + pwm = 255 - (255 * (int)data->dac)/180; + else + pwm = 255 - (255 * (int)data->dac)/76; + + if (pwm < 0) + pwm = 0; + + return sprintf(buf, "%d\n", pwm); +} + +static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max6650_data *data = i2c_get_clientdata(client); + int pwm = simple_strtoul(buf, NULL, 10); + + pwm = SENSORS_LIMIT(pwm, 0, 255); + + mutex_lock(&data->update_lock); + + if (data->config & MAX6650_CFG_V12) + data->dac = 180 - (180 * pwm)/255; + else + data->dac = 76 - (76 * pwm)/255; + + i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac); + + mutex_unlock(&data->update_lock); + + return count; +} + +/* + * Get/Set controller mode: + * Possible values: + * 0 = Fan always on + * 1 = Open loop, Voltage is set according to speed, not regulated. + * 2 = Closed loop, RPM for all fans regulated by fan1 tachometer + */ + +static ssize_t get_enable(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct max6650_data *data = max6650_update_device(dev); + int mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4; + int sysfs_modes[4] = {0, 1, 2, 1}; + + return sprintf(buf, "%d\n", sysfs_modes[mode]); +} + +static ssize_t set_enable(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max6650_data *data = i2c_get_clientdata(client); + int mode = simple_strtoul(buf, NULL, 10); + int max6650_modes[3] = {0, 3, 2}; + + if ((mode < 0)||(mode > 2)) { + dev_err(&client->dev, + "illegal value for pwm1_enable (%d)\n", mode); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + data->config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG); + data->config = (data->config & ~MAX6650_CFG_MODE_MASK) + | (max6650_modes[mode] << 4); + + i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, data->config); + + mutex_unlock(&data->update_lock); + + return count; +} + +/* + * Read/write functions for fan1_div sysfs file. The MAX6650 has no such + * divider. We handle this by converting between divider and counttime: + * + * (counttime == k) <==> (divider == 2^k), k = 0, 1, 2, or 3 + * + * Lower values of k allow to connect a faster fan without the risk of + * counter overflow. The price is lower resolution. You can also set counttime + * using the module parameter. Note that the module parameter "prescaler" also + * influences the behaviour. Unfortunately, there's no sysfs attribute + * defined for that. See the data sheet for details. + */ + +static ssize_t get_div(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct max6650_data *data = max6650_update_device(dev); + + return sprintf(buf, "%d\n", DIV_FROM_REG(data->count)); +} + +static ssize_t set_div(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max6650_data *data = i2c_get_clientdata(client); + int div = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + switch (div) { + case 1: + data->count = 0; + break; + case 2: + data->count = 1; + break; + case 4: + data->count = 2; + break; + case 8: + data->count = 3; + break; + default: + dev_err(&client->dev, + "illegal value for fan divider (%d)\n", div); + return -EINVAL; + } + + i2c_smbus_write_byte_data(client, MAX6650_REG_COUNT, data->count); + mutex_unlock(&data->update_lock); + + return count; +} + +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); +static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3); +static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target); +static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div); +static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable); +static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); + + +static struct attribute *max6650_attrs[] = { + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &dev_attr_fan1_target.attr, + &dev_attr_fan1_div.attr, + &dev_attr_pwm1_enable.attr, + &dev_attr_pwm1.attr, + NULL +}; + +static struct attribute_group max6650_attr_grp = { + .attrs = max6650_attrs, +}; + +/* + * Real code + */ + +static int max6650_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) { + dev_dbg(&adapter->dev, + "FATAL: max6650_attach_adapter class HWMON not set\n"); + return 0; + } + + return i2c_probe(adapter, &addr_data, max6650_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ + +static int max6650_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct max6650_data *data; + int err = -ENODEV; + + dev_dbg(&adapter->dev, "max6650_detect called, kind = %d\n", kind); + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support " + "byte read mode, skipping.\n"); + return 0; + } + + if (!(data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL))) { + dev_err(&adapter->dev, "max6650: out of memory.\n"); + return -ENOMEM; + } + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &max6650_driver; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip (actually there is only + * one possible kind of chip for now, max6650). A zero kind means that + * the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + * + * Currently I can find no way to distinguish between a MAX6650 and + * a MAX6651. This driver has only been tried on the former. + */ + + if ((kind < 0) && + ( (i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG) & 0xC0) + ||(i2c_smbus_read_byte_data(client, MAX6650_REG_GPIO_STAT) & 0xE0) + ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN) & 0xE0) + ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM) & 0xE0) + ||(i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT) & 0xFC))) { + dev_dbg(&adapter->dev, + "max6650: detection failed at 0x%02x.\n", address); + goto err_free; + } + + dev_info(&adapter->dev, "max6650: chip found at 0x%02x.\n", address); + + strlcpy(client->name, "max6650", I2C_NAME_SIZE); + mutex_init(&data->update_lock); + + if ((err = i2c_attach_client(client))) { + dev_err(&adapter->dev, "max6650: failed to attach client.\n"); + goto err_free; + } + + /* + * Initialize the max6650 chip + */ + if (max6650_init_client(client)) + goto err_detach; + + err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp); + if (err) + goto err_detach; + + data->class_dev = hwmon_device_register(&client->dev); + if (!IS_ERR(data->class_dev)) + return 0; + + err = PTR_ERR(data->class_dev); + dev_err(&client->dev, "error registering hwmon device.\n"); + sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); +err_detach: + i2c_detach_client(client); +err_free: + kfree(data); + return err; +} + +static int max6650_detach_client(struct i2c_client *client) +{ + struct max6650_data *data = i2c_get_clientdata(client); + int err; + + sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); + hwmon_device_unregister(data->class_dev); + err = i2c_detach_client(client); + if (!err) + kfree(data); + return err; +} + +static int max6650_init_client(struct i2c_client *client) +{ + struct max6650_data *data = i2c_get_clientdata(client); + int config; + int err = -EIO; + + config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG); + + if (config < 0) { + dev_err(&client->dev, "Error reading config, aborting.\n"); + return err; + } + + switch (fan_voltage) { + case 0: + break; + case 5: + config &= ~MAX6650_CFG_V12; + break; + case 12: + config |= MAX6650_CFG_V12; + break; + default: + dev_err(&client->dev, + "illegal value for fan_voltage (%d)\n", + fan_voltage); + } + + dev_info(&client->dev, "Fan voltage is set to %dV.\n", + (config & MAX6650_CFG_V12) ? 12 : 5); + + switch (prescaler) { + case 0: + break; + case 1: + config &= ~MAX6650_CFG_PRESCALER_MASK; + break; + case 2: + config = (config & ~MAX6650_CFG_PRESCALER_MASK) + | MAX6650_CFG_PRESCALER_2; + break; + case 4: + config = (config & ~MAX6650_CFG_PRESCALER_MASK) + | MAX6650_CFG_PRESCALER_4; + break; + case 8: + config = (config & ~MAX6650_CFG_PRESCALER_MASK) + | MAX6650_CFG_PRESCALER_8; + break; + case 16: + config = (config & ~MAX6650_CFG_PRESCALER_MASK) + | MAX6650_CFG_PRESCALER_16; + break; + default: + dev_err(&client->dev, + "illegal value for prescaler (%d)\n", + prescaler); + } + + dev_info(&client->dev, "Prescaler is set to %d.\n", + 1 << (config & MAX6650_CFG_PRESCALER_MASK)); + + /* If mode is set to "full off", we change it to "open loop" and + * set DAC to 255, which has the same effect. We do this because + * there's no "full off" mode defined in hwmon specifcations. + */ + + if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) { + dev_dbg(&client->dev, "Change mode to open loop, full off.\n"); + config = (config & ~MAX6650_CFG_MODE_MASK) + | MAX6650_CFG_MODE_OPEN_LOOP; + if (i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, 255)) { + dev_err(&client->dev, "DAC write error, aborting.\n"); + return err; + } + } + + if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) { + dev_err(&client->dev, "Config write error, aborting.\n"); + return err; + } + + data->config = config; + data->count = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT); + + return 0; +} + +static const u8 tach_reg[] = { + MAX6650_REG_TACH0, + MAX6650_REG_TACH1, + MAX6650_REG_TACH2, + MAX6650_REG_TACH3, +}; + +static struct max6650_data *max6650_update_device(struct device *dev) +{ + int i; + struct i2c_client *client = to_i2c_client(dev); + struct max6650_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + data->speed = i2c_smbus_read_byte_data(client, + MAX6650_REG_SPEED); + data->config = i2c_smbus_read_byte_data(client, + MAX6650_REG_CONFIG); + for (i = 0; i < 4; i++) { + data->tach[i] = i2c_smbus_read_byte_data(client, + tach_reg[i]); + } + data->count = i2c_smbus_read_byte_data(client, + MAX6650_REG_COUNT); + data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init sensors_max6650_init(void) +{ + return i2c_add_driver(&max6650_driver); +} + +static void __exit sensors_max6650_exit(void) +{ + i2c_del_driver(&max6650_driver); +} + +MODULE_AUTHOR("Hans J. Koch"); +MODULE_DESCRIPTION("MAX6650 sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_max6650_init); +module_exit(sensors_max6650_exit); diff --git a/trunk/drivers/hwmon/pc87427.c b/trunk/drivers/hwmon/pc87427.c index affa21a5ccfd..29354fa26f81 100644 --- a/trunk/drivers/hwmon/pc87427.c +++ b/trunk/drivers/hwmon/pc87427.c @@ -31,6 +31,7 @@ #include #include #include +#include #include static struct platform_device *pdev; @@ -429,6 +430,12 @@ static int __devinit pc87427_probe(struct platform_device *pdev) /* This will need to be revisited when we add support for temperature and voltage monitoring. */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) { + err = -EBUSY; + dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n", + (unsigned long)res->start, (unsigned long)res->end); + goto exit_kfree; + } data->address[0] = res->start; mutex_init(&data->lock); @@ -438,7 +445,7 @@ static int __devinit pc87427_probe(struct platform_device *pdev) /* Register sysfs hooks */ if ((err = device_create_file(&pdev->dev, &dev_attr_name))) - goto exit_kfree; + goto exit_release_region; for (i = 0; i < 8; i++) { if (!(data->fan_enabled & (1 << i))) continue; @@ -462,6 +469,8 @@ static int __devinit pc87427_probe(struct platform_device *pdev) continue; sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]); } +exit_release_region: + release_region(res->start, res->end - res->start + 1); exit_kfree: platform_set_drvdata(pdev, NULL); kfree(data); @@ -472,6 +481,7 @@ static int __devinit pc87427_probe(struct platform_device *pdev) static int __devexit pc87427_remove(struct platform_device *pdev) { struct pc87427_data *data = platform_get_drvdata(pdev); + struct resource *res; int i; platform_set_drvdata(pdev, NULL); @@ -484,6 +494,9 @@ static int __devexit pc87427_remove(struct platform_device *pdev) } kfree(data); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start, res->end - res->start + 1); + return 0; } diff --git a/trunk/drivers/hwmon/smsc47b397.c b/trunk/drivers/hwmon/smsc47b397.c index 72b0e2d8650c..943abbd95ab5 100644 --- a/trunk/drivers/hwmon/smsc47b397.c +++ b/trunk/drivers/hwmon/smsc47b397.c @@ -30,16 +30,17 @@ #include #include #include -#include -#include +#include #include +#include #include #include #include #include -/* Address is autodetected, there is no default value */ -static unsigned short address; +static struct platform_device *pdev; + +#define DRVNAME "smsc47b397" /* Super-I/0 registers and commands */ @@ -91,7 +92,8 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80}; #define SMSC47B397_REG_FAN_MSB(nr) (0x29 + 2 * (nr)) struct smsc47b397_data { - struct i2c_client client; + unsigned short addr; + const char *name; struct class_device *class_dev; struct mutex lock; @@ -104,45 +106,43 @@ struct smsc47b397_data { u8 temp[4]; }; -static int smsc47b397_read_value(struct i2c_client *client, u8 reg) +static int smsc47b397_read_value(struct smsc47b397_data* data, u8 reg) { - struct smsc47b397_data *data = i2c_get_clientdata(client); int res; mutex_lock(&data->lock); - outb(reg, client->addr); - res = inb_p(client->addr + 1); + outb(reg, data->addr); + res = inb_p(data->addr + 1); mutex_unlock(&data->lock); return res; } static struct smsc47b397_data *smsc47b397_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct smsc47b397_data *data = i2c_get_clientdata(client); + struct smsc47b397_data *data = dev_get_drvdata(dev); int i; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - dev_dbg(&client->dev, "starting device update...\n"); + dev_dbg(dev, "starting device update...\n"); /* 4 temperature inputs, 4 fan inputs */ for (i = 0; i < 4; i++) { - data->temp[i] = smsc47b397_read_value(client, + data->temp[i] = smsc47b397_read_value(data, SMSC47B397_REG_TEMP(i)); /* must read LSB first */ - data->fan[i] = smsc47b397_read_value(client, + data->fan[i] = smsc47b397_read_value(data, SMSC47B397_REG_FAN_LSB(i)); - data->fan[i] |= smsc47b397_read_value(client, + data->fan[i] |= smsc47b397_read_value(data, SMSC47B397_REG_FAN_MSB(i)) << 8; } data->last_updated = jiffies; data->valid = 1; - dev_dbg(&client->dev, "... device update complete\n"); + dev_dbg(dev, "... device update complete\n"); } mutex_unlock(&data->update_lock); @@ -157,24 +157,18 @@ static int temp_from_reg(u8 reg) return (s8)reg * 1000; } -/* 0 <= nr <= 3 */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) +static ssize_t show_temp(struct device *dev, struct device_attribute + *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct smsc47b397_data *data = smsc47b397_update_device(dev); - return sprintf(buf, "%d\n", temp_from_reg(data->temp[nr])); + return sprintf(buf, "%d\n", temp_from_reg(data->temp[attr->index])); } -#define sysfs_temp(num) \ -static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL) - -sysfs_temp(1); -sysfs_temp(2); -sysfs_temp(3); -sysfs_temp(4); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); /* FAN: 1 RPM/bit REG: count of 90kHz pulses / revolution */ @@ -183,35 +177,37 @@ static int fan_from_reg(u16 reg) return 90000 * 60 / reg; } -/* 0 <= nr <= 3 */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) +static ssize_t show_fan(struct device *dev, struct device_attribute + *devattr, char *buf) { - struct smsc47b397_data *data = smsc47b397_update_device(dev); - return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr])); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct smsc47b397_data *data = smsc47b397_update_device(dev); + return sprintf(buf, "%d\n", fan_from_reg(data->fan[attr->index])); } +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); +static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3); -#define sysfs_fan(num) \ -static ssize_t show_fan##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, num-1); \ -} \ -static DEVICE_ATTR(fan##num##_input, S_IRUGO, show_fan##num, NULL) - -sysfs_fan(1); -sysfs_fan(2); -sysfs_fan(3); -sysfs_fan(4); +static ssize_t show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct smsc47b397_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->name); +} +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); static struct attribute *smsc47b397_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp3_input.attr, - &dev_attr_temp4_input.attr, - &dev_attr_fan1_input.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan3_input.attr, - &dev_attr_fan4_input.attr, - + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + + &dev_attr_name.attr, NULL }; @@ -219,44 +215,44 @@ static const struct attribute_group smsc47b397_group = { .attrs = smsc47b397_attributes, }; -static int smsc47b397_detach_client(struct i2c_client *client) +static int __devexit smsc47b397_remove(struct platform_device *pdev) { - struct smsc47b397_data *data = i2c_get_clientdata(client); - int err; + struct smsc47b397_data *data = platform_get_drvdata(pdev); + struct resource *res; hwmon_device_unregister(data->class_dev); - sysfs_remove_group(&client->dev.kobj, &smsc47b397_group); - - if ((err = i2c_detach_client(client))) - return err; - - release_region(client->addr, SMSC_EXTENT); + sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start, SMSC_EXTENT); kfree(data); return 0; } -static int smsc47b397_detect(struct i2c_adapter *adapter); +static int smsc47b397_probe(struct platform_device *pdev); -static struct i2c_driver smsc47b397_driver = { +static struct platform_driver smsc47b397_driver = { .driver = { .owner = THIS_MODULE, - .name = "smsc47b397", + .name = DRVNAME, }, - .attach_adapter = smsc47b397_detect, - .detach_client = smsc47b397_detach_client, + .probe = smsc47b397_probe, + .remove = __devexit_p(smsc47b397_remove), }; -static int smsc47b397_detect(struct i2c_adapter *adapter) +static int __devinit smsc47b397_probe(struct platform_device *pdev) { - struct i2c_client *new_client; + struct device *dev = &pdev->dev; struct smsc47b397_data *data; + struct resource *res; int err = 0; - if (!request_region(address, SMSC_EXTENT, + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, SMSC_EXTENT, smsc47b397_driver.driver.name)) { - dev_err(&adapter->dev, "Region 0x%x already in use!\n", - address); + dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", + (unsigned long)res->start, + (unsigned long)res->start + SMSC_EXTENT - 1); return -EBUSY; } @@ -265,25 +261,16 @@ static int smsc47b397_detect(struct i2c_adapter *adapter) goto error_release; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; + data->addr = res->start; + data->name = "smsc47b397"; mutex_init(&data->lock); - new_client->adapter = adapter; - new_client->driver = &smsc47b397_driver; - new_client->flags = 0; - - strlcpy(new_client->name, "smsc47b397", I2C_NAME_SIZE); - mutex_init(&data->update_lock); + platform_set_drvdata(pdev, data); - if ((err = i2c_attach_client(new_client))) + if ((err = sysfs_create_group(&dev->kobj, &smsc47b397_group))) goto error_free; - if ((err = sysfs_create_group(&new_client->dev.kobj, &smsc47b397_group))) - goto error_detach; - - data->class_dev = hwmon_device_register(&new_client->dev); + data->class_dev = hwmon_device_register(dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); goto error_remove; @@ -292,13 +279,50 @@ static int smsc47b397_detect(struct i2c_adapter *adapter) return 0; error_remove: - sysfs_remove_group(&new_client->dev.kobj, &smsc47b397_group); -error_detach: - i2c_detach_client(new_client); + sysfs_remove_group(&dev->kobj, &smsc47b397_group); error_free: kfree(data); error_release: - release_region(address, SMSC_EXTENT); + release_region(res->start, SMSC_EXTENT); + return err; +} + +static int __init smsc47b397_device_add(unsigned short address) +{ + struct resource res = { + .start = address, + .end = address + SMSC_EXTENT - 1, + .name = DRVNAME, + .flags = IORESOURCE_IO, + }; + int err; + + pdev = platform_device_alloc(DRVNAME, address); + if (!pdev) { + err = -ENOMEM; + printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + goto exit; + } + + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed " + "(%d)\n", err); + goto exit_device_put; + } + + err = platform_device_add(pdev); + if (err) { + printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", + err); + goto exit_device_put; + } + + return 0; + +exit_device_put: + platform_device_put(pdev); +exit: return err; } @@ -320,7 +344,7 @@ static int __init smsc47b397_find(unsigned short *addr) *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8) | superio_inb(SUPERIO_REG_BASE_LSB); - printk(KERN_INFO "smsc47b397: found SMSC %s " + printk(KERN_INFO DRVNAME ": found SMSC %s " "(base address 0x%04x, revision %u)\n", id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev); @@ -330,17 +354,33 @@ static int __init smsc47b397_find(unsigned short *addr) static int __init smsc47b397_init(void) { + unsigned short address; int ret; if ((ret = smsc47b397_find(&address))) return ret; - return i2c_isa_add_driver(&smsc47b397_driver); + ret = platform_driver_register(&smsc47b397_driver); + if (ret) + goto exit; + + /* Sets global pdev as a side effect */ + ret = smsc47b397_device_add(address); + if (ret) + goto exit_driver; + + return 0; + +exit_driver: + platform_driver_unregister(&smsc47b397_driver); +exit: + return ret; } static void __exit smsc47b397_exit(void) { - i2c_isa_del_driver(&smsc47b397_driver); + platform_device_unregister(pdev); + platform_driver_unregister(&smsc47b397_driver); } MODULE_AUTHOR("Mark M. Hoffman "); diff --git a/trunk/drivers/hwmon/smsc47m1.c b/trunk/drivers/hwmon/smsc47m1.c index beb881c4b2e8..1e21c8cc948f 100644 --- a/trunk/drivers/hwmon/smsc47m1.c +++ b/trunk/drivers/hwmon/smsc47m1.c @@ -3,10 +3,11 @@ for hardware monitoring Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x, - LPC47M14x, LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips. + LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997 + Super-I/O chips. Copyright (C) 2002 Mark D. Studebaker - Copyright (C) 2004 Jean Delvare + Copyright (C) 2004-2007 Jean Delvare Ported to Linux 2.6 by Gabriele Gorla and Jean Delvare @@ -29,17 +30,19 @@ #include #include #include -#include -#include +#include #include +#include #include #include #include #include #include -/* Address is autodetected, there is no default value */ -static unsigned short address; +static struct platform_device *pdev; + +#define DRVNAME "smsc47m1" +enum chips { smsc47m1, smsc47m2 }; /* Super-I/0 registers and commands */ @@ -87,10 +90,18 @@ superio_exit(void) #define SMSC47M1_REG_ALARM 0x04 #define SMSC47M1_REG_TPIN(nr) (0x34 - (nr)) #define SMSC47M1_REG_PPIN(nr) (0x36 - (nr)) -#define SMSC47M1_REG_PWM(nr) (0x56 + (nr)) #define SMSC47M1_REG_FANDIV 0x58 -#define SMSC47M1_REG_FAN(nr) (0x59 + (nr)) -#define SMSC47M1_REG_FAN_PRELOAD(nr) (0x5B + (nr)) + +static const u8 SMSC47M1_REG_FAN[3] = { 0x59, 0x5a, 0x6b }; +static const u8 SMSC47M1_REG_FAN_PRELOAD[3] = { 0x5b, 0x5c, 0x6c }; +static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 }; + +#define SMSC47M2_REG_ALARM6 0x09 +#define SMSC47M2_REG_TPIN1 0x38 +#define SMSC47M2_REG_TPIN2 0x37 +#define SMSC47M2_REG_TPIN3 0x2d +#define SMSC47M2_REG_PPIN3 0x2c +#define SMSC47M2_REG_FANDIV3 0x6a #define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \ 983040/((192-(reg))*(div))) @@ -102,45 +113,57 @@ superio_exit(void) #define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E) struct smsc47m1_data { - struct i2c_client client; + unsigned short addr; + const char *name; + enum chips type; struct class_device *class_dev; - struct mutex lock; struct mutex update_lock; unsigned long last_updated; /* In jiffies */ - u8 fan[2]; /* Register value */ - u8 fan_preload[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ + u8 fan[3]; /* Register value */ + u8 fan_preload[3]; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ u8 alarms; /* Register encoding */ - u8 pwm[2]; /* Register value (bit 7 is enable) */ + u8 pwm[3]; /* Register value (bit 0 is disable) */ }; +struct smsc47m1_sio_data { + enum chips type; +}; -static int smsc47m1_detect(struct i2c_adapter *adapter); -static int smsc47m1_detach_client(struct i2c_client *client); - -static int smsc47m1_read_value(struct i2c_client *client, u8 reg); -static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value); +static int smsc47m1_probe(struct platform_device *pdev); +static int smsc47m1_remove(struct platform_device *pdev); static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, int init); +static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg) +{ + return inb_p(data->addr + reg); +} -static struct i2c_driver smsc47m1_driver = { +static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg, + u8 value) +{ + outb_p(value, data->addr + reg); +} + +static struct platform_driver smsc47m1_driver = { .driver = { .owner = THIS_MODULE, - .name = "smsc47m1", + .name = DRVNAME, }, - .attach_adapter = smsc47m1_detect, - .detach_client = smsc47m1_detach_client, + .probe = smsc47m1_probe, + .remove = __devexit_p(smsc47m1_remove), }; -/* nr is 0 or 1 in the callback functions below */ - -static ssize_t get_fan(struct device *dev, char *buf, int nr) +static ssize_t get_fan(struct device *dev, struct device_attribute + *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + int nr = attr->index; /* This chip (stupidly) stops monitoring fan speed if PWM is enabled and duty cycle is 0%. This is fine if the monitoring and control concern the same fan, but troublesome if they are @@ -152,43 +175,54 @@ static ssize_t get_fan(struct device *dev, char *buf, int nr) return sprintf(buf, "%d\n", rpm); } -static ssize_t get_fan_min(struct device *dev, char *buf, int nr) +static ssize_t get_fan_min(struct device *dev, struct device_attribute + *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + int nr = attr->index; int rpm = MIN_FROM_REG(data->fan_preload[nr], DIV_FROM_REG(data->fan_div[nr])); return sprintf(buf, "%d\n", rpm); } -static ssize_t get_fan_div(struct device *dev, char *buf, int nr) +static ssize_t get_fan_div(struct device *dev, struct device_attribute + *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index])); } -static ssize_t get_pwm(struct device *dev, char *buf, int nr) +static ssize_t get_pwm(struct device *dev, struct device_attribute + *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); + return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[attr->index])); } -static ssize_t get_pwm_en(struct device *dev, char *buf, int nr) +static ssize_t get_pwm_en(struct device *dev, struct device_attribute + *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr])); + return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[attr->index])); } -static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t get_alarms(struct device *dev, struct device_attribute + *devattr, char *buf) { struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); return sprintf(buf, "%d\n", data->alarms); } -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_min(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct smsc47m1_data *data = dev_get_drvdata(dev); + int nr = attr->index; long rpmdiv, val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); @@ -200,7 +234,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, } data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv); - smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), + smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr], data->fan_preload[nr]); mutex_unlock(&data->update_lock); @@ -211,12 +245,12 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, determined in part by the fan clock divider. This follows the principle of least surprise; the user doesn't expect the fan minimum to change just because the divider changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_div(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct smsc47m1_data *data = dev_get_drvdata(dev); + int nr = attr->index; long new_div = simple_strtol(buf, NULL, 10), tmp; u8 old_div = DIV_FROM_REG(data->fan_div[nr]); @@ -234,27 +268,38 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, return -EINVAL; } - tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F; - tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6); - smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp); + switch (nr) { + case 0: + case 1: + tmp = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV) + & ~(0x03 << (4 + 2 * nr)); + tmp |= data->fan_div[nr] << (4 + 2 * nr); + smsc47m1_write_value(data, SMSC47M1_REG_FANDIV, tmp); + break; + case 2: + tmp = smsc47m1_read_value(data, SMSC47M2_REG_FANDIV3) & 0xCF; + tmp |= data->fan_div[2] << 4; + smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp); + break; + } /* Preserve fan min */ tmp = 192 - (old_div * (192 - data->fan_preload[nr]) + new_div / 2) / new_div; data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191); - smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), + smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr], data->fan_preload[nr]); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_pwm(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_pwm(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct smsc47m1_data *data = dev_get_drvdata(dev); + int nr = attr->index; long val = simple_strtol(buf, NULL, 10); if (val < 0 || val > 255) @@ -263,19 +308,19 @@ static ssize_t set_pwm(struct device *dev, const char *buf, mutex_lock(&data->update_lock); data->pwm[nr] &= 0x81; /* Preserve additional bits */ data->pwm[nr] |= PWM_TO_REG(val); - smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), + smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr], data->pwm[nr]); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_pwm_en(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_pwm_en(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct smsc47m1_data *data = dev_get_drvdata(dev); + int nr = attr->index; long val = simple_strtol(buf, NULL, 10); if (val != 0 && val != 1) @@ -284,7 +329,7 @@ static ssize_t set_pwm_en(struct device *dev, const char *buf, mutex_lock(&data->update_lock); data->pwm[nr] &= 0xFE; /* preserve the other bits */ data->pwm[nr] |= !val; - smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), + smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr], data->pwm[nr]); mutex_unlock(&data->update_lock); @@ -292,79 +337,55 @@ static ssize_t set_pwm_en(struct device *dev, const char *buf, } #define fan_present(offset) \ -static ssize_t get_fan##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_fan(dev, buf, offset - 1); \ -} \ -static ssize_t get_fan##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t get_fan##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan##offset##_div (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static ssize_t get_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static ssize_t get_pwm##offset##_en (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_pwm_en(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_en (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_en(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset, \ - NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - get_fan##offset##_min, set_fan##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - get_fan##offset##_div, set_fan##offset##_div); \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - get_pwm##offset, set_pwm##offset); \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - get_pwm##offset##_en, set_pwm##offset##_en); +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan, \ + NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + get_fan_min, set_fan_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + get_fan_div, set_fan_div, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + get_pwm, set_pwm, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ + get_pwm_en, set_pwm_en, offset - 1) fan_present(1); fan_present(2); +fan_present(3); static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); +static ssize_t show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct smsc47m1_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->name); +} +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + /* Almost all sysfs files may or may not be created depending on the chip setup so we create them individually. It is still convenient to define a group to remove them all at once. */ static struct attribute *smsc47m1_attributes[] = { - &dev_attr_fan1_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan1_div.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan2_div.attr, - - &dev_attr_pwm1.attr, - &dev_attr_pwm1_enable.attr, - &dev_attr_pwm2.attr, - &dev_attr_pwm2_enable.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan3_div.dev_attr.attr, + + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, + &sensor_dev_attr_pwm3_enable.dev_attr.attr, &dev_attr_alarms.attr, + &dev_attr_name.attr, NULL }; @@ -372,7 +393,8 @@ static const struct attribute_group smsc47m1_group = { .attrs = smsc47m1_attributes, }; -static int __init smsc47m1_find(unsigned short *addr) +static int __init smsc47m1_find(unsigned short *addr, + struct smsc47m1_sio_data *sio_data) { u8 val; @@ -386,18 +408,32 @@ static int __init smsc47m1_find(unsigned short *addr) * can do much more besides (device id 0x60). * The LPC47M997 is undocumented, but seems to be compatible with * the LPC47M192, and has the same device id. + * The LPC47M292 (device id 0x6B) is somewhat compatible, but it + * supports a 3rd fan, and the pin configuration registers are + * unfortunately different. */ - if (val == 0x51) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); - else if (val == 0x59) - printk(KERN_INFO "smsc47m1: Found SMSC " - "LPC47M10x/LPC47M112/LPC47M13x\n"); - else if (val == 0x5F) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); - else if (val == 0x60) - printk(KERN_INFO "smsc47m1: Found SMSC " - "LPC47M15x/LPC47M192/LPC47M997\n"); - else { + switch (val) { + case 0x51: + pr_info(DRVNAME ": Found SMSC LPC47B27x\n"); + sio_data->type = smsc47m1; + break; + case 0x59: + pr_info(DRVNAME ": Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n"); + sio_data->type = smsc47m1; + break; + case 0x5F: + pr_info(DRVNAME ": Found SMSC LPC47M14x\n"); + sio_data->type = smsc47m1; + break; + case 0x60: + pr_info(DRVNAME ": Found SMSC LPC47M15x/LPC47M192/LPC47M997\n"); + sio_data->type = smsc47m1; + break; + case 0x6B: + pr_info(DRVNAME ": Found SMSC LPC47M292\n"); + sio_data->type = smsc47m2; + break; + default: superio_exit(); return -ENODEV; } @@ -407,7 +443,7 @@ static int __init smsc47m1_find(unsigned short *addr) | superio_inb(SUPERIO_REG_BASE + 1); val = superio_inb(SUPERIO_REG_ACT); if (*addr == 0 || (val & 0x01) == 0) { - printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n"); + pr_info(DRVNAME ": Device is disabled, will not use\n"); superio_exit(); return -ENODEV; } @@ -416,15 +452,25 @@ static int __init smsc47m1_find(unsigned short *addr) return 0; } -static int smsc47m1_detect(struct i2c_adapter *adapter) +static int __devinit smsc47m1_probe(struct platform_device *pdev) { - struct i2c_client *new_client; + struct device *dev = &pdev->dev; + struct smsc47m1_sio_data *sio_data = dev->platform_data; struct smsc47m1_data *data; + struct resource *res; int err = 0; - int fan1, fan2, pwm1, pwm2; - - if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.driver.name)) { - dev_err(&adapter->dev, "Region 0x%x already in use!\n", address); + int fan1, fan2, fan3, pwm1, pwm2, pwm3; + + static const char *names[] = { + "smsc47m1", + "smsc47m2", + }; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, SMSC_EXTENT, DRVNAME)) { + dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", + (unsigned long)res->start, + (unsigned long)res->end); return -EBUSY; } @@ -433,93 +479,114 @@ static int smsc47m1_detect(struct i2c_adapter *adapter) goto error_release; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - mutex_init(&data->lock); - new_client->adapter = adapter; - new_client->driver = &smsc47m1_driver; - new_client->flags = 0; - - strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE); + data->addr = res->start; + data->type = sio_data->type; + data->name = names[sio_data->type]; mutex_init(&data->update_lock); + platform_set_drvdata(pdev, data); /* If no function is properly configured, there's no point in actually registering the chip. */ - fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05) - == 0x05; - fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05) - == 0x05; - pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05) + pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05) == 0x04; - pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05) + pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05) == 0x04; - if (!(fan1 || fan2 || pwm1 || pwm2)) { - dev_warn(&adapter->dev, "Device at 0x%x is not configured, " - "will not use\n", new_client->addr); + if (data->type == smsc47m2) { + fan1 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN1) + & 0x0d) == 0x09; + fan2 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN2) + & 0x0d) == 0x09; + fan3 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN3) + & 0x0d) == 0x0d; + pwm3 = (smsc47m1_read_value(data, SMSC47M2_REG_PPIN3) + & 0x0d) == 0x08; + } else { + fan1 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(0)) + & 0x05) == 0x05; + fan2 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(1)) + & 0x05) == 0x05; + fan3 = 0; + pwm3 = 0; + } + if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) { + dev_warn(dev, "Device not configured, will not use\n"); err = -ENODEV; goto error_free; } - if ((err = i2c_attach_client(new_client))) - goto error_free; - /* Some values (fan min, clock dividers, pwm registers) may be needed before any update is triggered, so we better read them at least once here. We don't usually do it that way, but in this particular case, manually reading 5 registers out of 8 doesn't make much sense and we're better using the existing function. */ - smsc47m1_update_device(&new_client->dev, 1); + smsc47m1_update_device(dev, 1); /* Register sysfs hooks */ if (fan1) { - if ((err = device_create_file(&new_client->dev, - &dev_attr_fan1_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_fan1_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_fan1_div))) + if ((err = device_create_file(dev, + &sensor_dev_attr_fan1_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan1_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan1_div.dev_attr))) goto error_remove_files; } else - dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, " - "skipping\n"); + dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n"); if (fan2) { - if ((err = device_create_file(&new_client->dev, - &dev_attr_fan2_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_fan2_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_fan2_div))) + if ((err = device_create_file(dev, + &sensor_dev_attr_fan2_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan2_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan2_div.dev_attr))) goto error_remove_files; } else - dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, " - "skipping\n"); + dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n"); + + if (fan3) { + if ((err = device_create_file(dev, + &sensor_dev_attr_fan3_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan3_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan3_div.dev_attr))) + goto error_remove_files; + } else + dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n"); if (pwm1) { - if ((err = device_create_file(&new_client->dev, - &dev_attr_pwm1)) - || (err = device_create_file(&new_client->dev, - &dev_attr_pwm1_enable))) + if ((err = device_create_file(dev, + &sensor_dev_attr_pwm1.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm1_enable.dev_attr))) goto error_remove_files; } else - dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, " - "skipping\n"); + dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n"); + if (pwm2) { - if ((err = device_create_file(&new_client->dev, - &dev_attr_pwm2)) - || (err = device_create_file(&new_client->dev, - &dev_attr_pwm2_enable))) + if ((err = device_create_file(dev, + &sensor_dev_attr_pwm2.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm2_enable.dev_attr))) + goto error_remove_files; + } else + dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n"); + + if (pwm3) { + if ((err = device_create_file(dev, + &sensor_dev_attr_pwm3.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm3_enable.dev_attr))) goto error_remove_files; } else - dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, " - "skipping\n"); + dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n"); - if ((err = device_create_file(&new_client->dev, &dev_attr_alarms))) + if ((err = device_create_file(dev, &dev_attr_alarms))) goto error_remove_files; - data->class_dev = hwmon_device_register(&new_client->dev); + data->class_dev = hwmon_device_register(dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); goto error_remove_files; @@ -528,78 +595,71 @@ static int smsc47m1_detect(struct i2c_adapter *adapter) return 0; error_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &smsc47m1_group); - i2c_detach_client(new_client); + sysfs_remove_group(&dev->kobj, &smsc47m1_group); error_free: kfree(data); error_release: - release_region(address, SMSC_EXTENT); + release_region(res->start, SMSC_EXTENT); return err; } -static int smsc47m1_detach_client(struct i2c_client *client) +static int __devexit smsc47m1_remove(struct platform_device *pdev) { - struct smsc47m1_data *data = i2c_get_clientdata(client); - int err; + struct smsc47m1_data *data = platform_get_drvdata(pdev); + struct resource *res; + platform_set_drvdata(pdev, NULL); hwmon_device_unregister(data->class_dev); - sysfs_remove_group(&client->dev.kobj, &smsc47m1_group); - - if ((err = i2c_detach_client(client))) - return err; + sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group); - release_region(client->addr, SMSC_EXTENT); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start, SMSC_EXTENT); kfree(data); return 0; } -static int smsc47m1_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); - res = inb_p(client->addr + reg); - mutex_unlock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); - return res; -} - -static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); - outb_p(value, client->addr + reg); - mutex_unlock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); -} - static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, int init) { - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); + struct smsc47m1_data *data = dev_get_drvdata(dev); mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) { - int i; - - for (i = 0; i < 2; i++) { - data->fan[i] = smsc47m1_read_value(client, - SMSC47M1_REG_FAN(i)); - data->fan_preload[i] = smsc47m1_read_value(client, - SMSC47M1_REG_FAN_PRELOAD(i)); - data->pwm[i] = smsc47m1_read_value(client, - SMSC47M1_REG_PWM(i)); + int i, fan_nr; + fan_nr = data->type == smsc47m2 ? 3 : 2; + + for (i = 0; i < fan_nr; i++) { + data->fan[i] = smsc47m1_read_value(data, + SMSC47M1_REG_FAN[i]); + data->fan_preload[i] = smsc47m1_read_value(data, + SMSC47M1_REG_FAN_PRELOAD[i]); + data->pwm[i] = smsc47m1_read_value(data, + SMSC47M1_REG_PWM[i]); } - i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); + i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV); data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = i >> 6; - data->alarms = smsc47m1_read_value(client, + data->alarms = smsc47m1_read_value(data, SMSC47M1_REG_ALARM) >> 6; /* Clear alarms if needed */ if (data->alarms) - smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0); + smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0); + + if (fan_nr >= 3) { + data->fan_div[2] = (smsc47m1_read_value(data, + SMSC47M2_REG_FANDIV3) >> 4) & 0x03; + data->alarms |= (smsc47m1_read_value(data, + SMSC47M2_REG_ALARM6) & 0x40) >> 4; + /* Clear alarm if needed */ + if (data->alarms & 0x04) + smsc47m1_write_value(data, + SMSC47M2_REG_ALARM6, + 0x40); + } data->last_updated = jiffies; } @@ -608,18 +668,86 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, return data; } +static int __init smsc47m1_device_add(unsigned short address, + const struct smsc47m1_sio_data *sio_data) +{ + struct resource res = { + .start = address, + .end = address + SMSC_EXTENT - 1, + .name = DRVNAME, + .flags = IORESOURCE_IO, + }; + int err; + + pdev = platform_device_alloc(DRVNAME, address); + if (!pdev) { + err = -ENOMEM; + printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + goto exit; + } + + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed " + "(%d)\n", err); + goto exit_device_put; + } + + pdev->dev.platform_data = kmalloc(sizeof(struct smsc47m1_sio_data), + GFP_KERNEL); + if (!pdev->dev.platform_data) { + err = -ENOMEM; + printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + goto exit_device_put; + } + memcpy(pdev->dev.platform_data, sio_data, + sizeof(struct smsc47m1_sio_data)); + + err = platform_device_add(pdev); + if (err) { + printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", + err); + goto exit_device_put; + } + + return 0; + +exit_device_put: + platform_device_put(pdev); +exit: + return err; +} + static int __init sm_smsc47m1_init(void) { - if (smsc47m1_find(&address)) { + int err; + unsigned short address; + struct smsc47m1_sio_data sio_data; + + if (smsc47m1_find(&address, &sio_data)) return -ENODEV; - } - return i2c_isa_add_driver(&smsc47m1_driver); + err = platform_driver_register(&smsc47m1_driver); + if (err) + goto exit; + + /* Sets global pdev as a side effect */ + err = smsc47m1_device_add(address, &sio_data); + if (err) + goto exit_driver; + + return 0; + +exit_driver: + platform_driver_unregister(&smsc47m1_driver); +exit: + return err; } static void __exit sm_smsc47m1_exit(void) { - i2c_isa_del_driver(&smsc47m1_driver); + platform_device_unregister(pdev); + platform_driver_unregister(&smsc47m1_driver); } MODULE_AUTHOR("Mark D. Studebaker "); diff --git a/trunk/drivers/hwmon/smsc47m192.c b/trunk/drivers/hwmon/smsc47m192.c index a6833f437395..a012f396f354 100644 --- a/trunk/drivers/hwmon/smsc47m192.c +++ b/trunk/drivers/hwmon/smsc47m192.c @@ -1,6 +1,6 @@ /* smsc47m192.c - Support for hardware monitoring block of - SMSC LPC47M192 and LPC47M997 Super I/O chips + SMSC LPC47M192 and compatible Super I/O chips Copyright (C) 2006 Hartmut Rick @@ -518,7 +518,7 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address, && (i2c_smbus_read_byte_data(client, SMSC47M192_REG_VID4) & 0xfe) == 0x80) { dev_info(&adapter->dev, - "found SMSC47M192 or SMSC47M997, " + "found SMSC47M192 or compatible, " "version 2, stepping A%d\n", version & 0x0f); } else { dev_dbg(&adapter->dev, diff --git a/trunk/drivers/hwmon/vt1211.c b/trunk/drivers/hwmon/vt1211.c index 89c23d6add7b..9f3e332c5b7f 100644 --- a/trunk/drivers/hwmon/vt1211.c +++ b/trunk/drivers/hwmon/vt1211.c @@ -31,6 +31,7 @@ #include #include #include +#include #include static int uch_config = -1; @@ -1130,6 +1131,12 @@ static int __devinit vt1211_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) { + err = -EBUSY; + dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", + (unsigned long)res->start, (unsigned long)res->end); + goto EXIT_KFREE; + } data->addr = res->start; data->name = DRVNAME; mutex_init(&data->update_lock); @@ -1197,6 +1204,8 @@ static int __devinit vt1211_probe(struct platform_device *pdev) dev_err(dev, "Sysfs interface creation failed (%d)\n", err); EXIT_DEV_REMOVE_SILENT: vt1211_remove_sysfs(pdev); + release_region(res->start, res->end - res->start + 1); +EXIT_KFREE: platform_set_drvdata(pdev, NULL); kfree(data); EXIT: @@ -1206,12 +1215,16 @@ static int __devinit vt1211_probe(struct platform_device *pdev) static int __devexit vt1211_remove(struct platform_device *pdev) { struct vt1211_data *data = platform_get_drvdata(pdev); + struct resource *res; hwmon_device_unregister(data->class_dev); vt1211_remove_sysfs(pdev); platform_set_drvdata(pdev, NULL); kfree(data); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start, res->end - res->start + 1); + return 0; } diff --git a/trunk/drivers/hwmon/w83627hf.c b/trunk/drivers/hwmon/w83627hf.c index d7e240635b3b..a5b774b07cbd 100644 --- a/trunk/drivers/hwmon/w83627hf.c +++ b/trunk/drivers/hwmon/w83627hf.c @@ -5,6 +5,7 @@ Philip Edelbrock , and Mark Studebaker Ported to 2.6 by Bernhard C. Schrenk + Copyright (c) 2007 Jean Delvare 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 @@ -42,15 +43,20 @@ #include #include #include -#include -#include +#include #include #include #include #include +#include #include #include "lm75.h" +static struct platform_device *pdev; + +#define DRVNAME "w83627hf" +enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf }; + static u16 force_addr; module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, @@ -60,12 +66,6 @@ module_param(force_i2c, byte, 0); MODULE_PARM_DESC(force_i2c, "Initialize the i2c address of the sensors"); -/* The actual ISA address is read from Super-I/O configuration space */ -static unsigned short address; - -/* Insmod parameters */ -enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf, w83687thf }; - static int reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to one to reset chip on load"); @@ -156,9 +156,9 @@ superio_exit(void) #define WINB_REGION_OFFSET 5 #define WINB_REGION_SIZE 2 -/* Where are the sensors address/data registers relative to the base address */ -#define W83781D_ADDR_REG_OFFSET 5 -#define W83781D_DATA_REG_OFFSET 6 +/* Where are the sensors address/data registers relative to the region offset */ +#define W83781D_ADDR_REG_OFFSET 0 +#define W83781D_DATA_REG_OFFSET 1 /* The W83781D registers */ /* The W83782D registers for nr=7,8 are in bank 5 */ @@ -289,7 +289,8 @@ static inline u8 DIV_TO_REG(long val) /* For each registered chip, we need to keep some data in memory. The structure is dynamically allocated. */ struct w83627hf_data { - struct i2c_client client; + unsigned short addr; + const char *name; struct class_device *class_dev; struct mutex lock; enum chips type; @@ -298,9 +299,6 @@ struct w83627hf_data { char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - struct i2c_client *lm75; /* for secondary I2C addresses */ - /* pointer to array of 2 subclients */ - u8 in[9]; /* Register value */ u8 in_max[9]; /* Register value */ u8 in_min[9]; /* Register value */ @@ -327,22 +325,26 @@ struct w83627hf_data { u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */ }; +struct w83627hf_sio_data { + enum chips type; +}; + -static int w83627hf_detect(struct i2c_adapter *adapter); -static int w83627hf_detach_client(struct i2c_client *client); +static int w83627hf_probe(struct platform_device *pdev); +static int w83627hf_remove(struct platform_device *pdev); -static int w83627hf_read_value(struct i2c_client *client, u16 reg); -static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value); +static int w83627hf_read_value(struct w83627hf_data *data, u16 reg); +static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value); static struct w83627hf_data *w83627hf_update_device(struct device *dev); -static void w83627hf_init_client(struct i2c_client *client); +static void w83627hf_init_device(struct platform_device *pdev); -static struct i2c_driver w83627hf_driver = { +static struct platform_driver w83627hf_driver = { .driver = { .owner = THIS_MODULE, - .name = "w83627hf", + .name = DRVNAME, }, - .attach_adapter = w83627hf_detect, - .detach_client = w83627hf_detach_client, + .probe = w83627hf_probe, + .remove = __devexit_p(w83627hf_remove), }; /* following are the sysfs callback functions */ @@ -360,15 +362,14 @@ show_in_reg(in_max) static ssize_t \ store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627hf_data *data = i2c_get_clientdata(client); \ + struct w83627hf_data *data = dev_get_drvdata(dev); \ u32 val; \ \ val = simple_strtoul(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->in_##reg[nr] = IN_TO_REG(val); \ - w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \ + w83627hf_write_value(data, W83781D_REG_IN_##REG(nr), \ data->in_##reg[nr]); \ \ mutex_unlock(&data->update_lock); \ @@ -452,8 +453,7 @@ static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *at static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); + struct w83627hf_data *data = dev_get_drvdata(dev); u32 val; val = simple_strtoul(buf, NULL, 10); @@ -472,7 +472,7 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a /* use VRM8 (standard) calculation */ data->in_min[0] = IN_TO_REG(val); - w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]); + w83627hf_write_value(data, W83781D_REG_IN_MIN(0), data->in_min[0]); mutex_unlock(&data->update_lock); return count; } @@ -480,8 +480,7 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); + struct w83627hf_data *data = dev_get_drvdata(dev); u32 val; val = simple_strtoul(buf, NULL, 10); @@ -500,7 +499,7 @@ static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *a /* use VRM8 (standard) calculation */ data->in_max[0] = IN_TO_REG(val); - w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]); + w83627hf_write_value(data, W83781D_REG_IN_MAX(0), data->in_max[0]); mutex_unlock(&data->update_lock); return count; } @@ -525,8 +524,7 @@ show_fan_reg(fan_min); static ssize_t store_fan_min(struct device *dev, const char *buf, size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); + struct w83627hf_data *data = dev_get_drvdata(dev); u32 val; val = simple_strtoul(buf, NULL, 10); @@ -534,7 +532,7 @@ store_fan_min(struct device *dev, const char *buf, size_t count, int nr) mutex_lock(&data->update_lock); data->fan_min[nr - 1] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr), + w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr - 1]); mutex_unlock(&data->update_lock); @@ -587,8 +585,7 @@ show_temp_reg(temp_max_hyst); static ssize_t \ store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627hf_data *data = i2c_get_clientdata(client); \ + struct w83627hf_data *data = dev_get_drvdata(dev); \ u32 val; \ \ val = simple_strtoul(buf, NULL, 10); \ @@ -597,11 +594,11 @@ store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ \ if (nr >= 2) { /* TEMP2 and TEMP3 */ \ data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ - w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \ data->temp_##reg##_add[nr-2]); \ } else { /* TEMP1 */ \ data->temp_##reg = TEMP_TO_REG(val); \ - w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \ data->temp_##reg); \ } \ \ @@ -659,8 +656,7 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); + struct w83627hf_data *data = dev_get_drvdata(dev); u32 val; val = simple_strtoul(buf, NULL, 10); @@ -695,8 +691,7 @@ static ssize_t store_beep_reg(struct device *dev, const char *buf, size_t count, int update_mask) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); + struct w83627hf_data *data = dev_get_drvdata(dev); u32 val, val2; val = simple_strtoul(buf, NULL, 10); @@ -705,18 +700,18 @@ store_beep_reg(struct device *dev, const char *buf, size_t count, if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ data->beep_mask = BEEP_MASK_TO_REG(val); - w83627hf_write_value(client, W83781D_REG_BEEP_INTS1, + w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, data->beep_mask & 0xff); - w83627hf_write_value(client, W83781D_REG_BEEP_INTS3, + w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, ((data->beep_mask) >> 16) & 0xff); val2 = (data->beep_mask >> 8) & 0x7f; } else { /* We are storing beep_enable */ val2 = - w83627hf_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; + w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f; data->beep_enable = BEEP_ENABLE_TO_REG(val); } - w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, + w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, val2 | data->beep_enable << 7); mutex_unlock(&data->update_lock); @@ -754,8 +749,7 @@ show_fan_div_reg(struct device *dev, char *buf, int nr) static ssize_t store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); + struct w83627hf_data *data = dev_get_drvdata(dev); unsigned long min; u8 reg; unsigned long val = simple_strtoul(buf, NULL, 10); @@ -768,19 +762,19 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) data->fan_div[nr] = DIV_TO_REG(val); - reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) + reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) & (nr==0 ? 0xcf : 0x3f)) | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); - w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); + w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); - reg = (w83627hf_read_value(client, W83781D_REG_VBAT) + reg = (w83627hf_read_value(data, W83781D_REG_VBAT) & ~(1 << (5 + nr))) | ((data->fan_div[nr] & 0x04) << (3 + nr)); - w83627hf_write_value(client, W83781D_REG_VBAT, reg); + w83627hf_write_value(data, W83781D_REG_VBAT, reg); /* Restore fan_min */ data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); + w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; @@ -814,8 +808,7 @@ show_pwm_reg(struct device *dev, char *buf, int nr) static ssize_t store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); + struct w83627hf_data *data = dev_get_drvdata(dev); u32 val; val = simple_strtoul(buf, NULL, 10); @@ -825,14 +818,14 @@ store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) if (data->type == w83627thf) { /* bits 0-3 are reserved in 627THF */ data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0; - w83627hf_write_value(client, + w83627hf_write_value(data, W836X7HF_REG_PWM(data->type, nr), data->pwm[nr - 1] | - (w83627hf_read_value(client, + (w83627hf_read_value(data, W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); } else { data->pwm[nr - 1] = PWM_TO_REG(val); - w83627hf_write_value(client, + w83627hf_write_value(data, W836X7HF_REG_PWM(data->type, nr), data->pwm[nr - 1]); } @@ -868,8 +861,7 @@ show_sensor_reg(struct device *dev, char *buf, int nr) static ssize_t store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); + struct w83627hf_data *data = dev_get_drvdata(dev); u32 val, tmp; val = simple_strtoul(buf, NULL, 10); @@ -878,31 +870,31 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) switch (val) { case 1: /* PII/Celeron diode */ - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - w83627hf_write_value(client, W83781D_REG_SCFG1, + tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); + w83627hf_write_value(data, W83781D_REG_SCFG1, tmp | BIT_SCFG1[nr - 1]); - tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); - w83627hf_write_value(client, W83781D_REG_SCFG2, + tmp = w83627hf_read_value(data, W83781D_REG_SCFG2); + w83627hf_write_value(data, W83781D_REG_SCFG2, tmp | BIT_SCFG2[nr - 1]); data->sens[nr - 1] = val; break; case 2: /* 3904 */ - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - w83627hf_write_value(client, W83781D_REG_SCFG1, + tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); + w83627hf_write_value(data, W83781D_REG_SCFG1, tmp | BIT_SCFG1[nr - 1]); - tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); - w83627hf_write_value(client, W83781D_REG_SCFG2, + tmp = w83627hf_read_value(data, W83781D_REG_SCFG2); + w83627hf_write_value(data, W83781D_REG_SCFG2, tmp & ~BIT_SCFG2[nr - 1]); data->sens[nr - 1] = val; break; case W83781D_DEFAULT_BETA: /* thermistor */ - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - w83627hf_write_value(client, W83781D_REG_SCFG1, + tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); + w83627hf_write_value(data, W83781D_REG_SCFG1, tmp & ~BIT_SCFG1[nr - 1]); data->sens[nr - 1] = val; break; default: - dev_err(&client->dev, + dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n", (long) val, W83781D_DEFAULT_BETA); break; @@ -929,35 +921,85 @@ sysfs_sensor(1); sysfs_sensor(2); sysfs_sensor(3); -static int __init w83627hf_find(int sioaddr, unsigned short *addr) +static ssize_t show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct w83627hf_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->name); +} +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + +static int __init w83627hf_find(int sioaddr, unsigned short *addr, + struct w83627hf_sio_data *sio_data) { + int err = -ENODEV; u16 val; + static const __initdata char *names[] = { + "W83627HF", + "W83627THF", + "W83697HF", + "W83637HF", + "W83687THF", + }; + REG = sioaddr; VAL = sioaddr + 1; superio_enter(); val= superio_inb(DEVID); - if(val != W627_DEVID && - val != W627THF_DEVID && - val != W697_DEVID && - val != W637_DEVID && - val != W687THF_DEVID) { - superio_exit(); - return -ENODEV; + switch (val) { + case W627_DEVID: + sio_data->type = w83627hf; + break; + case W627THF_DEVID: + sio_data->type = w83627thf; + break; + case W697_DEVID: + sio_data->type = w83697hf; + break; + case W637_DEVID: + sio_data->type = w83637hf; + break; + case W687THF_DEVID: + sio_data->type = w83687thf; + break; + default: + pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%x)\n", val); + goto exit; } superio_select(W83627HF_LD_HWM); + force_addr &= WINB_ALIGNMENT; + if (force_addr) { + printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n", + force_addr); + superio_outb(WINB_BASE_REG, force_addr >> 8); + superio_outb(WINB_BASE_REG + 1, force_addr & 0xff); + } val = (superio_inb(WINB_BASE_REG) << 8) | superio_inb(WINB_BASE_REG + 1); *addr = val & WINB_ALIGNMENT; - if (*addr == 0 && force_addr == 0) { - superio_exit(); - return -ENODEV; + if (*addr == 0) { + printk(KERN_WARNING DRVNAME ": Base address not set, " + "skipping\n"); + goto exit; } + val = superio_inb(WINB_ACT_REG); + if (!(val & 0x01)) { + printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n"); + superio_outb(WINB_ACT_REG, val | 0x01); + } + + err = 0; + pr_info(DRVNAME ": Found %s chip at %#x\n", + names[sio_data->type], *addr); + + exit: superio_exit(); - return 0; + return err; } static struct attribute *w83627hf_attributes[] = { @@ -1003,6 +1045,7 @@ static struct attribute *w83627hf_attributes[] = { &dev_attr_pwm1.attr, &dev_attr_pwm2.attr, + &dev_attr_name.attr, NULL }; @@ -1039,161 +1082,92 @@ static const struct attribute_group w83627hf_group_opt = { .attrs = w83627hf_attributes_opt, }; -static int w83627hf_detect(struct i2c_adapter *adapter) +static int __devinit w83627hf_probe(struct platform_device *pdev) { - int val, kind; - struct i2c_client *new_client; + struct device *dev = &pdev->dev; + struct w83627hf_sio_data *sio_data = dev->platform_data; struct w83627hf_data *data; - int err = 0; - const char *client_name = ""; - - if(force_addr) - address = force_addr & WINB_ALIGNMENT; + struct resource *res; + int err; - if (!request_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE, - w83627hf_driver.driver.name)) { + static const char *names[] = { + "w83627hf", + "w83627thf", + "w83697hf", + "w83637hf", + "w83687thf", + }; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) { + dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", + (unsigned long)res->start, + (unsigned long)(res->start + WINB_REGION_SIZE - 1)); err = -EBUSY; goto ERROR0; } - if(force_addr) { - printk("w83627hf.o: forcing ISA address 0x%04X\n", address); - superio_enter(); - superio_select(W83627HF_LD_HWM); - superio_outb(WINB_BASE_REG, address >> 8); - superio_outb(WINB_BASE_REG+1, address & 0xff); - superio_exit(); - } - - superio_enter(); - val= superio_inb(DEVID); - if(val == W627_DEVID) - kind = w83627hf; - else if(val == W697_DEVID) - kind = w83697hf; - else if(val == W627THF_DEVID) - kind = w83627thf; - else if(val == W637_DEVID) - kind = w83637hf; - else if (val == W687THF_DEVID) - kind = w83687thf; - else { - dev_info(&adapter->dev, - "Unsupported chip (dev_id=0x%02X).\n", val); - goto ERROR1; - } - - superio_select(W83627HF_LD_HWM); - if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0) - superio_outb(WINB_ACT_REG, 1); - superio_exit(); - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access w83627hf_{read,write}_value. */ - if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR1; } - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; + data->addr = res->start; + data->type = sio_data->type; + data->name = names[sio_data->type]; mutex_init(&data->lock); - new_client->adapter = adapter; - new_client->driver = &w83627hf_driver; - new_client->flags = 0; - - - if (kind == w83627hf) { - client_name = "w83627hf"; - } else if (kind == w83627thf) { - client_name = "w83627thf"; - } else if (kind == w83697hf) { - client_name = "w83697hf"; - } else if (kind == w83637hf) { - client_name = "w83637hf"; - } else if (kind == w83687thf) { - client_name = "w83687thf"; - } - - /* Fill in the remaining client fields and put into the global list */ - strlcpy(new_client->name, client_name, I2C_NAME_SIZE); - data->type = kind; - data->valid = 0; mutex_init(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - data->lm75 = NULL; + platform_set_drvdata(pdev, data); /* Initialize the chip */ - w83627hf_init_client(new_client); + w83627hf_init_device(pdev); /* A few vars need to be filled upon startup */ - data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1)); - data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2)); - data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3)); + data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1)); + data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2)); + data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3)); /* Register common device attributes */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &w83627hf_group))) + if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group))) goto ERROR3; /* Register chip-specific device attributes */ - if (kind == w83627hf || kind == w83697hf) - if ((err = device_create_file(&new_client->dev, - &dev_attr_in5_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in5_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in5_max)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in6_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in6_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in6_max))) + if (data->type == w83627hf || data->type == w83697hf) + if ((err = device_create_file(dev, &dev_attr_in5_input)) + || (err = device_create_file(dev, &dev_attr_in5_min)) + || (err = device_create_file(dev, &dev_attr_in5_max)) + || (err = device_create_file(dev, &dev_attr_in6_input)) + || (err = device_create_file(dev, &dev_attr_in6_min)) + || (err = device_create_file(dev, &dev_attr_in6_max))) goto ERROR4; - if (kind != w83697hf) - if ((err = device_create_file(&new_client->dev, - &dev_attr_in1_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in1_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in1_max)) - || (err = device_create_file(&new_client->dev, - &dev_attr_fan3_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_fan3_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_fan3_div)) - || (err = device_create_file(&new_client->dev, - &dev_attr_temp3_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_temp3_max)) - || (err = device_create_file(&new_client->dev, - &dev_attr_temp3_max_hyst)) - || (err = device_create_file(&new_client->dev, - &dev_attr_temp3_type))) + if (data->type != w83697hf) + if ((err = device_create_file(dev, &dev_attr_in1_input)) + || (err = device_create_file(dev, &dev_attr_in1_min)) + || (err = device_create_file(dev, &dev_attr_in1_max)) + || (err = device_create_file(dev, &dev_attr_fan3_input)) + || (err = device_create_file(dev, &dev_attr_fan3_min)) + || (err = device_create_file(dev, &dev_attr_fan3_div)) + || (err = device_create_file(dev, &dev_attr_temp3_input)) + || (err = device_create_file(dev, &dev_attr_temp3_max)) + || (err = device_create_file(dev, &dev_attr_temp3_max_hyst)) + || (err = device_create_file(dev, &dev_attr_temp3_type))) goto ERROR4; - if (kind != w83697hf && data->vid != 0xff) - if ((err = device_create_file(&new_client->dev, - &dev_attr_cpu0_vid)) - || (err = device_create_file(&new_client->dev, - &dev_attr_vrm))) + if (data->type != w83697hf && data->vid != 0xff) { + /* Convert VID to voltage based on VRM */ + data->vrm = vid_which_vrm(); + + if ((err = device_create_file(dev, &dev_attr_cpu0_vid)) + || (err = device_create_file(dev, &dev_attr_vrm))) goto ERROR4; + } - if (kind == w83627thf || kind == w83637hf || kind == w83687thf) - if ((err = device_create_file(&new_client->dev, - &dev_attr_pwm3))) + if (data->type == w83627thf || data->type == w83637hf + || data->type == w83687thf) + if ((err = device_create_file(dev, &dev_attr_pwm3))) goto ERROR4; - data->class_dev = hwmon_device_register(&new_client->dev); + data->class_dev = hwmon_device_register(dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); goto ERROR4; @@ -1202,47 +1176,37 @@ static int w83627hf_detect(struct i2c_adapter *adapter) return 0; ERROR4: - sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group); - sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group_opt); + sysfs_remove_group(&dev->kobj, &w83627hf_group); + sysfs_remove_group(&dev->kobj, &w83627hf_group_opt); ERROR3: - i2c_detach_client(new_client); - ERROR2: kfree(data); ERROR1: - release_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE); + release_region(res->start, WINB_REGION_SIZE); ERROR0: return err; } -static int w83627hf_detach_client(struct i2c_client *client) +static int __devexit w83627hf_remove(struct platform_device *pdev) { - struct w83627hf_data *data = i2c_get_clientdata(client); - int err; + struct w83627hf_data *data = platform_get_drvdata(pdev); + struct resource *res; + platform_set_drvdata(pdev, NULL); hwmon_device_unregister(data->class_dev); - sysfs_remove_group(&client->dev.kobj, &w83627hf_group); - sysfs_remove_group(&client->dev.kobj, &w83627hf_group_opt); - - if ((err = i2c_detach_client(client))) - return err; - - release_region(client->addr + WINB_REGION_OFFSET, WINB_REGION_SIZE); + sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group); + sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt); kfree(data); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start, WINB_REGION_SIZE); + return 0; } -/* - ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int w83627hf_read_value(struct i2c_client *client, u16 reg) +static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) { - struct w83627hf_data *data = i2c_get_clientdata(client); int res, word_sized; mutex_lock(&data->lock); @@ -1253,29 +1217,29 @@ static int w83627hf_read_value(struct i2c_client *client, u16 reg) || ((reg & 0x00ff) == 0x55)); if (reg & 0xff00) { outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); + data->addr + W83781D_ADDR_REG_OFFSET); outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); + data->addr + W83781D_DATA_REG_OFFSET); } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); + outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); + res = inb_p(data->addr + W83781D_DATA_REG_OFFSET); if (word_sized) { outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); + data->addr + W83781D_ADDR_REG_OFFSET); res = - (res << 8) + inb_p(client->addr + + (res << 8) + inb_p(data->addr + W83781D_DATA_REG_OFFSET); } if (reg & 0xff00) { outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + data->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); } mutex_unlock(&data->lock); return res; } -static int w83627thf_read_gpio5(struct i2c_client *client) +static int __devinit w83627thf_read_gpio5(struct platform_device *pdev) { int res = 0xff, sel; @@ -1284,7 +1248,7 @@ static int w83627thf_read_gpio5(struct i2c_client *client) /* Make sure these GPIO pins are enabled */ if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) { - dev_dbg(&client->dev, "GPIO5 disabled, no VID function\n"); + dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n"); goto exit; } @@ -1292,12 +1256,12 @@ static int w83627thf_read_gpio5(struct i2c_client *client) There must be at least five (VRM 9), and possibly 6 (VRM 10) */ sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f; if ((sel & 0x1f) != 0x1f) { - dev_dbg(&client->dev, "GPIO5 not configured for VID " + dev_dbg(&pdev->dev, "GPIO5 not configured for VID " "function\n"); goto exit; } - dev_info(&client->dev, "Reading VID from GPIO5\n"); + dev_info(&pdev->dev, "Reading VID from GPIO5\n"); res = superio_inb(W83627THF_GPIO5_DR) & sel; exit: @@ -1305,7 +1269,7 @@ static int w83627thf_read_gpio5(struct i2c_client *client) return res; } -static int w83687thf_read_vid(struct i2c_client *client) +static int __devinit w83687thf_read_vid(struct platform_device *pdev) { int res = 0xff; @@ -1314,13 +1278,13 @@ static int w83687thf_read_vid(struct i2c_client *client) /* Make sure these GPIO pins are enabled */ if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) { - dev_dbg(&client->dev, "VID disabled, no VID function\n"); + dev_dbg(&pdev->dev, "VID disabled, no VID function\n"); goto exit; } /* Make sure the pins are configured for input */ if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) { - dev_dbg(&client->dev, "VID configured as output, " + dev_dbg(&pdev->dev, "VID configured as output, " "no VID function\n"); goto exit; } @@ -1332,9 +1296,8 @@ static int w83687thf_read_vid(struct i2c_client *client) return res; } -static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) +static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) { - struct w83627hf_data *data = i2c_get_clientdata(client); int word_sized; mutex_lock(&data->lock); @@ -1344,33 +1307,33 @@ static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) || ((reg & 0x00ff) == 0x55)); if (reg & 0xff00) { outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); + data->addr + W83781D_ADDR_REG_OFFSET); outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); + data->addr + W83781D_DATA_REG_OFFSET); } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); if (word_sized) { outb_p(value >> 8, - client->addr + W83781D_DATA_REG_OFFSET); + data->addr + W83781D_DATA_REG_OFFSET); outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); + data->addr + W83781D_ADDR_REG_OFFSET); } outb_p(value & 0xff, - client->addr + W83781D_DATA_REG_OFFSET); + data->addr + W83781D_DATA_REG_OFFSET); if (reg & 0xff00) { outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + data->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); } mutex_unlock(&data->lock); return 0; } -static void w83627hf_init_client(struct i2c_client *client) +static void __devinit w83627hf_init_device(struct platform_device *pdev) { - struct w83627hf_data *data = i2c_get_clientdata(client); + struct w83627hf_data *data = platform_get_drvdata(pdev); int i; - int type = data->type; + enum chips type = data->type; u8 tmp; if (reset) { @@ -1379,57 +1342,53 @@ static void w83627hf_init_client(struct i2c_client *client) speed...) so it is now optional. It might even go away if nobody reports it as being useful, as I see very little reason why this would be needed at all. */ - dev_info(&client->dev, "If reset=1 solved a problem you were " + dev_info(&pdev->dev, "If reset=1 solved a problem you were " "having, please report!\n"); /* save this register */ - i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG); + i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG); /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others */ - w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80); + w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80); /* Restore the register and disable power-on abnormal beep. This saves FAN 1/2/3 input/output values set by BIOS. */ - w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); + w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80); /* Disable master beep-enable (reset turns it on). Individual beeps should be reset to off but for some reason disabling this bit helps some people not get beeped */ - w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0); + w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0); } /* Minimize conflicts with other winbond i2c-only clients... */ /* disable i2c subclients... how to disable main i2c client?? */ /* force i2c address to relatively uncommon address */ - w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89); - w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c); + w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89); + w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c); /* Read VID only once */ - if (w83627hf == data->type || w83637hf == data->type) { - int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - int hi = w83627hf_read_value(client, W83781D_REG_CHIPID); + if (type == w83627hf || type == w83637hf) { + int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); + int hi = w83627hf_read_value(data, W83781D_REG_CHIPID); data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); - } else if (w83627thf == data->type) { - data->vid = w83627thf_read_gpio5(client); - } else if (w83687thf == data->type) { - data->vid = w83687thf_read_vid(client); + } else if (type == w83627thf) { + data->vid = w83627thf_read_gpio5(pdev); + } else if (type == w83687thf) { + data->vid = w83687thf_read_vid(pdev); } /* Read VRM & OVT Config only once */ - if (w83627thf == data->type || w83637hf == data->type - || w83687thf == data->type) { + if (type == w83627thf || type == w83637hf || type == w83687thf) { data->vrm_ovt = - w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); + w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG); } - /* Convert VID to voltage based on VRM */ - data->vrm = vid_which_vrm(); - - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); + tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); for (i = 1; i <= 3; i++) { if (!(tmp & BIT_SCFG1[i - 1])) { data->sens[i - 1] = W83781D_DEFAULT_BETA; } else { if (w83627hf_read_value - (client, + (data, W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) data->sens[i - 1] = 1; else @@ -1441,38 +1400,37 @@ static void w83627hf_init_client(struct i2c_client *client) if(init) { /* Enable temp2 */ - tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG); + tmp = w83627hf_read_value(data, W83781D_REG_TEMP2_CONFIG); if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp2, readings " + dev_warn(&pdev->dev, "Enabling temp2, readings " "might not make sense\n"); - w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG, + w83627hf_write_value(data, W83781D_REG_TEMP2_CONFIG, tmp & 0xfe); } /* Enable temp3 */ if (type != w83697hf) { - tmp = w83627hf_read_value(client, + tmp = w83627hf_read_value(data, W83781D_REG_TEMP3_CONFIG); if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp3, " + dev_warn(&pdev->dev, "Enabling temp3, " "readings might not make sense\n"); - w83627hf_write_value(client, + w83627hf_write_value(data, W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); } } } /* Start monitoring */ - w83627hf_write_value(client, W83781D_REG_CONFIG, - (w83627hf_read_value(client, + w83627hf_write_value(data, W83781D_REG_CONFIG, + (w83627hf_read_value(data, W83781D_REG_CONFIG) & 0xf7) | 0x01); } static struct w83627hf_data *w83627hf_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); + struct w83627hf_data *data = dev_get_drvdata(dev); int i; mutex_lock(&data->update_lock); @@ -1486,23 +1444,23 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) && (i == 5 || i == 6))) continue; data->in[i] = - w83627hf_read_value(client, W83781D_REG_IN(i)); + w83627hf_read_value(data, W83781D_REG_IN(i)); data->in_min[i] = - w83627hf_read_value(client, + w83627hf_read_value(data, W83781D_REG_IN_MIN(i)); data->in_max[i] = - w83627hf_read_value(client, + w83627hf_read_value(data, W83781D_REG_IN_MAX(i)); } for (i = 1; i <= 3; i++) { data->fan[i - 1] = - w83627hf_read_value(client, W83781D_REG_FAN(i)); + w83627hf_read_value(data, W83781D_REG_FAN(i)); data->fan_min[i - 1] = - w83627hf_read_value(client, + w83627hf_read_value(data, W83781D_REG_FAN_MIN(i)); } for (i = 1; i <= 3; i++) { - u8 tmp = w83627hf_read_value(client, + u8 tmp = w83627hf_read_value(data, W836X7HF_REG_PWM(data->type, i)); /* bits 0-3 are reserved in 627THF */ if (data->type == w83627thf) @@ -1513,47 +1471,47 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) break; } - data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1)); + data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1)); data->temp_max = - w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1)); + w83627hf_read_value(data, W83781D_REG_TEMP_OVER(1)); data->temp_max_hyst = - w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1)); + w83627hf_read_value(data, W83781D_REG_TEMP_HYST(1)); data->temp_add[0] = - w83627hf_read_value(client, W83781D_REG_TEMP(2)); + w83627hf_read_value(data, W83781D_REG_TEMP(2)); data->temp_max_add[0] = - w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2)); + w83627hf_read_value(data, W83781D_REG_TEMP_OVER(2)); data->temp_max_hyst_add[0] = - w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2)); + w83627hf_read_value(data, W83781D_REG_TEMP_HYST(2)); if (data->type != w83697hf) { data->temp_add[1] = - w83627hf_read_value(client, W83781D_REG_TEMP(3)); + w83627hf_read_value(data, W83781D_REG_TEMP(3)); data->temp_max_add[1] = - w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3)); + w83627hf_read_value(data, W83781D_REG_TEMP_OVER(3)); data->temp_max_hyst_add[1] = - w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3)); + w83627hf_read_value(data, W83781D_REG_TEMP_HYST(3)); } - i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); + i = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = (i >> 6) & 0x03; if (data->type != w83697hf) { - data->fan_div[2] = (w83627hf_read_value(client, + data->fan_div[2] = (w83627hf_read_value(data, W83781D_REG_PIN) >> 6) & 0x03; } - i = w83627hf_read_value(client, W83781D_REG_VBAT); + i = w83627hf_read_value(data, W83781D_REG_VBAT); data->fan_div[0] |= (i >> 3) & 0x04; data->fan_div[1] |= (i >> 4) & 0x04; if (data->type != w83697hf) data->fan_div[2] |= (i >> 5) & 0x04; data->alarms = - w83627hf_read_value(client, W83781D_REG_ALARM1) | - (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) | - (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16); - i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2); + w83627hf_read_value(data, W83781D_REG_ALARM1) | + (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) | + (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16); + i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2); data->beep_enable = i >> 7; data->beep_mask = ((i & 0x7f) << 8) | - w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) | - w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16; + w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) | + w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16; data->last_updated = jiffies; data->valid = 1; } @@ -1563,19 +1521,87 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) return data; } +static int __init w83627hf_device_add(unsigned short address, + const struct w83627hf_sio_data *sio_data) +{ + struct resource res = { + .start = address + WINB_REGION_OFFSET, + .end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1, + .name = DRVNAME, + .flags = IORESOURCE_IO, + }; + int err; + + pdev = platform_device_alloc(DRVNAME, address); + if (!pdev) { + err = -ENOMEM; + printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + goto exit; + } + + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed " + "(%d)\n", err); + goto exit_device_put; + } + + pdev->dev.platform_data = kmalloc(sizeof(struct w83627hf_sio_data), + GFP_KERNEL); + if (!pdev->dev.platform_data) { + err = -ENOMEM; + printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + goto exit_device_put; + } + memcpy(pdev->dev.platform_data, sio_data, + sizeof(struct w83627hf_sio_data)); + + err = platform_device_add(pdev); + if (err) { + printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", + err); + goto exit_device_put; + } + + return 0; + +exit_device_put: + platform_device_put(pdev); +exit: + return err; +} + static int __init sensors_w83627hf_init(void) { - if (w83627hf_find(0x2e, &address) - && w83627hf_find(0x4e, &address)) { + int err; + unsigned short address; + struct w83627hf_sio_data sio_data; + + if (w83627hf_find(0x2e, &address, &sio_data) + && w83627hf_find(0x4e, &address, &sio_data)) return -ENODEV; - } - return i2c_isa_add_driver(&w83627hf_driver); + err = platform_driver_register(&w83627hf_driver); + if (err) + goto exit; + + /* Sets global pdev as a side effect */ + err = w83627hf_device_add(address, &sio_data); + if (err) + goto exit_driver; + + return 0; + +exit_driver: + platform_driver_unregister(&w83627hf_driver); +exit: + return err; } static void __exit sensors_w83627hf_exit(void) { - i2c_isa_del_driver(&w83627hf_driver); + platform_device_unregister(pdev); + platform_driver_unregister(&w83627hf_driver); } MODULE_AUTHOR("Frodo Looijaard , " diff --git a/trunk/drivers/hwmon/w83781d.c b/trunk/drivers/hwmon/w83781d.c index a47da3ec5472..f85b48fea1c4 100644 --- a/trunk/drivers/hwmon/w83781d.c +++ b/trunk/drivers/hwmon/w83781d.c @@ -2,8 +2,9 @@ w83781d.c - Part of lm_sensors, Linux kernel modules for hardware monitoring Copyright (c) 1998 - 2001 Frodo Looijaard , - Philip Edelbrock , - and Mark Studebaker + Philip Edelbrock , + and Mark Studebaker + Copyright (c) 2007 Jean Delvare 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 @@ -38,15 +39,20 @@ #include #include #include -#include +#include +#include #include #include +#include #include #include #include #include #include "lm75.h" +/* ISA device, if found */ +static struct platform_device *pdev; + /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, @@ -75,8 +81,8 @@ MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); #define W83781D_ADDR_REG_OFFSET 5 #define W83781D_DATA_REG_OFFSET 6 -/* The W83781D registers */ -/* The W83782D registers for nr=7,8 are in bank 5 */ +/* The device registers */ +/* in nr from 0 to 8 */ #define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ (0x554 + (((nr) - 7) * 2))) #define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ @@ -84,12 +90,14 @@ MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); #define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ (0x550 + (nr) - 7)) -#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) -#define W83781D_REG_FAN(nr) (0x27 + (nr)) +/* fan nr from 0 to 2 */ +#define W83781D_REG_FAN_MIN(nr) (0x3b + (nr)) +#define W83781D_REG_FAN(nr) (0x28 + (nr)) #define W83781D_REG_BANK 0x4E #define W83781D_REG_TEMP2_CONFIG 0x152 #define W83781D_REG_TEMP3_CONFIG 0x252 +/* temp nr from 1 to 3 */ #define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ ((nr == 2) ? (0x0150) : \ (0x27))) @@ -127,19 +135,9 @@ MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); #define W83781D_REG_VBAT 0x5D /* PWM 782D (1-4) and 783S (1-2) only */ -#define W83781D_REG_PWM1 0x5B /* 782d and 783s/627hf datasheets disagree */ - /* on which is which; */ -#define W83781D_REG_PWM2 0x5A /* We follow the 782d convention here, */ - /* However 782d is probably wrong. */ -#define W83781D_REG_PWM3 0x5E -#define W83781D_REG_PWM4 0x5F +static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F }; #define W83781D_REG_PWMCLK12 0x5C #define W83781D_REG_PWMCLK34 0x45C -static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2, - W83781D_REG_PWM3, W83781D_REG_PWM4 -}; - -#define W83781D_REG_PWM(nr) (regpwm[(nr) - 1]) #define W83781D_REG_I2C_ADDR 0x48 #define W83781D_REG_I2C_SUBADDR 0x4A @@ -159,12 +157,9 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; #define W83781D_REG_RT_IDX 0x50 #define W83781D_REG_RT_VAL 0x51 -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16) / 10) +/* Conversions */ +#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255) +#define IN_FROM_REG(val) ((val) * 16) static inline u8 FAN_TO_REG(long rpm, int div) @@ -175,24 +170,24 @@ FAN_TO_REG(long rpm, int div) return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } -#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ - ((val) == 255 ? 0 : \ - 1350000 / ((val) * (div)))) +static inline long +FAN_FROM_REG(u8 val, int div) +{ + if (val == 0) + return -1; + if (val == 255) + return 0; + return 1350000 / (val * div); +} -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ - : (val)) / 1000, 0, 0xff)) -#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) +#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128) +#define TEMP_FROM_REG(val) ((val) * 1000) -#define PWM_FROM_REG(val) (val) -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) #define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \ (val) ^ 0x7fff : (val)) #define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \ (~(val)) & 0x7fff : (val) & 0xffffff) -#define BEEP_ENABLE_TO_REG(val) ((val) ? 1 : 0) -#define BEEP_ENABLE_FROM_REG(val) ((val) ? 1 : 0) - #define DIV_FROM_REG(val) (1 << (val)) static inline u8 @@ -207,7 +202,7 @@ DIV_TO_REG(long val, enum chips type) break; val >>= 1; } - return ((u8) i); + return i; } /* There are some complications in a module like this. First off, W83781D chips @@ -221,8 +216,8 @@ DIV_TO_REG(long val, enum chips type) a bit - except if there could be more than one SMBus. Groan. No solution for this yet. */ -/* For each registered chip, we need to keep some data in memory. - The structure is dynamically allocated. */ +/* For ISA chips, we abuse the i2c_client addr and name fields. We also use + the driver field to differentiate between I2C and ISA chips. */ struct w83781d_data { struct i2c_client client; struct class_device *class_dev; @@ -241,9 +236,9 @@ struct w83781d_data { u8 in_min[9]; /* Register value - 8 & 9 for 782D only */ u8 fan[3]; /* Register value */ u8 fan_min[3]; /* Register value */ - u8 temp; - u8 temp_max; /* Register value */ - u8 temp_max_hyst; /* Register value */ + s8 temp; /* Register value */ + s8 temp_max; /* Register value */ + s8 temp_max_hyst; /* Register value */ u16 temp_add[2]; /* Register value */ u16 temp_max_add[2]; /* Register value */ u16 temp_max_hyst_add[2]; /* Register value */ @@ -253,7 +248,7 @@ struct w83781d_data { u32 beep_mask; /* Register encoding, combined */ u8 beep_enable; /* Boolean */ u8 pwm[4]; /* Register value */ - u8 pwmenable[4]; /* Boolean */ + u8 pwm2_enable; /* Boolean */ u16 sens[3]; /* 782D/783S only. 1 = pentium diode; 2 = 3904 diode; 3000-5000 = thermistor beta. @@ -263,14 +258,16 @@ struct w83781d_data { }; static int w83781d_attach_adapter(struct i2c_adapter *adapter); -static int w83781d_isa_attach_adapter(struct i2c_adapter *adapter); static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind); static int w83781d_detach_client(struct i2c_client *client); -static int w83781d_read_value(struct i2c_client *client, u16 reg); -static int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value); +static int __devinit w83781d_isa_probe(struct platform_device *pdev); +static int __devexit w83781d_isa_remove(struct platform_device *pdev); + +static int w83781d_read_value(struct w83781d_data *data, u16 reg); +static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value); static struct w83781d_data *w83781d_update_device(struct device *dev); -static void w83781d_init_client(struct i2c_client *client); +static void w83781d_init_device(struct device *dev); static struct i2c_driver w83781d_driver = { .driver = { @@ -281,39 +278,44 @@ static struct i2c_driver w83781d_driver = { .detach_client = w83781d_detach_client, }; -static struct i2c_driver w83781d_isa_driver = { +static struct platform_driver w83781d_isa_driver = { .driver = { .owner = THIS_MODULE, - .name = "w83781d-isa", + .name = "w83781d", }, - .attach_adapter = w83781d_isa_attach_adapter, - .detach_client = w83781d_detach_client, + .probe = w83781d_isa_probe, + .remove = w83781d_isa_remove, }; /* following are the sysfs callback functions */ #define show_in_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \ + char *buf) \ { \ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = w83781d_update_device(dev); \ - return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr] * 10)); \ + return sprintf(buf, "%ld\n", \ + (long)IN_FROM_REG(data->reg[attr->index])); \ } show_in_reg(in); show_in_reg(in_min); show_in_reg(in_max); #define store_in_reg(REG, reg) \ -static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +static ssize_t store_in_##reg (struct device *dev, struct device_attribute \ + *da, const char *buf, size_t count) \ { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83781d_data *data = i2c_get_clientdata(client); \ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ + struct w83781d_data *data = dev_get_drvdata(dev); \ + int nr = attr->index; \ u32 val; \ \ - val = simple_strtoul(buf, NULL, 10) / 10; \ + val = simple_strtoul(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->in_##reg[nr] = IN_TO_REG(val); \ - w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \ + w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \ \ mutex_unlock(&data->update_lock); \ return count; \ @@ -321,29 +323,13 @@ static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count store_in_reg(MIN, min); store_in_reg(MAX, max); -#define sysfs_in_offset(offset) \ -static ssize_t \ -show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); - -#define sysfs_in_reg_offset(reg, offset) \ -static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_##reg (dev, buf, offset); \ -} \ -static ssize_t store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_in_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset); - #define sysfs_in_offsets(offset) \ -sysfs_in_offset(offset); \ -sysfs_in_reg_offset(min, offset); \ -sysfs_in_reg_offset(max, offset); +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in, NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, store_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, store_in_max, offset) sysfs_in_offsets(0); sysfs_in_offsets(1); @@ -356,63 +342,56 @@ sysfs_in_offsets(7); sysfs_in_offsets(8); #define show_fan_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \ + char *buf) \ { \ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = w83781d_update_device(dev); \ return sprintf(buf,"%ld\n", \ - FAN_FROM_REG(data->reg[nr-1], (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ + FAN_FROM_REG(data->reg[attr->index], \ + DIV_FROM_REG(data->fan_div[attr->index]))); \ } show_fan_reg(fan); show_fan_reg(fan_min); static ssize_t -store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +store_fan_min(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct w83781d_data *data = dev_get_drvdata(dev); + int nr = attr->index; u32 val; val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); - data->fan_min[nr - 1] = - FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); + data->fan_min[nr] = + FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), + data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; } -#define sysfs_fan_offset(offset) \ -static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); - -#define sysfs_fan_min_offset(offset) \ -static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset); \ -} \ -static ssize_t store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_fan_min(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset); - -sysfs_fan_offset(1); -sysfs_fan_min_offset(1); -sysfs_fan_offset(2); -sysfs_fan_min_offset(2); -sysfs_fan_offset(3); -sysfs_fan_min_offset(3); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, + show_fan_min, store_fan_min, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR, + show_fan_min, store_fan_min, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); +static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR, + show_fan_min, store_fan_min, 2); #define show_temp_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \ + char *buf) \ { \ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = w83781d_update_device(dev); \ + int nr = attr->index; \ if (nr >= 2) { /* TEMP2 and TEMP3 */ \ return sprintf(buf,"%d\n", \ LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ @@ -425,10 +404,12 @@ show_temp_reg(temp_max); show_temp_reg(temp_max_hyst); #define store_temp_reg(REG, reg) \ -static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +static ssize_t store_temp_##reg (struct device *dev, \ + struct device_attribute *da, const char *buf, size_t count) \ { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83781d_data *data = i2c_get_clientdata(client); \ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ + struct w83781d_data *data = dev_get_drvdata(dev); \ + int nr = attr->index; \ s32 val; \ \ val = simple_strtol(buf, NULL, 10); \ @@ -437,11 +418,11 @@ static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t cou \ if (nr >= 2) { /* TEMP2 and TEMP3 */ \ data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ - w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \ data->temp_##reg##_add[nr-2]); \ } else { /* TEMP1 */ \ data->temp_##reg = TEMP_TO_REG(val); \ - w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \ data->temp_##reg); \ } \ \ @@ -451,29 +432,13 @@ static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t cou store_temp_reg(OVER, max); store_temp_reg(HYST, max_hyst); -#define sysfs_temp_offset(offset) \ -static ssize_t \ -show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); - -#define sysfs_temp_reg_offset(reg, offset) \ -static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_##reg (dev, buf, offset); \ -} \ -static ssize_t store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_temp_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); - #define sysfs_temp_offsets(offset) \ -sysfs_temp_offset(offset); \ -sysfs_temp_reg_offset(max, offset); \ -sysfs_temp_reg_offset(max_hyst, offset); +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp, NULL, offset); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, store_temp_max, offset); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ + show_temp_max_hyst, store_temp_max_hyst, offset); sysfs_temp_offsets(1); sysfs_temp_offsets(2); @@ -498,8 +463,7 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); + struct w83781d_data *data = dev_get_drvdata(dev); u32 val; val = simple_strtoul(buf, NULL, 10); @@ -528,68 +492,67 @@ static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr static ssize_t show_beep_enable (struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", - (long)BEEP_ENABLE_FROM_REG(data->beep_enable)); + return sprintf(buf, "%ld\n", (long)data->beep_enable); } -#define BEEP_ENABLE 0 /* Store beep_enable */ -#define BEEP_MASK 1 /* Store beep_mask */ - static ssize_t -store_beep_reg(struct device *dev, const char *buf, size_t count, - int update_mask) +store_beep_mask(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val, val2; + struct w83781d_data *data = dev_get_drvdata(dev); + u32 val; val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); + data->beep_mask = BEEP_MASK_TO_REG(val, data->type); + w83781d_write_value(data, W83781D_REG_BEEP_INTS1, + data->beep_mask & 0xff); + w83781d_write_value(data, W83781D_REG_BEEP_INTS2, + ((data->beep_mask >> 8) & 0x7f) + | data->beep_enable << 7); + if (data->type != w83781d && data->type != as99127f) { + w83781d_write_value(data, W83781D_REG_BEEP_INTS3, + ((data->beep_mask) >> 16) & 0xff); + } + mutex_unlock(&data->update_lock); - if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ - data->beep_mask = BEEP_MASK_TO_REG(val, data->type); - w83781d_write_value(client, W83781D_REG_BEEP_INTS1, - data->beep_mask & 0xff); - - if ((data->type != w83781d) && (data->type != as99127f)) { - w83781d_write_value(client, W83781D_REG_BEEP_INTS3, - ((data->beep_mask) >> 16) & 0xff); - } + return count; +} - val2 = (data->beep_mask >> 8) & 0x7f; - } else { /* We are storing beep_enable */ - val2 = w83781d_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; - data->beep_enable = BEEP_ENABLE_TO_REG(val); - } +static ssize_t +store_beep_enable(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct w83781d_data *data = dev_get_drvdata(dev); + u32 val; - w83781d_write_value(client, W83781D_REG_BEEP_INTS2, - val2 | data->beep_enable << 7); + val = simple_strtoul(buf, NULL, 10); + if (val != 0 && val != 1) + return -EINVAL; + mutex_lock(&data->update_lock); + data->beep_enable = val; + val = w83781d_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f; + val |= data->beep_enable << 7; + w83781d_write_value(data, W83781D_REG_BEEP_INTS2, val); mutex_unlock(&data->update_lock); + return count; } -#define sysfs_beep(REG, reg) \ -static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_beep_##reg(dev, attr, buf); \ -} \ -static ssize_t store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_beep_reg(dev, buf, count, BEEP_##REG); \ -} \ -static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg); - -sysfs_beep(ENABLE, enable); -sysfs_beep(MASK, mask); +static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR, + show_beep_mask, store_beep_mask); +static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR, + show_beep_enable, store_beep_enable); static ssize_t -show_fan_div_reg(struct device *dev, char *buf, int nr) +show_fan_div(struct device *dev, struct device_attribute *da, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%ld\n", - (long) DIV_FROM_REG(data->fan_div[nr - 1])); + (long) DIV_FROM_REG(data->fan_div[attr->index])); } /* Note: we save and restore the fan minimum here, because its value is @@ -597,11 +560,13 @@ show_fan_div_reg(struct device *dev, char *buf, int nr) least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t -store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) +store_fan_div(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct w83781d_data *data = dev_get_drvdata(dev); unsigned long min; + int nr = attr->index; u8 reg; unsigned long val = simple_strtoul(buf, NULL, 10); @@ -613,77 +578,72 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) data->fan_div[nr] = DIV_TO_REG(val, data->type); - reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) + reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) & (nr==0 ? 0xcf : 0x3f)) | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); - w83781d_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); + w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); /* w83781d and as99127f don't have extended divisor bits */ if (data->type != w83781d && data->type != as99127f) { - reg = (w83781d_read_value(client, W83781D_REG_VBAT) + reg = (w83781d_read_value(data, W83781D_REG_VBAT) & ~(1 << (5 + nr))) | ((data->fan_div[nr] & 0x04) << (3 + nr)); - w83781d_write_value(client, W83781D_REG_VBAT, reg); + w83781d_write_value(data, W83781D_REG_VBAT, reg); } /* Restore fan_min */ data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); + w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; } -#define sysfs_fan_div(offset) \ -static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_fan_div_reg(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset); - -sysfs_fan_div(1); -sysfs_fan_div(2); -sysfs_fan_div(3); +static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, + show_fan_div, store_fan_div, 0); +static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, + show_fan_div, store_fan_div, 1); +static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR, + show_fan_div, store_fan_div, 2); static ssize_t -show_pwm_reg(struct device *dev, char *buf, int nr) +show_pwm(struct device *dev, struct device_attribute *da, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr - 1])); + return sprintf(buf, "%d\n", (int)data->pwm[attr->index]); } static ssize_t -show_pwmenable_reg(struct device *dev, char *buf, int nr) +show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->pwmenable[nr - 1]); + return sprintf(buf, "%d\n", (int)data->pwm2_enable); } static ssize_t -store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) +store_pwm(struct device *dev, struct device_attribute *da, const char *buf, + size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct w83781d_data *data = dev_get_drvdata(dev); + int nr = attr->index; u32 val; val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); - data->pwm[nr - 1] = PWM_TO_REG(val); - w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]); + data->pwm[nr] = SENSORS_LIMIT(val, 0, 255); + w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]); mutex_unlock(&data->update_lock); return count; } static ssize_t -store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) +store_pwm2_enable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); + struct w83781d_data *data = dev_get_drvdata(dev); u32 val, reg; val = simple_strtoul(buf, NULL, 10); @@ -693,15 +653,15 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) switch (val) { case 0: case 1: - reg = w83781d_read_value(client, W83781D_REG_PWMCLK12); - w83781d_write_value(client, W83781D_REG_PWMCLK12, + reg = w83781d_read_value(data, W83781D_REG_PWMCLK12); + w83781d_write_value(data, W83781D_REG_PWMCLK12, (reg & 0xf7) | (val << 3)); - reg = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); - w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, + reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG); + w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, (reg & 0xef) | (!val << 4)); - data->pwmenable[nr - 1] = val; + data->pwm2_enable = val; break; default: @@ -713,50 +673,29 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) return count; } -#define sysfs_pwm(offset) \ -static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_pwm_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_regs_pwm_##offset, store_regs_pwm_##offset); - -#define sysfs_pwmenable(offset) \ -static ssize_t show_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwmenable_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_pwmenable_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - show_regs_pwmenable_##offset, store_regs_pwmenable_##offset); - -sysfs_pwm(1); -sysfs_pwm(2); -sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */ -sysfs_pwm(3); -sysfs_pwm(4); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1); +static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2); +static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3); +/* only PWM2 can be enabled/disabled */ +static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, + show_pwm2_enable, store_pwm2_enable); static ssize_t -show_sensor_reg(struct device *dev, char *buf, int nr) +show_sensor(struct device *dev, struct device_attribute *da, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); + return sprintf(buf, "%d\n", (int)data->sens[attr->index]); } static ssize_t -store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) +store_sensor(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct w83781d_data *data = dev_get_drvdata(dev); + int nr = attr->index; u32 val, tmp; val = simple_strtoul(buf, NULL, 10); @@ -765,28 +704,28 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) switch (val) { case 1: /* PII/Celeron diode */ - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - w83781d_write_value(client, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); - tmp = w83781d_read_value(client, W83781D_REG_SCFG2); - w83781d_write_value(client, W83781D_REG_SCFG2, - tmp | BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; + tmp = w83781d_read_value(data, W83781D_REG_SCFG1); + w83781d_write_value(data, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr]); + tmp = w83781d_read_value(data, W83781D_REG_SCFG2); + w83781d_write_value(data, W83781D_REG_SCFG2, + tmp | BIT_SCFG2[nr]); + data->sens[nr] = val; break; case 2: /* 3904 */ - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - w83781d_write_value(client, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); - tmp = w83781d_read_value(client, W83781D_REG_SCFG2); - w83781d_write_value(client, W83781D_REG_SCFG2, - tmp & ~BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; + tmp = w83781d_read_value(data, W83781D_REG_SCFG1); + w83781d_write_value(data, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr]); + tmp = w83781d_read_value(data, W83781D_REG_SCFG2); + w83781d_write_value(data, W83781D_REG_SCFG2, + tmp & ~BIT_SCFG2[nr]); + data->sens[nr] = val; break; case W83781D_DEFAULT_BETA: /* thermistor */ - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - w83781d_write_value(client, W83781D_REG_SCFG1, - tmp & ~BIT_SCFG1[nr - 1]); - data->sens[nr - 1] = val; + tmp = w83781d_read_value(data, W83781D_REG_SCFG1); + w83781d_write_value(data, W83781D_REG_SCFG1, + tmp & ~BIT_SCFG1[nr]); + data->sens[nr] = val; break; default: dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n", @@ -798,20 +737,22 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) return count; } -#define sysfs_sensor(offset) \ -static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_sensor_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_sensor_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset); +static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR, + show_sensor, store_sensor, 0); +static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, + show_sensor, store_sensor, 0); +static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, + show_sensor, store_sensor, 0); -sysfs_sensor(1); -sysfs_sensor(2); -sysfs_sensor(3); +/* I2C devices get this name attribute automatically, but for ISA devices + we must create it by ourselves. */ +static ssize_t +show_name(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct w83781d_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->client.name); +} +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* This function is called when: * w83781d_driver is inserted (when this module is loaded), for each @@ -825,12 +766,6 @@ w83781d_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, w83781d_detect); } -static int -w83781d_isa_attach_adapter(struct i2c_adapter *adapter) -{ - return w83781d_detect(adapter, isa_address, -1); -} - /* Assumes that adapter is of I2C, not ISA variety. * OTHERWISE DON'T CALL THIS */ @@ -862,12 +797,12 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, goto ERROR_SC_1; } } - w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR, + w83781d_write_value(data, W83781D_REG_I2C_SUBADDR, (force_subclients[2] & 0x07) | ((force_subclients[3] & 0x07) << 4)); data->lm75[0]->addr = force_subclients[2]; } else { - val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR); + val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR); data->lm75[0]->addr = 0x48 + (val1 & 0x07); } @@ -937,20 +872,20 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, return err; } -#define IN_UNIT_ATTRS(X) \ - &dev_attr_in##X##_input.attr, \ - &dev_attr_in##X##_min.attr, \ - &dev_attr_in##X##_max.attr +#define IN_UNIT_ATTRS(X) \ + &sensor_dev_attr_in##X##_input.dev_attr.attr, \ + &sensor_dev_attr_in##X##_min.dev_attr.attr, \ + &sensor_dev_attr_in##X##_max.dev_attr.attr -#define FAN_UNIT_ATTRS(X) \ - &dev_attr_fan##X##_input.attr, \ - &dev_attr_fan##X##_min.attr, \ - &dev_attr_fan##X##_div.attr +#define FAN_UNIT_ATTRS(X) \ + &sensor_dev_attr_fan##X##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##X##_min.dev_attr.attr, \ + &sensor_dev_attr_fan##X##_div.dev_attr.attr -#define TEMP_UNIT_ATTRS(X) \ - &dev_attr_temp##X##_input.attr, \ - &dev_attr_temp##X##_max.attr, \ - &dev_attr_temp##X##_max_hyst.attr +#define TEMP_UNIT_ATTRS(X) \ + &sensor_dev_attr_temp##X##_input.dev_attr.attr, \ + &sensor_dev_attr_temp##X##_max.dev_attr.attr, \ + &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr static struct attribute* w83781d_attributes[] = { IN_UNIT_ATTRS(0), @@ -980,91 +915,115 @@ static struct attribute *w83781d_attributes_opt[] = { IN_UNIT_ATTRS(7), IN_UNIT_ATTRS(8), TEMP_UNIT_ATTRS(3), - &dev_attr_pwm1.attr, - &dev_attr_pwm2.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, + &sensor_dev_attr_pwm4.dev_attr.attr, &dev_attr_pwm2_enable.attr, - &dev_attr_pwm3.attr, - &dev_attr_pwm4.attr, - &dev_attr_temp1_type.attr, - &dev_attr_temp2_type.attr, - &dev_attr_temp3_type.attr, + &sensor_dev_attr_temp1_type.dev_attr.attr, + &sensor_dev_attr_temp2_type.dev_attr.attr, + &sensor_dev_attr_temp3_type.dev_attr.attr, NULL }; static const struct attribute_group w83781d_group_opt = { .attrs = w83781d_attributes_opt, }; +/* No clean up is done on error, it's up to the caller */ static int -w83781d_detect(struct i2c_adapter *adapter, int address, int kind) +w83781d_create_files(struct device *dev, int kind, int is_isa) { - int i = 0, val1 = 0, val2; - struct i2c_client *client; - struct device *dev; - struct w83781d_data *data; int err; - const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - enum vendor { winbond, asus } vendid; - if (!is_isa - && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - err = -EINVAL; - goto ERROR0; + if ((err = sysfs_create_group(&dev->kobj, &w83781d_group))) + return err; + + if (kind != w83783s) { + if ((err = device_create_file(dev, + &sensor_dev_attr_in1_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in1_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in1_max.dev_attr))) + return err; + } + if (kind != as99127f && kind != w83781d && kind != w83783s) { + if ((err = device_create_file(dev, + &sensor_dev_attr_in7_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in7_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in7_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in8_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in8_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in8_max.dev_attr))) + return err; + } + if (kind != w83783s) { + if ((err = device_create_file(dev, + &sensor_dev_attr_temp3_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_max_hyst.dev_attr))) + return err; } - /* Prevent users from forcing a kind for a bus it isn't supposed - to possibly be on */ - if (is_isa && (kind == as99127f || kind == w83783s)) { - dev_err(&adapter->dev, - "Cannot force I2C-only chip for ISA address 0x%02x.\n", - address); - err = -EINVAL; - goto ERROR0; + if (kind != w83781d && kind != as99127f) { + if ((err = device_create_file(dev, + &sensor_dev_attr_pwm1.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm2.dev_attr)) + || (err = device_create_file(dev, &dev_attr_pwm2_enable))) + return err; } - - if (is_isa) - if (!request_region(address, W83781D_EXTENT, - w83781d_isa_driver.driver.name)) { - dev_dbg(&adapter->dev, "Request of region " - "0x%x-0x%x for w83781d failed\n", address, - address + W83781D_EXTENT - 1); - err = -EBUSY; - goto ERROR0; + if (kind == w83782d && !is_isa) { + if ((err = device_create_file(dev, + &sensor_dev_attr_pwm3.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm4.dev_attr))) + return err; + } + + if (kind != as99127f && kind != w83781d) { + if ((err = device_create_file(dev, + &sensor_dev_attr_temp1_type.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp2_type.dev_attr))) + return err; + if (kind != w83783s) { + if ((err = device_create_file(dev, + &sensor_dev_attr_temp3_type.dev_attr))) + return err; } + } - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (kind < 0) { - if (is_isa) { + if (is_isa) { + err = device_create_file(&pdev->dev, &dev_attr_name); + if (err) + return err; + } -#define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like - chips. But only if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i - || inb_p(address + 3) != i - || inb_p(address + 7) != i) { - dev_dbg(&adapter->dev, "Detection of w83781d " - "chip failed at step 1\n"); - err = -ENODEV; - goto ERROR1; - } -#undef REALLY_SLOW_IO + return 0; +} - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - val2 = inb_p(address + 5) & 0x7f; - if (val2 != (~i & 0x7f)) { - outb_p(i, address + 5); - dev_dbg(&adapter->dev, "Detection of w83781d " - "chip failed at step 2 (0x%x != " - "0x%x at 0x%x)\n", val2, ~i & 0x7f, - address + 5); - err = -ENODEV; - goto ERROR1; - } - } +static int +w83781d_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int val1 = 0, val2; + struct i2c_client *client; + struct device *dev; + struct w83781d_data *data; + int err; + const char *client_name = ""; + enum vendor { winbond, asus } vendid; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + err = -EINVAL; + goto ERROR1; } /* OK. For now, we presume we have a valid client. We now create the @@ -1081,8 +1040,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) client->addr = address; mutex_init(&data->lock); client->adapter = adapter; - client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver; - client->flags = 0; + client->driver = &w83781d_driver; dev = &client->dev; /* Now, we do the remaining detection. */ @@ -1092,14 +1050,14 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) force_*=... parameter, and the Winbond will be reset to the right bank. */ if (kind < 0) { - if (w83781d_read_value(client, W83781D_REG_CONFIG) & 0x80) { + if (w83781d_read_value(data, W83781D_REG_CONFIG) & 0x80) { dev_dbg(&adapter->dev, "Detection of w83781d chip " "failed at step 3\n"); err = -ENODEV; goto ERROR2; } - val1 = w83781d_read_value(client, W83781D_REG_BANK); - val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN); + val1 = w83781d_read_value(data, W83781D_REG_BANK); + val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN); /* Check for Winbond or Asus ID if in bank 0 */ if ((!(val1 & 0x07)) && (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)) @@ -1111,10 +1069,10 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) } /* If Winbond SMBus, check address at 0x48. Asus doesn't support, except for as99127f rev.2 */ - if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || - ((val1 & 0x80) && (val2 == 0x5c)))) { + if ((!(val1 & 0x80) && (val2 == 0xa3)) || + ((val1 & 0x80) && (val2 == 0x5c))) { if (w83781d_read_value - (client, W83781D_REG_I2C_ADDR) != address) { + (data, W83781D_REG_I2C_ADDR) != address) { dev_dbg(&adapter->dev, "Detection of w83781d " "chip failed at step 5\n"); err = -ENODEV; @@ -1125,14 +1083,14 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) /* We have either had a force parameter, or we have already detected the Winbond. Put it now into bank 0 and Vendor ID High Byte */ - w83781d_write_value(client, W83781D_REG_BANK, - (w83781d_read_value(client, W83781D_REG_BANK) + w83781d_write_value(data, W83781D_REG_BANK, + (w83781d_read_value(data, W83781D_REG_BANK) & 0x78) | 0x80); /* Determine the chip type. */ if (kind <= 0) { /* get vendor ID */ - val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN); + val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN); if (val2 == 0x5c) vendid = winbond; else if (val2 == 0x12) @@ -1144,17 +1102,16 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) goto ERROR2; } - val1 = w83781d_read_value(client, W83781D_REG_WCHIPID); + val1 = w83781d_read_value(data, W83781D_REG_WCHIPID); if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond) kind = w83781d; else if (val1 == 0x30 && vendid == winbond) kind = w83782d; - else if (val1 == 0x40 && vendid == winbond && !is_isa - && address == 0x2d) + else if (val1 == 0x40 && vendid == winbond && address == 0x2d) kind = w83783s; else if (val1 == 0x21 && vendid == winbond) kind = w83627hf; - else if (val1 == 0x31 && !is_isa && address >= 0x28) + else if (val1 == 0x31 && address >= 0x28) kind = as99127f; else { if (kind == 0) @@ -1182,86 +1139,23 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) strlcpy(client->name, client_name, I2C_NAME_SIZE); data->type = kind; - data->valid = 0; - mutex_init(&data->update_lock); - /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(client))) goto ERROR2; /* attach secondary i2c lm75-like clients */ - if (!is_isa) { - if ((err = w83781d_detect_subclients(adapter, address, - kind, client))) - goto ERROR3; - } else { - data->lm75[0] = NULL; - data->lm75[1] = NULL; - } + if ((err = w83781d_detect_subclients(adapter, address, + kind, client))) + goto ERROR3; /* Initialize the chip */ - w83781d_init_client(client); - - /* A few vars need to be filled upon startup */ - for (i = 1; i <= 3; i++) { - data->fan_min[i - 1] = w83781d_read_value(client, - W83781D_REG_FAN_MIN(i)); - } - if (kind != w83781d && kind != as99127f) - for (i = 0; i < 4; i++) - data->pwmenable[i] = 1; + w83781d_init_device(dev); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&dev->kobj, &w83781d_group))) + err = w83781d_create_files(dev, kind, 0); + if (err) goto ERROR4; - if (kind != w83783s) { - if ((err = device_create_file(dev, &dev_attr_in1_input)) - || (err = device_create_file(dev, &dev_attr_in1_min)) - || (err = device_create_file(dev, &dev_attr_in1_max))) - goto ERROR4; - } - if (kind != as99127f && kind != w83781d && kind != w83783s) { - if ((err = device_create_file(dev, &dev_attr_in7_input)) - || (err = device_create_file(dev, &dev_attr_in7_min)) - || (err = device_create_file(dev, &dev_attr_in7_max)) - || (err = device_create_file(dev, &dev_attr_in8_input)) - || (err = device_create_file(dev, &dev_attr_in8_min)) - || (err = device_create_file(dev, &dev_attr_in8_max))) - goto ERROR4; - } - if (kind != w83783s) { - if ((err = device_create_file(dev, &dev_attr_temp3_input)) - || (err = device_create_file(dev, &dev_attr_temp3_max)) - || (err = device_create_file(dev, - &dev_attr_temp3_max_hyst))) - goto ERROR4; - } - - if (kind != w83781d && kind != as99127f) { - if ((err = device_create_file(dev, &dev_attr_pwm1)) - || (err = device_create_file(dev, &dev_attr_pwm2)) - || (err = device_create_file(dev, &dev_attr_pwm2_enable))) - goto ERROR4; - } - if (kind == w83782d && !is_isa) { - if ((err = device_create_file(dev, &dev_attr_pwm3)) - || (err = device_create_file(dev, &dev_attr_pwm4))) - goto ERROR4; - } - - if (kind != as99127f && kind != w83781d) { - if ((err = device_create_file(dev, &dev_attr_temp1_type)) - || (err = device_create_file(dev, - &dev_attr_temp2_type))) - goto ERROR4; - if (kind != w83783s) { - if ((err = device_create_file(dev, - &dev_attr_temp3_type))) - goto ERROR4; - } - } - data->class_dev = hwmon_device_register(dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); @@ -1287,9 +1181,6 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) ERROR2: kfree(data); ERROR1: - if (is_isa) - release_region(address, W83781D_EXTENT); -ERROR0: return err; } @@ -1305,8 +1196,6 @@ w83781d_detach_client(struct i2c_client *client) sysfs_remove_group(&client->dev.kobj, &w83781d_group); sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt); } - if (i2c_is_isa_client(client)) - release_region(client->addr, W83781D_EXTENT); if ((err = i2c_detach_client(client))) return err; @@ -1322,6 +1211,88 @@ w83781d_detach_client(struct i2c_client *client) return 0; } +static int __devinit +w83781d_isa_probe(struct platform_device *pdev) +{ + int err, reg; + struct w83781d_data *data; + struct resource *res; + const char *name; + + /* Reserve the ISA region */ + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, W83781D_EXTENT, "w83781d")) { + err = -EBUSY; + goto exit; + } + + if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release_region; + } + mutex_init(&data->lock); + data->client.addr = res->start; + i2c_set_clientdata(&data->client, data); + platform_set_drvdata(pdev, data); + + reg = w83781d_read_value(data, W83781D_REG_WCHIPID); + switch (reg) { + case 0x21: + data->type = w83627hf; + name = "w83627hf"; + break; + case 0x30: + data->type = w83782d; + name = "w83782d"; + break; + default: + data->type = w83781d; + name = "w83781d"; + } + strlcpy(data->client.name, name, I2C_NAME_SIZE); + + /* Initialize the W83781D chip */ + w83781d_init_device(&pdev->dev); + + /* Register sysfs hooks */ + err = w83781d_create_files(&pdev->dev, data->type, 1); + if (err) + goto exit_remove_files; + + data->class_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove_files; + } + + return 0; + + exit_remove_files: + sysfs_remove_group(&pdev->dev.kobj, &w83781d_group); + sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt); + device_remove_file(&pdev->dev, &dev_attr_name); + kfree(data); + exit_release_region: + release_region(res->start, W83781D_EXTENT); + exit: + return err; +} + +static int __devexit +w83781d_isa_remove(struct platform_device *pdev) +{ + struct w83781d_data *data = platform_get_drvdata(pdev); + + hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&pdev->dev.kobj, &w83781d_group); + sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt); + device_remove_file(&pdev->dev, &dev_attr_name); + release_region(data->client.addr, W83781D_EXTENT); + kfree(data); + + return 0; +} + /* The SMBus locks itself, usually, but nothing may access the Winbond between bank switches. ISA access must always be locked explicitly! We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, @@ -1329,14 +1300,14 @@ w83781d_detach_client(struct i2c_client *client) There are some ugly typecasts here, but the good news is - they should nowhere else be necessary! */ static int -w83781d_read_value(struct i2c_client *client, u16 reg) +w83781d_read_value(struct w83781d_data *data, u16 reg) { - struct w83781d_data *data = i2c_get_clientdata(client); + struct i2c_client *client = &data->client; int res, word_sized, bank; struct i2c_client *cl; mutex_lock(&data->lock); - if (i2c_is_isa_client(client)) { + if (!client->driver) { /* ISA device */ word_sized = (((reg & 0xff00) == 0x100) || ((reg & 0xff00) == 0x200)) && (((reg & 0x00ff) == 0x50) @@ -1398,14 +1369,14 @@ w83781d_read_value(struct i2c_client *client, u16 reg) } static int -w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) +w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value) { - struct w83781d_data *data = i2c_get_clientdata(client); + struct i2c_client *client = &data->client; int word_sized, bank; struct i2c_client *cl; mutex_lock(&data->lock); - if (i2c_is_isa_client(client)) { + if (!client->driver) { /* ISA device */ word_sized = (((reg & 0xff00) == 0x100) || ((reg & 0xff00) == 0x200)) && (((reg & 0x00ff) == 0x53) @@ -1462,13 +1433,18 @@ w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) } static void -w83781d_init_client(struct i2c_client *client) +w83781d_init_device(struct device *dev) { - struct w83781d_data *data = i2c_get_clientdata(client); + struct w83781d_data *data = dev_get_drvdata(dev); int i, p; int type = data->type; u8 tmp; + if (type == w83627hf) + dev_info(dev, "The W83627HF chip is better supported by the " + "w83627hf driver, support will be dropped from the " + "w83781d driver soon\n"); + if (reset && type != as99127f) { /* this resets registers we don't have documentation for on the as99127f */ /* Resetting the chip has been the default for a long time, @@ -1477,42 +1453,42 @@ w83781d_init_client(struct i2c_client *client) It might even go away if nobody reports it as being useful, as I see very little reason why this would be needed at all. */ - dev_info(&client->dev, "If reset=1 solved a problem you were " + dev_info(dev, "If reset=1 solved a problem you were " "having, please report!\n"); /* save these registers */ - i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); - p = w83781d_read_value(client, W83781D_REG_PWMCLK12); + i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG); + p = w83781d_read_value(data, W83781D_REG_PWMCLK12); /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others */ - w83781d_write_value(client, W83781D_REG_CONFIG, 0x80); + w83781d_write_value(data, W83781D_REG_CONFIG, 0x80); /* Restore the registers and disable power-on abnormal beep. This saves FAN 1/2/3 input/output values set by BIOS. */ - w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); - w83781d_write_value(client, W83781D_REG_PWMCLK12, p); + w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80); + w83781d_write_value(data, W83781D_REG_PWMCLK12, p); /* Disable master beep-enable (reset turns it on). Individual beep_mask should be reset to off but for some reason disabling this bit helps some people not get beeped */ - w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); + w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0); } /* Disable power-on abnormal beep, as advised by the datasheet. Already done if reset=1. */ if (init && !reset && type != as99127f) { - i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); - w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); + i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG); + w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80); } data->vrm = vid_which_vrm(); if ((type != w83781d) && (type != as99127f)) { - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + tmp = w83781d_read_value(data, W83781D_REG_SCFG1); for (i = 1; i <= 3; i++) { if (!(tmp & BIT_SCFG1[i - 1])) { data->sens[i - 1] = W83781D_DEFAULT_BETA; } else { if (w83781d_read_value - (client, + (data, W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) data->sens[i - 1] = 1; else @@ -1525,38 +1501,46 @@ w83781d_init_client(struct i2c_client *client) if (init && type != as99127f) { /* Enable temp2 */ - tmp = w83781d_read_value(client, W83781D_REG_TEMP2_CONFIG); + tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG); if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp2, readings " + dev_warn(dev, "Enabling temp2, readings " "might not make sense\n"); - w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG, + w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG, tmp & 0xfe); } /* Enable temp3 */ if (type != w83783s) { - tmp = w83781d_read_value(client, + tmp = w83781d_read_value(data, W83781D_REG_TEMP3_CONFIG); if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp3, " + dev_warn(dev, "Enabling temp3, " "readings might not make sense\n"); - w83781d_write_value(client, + w83781d_write_value(data, W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); } } } /* Start monitoring */ - w83781d_write_value(client, W83781D_REG_CONFIG, - (w83781d_read_value(client, + w83781d_write_value(data, W83781D_REG_CONFIG, + (w83781d_read_value(data, W83781D_REG_CONFIG) & 0xf7) | 0x01); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 3; i++) { + data->fan_min[i] = w83781d_read_value(data, + W83781D_REG_FAN_MIN(i)); + } + + mutex_init(&data->update_lock); } static struct w83781d_data *w83781d_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); + struct w83781d_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; int i; mutex_lock(&data->update_lock); @@ -1569,98 +1553,97 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) if (data->type == w83783s && i == 1) continue; /* 783S has no in1 */ data->in[i] = - w83781d_read_value(client, W83781D_REG_IN(i)); + w83781d_read_value(data, W83781D_REG_IN(i)); data->in_min[i] = - w83781d_read_value(client, W83781D_REG_IN_MIN(i)); + w83781d_read_value(data, W83781D_REG_IN_MIN(i)); data->in_max[i] = - w83781d_read_value(client, W83781D_REG_IN_MAX(i)); + w83781d_read_value(data, W83781D_REG_IN_MAX(i)); if ((data->type != w83782d) && (data->type != w83627hf) && (i == 6)) break; } - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = - w83781d_read_value(client, W83781D_REG_FAN(i)); - data->fan_min[i - 1] = - w83781d_read_value(client, W83781D_REG_FAN_MIN(i)); + for (i = 0; i < 3; i++) { + data->fan[i] = + w83781d_read_value(data, W83781D_REG_FAN(i)); + data->fan_min[i] = + w83781d_read_value(data, W83781D_REG_FAN_MIN(i)); } if (data->type != w83781d && data->type != as99127f) { - for (i = 1; i <= 4; i++) { - data->pwm[i - 1] = - w83781d_read_value(client, - W83781D_REG_PWM(i)); - if ((data->type != w83782d - || i2c_is_isa_client(client)) - && i == 2) + for (i = 0; i < 4; i++) { + data->pwm[i] = + w83781d_read_value(data, + W83781D_REG_PWM[i]); + if ((data->type != w83782d || !client->driver) + && i == 1) break; } /* Only PWM2 can be disabled */ - data->pwmenable[1] = (w83781d_read_value(client, + data->pwm2_enable = (w83781d_read_value(data, W83781D_REG_PWMCLK12) & 0x08) >> 3; } - data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1)); + data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1)); data->temp_max = - w83781d_read_value(client, W83781D_REG_TEMP_OVER(1)); + w83781d_read_value(data, W83781D_REG_TEMP_OVER(1)); data->temp_max_hyst = - w83781d_read_value(client, W83781D_REG_TEMP_HYST(1)); + w83781d_read_value(data, W83781D_REG_TEMP_HYST(1)); data->temp_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP(2)); + w83781d_read_value(data, W83781D_REG_TEMP(2)); data->temp_max_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP_OVER(2)); + w83781d_read_value(data, W83781D_REG_TEMP_OVER(2)); data->temp_max_hyst_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP_HYST(2)); + w83781d_read_value(data, W83781D_REG_TEMP_HYST(2)); if (data->type != w83783s) { data->temp_add[1] = - w83781d_read_value(client, W83781D_REG_TEMP(3)); + w83781d_read_value(data, W83781D_REG_TEMP(3)); data->temp_max_add[1] = - w83781d_read_value(client, + w83781d_read_value(data, W83781D_REG_TEMP_OVER(3)); data->temp_max_hyst_add[1] = - w83781d_read_value(client, + w83781d_read_value(data, W83781D_REG_TEMP_HYST(3)); } - i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); + i = w83781d_read_value(data, W83781D_REG_VID_FANDIV); data->vid = i & 0x0f; - data->vid |= (w83781d_read_value(client, + data->vid |= (w83781d_read_value(data, W83781D_REG_CHIPID) & 0x01) << 4; data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = (i >> 6) & 0x03; - data->fan_div[2] = (w83781d_read_value(client, + data->fan_div[2] = (w83781d_read_value(data, W83781D_REG_PIN) >> 6) & 0x03; if ((data->type != w83781d) && (data->type != as99127f)) { - i = w83781d_read_value(client, W83781D_REG_VBAT); + i = w83781d_read_value(data, W83781D_REG_VBAT); data->fan_div[0] |= (i >> 3) & 0x04; data->fan_div[1] |= (i >> 4) & 0x04; data->fan_div[2] |= (i >> 5) & 0x04; } if ((data->type == w83782d) || (data->type == w83627hf)) { - data->alarms = w83781d_read_value(client, + data->alarms = w83781d_read_value(data, W83782D_REG_ALARM1) - | (w83781d_read_value(client, + | (w83781d_read_value(data, W83782D_REG_ALARM2) << 8) - | (w83781d_read_value(client, + | (w83781d_read_value(data, W83782D_REG_ALARM3) << 16); } else if (data->type == w83783s) { - data->alarms = w83781d_read_value(client, + data->alarms = w83781d_read_value(data, W83782D_REG_ALARM1) - | (w83781d_read_value(client, + | (w83781d_read_value(data, W83782D_REG_ALARM2) << 8); } else { /* No real-time status registers, fall back to interrupt status registers */ - data->alarms = w83781d_read_value(client, + data->alarms = w83781d_read_value(data, W83781D_REG_ALARM1) - | (w83781d_read_value(client, + | (w83781d_read_value(data, W83781D_REG_ALARM2) << 8); } - i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2); + i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2); data->beep_enable = i >> 7; data->beep_mask = ((i & 0x7f) << 8) + - w83781d_read_value(client, W83781D_REG_BEEP_INTS1); + w83781d_read_value(data, W83781D_REG_BEEP_INTS1); if ((data->type != w83781d) && (data->type != as99127f)) { data->beep_mask |= - w83781d_read_value(client, + w83781d_read_value(data, W83781D_REG_BEEP_INTS3) << 16; } data->last_updated = jiffies; @@ -1672,6 +1655,133 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) return data; } +/* return 1 if a supported chip is found, 0 otherwise */ +static int __init +w83781d_isa_found(unsigned short address) +{ + int val, save, found = 0; + + if (!request_region(address, W83781D_EXTENT, "w83781d")) + return 0; + +#define REALLY_SLOW_IO + /* We need the timeouts for at least some W83781D-like + chips. But only if we read 'undefined' registers. */ + val = inb_p(address + 1); + if (inb_p(address + 2) != val + || inb_p(address + 3) != val + || inb_p(address + 7) != val) { + pr_debug("w83781d: Detection failed at step 1\n"); + goto release; + } +#undef REALLY_SLOW_IO + + /* We should be able to change the 7 LSB of the address port. The + MSB (busy flag) should be clear initially, set after the write. */ + save = inb_p(address + W83781D_ADDR_REG_OFFSET); + if (save & 0x80) { + pr_debug("w83781d: Detection failed at step 2\n"); + goto release; + } + val = ~save & 0x7f; + outb_p(val, address + W83781D_ADDR_REG_OFFSET); + if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) { + outb_p(save, address + W83781D_ADDR_REG_OFFSET); + pr_debug("w83781d: Detection failed at step 3\n"); + goto release; + } + + /* We found a device, now see if it could be a W83781D */ + outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET); + val = inb_p(address + W83781D_DATA_REG_OFFSET); + if (val & 0x80) { + pr_debug("w83781d: Detection failed at step 4\n"); + goto release; + } + outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET); + save = inb_p(address + W83781D_DATA_REG_OFFSET); + outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET); + val = inb_p(address + W83781D_DATA_REG_OFFSET); + if ((!(save & 0x80) && (val != 0xa3)) + || ((save & 0x80) && (val != 0x5c))) { + pr_debug("w83781d: Detection failed at step 5\n"); + goto release; + } + outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET); + val = inb_p(address + W83781D_DATA_REG_OFFSET); + if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */ + pr_debug("w83781d: Detection failed at step 6\n"); + goto release; + } + + /* The busy flag should be clear again */ + if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) { + pr_debug("w83781d: Detection failed at step 7\n"); + goto release; + } + + /* Determine the chip type */ + outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET); + save = inb_p(address + W83781D_DATA_REG_OFFSET); + outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET); + outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET); + val = inb_p(address + W83781D_DATA_REG_OFFSET); + if ((val & 0xfe) == 0x10 /* W83781D */ + || val == 0x30 /* W83782D */ + || val == 0x21) /* W83627HF */ + found = 1; + + if (found) + pr_info("w83781d: Found a %s chip at %#x\n", + val == 0x21 ? "W83627HF" : + val == 0x30 ? "W83782D" : "W83781D", (int)address); + + release: + release_region(address, W83781D_EXTENT); + return found; +} + +static int __init +w83781d_isa_device_add(unsigned short address) +{ + struct resource res = { + .start = address, + .end = address + W83781D_EXTENT, + .name = "w83781d", + .flags = IORESOURCE_IO, + }; + int err; + + pdev = platform_device_alloc("w83781d", address); + if (!pdev) { + err = -ENOMEM; + printk(KERN_ERR "w83781d: Device allocation failed\n"); + goto exit; + } + + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR "w83781d: Device resource addition failed " + "(%d)\n", err); + goto exit_device_put; + } + + err = platform_device_add(pdev); + if (err) { + printk(KERN_ERR "w83781d: Device addition failed (%d)\n", + err); + goto exit_device_put; + } + + return 0; + + exit_device_put: + platform_device_put(pdev); + exit: + pdev = NULL; + return err; +} + static int __init sensors_w83781d_init(void) { @@ -1679,21 +1789,36 @@ sensors_w83781d_init(void) res = i2c_add_driver(&w83781d_driver); if (res) - return res; + goto exit; + + if (w83781d_isa_found(isa_address)) { + res = platform_driver_register(&w83781d_isa_driver); + if (res) + goto exit_unreg_i2c_driver; - /* Don't exit if this one fails, we still want the I2C variants - to work! */ - if (i2c_isa_add_driver(&w83781d_isa_driver)) - isa_address = 0; + /* Sets global pdev as a side effect */ + res = w83781d_isa_device_add(isa_address); + if (res) + goto exit_unreg_isa_driver; + } return 0; + + exit_unreg_isa_driver: + platform_driver_unregister(&w83781d_isa_driver); + exit_unreg_i2c_driver: + i2c_del_driver(&w83781d_driver); + exit: + return res; } static void __exit sensors_w83781d_exit(void) { - if (isa_address) - i2c_isa_del_driver(&w83781d_isa_driver); + if (pdev) { + platform_device_unregister(pdev); + platform_driver_unregister(&w83781d_isa_driver); + } i2c_del_driver(&w83781d_driver); } diff --git a/trunk/drivers/i2c/busses/i2c-parport.c b/trunk/drivers/i2c/busses/i2c-parport.c index 8c953707253f..039a07fde908 100644 --- a/trunk/drivers/i2c/busses/i2c-parport.c +++ b/trunk/drivers/i2c/busses/i2c-parport.c @@ -175,6 +175,7 @@ static void i2c_parport_attach (struct parport *port) } adapter->algo_data.data = port; adapter->adapter.algo_data = &adapter->algo_data; + adapter->adapter.dev.parent = port->physport->dev; if (parport_claim_or_block(adapter->pdev) < 0) { printk(KERN_ERR "i2c-parport: Could not claim parallel port\n"); diff --git a/trunk/drivers/i2c/busses/i2c-pxa.c b/trunk/drivers/i2c/busses/i2c-pxa.c index c059b27fa881..873544ab598e 100644 --- a/trunk/drivers/i2c/busses/i2c-pxa.c +++ b/trunk/drivers/i2c/busses/i2c-pxa.c @@ -852,9 +852,7 @@ 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; @@ -902,14 +900,14 @@ static int i2c_pxa_probe(struct platform_device *dev) pxa_gpio_mode(GPIO117_I2CSCL_MD); pxa_gpio_mode(GPIO118_I2CSDA_MD); #endif - pxa_set_cken(CKEN14_I2C, 1); + pxa_set_cken(CKEN_I2C, 1); break; #ifdef CONFIG_PXA27x case 1: local_irq_disable(); PCFR |= PCFR_PI2CEN; local_irq_enable(); - pxa_set_cken(CKEN15_PWRI2C, 1); + pxa_set_cken(CKEN_PWRI2C, 1); #endif } @@ -924,6 +922,10 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &dev->dev; + if (plat) { + i2c->adap.class = plat->class; + } + ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { printk(KERN_INFO "I2C: Failed to add bus\n"); @@ -946,11 +948,11 @@ static int i2c_pxa_probe(struct platform_device *dev) ereqirq: switch (dev->id) { case 0: - pxa_set_cken(CKEN14_I2C, 0); + pxa_set_cken(CKEN_I2C, 0); break; #ifdef CONFIG_PXA27x case 1: - pxa_set_cken(CKEN15_PWRI2C, 0); + pxa_set_cken(CKEN_PWRI2C, 0); local_irq_disable(); PCFR &= ~PCFR_PI2CEN; local_irq_enable(); @@ -973,11 +975,11 @@ static int i2c_pxa_remove(struct platform_device *dev) free_irq(i2c->irq, i2c); switch (dev->id) { case 0: - pxa_set_cken(CKEN14_I2C, 0); + pxa_set_cken(CKEN_I2C, 0); break; #ifdef CONFIG_PXA27x case 1: - pxa_set_cken(CKEN15_PWRI2C, 0); + pxa_set_cken(CKEN_PWRI2C, 0); local_irq_disable(); PCFR &= ~PCFR_PI2CEN; local_irq_enable(); diff --git a/trunk/drivers/i2c/busses/scx200_acb.c b/trunk/drivers/i2c/busses/scx200_acb.c index 0db56e7bc34e..0d6bd4f7b7fa 100644 --- a/trunk/drivers/i2c/busses/scx200_acb.c +++ b/trunk/drivers/i2c/busses/scx200_acb.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/i2c/chips/tps65010.c b/trunk/drivers/i2c/chips/tps65010.c index 214fbb1423c5..7ed92dc3d833 100644 --- a/trunk/drivers/i2c/chips/tps65010.c +++ b/trunk/drivers/i2c/chips/tps65010.c @@ -351,8 +351,10 @@ static void tps65010_interrupt(struct tps65010 *tps) #if 0 /* REVISIT: this might need its own workqueue * plus tweaks including deadlock avoidance ... + * also needs to get error handling and probably + * an #ifdef CONFIG_SOFTWARE_SUSPEND */ - software_suspend(); + pm_suspend(PM_SUSPEND_DISK); #endif poll = 1; } diff --git a/trunk/drivers/i2c/i2c-dev.c b/trunk/drivers/i2c/i2c-dev.c index cb4fa9bef8cd..e7a709710592 100644 --- a/trunk/drivers/i2c/i2c-dev.c +++ b/trunk/drivers/i2c/i2c-dev.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/ide/pci/pdc202xx_new.c b/trunk/drivers/ide/pci/pdc202xx_new.c index 2da5cbb53566..2cdd629c653d 100644 --- a/trunk/drivers/ide/pci/pdc202xx_new.c +++ b/trunk/drivers/ide/pci/pdc202xx_new.c @@ -395,7 +395,7 @@ static void __devinit apple_kiwi_init(struct pci_dev *pdev) unsigned int class_rev = 0; u8 conf; - if (np == NULL || !device_is_compatible(np, "kiwi-root")) + if (np == NULL || !of_device_is_compatible(np, "kiwi-root")) return; pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev); diff --git a/trunk/drivers/ide/ppc/pmac.c b/trunk/drivers/ide/ppc/pmac.c index 071a030ec26e..a49ebe44babd 100644 --- a/trunk/drivers/ide/ppc/pmac.c +++ b/trunk/drivers/ide/ppc/pmac.c @@ -1157,32 +1157,32 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) pmif->cable_80 = 0; pmif->broken_dma = pmif->broken_dma_warn = 0; - if (device_is_compatible(np, "shasta-ata")) + if (of_device_is_compatible(np, "shasta-ata")) pmif->kind = controller_sh_ata6; - else if (device_is_compatible(np, "kauai-ata")) + else if (of_device_is_compatible(np, "kauai-ata")) pmif->kind = controller_un_ata6; - else if (device_is_compatible(np, "K2-UATA")) + else if (of_device_is_compatible(np, "K2-UATA")) pmif->kind = controller_k2_ata6; - else if (device_is_compatible(np, "keylargo-ata")) { + else if (of_device_is_compatible(np, "keylargo-ata")) { if (strcmp(np->name, "ata-4") == 0) pmif->kind = controller_kl_ata4; else pmif->kind = controller_kl_ata3; - } else if (device_is_compatible(np, "heathrow-ata")) + } else if (of_device_is_compatible(np, "heathrow-ata")) pmif->kind = controller_heathrow; else { pmif->kind = controller_ohare; pmif->broken_dma = 1; } - bidp = get_property(np, "AAPL,bus-id", NULL); + bidp = of_get_property(np, "AAPL,bus-id", NULL); pmif->aapl_bus_id = bidp ? *bidp : 0; /* Get cable type from device-tree */ if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6 || pmif->kind == controller_sh_ata6) { - const char* cable = get_property(np, "cable-type", NULL); + const char* cable = of_get_property(np, "cable-type", NULL); if (cable && !strncmp(cable, "80-", 3)) pmif->cable_80 = 1; } @@ -1190,8 +1190,8 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) * they have a 80 conductor cable, this seem to be always the case unless * the user mucked around */ - if (device_is_compatible(np, "K2-UATA") || - device_is_compatible(np, "shasta-ata")) + if (of_device_is_compatible(np, "K2-UATA") || + of_device_is_compatible(np, "shasta-ata")) pmif->cable_80 = 1; /* On Kauai-type controllers, we make sure the FCR is correct */ diff --git a/trunk/drivers/ieee1394/dv1394.c b/trunk/drivers/ieee1394/dv1394.c index 026e38face5c..208141377612 100644 --- a/trunk/drivers/ieee1394/dv1394.c +++ b/trunk/drivers/ieee1394/dv1394.c @@ -94,7 +94,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/ieee1394/raw1394.c b/trunk/drivers/ieee1394/raw1394.c index c6aefd9ad0e8..d382500f4210 100644 --- a/trunk/drivers/ieee1394/raw1394.c +++ b/trunk/drivers/ieee1394/raw1394.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/ieee1394/video1394.c b/trunk/drivers/ieee1394/video1394.c index 95ca26d75272..87ebd0846c34 100644 --- a/trunk/drivers/ieee1394/video1394.c +++ b/trunk/drivers/ieee1394/video1394.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/infiniband/core/fmr_pool.c b/trunk/drivers/infiniband/core/fmr_pool.c index 1d796e7c8199..a06bcc65a871 100644 --- a/trunk/drivers/infiniband/core/fmr_pool.c +++ b/trunk/drivers/infiniband/core/fmr_pool.c @@ -43,6 +43,8 @@ #include "core_priv.h" +#define PFX "fmr_pool: " + enum { IB_FMR_MAX_REMAPS = 32, @@ -150,7 +152,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool) #ifdef DEBUG if (fmr->ref_count !=0) { - printk(KERN_WARNING "Unmapping FMR 0x%08x with ref count %d", + printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d", fmr, fmr->ref_count); } #endif @@ -168,7 +170,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool) ret = ib_unmap_fmr(&fmr_list); if (ret) - printk(KERN_WARNING "ib_unmap_fmr returned %d", ret); + printk(KERN_WARNING PFX "ib_unmap_fmr returned %d", ret); spin_lock_irq(&pool->pool_lock); list_splice(&unmap_list, &pool->free_list); @@ -226,20 +228,20 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, device = pd->device; if (!device->alloc_fmr || !device->dealloc_fmr || !device->map_phys_fmr || !device->unmap_fmr) { - printk(KERN_WARNING "Device %s does not support fast memory regions", + printk(KERN_INFO PFX "Device %s does not support FMRs\n", device->name); return ERR_PTR(-ENOSYS); } attr = kmalloc(sizeof *attr, GFP_KERNEL); if (!attr) { - printk(KERN_WARNING "couldn't allocate device attr struct"); + printk(KERN_WARNING PFX "couldn't allocate device attr struct"); return ERR_PTR(-ENOMEM); } ret = ib_query_device(device, attr); if (ret) { - printk(KERN_WARNING "couldn't query device"); + printk(KERN_WARNING PFX "couldn't query device: %d", ret); kfree(attr); return ERR_PTR(ret); } @@ -253,7 +255,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, pool = kmalloc(sizeof *pool, GFP_KERNEL); if (!pool) { - printk(KERN_WARNING "couldn't allocate pool struct"); + printk(KERN_WARNING PFX "couldn't allocate pool struct"); return ERR_PTR(-ENOMEM); } @@ -270,7 +272,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket, GFP_KERNEL); if (!pool->cache_bucket) { - printk(KERN_WARNING "Failed to allocate cache in pool"); + printk(KERN_WARNING PFX "Failed to allocate cache in pool"); ret = -ENOMEM; goto out_free_pool; } @@ -294,7 +296,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, "ib_fmr(%s)", device->name); if (IS_ERR(pool->thread)) { - printk(KERN_WARNING "couldn't start cleanup thread"); + printk(KERN_WARNING PFX "couldn't start cleanup thread"); ret = PTR_ERR(pool->thread); goto out_free_pool; } @@ -311,8 +313,8 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, fmr = kmalloc(sizeof *fmr + params->max_pages_per_fmr * sizeof (u64), GFP_KERNEL); if (!fmr) { - printk(KERN_WARNING "failed to allocate fmr struct " - "for FMR %d", i); + printk(KERN_WARNING PFX "failed to allocate fmr " + "struct for FMR %d", i); goto out_fail; } @@ -323,7 +325,8 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, 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); + printk(KERN_WARNING PFX "fmr_create failed " + "for FMR %d", i); kfree(fmr); goto out_fail; } @@ -378,7 +381,7 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool) } if (i < pool->pool_size) - printk(KERN_WARNING "pool still has %d regions registered", + printk(KERN_WARNING PFX "pool still has %d regions registered", pool->pool_size - i); kfree(pool->cache_bucket); @@ -463,8 +466,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle, list_add(&fmr->list, &pool->free_list); spin_unlock_irqrestore(&pool->pool_lock, flags); - printk(KERN_WARNING "fmr_map returns %d\n", - result); + printk(KERN_WARNING PFX "fmr_map returns %d\n", result); return ERR_PTR(result); } @@ -516,7 +518,7 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr) #ifdef DEBUG if (fmr->ref_count < 0) - printk(KERN_WARNING "FMR %p has ref count %d < 0", + printk(KERN_WARNING PFX "FMR %p has ref count %d < 0", fmr, fmr->ref_count); #endif diff --git a/trunk/drivers/infiniband/core/mad.c b/trunk/drivers/infiniband/core/mad.c index 6edfecf1be72..85ccf13b8041 100644 --- a/trunk/drivers/infiniband/core/mad.c +++ b/trunk/drivers/infiniband/core/mad.c @@ -2771,7 +2771,7 @@ static int ib_mad_port_open(struct ib_device *device, cq_size = (IB_MAD_QP_SEND_SIZE + IB_MAD_QP_RECV_SIZE) * 2; port_priv->cq = ib_create_cq(port_priv->device, ib_mad_thread_completion_handler, - NULL, port_priv, cq_size); + NULL, port_priv, cq_size, 0); if (IS_ERR(port_priv->cq)) { printk(KERN_ERR PFX "Couldn't create ib_mad CQ\n"); ret = PTR_ERR(port_priv->cq); diff --git a/trunk/drivers/infiniband/core/uverbs_cmd.c b/trunk/drivers/infiniband/core/uverbs_cmd.c index 4fd75afa6a3a..bab66769be14 100644 --- a/trunk/drivers/infiniband/core/uverbs_cmd.c +++ b/trunk/drivers/infiniband/core/uverbs_cmd.c @@ -802,6 +802,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, INIT_LIST_HEAD(&obj->async_list); cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, + cmd.comp_vector, file->ucontext, &udata); if (IS_ERR(cq)) { ret = PTR_ERR(cq); diff --git a/trunk/drivers/infiniband/core/uverbs_main.c b/trunk/drivers/infiniband/core/uverbs_main.c index f8bc822a3cc3..d44e54799651 100644 --- a/trunk/drivers/infiniband/core/uverbs_main.c +++ b/trunk/drivers/infiniband/core/uverbs_main.c @@ -752,7 +752,7 @@ static void ib_uverbs_add_one(struct ib_device *device) spin_unlock(&map_lock); uverbs_dev->ib_dev = device; - uverbs_dev->num_comp_vectors = 1; + uverbs_dev->num_comp_vectors = device->num_comp_vectors; uverbs_dev->dev = cdev_alloc(); if (!uverbs_dev->dev) diff --git a/trunk/drivers/infiniband/core/verbs.c b/trunk/drivers/infiniband/core/verbs.c index ccdf93d30b01..86ed8af9c7e6 100644 --- a/trunk/drivers/infiniband/core/verbs.c +++ b/trunk/drivers/infiniband/core/verbs.c @@ -609,11 +609,11 @@ EXPORT_SYMBOL(ib_destroy_qp); struct ib_cq *ib_create_cq(struct ib_device *device, ib_comp_handler comp_handler, void (*event_handler)(struct ib_event *, void *), - void *cq_context, int cqe) + void *cq_context, int cqe, int comp_vector) { struct ib_cq *cq; - cq = device->create_cq(device, cqe, NULL, NULL); + cq = device->create_cq(device, cqe, comp_vector, NULL, NULL); if (!IS_ERR(cq)) { cq->device = device; diff --git a/trunk/drivers/infiniband/hw/amso1100/c2.h b/trunk/drivers/infiniband/hw/amso1100/c2.h index 04a9db5de881..fa58200217a1 100644 --- a/trunk/drivers/infiniband/hw/amso1100/c2.h +++ b/trunk/drivers/infiniband/hw/amso1100/c2.h @@ -519,7 +519,7 @@ extern void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq); extern void c2_cq_event(struct c2_dev *c2dev, u32 mq_index); extern void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index); extern int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry); -extern int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify); +extern int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags); /* CM */ extern int c2_llp_connect(struct iw_cm_id *cm_id, diff --git a/trunk/drivers/infiniband/hw/amso1100/c2_cq.c b/trunk/drivers/infiniband/hw/amso1100/c2_cq.c index 5175c99ee586..d2b3366786d6 100644 --- a/trunk/drivers/infiniband/hw/amso1100/c2_cq.c +++ b/trunk/drivers/infiniband/hw/amso1100/c2_cq.c @@ -217,17 +217,19 @@ int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) return npolled; } -int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) +int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags) { struct c2_mq_shared __iomem *shared; struct c2_cq *cq; + unsigned long flags; + int ret = 0; cq = to_c2cq(ibcq); shared = cq->mq.peer; - if (notify == IB_CQ_NEXT_COMP) + if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_NEXT_COMP) writeb(C2_CQ_NOTIFICATION_TYPE_NEXT, &shared->notification_type); - else if (notify == IB_CQ_SOLICITED) + else if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED) writeb(C2_CQ_NOTIFICATION_TYPE_NEXT_SE, &shared->notification_type); else return -EINVAL; @@ -241,7 +243,13 @@ int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) */ readb(&shared->armed); - return 0; + if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) { + spin_lock_irqsave(&cq->lock, flags); + ret = !c2_mq_empty(&cq->mq); + spin_unlock_irqrestore(&cq->lock, flags); + } + + return ret; } static void c2_free_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq) diff --git a/trunk/drivers/infiniband/hw/amso1100/c2_provider.c b/trunk/drivers/infiniband/hw/amso1100/c2_provider.c index 607c09bf764c..109166223c09 100644 --- a/trunk/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/trunk/drivers/infiniband/hw/amso1100/c2_provider.c @@ -290,7 +290,7 @@ static int c2_destroy_qp(struct ib_qp *ib_qp) return 0; } -static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries, +static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries, int vector, struct ib_ucontext *context, struct ib_udata *udata) { @@ -795,6 +795,7 @@ int c2_register_device(struct c2_dev *dev) memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid)); memcpy(&dev->ibdev.node_guid, dev->pseudo_netdev->dev_addr, 6); dev->ibdev.phys_port_cnt = 1; + dev->ibdev.num_comp_vectors = 1; dev->ibdev.dma_device = &dev->pcidev->dev; dev->ibdev.query_device = c2_query_device; dev->ibdev.query_port = c2_query_port; diff --git a/trunk/drivers/infiniband/hw/cxgb3/cxio_hal.c b/trunk/drivers/infiniband/hw/cxgb3/cxio_hal.c index f5e9aeec6f6e..76049afc7655 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/trunk/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -114,7 +114,10 @@ int cxio_hal_cq_op(struct cxio_rdev *rdev_p, struct t3_cq *cq, return -EIO; } } + + return 1; } + return 0; } diff --git a/trunk/drivers/infiniband/hw/cxgb3/cxio_wr.h b/trunk/drivers/infiniband/hw/cxgb3/cxio_wr.h index 90d7b8972cb4..ff7290eacefb 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/trunk/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -38,6 +38,7 @@ #include "firmware_exports.h" #define T3_MAX_SGE 4 +#define T3_MAX_INLINE 64 #define Q_EMPTY(rptr,wptr) ((rptr)==(wptr)) #define Q_FULL(rptr,wptr,size_log2) ( (((wptr)-(rptr))>>(size_log2)) && \ diff --git a/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c b/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c index 3b4b0acd707f..b2faff5abce8 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -1109,6 +1109,15 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) PDBG("%s ep %p\n", __FUNCTION__, ep); + /* + * We get 2 abort replies from the HW. The first one must + * be ignored except for scribbling that we need one more. + */ + if (!(ep->flags & ABORT_REQ_IN_PROGRESS)) { + ep->flags |= ABORT_REQ_IN_PROGRESS; + return CPL_RET_BUF_DONE; + } + close_complete_upcall(ep); state_set(&ep->com, DEAD); release_ep_resources(ep); @@ -1189,6 +1198,7 @@ static int listen_stop(struct iwch_listen_ep *ep) } req = (struct cpl_close_listserv_req *) skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + req->cpu_idx = 0; OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, ep->stid)); skb->priority = 1; ep->com.tdev->send(ep->com.tdev, skb); @@ -1475,6 +1485,15 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) int ret; int state; + /* + * We get 2 peer aborts from the HW. The first one must + * be ignored except for scribbling that we need one more. + */ + if (!(ep->flags & PEER_ABORT_IN_PROGRESS)) { + ep->flags |= PEER_ABORT_IN_PROGRESS; + return CPL_RET_BUF_DONE; + } + if (is_neg_adv_abort(req->status)) { PDBG("%s neg_adv_abort ep %p tid %d\n", __FUNCTION__, ep, ep->hwtid); diff --git a/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.h b/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.h index 0c6f281bd4a0..21a388c313cf 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.h +++ b/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.h @@ -143,6 +143,11 @@ enum iwch_ep_state { DEAD, }; +enum iwch_ep_flags { + PEER_ABORT_IN_PROGRESS = (1 << 0), + ABORT_REQ_IN_PROGRESS = (1 << 1), +}; + struct iwch_ep_common { struct iw_cm_id *cm_id; struct iwch_qp *qp; @@ -181,6 +186,7 @@ struct iwch_ep { u16 plen; u32 ird; u32 ord; + u32 flags; }; static inline struct iwch_ep *to_ep(struct iw_cm_id *cm_id) diff --git a/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c b/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c index af28a317016d..a891493fd340 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -139,7 +139,7 @@ static int iwch_destroy_cq(struct ib_cq *ib_cq) return 0; } -static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, +static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int vector, struct ib_ucontext *ib_context, struct ib_udata *udata) { @@ -292,7 +292,7 @@ static int iwch_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata) #endif } -static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) +static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) { struct iwch_dev *rhp; struct iwch_cq *chp; @@ -303,7 +303,7 @@ static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) chp = to_iwch_cq(ibcq); rhp = chp->rhp; - if (notify == IB_CQ_SOLICITED) + if ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED) cq_op = CQ_ARM_SE; else cq_op = CQ_ARM_AN; @@ -317,9 +317,11 @@ static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) PDBG("%s rptr 0x%x\n", __FUNCTION__, chp->cq.rptr); err = cxio_hal_cq_op(&rhp->rdev, &chp->cq, cq_op, 0); spin_unlock_irqrestore(&chp->lock, flag); - if (err) + if (err < 0) printk(KERN_ERR MOD "Error %d rearming CQID 0x%x\n", err, chp->cq.cqid); + if (err > 0 && !(flags & IB_CQ_REPORT_MISSED_EVENTS)) + err = 0; return err; } @@ -780,6 +782,9 @@ static struct ib_qp *iwch_create_qp(struct ib_pd *pd, if (rqsize > T3_MAX_RQ_SIZE) return ERR_PTR(-EINVAL); + if (attrs->cap.max_inline_data > T3_MAX_INLINE) + return ERR_PTR(-EINVAL); + /* * NOTE: The SQ and total WQ sizes don't need to be * a power of two. However, all the code assumes @@ -1107,6 +1112,7 @@ int iwch_register_device(struct iwch_dev *dev) dev->ibdev.node_type = RDMA_NODE_RNIC; memcpy(dev->ibdev.node_desc, IWCH_NODE_DESC, sizeof(IWCH_NODE_DESC)); dev->ibdev.phys_port_cnt = dev->rdev.port_info.nports; + dev->ibdev.num_comp_vectors = 1; dev->ibdev.dma_device = &(dev->rdev.rnic_info.pdev->dev); dev->ibdev.query_device = iwch_query_device; dev->ibdev.query_port = iwch_query_port; diff --git a/trunk/drivers/infiniband/hw/cxgb3/iwch_qp.c b/trunk/drivers/infiniband/hw/cxgb3/iwch_qp.c index 0a472c9b44db..714dddbc9a98 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/trunk/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -471,43 +471,62 @@ int iwch_bind_mw(struct ib_qp *qp, return err; } -static void build_term_codes(int t3err, u8 *layer_type, u8 *ecode, int tagged) +static inline void build_term_codes(struct respQ_msg_t *rsp_msg, + u8 *layer_type, u8 *ecode) { - switch (t3err) { + int status = TPT_ERR_INTERNAL_ERR; + int tagged = 0; + int opcode = -1; + int rqtype = 0; + int send_inv = 0; + + if (rsp_msg) { + status = CQE_STATUS(rsp_msg->cqe); + opcode = CQE_OPCODE(rsp_msg->cqe); + rqtype = RQ_TYPE(rsp_msg->cqe); + send_inv = (opcode == T3_SEND_WITH_INV) || + (opcode == T3_SEND_WITH_SE_INV); + tagged = (opcode == T3_RDMA_WRITE) || + (rqtype && (opcode == T3_READ_RESP)); + } + + switch (status) { case TPT_ERR_STAG: - if (tagged == 1) { - *layer_type = LAYER_DDP|DDP_TAGGED_ERR; - *ecode = DDPT_INV_STAG; - } else if (tagged == 2) { + if (send_inv) { + *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; + *ecode = RDMAP_CANT_INV_STAG; + } else { *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; *ecode = RDMAP_INV_STAG; } break; case TPT_ERR_PDID: + *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; + if ((opcode == T3_SEND_WITH_INV) || + (opcode == T3_SEND_WITH_SE_INV)) + *ecode = RDMAP_CANT_INV_STAG; + else + *ecode = RDMAP_STAG_NOT_ASSOC; + break; case TPT_ERR_QPID: + *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; + *ecode = RDMAP_STAG_NOT_ASSOC; + break; case TPT_ERR_ACCESS: - if (tagged == 1) { - *layer_type = LAYER_DDP|DDP_TAGGED_ERR; - *ecode = DDPT_STAG_NOT_ASSOC; - } else if (tagged == 2) { - *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; - *ecode = RDMAP_STAG_NOT_ASSOC; - } + *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; + *ecode = RDMAP_ACC_VIOL; break; case TPT_ERR_WRAP: *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; *ecode = RDMAP_TO_WRAP; break; case TPT_ERR_BOUND: - if (tagged == 1) { + if (tagged) { *layer_type = LAYER_DDP|DDP_TAGGED_ERR; *ecode = DDPT_BASE_BOUNDS; - } else if (tagged == 2) { + } else { *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; *ecode = RDMAP_BASE_BOUNDS; - } else { - *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; - *ecode = DDPU_MSG_TOOBIG; } break; case TPT_ERR_INVALIDATE_SHARED_MR: @@ -591,8 +610,6 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg) { union t3_wr *wqe; struct terminate_message *term; - int status; - int tagged = 0; struct sk_buff *skb; PDBG("%s %d\n", __FUNCTION__, __LINE__); @@ -610,17 +627,7 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg) /* immediate data starts here. */ term = (struct terminate_message *)wqe->send.sgl; - if (rsp_msg) { - status = CQE_STATUS(rsp_msg->cqe); - if (CQE_OPCODE(rsp_msg->cqe) == T3_RDMA_WRITE) - tagged = 1; - if ((CQE_OPCODE(rsp_msg->cqe) == T3_READ_REQ) || - (CQE_OPCODE(rsp_msg->cqe) == T3_READ_RESP)) - tagged = 2; - } else { - status = TPT_ERR_INTERNAL_ERR; - } - build_term_codes(status, &term->layer_etype, &term->ecode, tagged); + build_term_codes(rsp_msg, &term->layer_etype, &term->ecode); build_fw_riwrh((void *)wqe, T3_WR_SEND, T3_COMPLETION_FLAG | T3_NOTIFY_FLAG, 1, qhp->ep->hwtid, 5); diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_cq.c b/trunk/drivers/infiniband/hw/ehca/ehca_cq.c index e2cdc1a16fe9..67f0670fe3b1 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_cq.c @@ -113,7 +113,7 @@ struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num) return ret; } -struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, +struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, struct ib_ucontext *context, struct ib_udata *udata) { diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_iverbs.h b/trunk/drivers/infiniband/hw/ehca/ehca_iverbs.h index 95fd59fb4528..e14b029332c8 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_iverbs.h +++ b/trunk/drivers/infiniband/hw/ehca/ehca_iverbs.h @@ -123,7 +123,7 @@ int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq); void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq); -struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, +struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, struct ib_ucontext *context, struct ib_udata *udata); @@ -135,7 +135,7 @@ int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc); int ehca_peek_cq(struct ib_cq *cq, int wc_cnt); -int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify); +int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags); struct ib_qp *ehca_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *init_attr, diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_main.c b/trunk/drivers/infiniband/hw/ehca/ehca_main.c index 4700085ba834..fe90e7454560 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_main.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_main.c @@ -313,6 +313,7 @@ int ehca_init_device(struct ehca_shca *shca) shca->ib_device.node_type = RDMA_NODE_IB_CA; shca->ib_device.phys_port_cnt = shca->num_ports; + shca->ib_device.num_comp_vectors = 1; shca->ib_device.dma_device = &shca->ibmebus_dev->ofdev.dev; shca->ib_device.query_device = ehca_query_device; shca->ib_device.query_port = ehca_query_port; @@ -375,7 +376,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port) return -EPERM; } - ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10); + ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10, 0); if (IS_ERR(ibcq)) { ehca_err(&shca->ib_device, "Cannot create AQP1 CQ."); return PTR_ERR(ibcq); @@ -569,7 +570,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev, struct ib_pd *ibpd; int ret; - handle = get_property(dev->ofdev.node, "ibm,hca-handle", NULL); + handle = of_get_property(dev->ofdev.node, "ibm,hca-handle", NULL); if (!handle) { ehca_gen_err("Cannot get eHCA handle for adapter: %s.", dev->ofdev.node->full_name); diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_reqs.c b/trunk/drivers/infiniband/hw/ehca/ehca_reqs.c index 08d3f892d9f3..caec9dee09e1 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -634,11 +634,13 @@ int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc) return ret; } -int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify) +int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags) { struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); + unsigned long spl_flags; + int ret = 0; - switch (cq_notify) { + switch (notify_flags & IB_CQ_SOLICITED_MASK) { case IB_CQ_SOLICITED: hipz_set_cqx_n0(my_cq, 1); break; @@ -649,5 +651,11 @@ int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify) return -EINVAL; } - return 0; + if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) { + spin_lock_irqsave(&my_cq->spinlock, spl_flags); + ret = ipz_qeit_is_valid(&my_cq->ipz_queue); + spin_unlock_irqrestore(&my_cq->spinlock, spl_flags); + } + + return ret; } diff --git a/trunk/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/trunk/drivers/infiniband/hw/ehca/ipz_pt_fn.h index 8199c45768a3..57f141a36bce 100644 --- a/trunk/drivers/infiniband/hw/ehca/ipz_pt_fn.h +++ b/trunk/drivers/infiniband/hw/ehca/ipz_pt_fn.h @@ -140,6 +140,14 @@ static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue) return cqe; } +static inline int ipz_qeit_is_valid(struct ipz_queue *queue) +{ + struct ehca_cqe *cqe = ipz_qeit_get(queue); + u32 cqe_flags = cqe->cqe_flags; + + return cqe_flags >> 7 == (queue->toggle_state & 1); +} + /* * returns and resets Queue Entry iterator * returns address (kv) of first Queue Entry diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_cq.c b/trunk/drivers/infiniband/hw/ipath/ipath_cq.c index ea78e6dddc90..3e9241badba0 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_cq.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_cq.c @@ -204,7 +204,7 @@ static void send_complete(unsigned long data) * * Called by ib_create_cq() in the generic verbs code. */ -struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, +struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector, struct ib_ucontext *context, struct ib_udata *udata) { @@ -243,33 +243,21 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, * See ipath_mmap() for details. */ if (udata && udata->outlen >= sizeof(__u64)) { - struct ipath_mmap_info *ip; - __u64 offset = (__u64) wc; int err; + u32 s = sizeof *wc + sizeof(struct ib_wc) * entries; - err = ib_copy_to_udata(udata, &offset, sizeof(offset)); - if (err) { - ret = ERR_PTR(err); + cq->ip = ipath_create_mmap_info(dev, s, context, wc); + if (!cq->ip) { + ret = ERR_PTR(-ENOMEM); goto bail_wc; } - /* Allocate info for ipath_mmap(). */ - ip = kmalloc(sizeof(*ip), GFP_KERNEL); - if (!ip) { - ret = ERR_PTR(-ENOMEM); - goto bail_wc; + err = ib_copy_to_udata(udata, &cq->ip->offset, + sizeof(cq->ip->offset)); + if (err) { + ret = ERR_PTR(err); + goto bail_ip; } - cq->ip = ip; - ip->context = context; - ip->obj = wc; - kref_init(&ip->ref); - ip->mmap_cnt = 0; - ip->size = PAGE_ALIGN(sizeof(*wc) + - sizeof(struct ib_wc) * entries); - spin_lock_irq(&dev->pending_lock); - ip->next = dev->pending_mmaps; - dev->pending_mmaps = ip; - spin_unlock_irq(&dev->pending_lock); } else cq->ip = NULL; @@ -277,12 +265,18 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, if (dev->n_cqs_allocated == ib_ipath_max_cqs) { spin_unlock(&dev->n_cqs_lock); ret = ERR_PTR(-ENOMEM); - goto bail_wc; + goto bail_ip; } dev->n_cqs_allocated++; spin_unlock(&dev->n_cqs_lock); + if (cq->ip) { + spin_lock_irq(&dev->pending_lock); + list_add(&cq->ip->pending_mmaps, &dev->pending_mmaps); + spin_unlock_irq(&dev->pending_lock); + } + /* * ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe. * The number of entries should be >= the number requested or return @@ -301,12 +295,12 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, goto done; +bail_ip: + kfree(cq->ip); bail_wc: vfree(wc); - bail_cq: kfree(cq); - done: return ret; } @@ -340,17 +334,18 @@ int ipath_destroy_cq(struct ib_cq *ibcq) /** * ipath_req_notify_cq - change the notification type for a completion queue * @ibcq: the completion queue - * @notify: the type of notification to request + * @notify_flags: the type of notification to request * * Returns 0 for success. * * This may be called from interrupt context. Also called by * ib_req_notify_cq() in the generic verbs code. */ -int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) +int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags) { struct ipath_cq *cq = to_icq(ibcq); unsigned long flags; + int ret = 0; spin_lock_irqsave(&cq->lock, flags); /* @@ -358,9 +353,15 @@ int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) * any other transitions (see C11-31 and C11-32 in ch. 11.4.2.2). */ if (cq->notify != IB_CQ_NEXT_COMP) - cq->notify = notify; + cq->notify = notify_flags & IB_CQ_SOLICITED_MASK; + + if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) && + cq->queue->head != cq->queue->tail) + ret = 1; + spin_unlock_irqrestore(&cq->lock, flags); - return 0; + + return ret; } /** @@ -443,13 +444,12 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) if (cq->ip) { struct ipath_ibdev *dev = to_idev(ibcq->device); struct ipath_mmap_info *ip = cq->ip; + u32 s = sizeof *wc + sizeof(struct ib_wc) * cqe; - ip->obj = wc; - ip->size = PAGE_ALIGN(sizeof(*wc) + - sizeof(struct ib_wc) * cqe); + ipath_update_mmap_info(dev, ip, s, wc); spin_lock_irq(&dev->pending_lock); - ip->next = dev->pending_mmaps; - dev->pending_mmaps = ip; + if (list_empty(&ip->pending_mmaps)) + list_add(&ip->pending_mmaps, &dev->pending_mmaps); spin_unlock_irq(&dev->pending_lock); } diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_fs.c b/trunk/drivers/infiniband/hw/ipath/ipath_fs.c index 036ed1ef1796..ebd5c7bd2cdb 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_fs.c @@ -523,7 +523,7 @@ static int ipathfs_fill_super(struct super_block *sb, void *data, int ret; static struct tree_descr files[] = { - [1] = {"atomic_stats", &atomic_stats_ops, S_IRUGO}, + [2] = {"atomic_stats", &atomic_stats_ops, S_IRUGO}, {""}, }; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_mmap.c b/trunk/drivers/infiniband/hw/ipath/ipath_mmap.c index a82157db4689..937bc3396b53 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_mmap.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_mmap.c @@ -46,6 +46,11 @@ void ipath_release_mmap_info(struct kref *ref) { struct ipath_mmap_info *ip = container_of(ref, struct ipath_mmap_info, ref); + struct ipath_ibdev *dev = to_idev(ip->context->device); + + spin_lock_irq(&dev->pending_lock); + list_del(&ip->pending_mmaps); + spin_unlock_irq(&dev->pending_lock); vfree(ip->obj); kfree(ip); @@ -60,14 +65,12 @@ static void ipath_vma_open(struct vm_area_struct *vma) struct ipath_mmap_info *ip = vma->vm_private_data; kref_get(&ip->ref); - ip->mmap_cnt++; } static void ipath_vma_close(struct vm_area_struct *vma) { struct ipath_mmap_info *ip = vma->vm_private_data; - ip->mmap_cnt--; kref_put(&ip->ref, ipath_release_mmap_info); } @@ -87,7 +90,7 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) struct ipath_ibdev *dev = to_idev(context->device); unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long size = vma->vm_end - vma->vm_start; - struct ipath_mmap_info *ip, **pp; + struct ipath_mmap_info *ip, *pp; int ret = -EINVAL; /* @@ -96,15 +99,16 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) * CQ, QP, or SRQ is soon followed by a call to mmap(). */ spin_lock_irq(&dev->pending_lock); - for (pp = &dev->pending_mmaps; (ip = *pp); pp = &ip->next) { + list_for_each_entry_safe(ip, pp, &dev->pending_mmaps, + pending_mmaps) { /* Only the creator is allowed to mmap the object */ - if (context != ip->context || (void *) offset != ip->obj) + if (context != ip->context || (__u64) offset != ip->offset) continue; /* Don't allow a mmap larger than the object. */ if (size > ip->size) break; - *pp = ip->next; + list_del_init(&ip->pending_mmaps); spin_unlock_irq(&dev->pending_lock); ret = remap_vmalloc_range(vma, ip->obj, 0); @@ -119,3 +123,51 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) done: return ret; } + +/* + * Allocate information for ipath_mmap + */ +struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev, + u32 size, + struct ib_ucontext *context, + void *obj) { + struct ipath_mmap_info *ip; + + ip = kmalloc(sizeof *ip, GFP_KERNEL); + if (!ip) + goto bail; + + size = PAGE_ALIGN(size); + + spin_lock_irq(&dev->mmap_offset_lock); + if (dev->mmap_offset == 0) + dev->mmap_offset = PAGE_SIZE; + ip->offset = dev->mmap_offset; + dev->mmap_offset += size; + spin_unlock_irq(&dev->mmap_offset_lock); + + INIT_LIST_HEAD(&ip->pending_mmaps); + ip->size = size; + ip->context = context; + ip->obj = obj; + kref_init(&ip->ref); + +bail: + return ip; +} + +void ipath_update_mmap_info(struct ipath_ibdev *dev, + struct ipath_mmap_info *ip, + u32 size, void *obj) { + size = PAGE_ALIGN(size); + + spin_lock_irq(&dev->mmap_offset_lock); + if (dev->mmap_offset == 0) + dev->mmap_offset = PAGE_SIZE; + ip->offset = dev->mmap_offset; + dev->mmap_offset += size; + spin_unlock_irq(&dev->mmap_offset_lock); + + ip->size = size; + ip->obj = obj; +} diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_qp.c b/trunk/drivers/infiniband/hw/ipath/ipath_qp.c index 16db9ac0b402..bfef08ecd342 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_qp.c @@ -844,34 +844,36 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, * See ipath_mmap() for details. */ if (udata && udata->outlen >= sizeof(__u64)) { - struct ipath_mmap_info *ip; - __u64 offset = (__u64) qp->r_rq.wq; int err; - err = ib_copy_to_udata(udata, &offset, sizeof(offset)); - if (err) { - ret = ERR_PTR(err); - goto bail_rwq; - } + if (!qp->r_rq.wq) { + __u64 offset = 0; - if (qp->r_rq.wq) { - /* Allocate info for ipath_mmap(). */ - ip = kmalloc(sizeof(*ip), GFP_KERNEL); - if (!ip) { + err = ib_copy_to_udata(udata, &offset, + sizeof(offset)); + if (err) { + ret = ERR_PTR(err); + goto bail_rwq; + } + } else { + u32 s = sizeof(struct ipath_rwq) + + qp->r_rq.size * sz; + + qp->ip = + ipath_create_mmap_info(dev, s, + ibpd->uobject->context, + qp->r_rq.wq); + if (!qp->ip) { ret = ERR_PTR(-ENOMEM); goto bail_rwq; } - qp->ip = ip; - ip->context = ibpd->uobject->context; - ip->obj = qp->r_rq.wq; - kref_init(&ip->ref); - ip->mmap_cnt = 0; - ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) + - qp->r_rq.size * sz); - spin_lock_irq(&dev->pending_lock); - ip->next = dev->pending_mmaps; - dev->pending_mmaps = ip; - spin_unlock_irq(&dev->pending_lock); + + err = ib_copy_to_udata(udata, &(qp->ip->offset), + sizeof(qp->ip->offset)); + if (err) { + ret = ERR_PTR(err); + goto bail_ip; + } } } @@ -885,6 +887,12 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, dev->n_qps_allocated++; spin_unlock(&dev->n_qps_lock); + if (qp->ip) { + spin_lock_irq(&dev->pending_lock); + list_add(&qp->ip->pending_mmaps, &dev->pending_mmaps); + spin_unlock_irq(&dev->pending_lock); + } + ret = &qp->ibqp; goto bail; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_rc.c b/trunk/drivers/infiniband/hw/ipath/ipath_rc.c index b4b88d0b53f5..1915771fd038 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_rc.c @@ -98,13 +98,21 @@ static int ipath_make_rc_ack(struct ipath_qp *qp, case OP(RDMA_READ_RESPONSE_LAST): case OP(RDMA_READ_RESPONSE_ONLY): case OP(ATOMIC_ACKNOWLEDGE): - qp->s_ack_state = OP(ACKNOWLEDGE); + /* + * We can increment the tail pointer now that the last + * response has been sent instead of only being + * constructed. + */ + if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC) + qp->s_tail_ack_queue = 0; /* FALLTHROUGH */ + case OP(SEND_ONLY): case OP(ACKNOWLEDGE): /* Check for no next entry in the queue. */ if (qp->r_head_ack_queue == qp->s_tail_ack_queue) { if (qp->s_flags & IPATH_S_ACK_PENDING) goto normal; + qp->s_ack_state = OP(ACKNOWLEDGE); goto bail; } @@ -117,12 +125,8 @@ static int ipath_make_rc_ack(struct ipath_qp *qp, if (len > pmtu) { len = pmtu; qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST); - } else { + } else qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY); - if (++qp->s_tail_ack_queue > - IPATH_MAX_RDMA_ATOMIC) - qp->s_tail_ack_queue = 0; - } ohdr->u.aeth = ipath_compute_aeth(qp); hwords++; qp->s_ack_rdma_psn = e->psn; @@ -139,8 +143,6 @@ static int ipath_make_rc_ack(struct ipath_qp *qp, cpu_to_be32(e->atomic_data); hwords += sizeof(ohdr->u.at) / sizeof(u32); bth2 = e->psn; - if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC) - qp->s_tail_ack_queue = 0; } bth0 = qp->s_ack_state << 24; break; @@ -156,8 +158,6 @@ static int ipath_make_rc_ack(struct ipath_qp *qp, ohdr->u.aeth = ipath_compute_aeth(qp); hwords++; qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST); - if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC) - qp->s_tail_ack_queue = 0; } bth0 = qp->s_ack_state << 24; bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK; @@ -171,7 +171,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp, * the ACK before setting s_ack_state to ACKNOWLEDGE * (see above). */ - qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE); + qp->s_ack_state = OP(SEND_ONLY); qp->s_flags &= ~IPATH_S_ACK_PENDING; qp->s_cur_sge = NULL; if (qp->s_nak_state) @@ -223,23 +223,18 @@ int ipath_make_rc_req(struct ipath_qp *qp, /* Sending responses has higher priority over sending requests. */ if ((qp->r_head_ack_queue != qp->s_tail_ack_queue || (qp->s_flags & IPATH_S_ACK_PENDING) || - qp->s_ack_state != IB_OPCODE_RC_ACKNOWLEDGE) && + qp->s_ack_state != OP(ACKNOWLEDGE)) && ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p)) goto done; if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) || - qp->s_rnr_timeout) + qp->s_rnr_timeout || qp->s_wait_credit) goto bail; /* Limit the number of packets sent without an ACK. */ if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT) > 0) { qp->s_wait_credit = 1; dev->n_rc_stalls++; - spin_lock(&dev->pending_lock); - if (list_empty(&qp->timerwait)) - list_add_tail(&qp->timerwait, - &dev->pending[dev->pending_index]); - spin_unlock(&dev->pending_lock); goto bail; } @@ -587,9 +582,12 @@ static void send_rc_ack(struct ipath_qp *qp) u32 hwords; struct ipath_ib_header hdr; struct ipath_other_headers *ohdr; + unsigned long flags; /* Don't send ACK or NAK if a RDMA read or atomic is pending. */ - if (qp->r_head_ack_queue != qp->s_tail_ack_queue) + if (qp->r_head_ack_queue != qp->s_tail_ack_queue || + (qp->s_flags & IPATH_S_ACK_PENDING) || + qp->s_ack_state != OP(ACKNOWLEDGE)) goto queue_ack; /* Construct the header. */ @@ -640,11 +638,11 @@ static void send_rc_ack(struct ipath_qp *qp) dev->n_rc_qacks++; queue_ack: - spin_lock_irq(&qp->s_lock); + spin_lock_irqsave(&qp->s_lock, flags); qp->s_flags |= IPATH_S_ACK_PENDING; qp->s_nak_state = qp->r_nak_state; qp->s_ack_psn = qp->r_ack_psn; - spin_unlock_irq(&qp->s_lock); + spin_unlock_irqrestore(&qp->s_lock, flags); /* Call ipath_do_rc_send() in another thread. */ tasklet_hi_schedule(&qp->s_task); @@ -1261,6 +1259,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, wc.dlid_path_bits = 0; wc.port_num = 0; ipath_sqerror_qp(qp, &wc); + spin_unlock_irqrestore(&qp->s_lock, flags); bail: return; } @@ -1294,6 +1293,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, struct ipath_ack_entry *e; u8 i, prev; int old_req; + unsigned long flags; if (diff > 0) { /* @@ -1327,7 +1327,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, psn &= IPATH_PSN_MASK; e = NULL; old_req = 1; - spin_lock_irq(&qp->s_lock); + spin_lock_irqsave(&qp->s_lock, flags); for (i = qp->r_head_ack_queue; ; i = prev) { if (i == qp->s_tail_ack_queue) old_req = 0; @@ -1425,7 +1425,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, * after all the previous RDMA reads and atomics. */ if (i == qp->r_head_ack_queue) { - spin_unlock_irq(&qp->s_lock); + spin_unlock_irqrestore(&qp->s_lock, flags); qp->r_nak_state = 0; qp->r_ack_psn = qp->r_psn - 1; goto send_ack; @@ -1439,11 +1439,10 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, break; } qp->r_nak_state = 0; - spin_unlock_irq(&qp->s_lock); tasklet_hi_schedule(&qp->s_task); unlock_done: - spin_unlock_irq(&qp->s_lock); + spin_unlock_irqrestore(&qp->s_lock, flags); done: return 1; @@ -1453,10 +1452,12 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err) { - spin_lock_irq(&qp->s_lock); + unsigned long flags; + + spin_lock_irqsave(&qp->s_lock, flags); qp->state = IB_QPS_ERR; ipath_error_qp(qp, err); - spin_unlock_irq(&qp->s_lock); + spin_unlock_irqrestore(&qp->s_lock, flags); } /** diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_srq.c b/trunk/drivers/infiniband/hw/ipath/ipath_srq.c index 94033503400c..03acae66ba81 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_srq.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_srq.c @@ -139,33 +139,24 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd, * See ipath_mmap() for details. */ if (udata && udata->outlen >= sizeof(__u64)) { - struct ipath_mmap_info *ip; - __u64 offset = (__u64) srq->rq.wq; int err; + u32 s = sizeof(struct ipath_rwq) + srq->rq.size * sz; - err = ib_copy_to_udata(udata, &offset, sizeof(offset)); - if (err) { - ret = ERR_PTR(err); + srq->ip = + ipath_create_mmap_info(dev, s, + ibpd->uobject->context, + srq->rq.wq); + if (!srq->ip) { + ret = ERR_PTR(-ENOMEM); goto bail_wq; } - /* Allocate info for ipath_mmap(). */ - ip = kmalloc(sizeof(*ip), GFP_KERNEL); - if (!ip) { - ret = ERR_PTR(-ENOMEM); - goto bail_wq; + err = ib_copy_to_udata(udata, &srq->ip->offset, + sizeof(srq->ip->offset)); + if (err) { + ret = ERR_PTR(err); + goto bail_ip; } - srq->ip = ip; - ip->context = ibpd->uobject->context; - ip->obj = srq->rq.wq; - kref_init(&ip->ref); - ip->mmap_cnt = 0; - ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) + - srq->rq.size * sz); - spin_lock_irq(&dev->pending_lock); - ip->next = dev->pending_mmaps; - dev->pending_mmaps = ip; - spin_unlock_irq(&dev->pending_lock); } else srq->ip = NULL; @@ -181,21 +172,27 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd, if (dev->n_srqs_allocated == ib_ipath_max_srqs) { spin_unlock(&dev->n_srqs_lock); ret = ERR_PTR(-ENOMEM); - goto bail_wq; + goto bail_ip; } dev->n_srqs_allocated++; spin_unlock(&dev->n_srqs_lock); + if (srq->ip) { + spin_lock_irq(&dev->pending_lock); + list_add(&srq->ip->pending_mmaps, &dev->pending_mmaps); + spin_unlock_irq(&dev->pending_lock); + } + ret = &srq->ibsrq; goto done; +bail_ip: + kfree(srq->ip); bail_wq: vfree(srq->rq.wq); - bail_srq: kfree(srq); - done: return ret; } @@ -312,13 +309,13 @@ int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, if (srq->ip) { struct ipath_mmap_info *ip = srq->ip; struct ipath_ibdev *dev = to_idev(srq->ibsrq.device); + u32 s = sizeof(struct ipath_rwq) + size * sz; - ip->obj = wq; - ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) + - size * sz); + ipath_update_mmap_info(dev, ip, s, wq); spin_lock_irq(&dev->pending_lock); - ip->next = dev->pending_mmaps; - dev->pending_mmaps = ip; + if (list_empty(&ip->pending_mmaps)) + list_add(&ip->pending_mmaps, + &dev->pending_mmaps); spin_unlock_irq(&dev->pending_lock); } } else if (attr_mask & IB_SRQ_LIMIT) { diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c index 18c6df2052c2..12933e77c7e9 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -1476,7 +1476,10 @@ int ipath_register_ib_device(struct ipath_devdata *dd) ret = -ENOMEM; goto err_lk; } + INIT_LIST_HEAD(&idev->pending_mmaps); spin_lock_init(&idev->pending_lock); + idev->mmap_offset = PAGE_SIZE; + spin_lock_init(&idev->mmap_offset_lock); INIT_LIST_HEAD(&idev->pending[0]); INIT_LIST_HEAD(&idev->pending[1]); INIT_LIST_HEAD(&idev->pending[2]); @@ -1558,6 +1561,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd) (1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV); dev->node_type = RDMA_NODE_IB_CA; dev->phys_port_cnt = 1; + dev->num_comp_vectors = 1; dev->dma_device = &dd->pcidev->dev; dev->query_device = ipath_query_device; dev->modify_device = ipath_modify_device; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h index 7c4929f1cb5b..7064fc222727 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -173,12 +173,12 @@ struct ipath_ah { * this as its vm_private_data. */ struct ipath_mmap_info { - struct ipath_mmap_info *next; + struct list_head pending_mmaps; struct ib_ucontext *context; void *obj; + __u64 offset; struct kref ref; unsigned size; - unsigned mmap_cnt; }; /* @@ -422,7 +422,7 @@ struct ipath_qp { #define IPATH_S_RDMAR_PENDING 0x04 #define IPATH_S_ACK_PENDING 0x08 -#define IPATH_PSN_CREDIT 2048 +#define IPATH_PSN_CREDIT 512 /* * Since struct ipath_swqe is not a fixed size, we can't simply index into @@ -485,9 +485,10 @@ struct ipath_opcode_stats { struct ipath_ibdev { struct ib_device ibdev; - struct list_head dev_list; struct ipath_devdata *dd; - struct ipath_mmap_info *pending_mmaps; + struct list_head pending_mmaps; + spinlock_t mmap_offset_lock; + u32 mmap_offset; int ib_unit; /* This is the device number */ u16 sm_lid; /* in host order */ u8 sm_sl; @@ -734,13 +735,13 @@ int ipath_destroy_srq(struct ib_srq *ibsrq); int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry); -struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, +struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector, struct ib_ucontext *context, struct ib_udata *udata); int ipath_destroy_cq(struct ib_cq *ibcq); -int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify); +int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags); int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata); @@ -768,6 +769,15 @@ int ipath_dealloc_fmr(struct ib_fmr *ibfmr); void ipath_release_mmap_info(struct kref *ref); +struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev, + u32 size, + struct ib_ucontext *context, + void *obj); + +void ipath_update_mmap_info(struct ipath_ibdev *dev, + struct ipath_mmap_info *ip, + u32 size, void *obj); + int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev); diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_cq.c b/trunk/drivers/infiniband/hw/mthca/mthca_cq.c index efd79ef109a6..cf0868f6e965 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_cq.c @@ -726,11 +726,12 @@ int mthca_poll_cq(struct ib_cq *ibcq, int num_entries, return err == 0 || err == -EAGAIN ? npolled : err; } -int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify) +int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags) { __be32 doorbell[2]; - doorbell[0] = cpu_to_be32((notify == IB_CQ_SOLICITED ? + doorbell[0] = cpu_to_be32(((flags & IB_CQ_SOLICITED_MASK) == + IB_CQ_SOLICITED ? MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL : MTHCA_TAVOR_CQ_DB_REQ_NOT) | to_mcq(cq)->cqn); @@ -743,7 +744,7 @@ int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify) return 0; } -int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) +int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) { struct mthca_cq *cq = to_mcq(ibcq); __be32 doorbell[2]; @@ -755,7 +756,8 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) doorbell[0] = ci; doorbell[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) | - (notify == IB_CQ_SOLICITED ? 1 : 2)); + ((flags & IB_CQ_SOLICITED_MASK) == + IB_CQ_SOLICITED ? 1 : 2)); mthca_write_db_rec(doorbell, cq->arm_db); @@ -766,7 +768,7 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) wmb(); doorbell[0] = cpu_to_be32((sn << 28) | - (notify == IB_CQ_SOLICITED ? + ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL : MTHCA_ARBEL_CQ_DB_REQ_NOT) | cq->cqn); diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_dev.h b/trunk/drivers/infiniband/hw/mthca/mthca_dev.h index b7e42efaf43d..9bae3cc60603 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/trunk/drivers/infiniband/hw/mthca/mthca_dev.h @@ -495,8 +495,8 @@ void mthca_unmap_eq_icm(struct mthca_dev *dev); int mthca_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry); -int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify); -int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify); +int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags); +int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags); int mthca_init_cq(struct mthca_dev *dev, int nent, struct mthca_ucontext *ctx, u32 pdn, struct mthca_cq *cq); diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_provider.c b/trunk/drivers/infiniband/hw/mthca/mthca_provider.c index 47e6fd46d9c2..1c05486c3c68 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_provider.c @@ -663,6 +663,7 @@ static int mthca_destroy_qp(struct ib_qp *qp) } static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries, + int comp_vector, struct ib_ucontext *context, struct ib_udata *udata) { @@ -1292,6 +1293,7 @@ int mthca_register_device(struct mthca_dev *dev) (1ull << IB_USER_VERBS_CMD_DETACH_MCAST); dev->ib_dev.node_type = RDMA_NODE_IB_CA; dev->ib_dev.phys_port_cnt = dev->limits.num_ports; + dev->ib_dev.num_comp_vectors = 1; dev->ib_dev.dma_device = &dev->pdev->dev; dev->ib_dev.query_device = mthca_query_device; dev->ib_dev.query_port = mthca_query_port; diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_qp.c b/trunk/drivers/infiniband/hw/mthca/mthca_qp.c index 8fe6fee7a97a..fee60c852d14 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_qp.c @@ -701,6 +701,19 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH); } + if (ibqp->qp_type == IB_QPT_RC && + cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) { + u8 sched_queue = ibqp->uobject ? 0x2 : 0x1; + + if (mthca_is_memfree(dev)) + qp_context->rlkey_arbel_sched_queue |= sched_queue; + else + qp_context->tavor_sched_queue |= cpu_to_be32(sched_queue); + + qp_param->opt_param_mask |= + cpu_to_be32(MTHCA_QP_OPTPAR_SCHED_QUEUE); + } + if (attr_mask & IB_QP_TIMEOUT) { qp_context->pri_path.ackto = attr->timeout << 3; qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ACK_TIMEOUT); diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib.h b/trunk/drivers/infiniband/ulp/ipoib/ipoib.h index d8f6bb4f53fc..87310eeb6df0 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib.h @@ -310,6 +310,7 @@ extern struct workqueue_struct *ipoib_workqueue; /* functions */ +int ipoib_poll(struct net_device *dev, int *budget); void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr); struct ipoib_ah *ipoib_create_ah(struct net_device *dev, diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 0c4e59b906cd..785bc8505f2a 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -370,7 +370,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) if (!likely(wr_id & IPOIB_CM_RX_UPDATE_MASK)) { p = wc->qp->qp_context; - if (time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) { + if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) { spin_lock_irqsave(&priv->lock, flags); p->jiffies = jiffies; /* Move this entry to list head, but do @@ -416,7 +416,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) skb->dev = dev; /* XXX get correct PACKET_ type here */ skb->pkt_type = PACKET_HOST; - netif_rx_ni(skb); + netif_receive_skb(skb); repost: if (unlikely(ipoib_cm_post_receive(dev, wr_id))) @@ -592,7 +592,9 @@ int ipoib_cm_dev_open(struct net_device *dev) priv->cm.id = ib_create_cm_id(priv->ca, ipoib_cm_rx_handler, dev); if (IS_ERR(priv->cm.id)) { printk(KERN_WARNING "%s: failed to create CM ID\n", priv->ca->name); - return IS_ERR(priv->cm.id); + ret = PTR_ERR(priv->cm.id); + priv->cm.id = NULL; + return ret; } ret = ib_cm_listen(priv->cm.id, cpu_to_be64(IPOIB_CM_IETF_ID | priv->qp->qp_num), @@ -601,6 +603,7 @@ int ipoib_cm_dev_open(struct net_device *dev) printk(KERN_WARNING "%s: failed to listen on ID 0x%llx\n", priv->ca->name, IPOIB_CM_IETF_ID | priv->qp->qp_num); ib_destroy_cm_id(priv->cm.id); + priv->cm.id = NULL; return ret; } return 0; @@ -611,10 +614,11 @@ void ipoib_cm_dev_stop(struct net_device *dev) struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_cm_rx *p; - if (!IPOIB_CM_SUPPORTED(dev->dev_addr)) + if (!IPOIB_CM_SUPPORTED(dev->dev_addr) || !priv->cm.id) return; ib_destroy_cm_id(priv->cm.id); + priv->cm.id = NULL; spin_lock_irq(&priv->lock); while (!list_empty(&priv->cm.passive_ids)) { p = list_entry(priv->cm.passive_ids.next, typeof(*p), list); @@ -789,7 +793,7 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn, } p->cq = ib_create_cq(priv->ca, ipoib_cm_tx_completion, NULL, p, - ipoib_sendq_size + 1); + ipoib_sendq_size + 1, 0); if (IS_ERR(p->cq)) { ret = PTR_ERR(p->cq); ipoib_warn(priv, "failed to allocate tx cq: %d\n", ret); diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 1bdb9101911a..68d72c6f7ffb 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -226,7 +226,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) skb->dev = dev; /* XXX get correct PACKET_ type here */ skb->pkt_type = PACKET_HOST; - netif_rx_ni(skb); + netif_receive_skb(skb); } else { ipoib_dbg_data(priv, "dropping loopback packet\n"); dev_kfree_skb_any(skb); @@ -280,28 +280,63 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) wc->status, wr_id, wc->vendor_err); } -static void ipoib_ib_handle_wc(struct net_device *dev, struct ib_wc *wc) +int ipoib_poll(struct net_device *dev, int *budget) { - if (wc->wr_id & IPOIB_CM_OP_SRQ) - ipoib_cm_handle_rx_wc(dev, wc); - else if (wc->wr_id & IPOIB_OP_RECV) - ipoib_ib_handle_rx_wc(dev, wc); - else - ipoib_ib_handle_tx_wc(dev, wc); + struct ipoib_dev_priv *priv = netdev_priv(dev); + int max = min(*budget, dev->quota); + int done; + int t; + int empty; + int n, i; + + done = 0; + empty = 0; + + while (max) { + t = min(IPOIB_NUM_WC, max); + n = ib_poll_cq(priv->cq, t, priv->ibwc); + + for (i = 0; i < n; ++i) { + struct ib_wc *wc = priv->ibwc + i; + + if (wc->wr_id & IPOIB_CM_OP_SRQ) { + ++done; + --max; + ipoib_cm_handle_rx_wc(dev, wc); + } else if (wc->wr_id & IPOIB_OP_RECV) { + ++done; + --max; + ipoib_ib_handle_rx_wc(dev, wc); + } else + ipoib_ib_handle_tx_wc(dev, wc); + } + + if (n != t) { + empty = 1; + break; + } + } + + dev->quota -= done; + *budget -= done; + + if (empty) { + netif_rx_complete(dev); + if (unlikely(ib_req_notify_cq(priv->cq, + IB_CQ_NEXT_COMP | + IB_CQ_REPORT_MISSED_EVENTS)) && + netif_rx_reschedule(dev, 0)) + return 1; + + return 0; + } + + return 1; } void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr) { - struct net_device *dev = (struct net_device *) dev_ptr; - struct ipoib_dev_priv *priv = netdev_priv(dev); - int n, i; - - ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); - do { - n = ib_poll_cq(cq, IPOIB_NUM_WC, priv->ibwc); - for (i = 0; i < n; ++i) - ipoib_ib_handle_wc(dev, priv->ibwc + i); - } while (n == IPOIB_NUM_WC); + netif_rx_schedule(dev_ptr); } static inline int post_send(struct ipoib_dev_priv *priv, @@ -514,9 +549,10 @@ int ipoib_ib_dev_stop(struct net_device *dev) struct ib_qp_attr qp_attr; unsigned long begin; struct ipoib_tx_buf *tx_req; - int i; + int i, n; clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags); + netif_poll_disable(dev); ipoib_cm_dev_stop(dev); @@ -568,6 +604,18 @@ int ipoib_ib_dev_stop(struct net_device *dev) goto timeout; } + do { + n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc); + for (i = 0; i < n; ++i) { + if (priv->ibwc[i].wr_id & IPOIB_CM_OP_SRQ) + ipoib_cm_handle_rx_wc(dev, priv->ibwc + i); + else if (priv->ibwc[i].wr_id & IPOIB_OP_RECV) + ipoib_ib_handle_rx_wc(dev, priv->ibwc + i); + else + ipoib_ib_handle_tx_wc(dev, priv->ibwc + i); + } + } while (n == IPOIB_NUM_WC); + msleep(1); } @@ -596,6 +644,9 @@ int ipoib_ib_dev_stop(struct net_device *dev) msleep(1); } + netif_poll_enable(dev); + ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP); + return 0; } diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c index b4c380c5a3ba..0a428f2b05c7 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -948,6 +948,8 @@ static void ipoib_setup(struct net_device *dev) dev->hard_header = ipoib_hard_header; dev->set_multicast_list = ipoib_set_mcast_list; dev->neigh_setup = ipoib_neigh_setup_dev; + dev->poll = ipoib_poll; + dev->weight = 100; dev->watchdog_timeo = HZ; diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 7f3ec205e35f..5c3c6a43a52b 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -187,7 +187,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) if (!ret) size += ipoib_recvq_size; - priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size); + priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0); if (IS_ERR(priv->cq)) { printk(KERN_WARNING "%s: failed to create CQ\n", ca->name); goto out_free_mr; diff --git a/trunk/drivers/infiniband/ulp/iser/iser_verbs.c b/trunk/drivers/infiniband/ulp/iser/iser_verbs.c index 1fc967464a28..3702e2375553 100644 --- a/trunk/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/trunk/drivers/infiniband/ulp/iser/iser_verbs.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -76,7 +75,7 @@ static int iser_create_device_ib_res(struct iser_device *device) iser_cq_callback, iser_cq_event_callback, (void *)device, - ISER_MAX_CQ_LEN); + ISER_MAX_CQ_LEN, 0); if (IS_ERR(device->cq)) goto cq_err; diff --git a/trunk/drivers/infiniband/ulp/srp/ib_srp.c b/trunk/drivers/infiniband/ulp/srp/ib_srp.c index 5e8ac577f0ad..39bf057fbc43 100644 --- a/trunk/drivers/infiniband/ulp/srp/ib_srp.c +++ b/trunk/drivers/infiniband/ulp/srp/ib_srp.c @@ -197,7 +197,7 @@ static int srp_create_target_ib(struct srp_target_port *target) return -ENOMEM; target->cq = ib_create_cq(target->srp_host->dev->dev, srp_completion, - NULL, target, SRP_CQ_SIZE); + NULL, target, SRP_CQ_SIZE, 0); if (IS_ERR(target->cq)) { ret = PTR_ERR(target->cq); goto out; @@ -1468,6 +1468,25 @@ static ssize_t show_dgid(struct class_device *cdev, char *buf) be16_to_cpu(((__be16 *) target->path.dgid.raw)[7])); } +static ssize_t show_orig_dgid(struct class_device *cdev, char *buf) +{ + struct srp_target_port *target = host_to_target(class_to_shost(cdev)); + + if (target->state == SRP_TARGET_DEAD || + target->state == SRP_TARGET_REMOVED) + return -ENODEV; + + return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + be16_to_cpu(target->orig_dgid[0]), + be16_to_cpu(target->orig_dgid[1]), + be16_to_cpu(target->orig_dgid[2]), + be16_to_cpu(target->orig_dgid[3]), + be16_to_cpu(target->orig_dgid[4]), + be16_to_cpu(target->orig_dgid[5]), + be16_to_cpu(target->orig_dgid[6]), + be16_to_cpu(target->orig_dgid[7])); +} + static ssize_t show_zero_req_lim(struct class_device *cdev, char *buf) { struct srp_target_port *target = host_to_target(class_to_shost(cdev)); @@ -1498,6 +1517,7 @@ static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL); static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL); static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL); +static CLASS_DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL); static CLASS_DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL); static CLASS_DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL); static CLASS_DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL); @@ -1508,6 +1528,7 @@ static struct class_device_attribute *srp_host_attrs[] = { &class_device_attr_service_id, &class_device_attr_pkey, &class_device_attr_dgid, + &class_device_attr_orig_dgid, &class_device_attr_zero_req_lim, &class_device_attr_local_ib_port, &class_device_attr_local_ib_device, @@ -1516,7 +1537,8 @@ static struct class_device_attribute *srp_host_attrs[] = { static struct scsi_host_template srp_template = { .module = THIS_MODULE, - .name = DRV_NAME, + .name = "InfiniBand SRP initiator", + .proc_name = DRV_NAME, .info = srp_target_info, .queuecommand = srp_queuecommand, .eh_abort_handler = srp_abort, @@ -1662,6 +1684,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16); } kfree(p); + memcpy(target->orig_dgid, target->path.dgid.raw, 16); break; case SRP_OPT_PKEY: diff --git a/trunk/drivers/infiniband/ulp/srp/ib_srp.h b/trunk/drivers/infiniband/ulp/srp/ib_srp.h index 2f3319c719a5..1d53c7bc368f 100644 --- a/trunk/drivers/infiniband/ulp/srp/ib_srp.h +++ b/trunk/drivers/infiniband/ulp/srp/ib_srp.h @@ -129,6 +129,7 @@ struct srp_target_port { unsigned int scsi_id; struct ib_sa_path_rec path; + __be16 orig_dgid[8]; struct ib_sa_query *path_query; int path_query_id; diff --git a/trunk/drivers/input/Kconfig b/trunk/drivers/input/Kconfig index 96232313b1b9..0e9b69535ad6 100644 --- a/trunk/drivers/input/Kconfig +++ b/trunk/drivers/input/Kconfig @@ -153,6 +153,8 @@ source "drivers/input/mouse/Kconfig" source "drivers/input/joystick/Kconfig" +source "drivers/input/tablet/Kconfig" + source "drivers/input/touchscreen/Kconfig" source "drivers/input/misc/Kconfig" diff --git a/trunk/drivers/input/Makefile b/trunk/drivers/input/Makefile index b4cd10653c4f..8a2dd987546c 100644 --- a/trunk/drivers/input/Makefile +++ b/trunk/drivers/input/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_INPUT_EVBUG) += evbug.o obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/ obj-$(CONFIG_INPUT_MOUSE) += mouse/ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ +obj-$(CONFIG_INPUT_TABLET) += tablet/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ diff --git a/trunk/drivers/input/evdev.c b/trunk/drivers/input/evdev.c index 1f6fcec0c6fc..55a72592704c 100644 --- a/trunk/drivers/input/evdev.c +++ b/trunk/drivers/input/evdev.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -512,7 +511,7 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { - long *bits; + unsigned long *bits; int len; switch (_IOC_NR(cmd) & EV_MAX) { @@ -557,7 +556,7 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { - int t = _IOC_NR(cmd) & ABS_MAX; + t = _IOC_NR(cmd) & ABS_MAX; abs.value = dev->abs[t]; abs.minimum = dev->absmin[t]; @@ -577,7 +576,7 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { - int t = _IOC_NR(cmd) & ABS_MAX; + t = _IOC_NR(cmd) & ABS_MAX; if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) return -EFAULT; diff --git a/trunk/drivers/input/ff-core.c b/trunk/drivers/input/ff-core.c index 783b3412cead..eebc72465fc9 100644 --- a/trunk/drivers/input/ff-core.c +++ b/trunk/drivers/input/ff-core.c @@ -281,7 +281,8 @@ int input_ff_event(struct input_dev *dev, unsigned int type, break; default: - ff->playback(dev, code, value); + if (check_effect_access(ff, code, NULL) == 0) + ff->playback(dev, code, value); break; } diff --git a/trunk/drivers/input/input.c b/trunk/drivers/input/input.c index 915e9ab7cab0..ccd8abafcb70 100644 --- a/trunk/drivers/input/input.c +++ b/trunk/drivers/input/input.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include diff --git a/trunk/drivers/input/joydev.c b/trunk/drivers/input/joydev.c index 9bcc5425049b..06f0541b24da 100644 --- a/trunk/drivers/input/joydev.c +++ b/trunk/drivers/input/joydev.c @@ -24,7 +24,6 @@ #include #include #include -#include #include MODULE_AUTHOR("Vojtech Pavlik "); diff --git a/trunk/drivers/input/joystick/Kconfig b/trunk/drivers/input/joystick/Kconfig index 271263443c37..82f563e24fdb 100644 --- a/trunk/drivers/input/joystick/Kconfig +++ b/trunk/drivers/input/joystick/Kconfig @@ -2,7 +2,7 @@ # Joystick driver configuration # menuconfig INPUT_JOYSTICK - bool "Joysticks" + bool "Joysticks/Gamepads" help If you have a joystick, 6dof controller, gamepad, steering wheel, weapon control system or something like that you can say Y here @@ -196,7 +196,7 @@ config JOYSTICK_TWIDJOY config JOYSTICK_DB9 tristate "Multisystem, Sega Genesis, Saturn joysticks and gamepads" depends on PARPORT - ---help--- + help Say Y here if you have a Sega Master System gamepad, Sega Genesis gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga, Commodore, Amstrad CPC joystick connected to your parallel port. @@ -253,4 +253,18 @@ config JOYSTICK_JOYDUMP To compile this driver as a module, choose M here: the module will be called joydump. +config JOYSTICK_XPAD + tristate "X-Box gamepad support" + select USB + help + Say Y here if you want to use the X-Box pad with your computer. + Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV) + and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well. + + For information about how to connect the X-Box pad to USB, see + . + + To compile this driver as a module, choose M here: the + module will be called xpad. + endif diff --git a/trunk/drivers/input/joystick/Makefile b/trunk/drivers/input/joystick/Makefile index 5231f6ff75b8..e855abb0cc51 100644 --- a/trunk/drivers/input/joystick/Makefile +++ b/trunk/drivers/input/joystick/Makefile @@ -26,5 +26,6 @@ obj-$(CONFIG_JOYSTICK_TMDC) += tmdc.o obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o obj-$(CONFIG_JOYSTICK_TWIDJOY) += twidjoy.o obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o +obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o obj-$(CONFIG_JOYSTICK_IFORCE) += iforce/ diff --git a/trunk/drivers/input/joystick/analog.c b/trunk/drivers/input/joystick/analog.c index 1c1afb5d4684..bdd157c1ebf8 100644 --- a/trunk/drivers/input/joystick/analog.c +++ b/trunk/drivers/input/joystick/analog.c @@ -53,7 +53,7 @@ MODULE_LICENSE("GPL"); #define ANALOG_PORTS 16 static char *js[ANALOG_PORTS]; -static int js_nargs; +static unsigned int js_nargs; static int analog_options[ANALOG_PORTS]; module_param_array_named(map, js, charp, &js_nargs, 0); MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities"); diff --git a/trunk/drivers/input/joystick/db9.c b/trunk/drivers/input/joystick/db9.c index c27593bf9978..86ad1027e12a 100644 --- a/trunk/drivers/input/joystick/db9.c +++ b/trunk/drivers/input/joystick/db9.c @@ -46,17 +46,17 @@ MODULE_LICENSE("GPL"); struct db9_config { int args[2]; - int nargs; + unsigned int nargs; }; #define DB9_MAX_PORTS 3 -static struct db9_config db9[DB9_MAX_PORTS] __initdata; +static struct db9_config db9_cfg[DB9_MAX_PORTS] __initdata; -module_param_array_named(dev, db9[0].args, int, &db9[0].nargs, 0); +module_param_array_named(dev, db9_cfg[0].args, int, &db9_cfg[0].nargs, 0); MODULE_PARM_DESC(dev, "Describes first attached device (,)"); -module_param_array_named(dev2, db9[1].args, int, &db9[0].nargs, 0); +module_param_array_named(dev2, db9_cfg[1].args, int, &db9_cfg[0].nargs, 0); MODULE_PARM_DESC(dev2, "Describes second attached device (,)"); -module_param_array_named(dev3, db9[2].args, int, &db9[2].nargs, 0); +module_param_array_named(dev3, db9_cfg[2].args, int, &db9_cfg[2].nargs, 0); MODULE_PARM_DESC(dev3, "Describes third attached device (,)"); #define DB9_ARG_PARPORT 0 @@ -680,17 +680,17 @@ static int __init db9_init(void) int err = 0; for (i = 0; i < DB9_MAX_PORTS; i++) { - if (db9[i].nargs == 0 || db9[i].args[DB9_ARG_PARPORT] < 0) + if (db9_cfg[i].nargs == 0 || db9_cfg[i].args[DB9_ARG_PARPORT] < 0) continue; - if (db9[i].nargs < 2) { + if (db9_cfg[i].nargs < 2) { printk(KERN_ERR "db9.c: Device type must be specified.\n"); err = -EINVAL; break; } - db9_base[i] = db9_probe(db9[i].args[DB9_ARG_PARPORT], - db9[i].args[DB9_ARG_MODE]); + db9_base[i] = db9_probe(db9_cfg[i].args[DB9_ARG_PARPORT], + db9_cfg[i].args[DB9_ARG_MODE]); if (IS_ERR(db9_base[i])) { err = PTR_ERR(db9_base[i]); break; diff --git a/trunk/drivers/input/joystick/gamecon.c b/trunk/drivers/input/joystick/gamecon.c index c71b58fe225d..1a452e0e5f25 100644 --- a/trunk/drivers/input/joystick/gamecon.c +++ b/trunk/drivers/input/joystick/gamecon.c @@ -48,16 +48,16 @@ MODULE_LICENSE("GPL"); struct gc_config { int args[GC_MAX_DEVICES + 1]; - int nargs; + unsigned int nargs; }; -static struct gc_config gc[GC_MAX_PORTS] __initdata; +static struct gc_config gc_cfg[GC_MAX_PORTS] __initdata; -module_param_array_named(map, gc[0].args, int, &gc[0].nargs, 0); +module_param_array_named(map, gc_cfg[0].args, int, &gc_cfg[0].nargs, 0); MODULE_PARM_DESC(map, "Describes first set of devices (,,,..)"); -module_param_array_named(map2, gc[1].args, int, &gc[1].nargs, 0); +module_param_array_named(map2, gc_cfg[1].args, int, &gc_cfg[1].nargs, 0); MODULE_PARM_DESC(map2, "Describes second set of devices"); -module_param_array_named(map3, gc[2].args, int, &gc[2].nargs, 0); +module_param_array_named(map3, gc_cfg[2].args, int, &gc_cfg[2].nargs, 0); MODULE_PARM_DESC(map3, "Describes third set of devices"); /* see also gs_psx_delay parameter in PSX support section */ @@ -810,16 +810,17 @@ static int __init gc_init(void) int err = 0; for (i = 0; i < GC_MAX_PORTS; i++) { - if (gc[i].nargs == 0 || gc[i].args[0] < 0) + if (gc_cfg[i].nargs == 0 || gc_cfg[i].args[0] < 0) continue; - if (gc[i].nargs < 2) { + if (gc_cfg[i].nargs < 2) { printk(KERN_ERR "gamecon.c: at least one device must be specified\n"); err = -EINVAL; break; } - gc_base[i] = gc_probe(gc[i].args[0], gc[i].args + 1, gc[i].nargs - 1); + gc_base[i] = gc_probe(gc_cfg[i].args[0], + gc_cfg[i].args + 1, gc_cfg[i].nargs - 1); if (IS_ERR(gc_base[i])) { err = PTR_ERR(gc_base[i]); break; diff --git a/trunk/drivers/input/joystick/iforce/iforce.h b/trunk/drivers/input/joystick/iforce/iforce.h index dadcf4fb92ae..40a853ac21c7 100644 --- a/trunk/drivers/input/joystick/iforce/iforce.h +++ b/trunk/drivers/input/joystick/iforce/iforce.h @@ -124,7 +124,7 @@ struct iforce { /* Buffer used for asynchronous sending of bytes to the device */ struct circ_buf xmit; unsigned char xmit_data[XMIT_SIZE]; - long xmit_flags[1]; + unsigned long xmit_flags[1]; /* Force Feedback */ wait_queue_head_t wait; diff --git a/trunk/drivers/input/joystick/turbografx.c b/trunk/drivers/input/joystick/turbografx.c index 0f2c60823b0b..8381c6f14373 100644 --- a/trunk/drivers/input/joystick/turbografx.c +++ b/trunk/drivers/input/joystick/turbografx.c @@ -48,16 +48,16 @@ MODULE_LICENSE("GPL"); struct tgfx_config { int args[TGFX_MAX_DEVICES + 1]; - int nargs; + unsigned int nargs; }; -static struct tgfx_config tgfx[TGFX_MAX_PORTS] __initdata; +static struct tgfx_config tgfx_cfg[TGFX_MAX_PORTS] __initdata; -module_param_array_named(map, tgfx[0].args, int, &tgfx[0].nargs, 0); +module_param_array_named(map, tgfx_cfg[0].args, int, &tgfx_cfg[0].nargs, 0); MODULE_PARM_DESC(map, "Describes first set of devices (,,,.."); -module_param_array_named(map2, tgfx[1].args, int, &tgfx[1].nargs, 0); +module_param_array_named(map2, tgfx_cfg[1].args, int, &tgfx_cfg[1].nargs, 0); MODULE_PARM_DESC(map2, "Describes second set of devices"); -module_param_array_named(map3, tgfx[2].args, int, &tgfx[2].nargs, 0); +module_param_array_named(map3, tgfx_cfg[2].args, int, &tgfx_cfg[2].nargs, 0); MODULE_PARM_DESC(map3, "Describes third set of devices"); #define TGFX_REFRESH_TIME HZ/100 /* 10 ms */ @@ -283,16 +283,18 @@ static int __init tgfx_init(void) int err = 0; for (i = 0; i < TGFX_MAX_PORTS; i++) { - if (tgfx[i].nargs == 0 || tgfx[i].args[0] < 0) + if (tgfx_cfg[i].nargs == 0 || tgfx_cfg[i].args[0] < 0) continue; - if (tgfx[i].nargs < 2) { + if (tgfx_cfg[i].nargs < 2) { printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n"); err = -EINVAL; break; } - tgfx_base[i] = tgfx_probe(tgfx[i].args[0], tgfx[i].args + 1, tgfx[i].nargs - 1); + tgfx_base[i] = tgfx_probe(tgfx_cfg[i].args[0], + tgfx_cfg[i].args + 1, + tgfx_cfg[i].nargs - 1); if (IS_ERR(tgfx_base[i])) { err = PTR_ERR(tgfx_base[i]); break; diff --git a/trunk/drivers/usb/input/xpad.c b/trunk/drivers/input/joystick/xpad.c similarity index 99% rename from trunk/drivers/usb/input/xpad.c rename to trunk/drivers/input/joystick/xpad.c index 735723912950..8c8cd95a6989 100644 --- a/trunk/drivers/usb/input/xpad.c +++ b/trunk/drivers/input/joystick/xpad.c @@ -74,7 +74,6 @@ #include #include #include -#include #include #define DRIVER_VERSION "v0.0.6" diff --git a/trunk/drivers/input/keyboard/Kconfig b/trunk/drivers/input/keyboard/Kconfig index 9f42e4d3649e..bd707b86c114 100644 --- a/trunk/drivers/input/keyboard/Kconfig +++ b/trunk/drivers/input/keyboard/Kconfig @@ -226,6 +226,7 @@ config KEYBOARD_PXA27x config KEYBOARD_AAED2000 tristate "AAED-2000 keyboard" depends on MACH_AAED2000 + select INPUT_POLLDEV default y help Say Y here to enable the keyboard on the Agilent AAED-2000 diff --git a/trunk/drivers/input/keyboard/aaed2000_kbd.c b/trunk/drivers/input/keyboard/aaed2000_kbd.c index 3a37505f067c..63d6ead6b877 100644 --- a/trunk/drivers/input/keyboard/aaed2000_kbd.c +++ b/trunk/drivers/input/keyboard/aaed2000_kbd.c @@ -14,12 +14,11 @@ #include #include #include -#include +#include #include #include #include #include -#include #include #include @@ -46,8 +45,7 @@ static unsigned char aaedkbd_keycode[NR_SCANCODES] = { struct aaedkbd { unsigned char keycode[ARRAY_SIZE(aaedkbd_keycode)]; - struct input_dev *input; - struct work_struct workq; + struct input_polled_dev *poll_dev; int kbdscan_state[KB_COLS]; int kbdscan_count[KB_COLS]; }; @@ -64,14 +62,15 @@ static void aaedkbd_report_col(struct aaedkbd *aaedkbd, scancode = SCANCODE(row, col); pressed = rowd & KB_ROWMASK(row); - input_report_key(aaedkbd->input, aaedkbd->keycode[scancode], pressed); + input_report_key(aaedkbd->poll_dev->input, + aaedkbd->keycode[scancode], pressed); } } /* Scan the hardware keyboard and push any changes up through the input layer */ -static void aaedkbd_work(void *data) +static void aaedkbd_poll(struct input_polled_dev *dev) { - struct aaedkbd *aaedkbd = data; + struct aaedkbd *aaedkbd = dev->private; unsigned int col, rowd; col = 0; @@ -90,51 +89,34 @@ static void aaedkbd_work(void *data) } while (col < KB_COLS); AAEC_GPIO_KSCAN = 0x07; - input_sync(aaedkbd->input); - - schedule_delayed_work(&aaedkbd->workq, msecs_to_jiffies(SCAN_INTERVAL)); -} - -static int aaedkbd_open(struct input_dev *indev) -{ - struct aaedkbd *aaedkbd = input_get_drvdata(indev); - - schedule_delayed_work(&aaedkbd->workq, msecs_to_jiffies(SCAN_INTERVAL)); - - return 0; -} - -static void aaedkbd_close(struct input_dev *indev) -{ - struct aaedkbd *aaedkbd = input_get_drvdata(indev); - - cancel_delayed_work(&aaedkbd->workq); - flush_scheduled_work(); + input_sync(dev->input); } static int __devinit aaedkbd_probe(struct platform_device *pdev) { struct aaedkbd *aaedkbd; + struct input_polled_dev *poll_dev; struct input_dev *input_dev; int i; int error; aaedkbd = kzalloc(sizeof(struct aaedkbd), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!aaedkbd || !input_dev) { + poll_dev = input_allocate_polled_device(); + if (!aaedkbd || !poll_dev) { error = -ENOMEM; goto fail; } platform_set_drvdata(pdev, aaedkbd); - aaedkbd->input = input_dev; - - /* Init keyboard rescan workqueue */ - INIT_WORK(&aaedkbd->workq, aaedkbd_work, aaedkbd); - + aaedkbd->poll_dev = poll_dev; memcpy(aaedkbd->keycode, aaedkbd_keycode, sizeof(aaedkbd->keycode)); + poll_dev->private = aaedkbd; + poll_dev->poll = aaedkbd_poll; + poll_dev->poll_interval = SCAN_INTERVAL; + + input_dev = poll_dev->input; input_dev->name = "AAED-2000 Keyboard"; input_dev->phys = "aaedkbd/input0"; input_dev->id.bustype = BUS_HOST; @@ -143,8 +125,6 @@ static int __devinit aaedkbd_probe(struct platform_device *pdev) input_dev->id.version = 0x0100; input_dev->dev.parent = &pdev->dev; - input_set_drvdata(input_dev, aaedkbd); - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); input_dev->keycode = aaedkbd->keycode; input_dev->keycodesize = sizeof(unsigned char); @@ -154,17 +134,14 @@ static int __devinit aaedkbd_probe(struct platform_device *pdev) set_bit(aaedkbd->keycode[i], input_dev->keybit); clear_bit(0, input_dev->keybit); - input_dev->open = aaedkbd_open; - input_dev->close = aaedkbd_close; - - error = input_register_device(aaedkbd->input); + error = input_register_polled_device(aaedkbd->poll_dev); if (error) goto fail; return 0; fail: kfree(aaedkbd); - input_free_device(input_dev); + input_free_polled_device(poll_dev); return error; } @@ -172,7 +149,8 @@ static int __devexit aaedkbd_remove(struct platform_device *pdev) { struct aaedkbd *aaedkbd = platform_get_drvdata(pdev); - input_unregister_device(aaedkbd->input); + input_unregister_polled_device(aaedkbd->poll_dev); + input_free_polled_device(aaedkbd->poll_dev); kfree(aaedkbd); return 0; diff --git a/trunk/drivers/input/misc/Kconfig b/trunk/drivers/input/misc/Kconfig index 1d0d3e765db6..6013ace94d98 100644 --- a/trunk/drivers/input/misc/Kconfig +++ b/trunk/drivers/input/misc/Kconfig @@ -40,6 +40,18 @@ config INPUT_M68K_BEEP tristate "M68k Beeper support" depends on M68K +config INPUT_IXP4XX_BEEPER + tristate "IXP4XX Beeper support" + depends on ARCH_IXP4XX + help + If you say yes here, you can connect a beeper to the + ixp4xx gpio pins. This is used by the LinkSys NSLU2. + + If unsure, say Y. + + To compile this driver as a module, choose M here: the + module will be called ixp4xx-beeper. + config INPUT_COBALT_BTNS tristate "Cobalt button interface" depends on MIPS_COBALT @@ -70,17 +82,79 @@ config INPUT_ATLAS_BTNS To compile this driver as a module, choose M here: the module will be called atlas_btns. -config INPUT_IXP4XX_BEEPER - tristate "IXP4XX Beeper support" - depends on ARCH_IXP4XX +config INPUT_ATI_REMOTE + tristate "ATI / X10 USB RF remote control" + select USB help - If you say yes here, you can connect a beeper to the - ixp4xx gpio pins. This is used by the LinkSys NSLU2. + Say Y here if you want to use an ATI or X10 "Lola" USB remote control. + These are RF remotes with USB receivers. + The ATI remote comes with many of ATI's All-In-Wonder video cards. + The X10 "Lola" remote is available at: + + This driver provides mouse pointer, left and right mouse buttons, + and maps all the other remote buttons to keypress events. + + To compile this driver as a module, choose M here: the module will be + called ati_remote. + +config INPUT_ATI_REMOTE2 + tristate "ATI / Philips USB RF remote control" + select USB + help + Say Y here if you want to use an ATI or Philips USB RF remote control. + These are RF remotes with USB receivers. + ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards + and is also available as a separate product. + This driver provides mouse pointer, left and right mouse buttons, + and maps all the other remote buttons to keypress events. + + To compile this driver as a module, choose M here: the module will be + called ati_remote2. + +config INPUT_KEYSPAN_REMOTE + tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" + depends on EXPERIMENTAL + select USB + help + Say Y here if you want to use a Keyspan DMR USB remote control. + Currently only the UIA-11 type of receiver has been tested. The tag + on the receiver that connects to the USB port should have a P/N that + will tell you what type of DMR you have. The UIA-10 type is not + supported at this time. This driver maps all buttons to keypress + events. - If unsure, say Y. + To compile this driver as a module, choose M here: the module will + be called keyspan_remote. + +config INPUT_POWERMATE + tristate "Griffin PowerMate and Contour Jog support" + select USB + help + Say Y here if you want to use Griffin PowerMate or Contour Jog devices. + These are aluminum dials which can measure clockwise and anticlockwise + rotation. The dial also acts as a pushbutton. The base contains an LED + which can be instructed to pulse or to switch to a particular intensity. + + You can download userspace tools from + . To compile this driver as a module, choose M here: the - module will be called ixp4xx-beeper. + module will be called powermate. + +config INPUT_YEALINK + tristate "Yealink usb-p1k voip phone" + depends EXPERIMENTAL + select USB + help + Say Y here if you want to enable keyboard and LCD functions of the + Yealink usb-p1k usb phones. The audio part is enabled by the generic + usb sound driver, so you might want to enable that as well. + + For information about how to use these additional functions, see + . + + To compile this driver as a module, choose M here: the module will be + called yealink. config INPUT_UINPUT tristate "User level driver support" diff --git a/trunk/drivers/input/misc/Makefile b/trunk/drivers/input/misc/Makefile index 21e3cca0d33e..8b2f7799e25c 100644 --- a/trunk/drivers/input/misc/Makefile +++ b/trunk/drivers/input/misc/Makefile @@ -8,9 +8,14 @@ obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o -obj-$(CONFIG_INPUT_UINPUT) += uinput.o +obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o +obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o +obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o +obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o +obj-$(CONFIG_INPUT_POWERMATE) += powermate.o +obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o -obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o +obj-$(CONFIG_INPUT_UINPUT) += uinput.o diff --git a/trunk/drivers/usb/input/ati_remote.c b/trunk/drivers/input/misc/ati_remote.c similarity index 100% rename from trunk/drivers/usb/input/ati_remote.c rename to trunk/drivers/input/misc/ati_remote.c diff --git a/trunk/drivers/usb/input/ati_remote2.c b/trunk/drivers/input/misc/ati_remote2.c similarity index 99% rename from trunk/drivers/usb/input/ati_remote2.c rename to trunk/drivers/input/misc/ati_remote2.c index a9032aa3465f..1031543e5c3f 100644 --- a/trunk/drivers/usb/input/ati_remote2.c +++ b/trunk/drivers/input/misc/ati_remote2.c @@ -405,9 +405,7 @@ static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2) for (i = 0; i < 2; i++) { usb_free_urb(ar2->urb[i]); - - if (ar2->buf[i]) - usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]); + usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]); } } diff --git a/trunk/drivers/usb/input/keyspan_remote.c b/trunk/drivers/input/misc/keyspan_remote.c similarity index 100% rename from trunk/drivers/usb/input/keyspan_remote.c rename to trunk/drivers/input/misc/keyspan_remote.c diff --git a/trunk/drivers/usb/input/map_to_7segment.h b/trunk/drivers/input/misc/map_to_7segment.h similarity index 100% rename from trunk/drivers/usb/input/map_to_7segment.h rename to trunk/drivers/input/misc/map_to_7segment.h diff --git a/trunk/drivers/usb/input/powermate.c b/trunk/drivers/input/misc/powermate.c similarity index 98% rename from trunk/drivers/usb/input/powermate.c rename to trunk/drivers/input/misc/powermate.c index 4f93a760faee..448a470d28f2 100644 --- a/trunk/drivers/usb/input/powermate.c +++ b/trunk/drivers/input/misc/powermate.c @@ -291,12 +291,10 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm) { - if (pm->data) - usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX, - pm->data, pm->data_dma); - if (pm->configcr) - usb_buffer_free(udev, sizeof(*(pm->configcr)), - pm->configcr, pm->configcr_dma); + usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX, + pm->data, pm->data_dma); + usb_buffer_free(udev, sizeof(*(pm->configcr)), + pm->configcr, pm->configcr_dma); } /* Called whenever a USB device matching one in our supported devices table is connected */ diff --git a/trunk/drivers/input/misc/uinput.c b/trunk/drivers/input/misc/uinput.c index 031467eadd31..a56ad4ba8fe2 100644 --- a/trunk/drivers/input/misc/uinput.c +++ b/trunk/drivers/input/misc/uinput.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/input/yealink.c b/trunk/drivers/input/misc/yealink.c similarity index 98% rename from trunk/drivers/usb/input/yealink.c rename to trunk/drivers/input/misc/yealink.c index c54f1a5dcb4a..ab15880fd566 100644 --- a/trunk/drivers/usb/input/yealink.c +++ b/trunk/drivers/input/misc/yealink.c @@ -29,7 +29,7 @@ * This driver is based on: * - the usbb2k-api http://savannah.nongnu.org/projects/usbb2k-api/ * - information from http://memeteau.free.fr/usbb2k - * - the xpad-driver drivers/usb/input/xpad.c + * - the xpad-driver drivers/input/joystick/xpad.c * * Thanks to: * - Olivier Vandorpe, for providing the usbb2k-api. @@ -818,18 +818,17 @@ static int usb_cleanup(struct yealink_dev *yld, int err) else input_unregister_device(yld->idev); } - if (yld->ctl_req) - usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)), - yld->ctl_req, yld->ctl_req_dma); - if (yld->ctl_data) - usb_buffer_free(yld->udev, USB_PKT_LEN, - yld->ctl_data, yld->ctl_dma); - if (yld->irq_data) - usb_buffer_free(yld->udev, USB_PKT_LEN, - yld->irq_data, yld->irq_dma); - - usb_free_urb(yld->urb_irq); /* parameter validation in core/urb */ - usb_free_urb(yld->urb_ctl); /* parameter validation in core/urb */ + + usb_free_urb(yld->urb_irq); + usb_free_urb(yld->urb_ctl); + + usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)), + yld->ctl_req, yld->ctl_req_dma); + usb_buffer_free(yld->udev, USB_PKT_LEN, + yld->ctl_data, yld->ctl_dma); + usb_buffer_free(yld->udev, USB_PKT_LEN, + yld->irq_data, yld->irq_dma); + kfree(yld); return err; } diff --git a/trunk/drivers/usb/input/yealink.h b/trunk/drivers/input/misc/yealink.h similarity index 100% rename from trunk/drivers/usb/input/yealink.h rename to trunk/drivers/input/misc/yealink.h diff --git a/trunk/drivers/input/mouse/Kconfig b/trunk/drivers/input/mouse/Kconfig index 81dd8c7211a7..2ccc114b3ff6 100644 --- a/trunk/drivers/input/mouse/Kconfig +++ b/trunk/drivers/input/mouse/Kconfig @@ -2,7 +2,7 @@ # Mouse driver configuration # menuconfig INPUT_MOUSE - bool "Mouse" + bool "Mice" default y help Say Y here, and a list of supported mice will be displayed. @@ -19,7 +19,7 @@ config MOUSE_PS2 select SERIO_LIBPS2 select SERIO_I8042 if X86_PC select SERIO_GSCPS2 if GSC - ---help--- + help Say Y here if you have a PS/2 mouse connected to your system. This includes the standard 2 or 3-button PS/2 mouse, as well as PS/2 mice with wheels and extra buttons, Microsoft, Logitech or Genius @@ -41,7 +41,7 @@ config MOUSE_PS2_ALPS bool "ALPS PS/2 mouse protocol extension" if EMBEDDED default y depends on MOUSE_PS2 - ---help--- + help Say Y here if you have an ALPS PS/2 touchpad connected to your system. @@ -51,7 +51,7 @@ config MOUSE_PS2_LOGIPS2PP bool "Logictech PS/2++ mouse protocol extension" if EMBEDDED default y depends on MOUSE_PS2 - ---help--- + help Say Y here if you have a Logictech PS/2++ mouse connected to your system. @@ -61,7 +61,7 @@ config MOUSE_PS2_SYNAPTICS bool "Synaptics PS/2 mouse protocol extension" if EMBEDDED default y depends on MOUSE_PS2 - ---help--- + help Say Y here if you have a Synaptics PS/2 TouchPad connected to your system. @@ -71,7 +71,7 @@ config MOUSE_PS2_LIFEBOOK bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED default y depends on MOUSE_PS2 - ---help--- + help Say Y here if you have a Fujitsu B-series Lifebook PS/2 TouchScreen connected to your system. @@ -81,7 +81,7 @@ config MOUSE_PS2_TRACKPOINT bool "IBM Trackpoint PS/2 mouse protocol extension" if EMBEDDED default y depends on MOUSE_PS2 - ---help--- + help Say Y here if you have an IBM Trackpoint PS/2 mouse connected to your system. @@ -90,7 +90,7 @@ config MOUSE_PS2_TRACKPOINT config MOUSE_PS2_TOUCHKIT bool "eGalax TouchKit PS/2 protocol extension" depends on MOUSE_PS2 - ---help--- + help Say Y here if you have an eGalax TouchKit PS/2 touchscreen connected to your system. @@ -99,7 +99,7 @@ config MOUSE_PS2_TOUCHKIT config MOUSE_SERIAL tristate "Serial mouse" select SERIO - ---help--- + help Say Y here if you have a serial (RS-232, COM port) mouse connected to your system. This includes Sun, MouseSystems, Microsoft, Logitech and all other compatible serial mice. @@ -109,6 +109,26 @@ config MOUSE_SERIAL To compile this driver as a module, choose M here: the module will be called sermouse. +config MOUSE_APPLETOUCH + tristate "Apple USB Touchpad support" + select USB + help + Say Y here if you want to use an Apple USB Touchpad. + + These are the touchpads that can be found on post-February 2005 + Apple Powerbooks (prior models have a Synaptics touchpad connected + to the ADB bus). + + This driver provides a basic mouse driver but can be interfaced + with the synaptics X11 driver to provide acceleration and + scrolling in X11. + + For further information, see + . + + To compile this driver as a module, choose M here: the + module will be called appletouch. + config MOUSE_INPORT tristate "InPort/MS/ATIXL busmouse" depends on ISA diff --git a/trunk/drivers/input/mouse/Makefile b/trunk/drivers/input/mouse/Makefile index 6a8f622927f2..aa4ba878533f 100644 --- a/trunk/drivers/input/mouse/Makefile +++ b/trunk/drivers/input/mouse/Makefile @@ -5,6 +5,7 @@ # Each configuration option enables a list of files. obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o +obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o obj-$(CONFIG_MOUSE_INPORT) += inport.o diff --git a/trunk/drivers/usb/input/appletouch.c b/trunk/drivers/input/mouse/appletouch.c similarity index 100% rename from trunk/drivers/usb/input/appletouch.c rename to trunk/drivers/input/mouse/appletouch.c diff --git a/trunk/drivers/input/mouse/synaptics.c b/trunk/drivers/input/mouse/synaptics.c index c77788bf932d..666ad3a53fdb 100644 --- a/trunk/drivers/input/mouse/synaptics.c +++ b/trunk/drivers/input/mouse/synaptics.c @@ -185,7 +185,7 @@ static int synaptics_query_hardware(struct psmouse *psmouse) int retries = 0; while ((retries++ < 3) && psmouse_reset(psmouse)) - printk(KERN_ERR "synaptics reset failed\n"); + /* empty */; if (synaptics_identify(psmouse)) return -1; diff --git a/trunk/drivers/input/mousedev.c b/trunk/drivers/input/mousedev.c index 7678e9876550..8675f9509393 100644 --- a/trunk/drivers/input/mousedev.c +++ b/trunk/drivers/input/mousedev.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/input/serio/i8042.c b/trunk/drivers/input/serio/i8042.c index 7c17377a65b9..3888dc307e0c 100644 --- a/trunk/drivers/input/serio/i8042.c +++ b/trunk/drivers/input/serio/i8042.c @@ -526,6 +526,33 @@ static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * i8042_toggle_aux - enables or disables AUX port on i8042 via command and + * verifies success by readinng CTR. Used when testing for presence of AUX + * port. + */ +static int __devinit i8042_toggle_aux(int on) +{ + unsigned char param; + int i; + + if (i8042_command(¶m, + on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE)) + return -1; + + /* some chips need some time to set the I8042_CTR_AUXDIS bit */ + for (i = 0; i < 100; i++) { + udelay(50); + + if (i8042_command(¶m, I8042_CMD_CTL_RCTR)) + return -1; + + if (!(param & I8042_CTR_AUXDIS) == on) + return 0; + } + + return -1; +} /* * i8042_check_aux() applies as much paranoia as it can at detecting @@ -580,16 +607,12 @@ static int __devinit i8042_check_aux(void) * Bit assignment test - filters out PS/2 i8042's in AT mode */ - if (i8042_command(¶m, I8042_CMD_AUX_DISABLE)) - return -1; - if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) { + if (i8042_toggle_aux(0)) { printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n"); } - if (i8042_command(¶m, I8042_CMD_AUX_ENABLE)) - return -1; - if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS)) + if (i8042_toggle_aux(1)) return -1; /* diff --git a/trunk/drivers/input/tablet/Kconfig b/trunk/drivers/input/tablet/Kconfig new file mode 100644 index 000000000000..12dfb0eb3262 --- /dev/null +++ b/trunk/drivers/input/tablet/Kconfig @@ -0,0 +1,74 @@ +# +# Tablet driver configuration +# +menuconfig INPUT_TABLET + bool "Tablets" + help + Say Y here, and a list of supported tablets will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +if INPUT_TABLET + +config TABLET_USB_ACECAD + tristate "Acecad Flair tablet support (USB)" + select USB + help + Say Y here if you want to use the USB version of the Acecad Flair + tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + To compile this driver as a module, choose M here: the + module will be called acecad. + +config TABLET_USB_AIPTEK + tristate "Aiptek 6000U/8000U tablet support (USB)" + select USB + help + Say Y here if you want to use the USB version of the Aiptek 6000U + or Aiptek 8000U tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + To compile this driver as a module, choose M here: the + module will be called aiptek. + +config TABLET_USB_GTCO + tristate "GTCO CalComp/InterWrite USB Support" + depends on USB && INPUT + help + Say Y here if you want to use the USB version of the GTCO + CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + To compile this driver as a module, choose M here: the + module will be called gtco. + +config TABLET_USB_KBTAB + tristate "KB Gear JamStudio tablet support (USB)" + select USB + help + Say Y here if you want to use the USB version of the KB Gear + JamStudio tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + To compile this driver as a module, choose M here: the + module will be called kbtab. + +config TABLET_USB_WACOM + tristate "Wacom Intuos/Graphire tablet support (USB)" + select USB + help + Say Y here if you want to use the USB version of the Wacom Intuos + or Graphire tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + To compile this driver as a module, choose M here: the + module will be called wacom. + +endif diff --git a/trunk/drivers/input/tablet/Makefile b/trunk/drivers/input/tablet/Makefile new file mode 100644 index 000000000000..ce8b9a9cfa40 --- /dev/null +++ b/trunk/drivers/input/tablet/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the tablet drivers +# + +# Multipart objects. +wacom-objs := wacom_wac.o wacom_sys.o + +obj-$(CONFIG_TABLET_USB_ACECAD) += acecad.o +obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o +obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o +obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o +obj-$(CONFIG_TABLET_USB_WACOM) += wacom.o diff --git a/trunk/drivers/usb/input/acecad.c b/trunk/drivers/input/tablet/acecad.c similarity index 99% rename from trunk/drivers/usb/input/acecad.c rename to trunk/drivers/input/tablet/acecad.c index be8e9243c062..dd2310458c46 100644 --- a/trunk/drivers/usb/input/acecad.c +++ b/trunk/drivers/input/tablet/acecad.c @@ -54,7 +54,7 @@ struct usb_acecad { struct input_dev *input; struct urb *irq; - signed char *data; + unsigned char *data; dma_addr_t data_dma; }; diff --git a/trunk/drivers/usb/input/aiptek.c b/trunk/drivers/input/tablet/aiptek.c similarity index 100% rename from trunk/drivers/usb/input/aiptek.c rename to trunk/drivers/input/tablet/aiptek.c diff --git a/trunk/drivers/usb/input/gtco.c b/trunk/drivers/input/tablet/gtco.c similarity index 100% rename from trunk/drivers/usb/input/gtco.c rename to trunk/drivers/input/tablet/gtco.c diff --git a/trunk/drivers/usb/input/kbtab.c b/trunk/drivers/input/tablet/kbtab.c similarity index 99% rename from trunk/drivers/usb/input/kbtab.c rename to trunk/drivers/input/tablet/kbtab.c index c4781b9d1297..91e6d00d4a43 100644 --- a/trunk/drivers/usb/input/kbtab.c +++ b/trunk/drivers/input/tablet/kbtab.c @@ -29,7 +29,7 @@ module_param(kb_pressure_click, int, 0); MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks"); struct kbtab { - signed char *data; + unsigned char *data; dma_addr_t data_dma; struct input_dev *dev; struct usb_device *usbdev; diff --git a/trunk/drivers/usb/input/wacom.h b/trunk/drivers/input/tablet/wacom.h similarity index 99% rename from trunk/drivers/usb/input/wacom.h rename to trunk/drivers/input/tablet/wacom.h index d85abfc5ab58..ef01a807ec0f 100644 --- a/trunk/drivers/usb/input/wacom.h +++ b/trunk/drivers/input/tablet/wacom.h @@ -1,5 +1,5 @@ /* - * drivers/usb/input/wacom.h + * drivers/input/tablet/wacom.h * * USB Wacom Graphire and Wacom Intuos tablet support * diff --git a/trunk/drivers/usb/input/wacom_sys.c b/trunk/drivers/input/tablet/wacom_sys.c similarity index 99% rename from trunk/drivers/usb/input/wacom_sys.c rename to trunk/drivers/input/tablet/wacom_sys.c index 1fe48208c2f4..83bddef66067 100644 --- a/trunk/drivers/usb/input/wacom_sys.c +++ b/trunk/drivers/input/tablet/wacom_sys.c @@ -1,5 +1,5 @@ /* - * drivers/usb/input/wacom_sys.c + * drivers/input/tablet/wacom_sys.c * * USB Wacom Graphire and Wacom Intuos tablet support - system specific code */ diff --git a/trunk/drivers/usb/input/wacom_wac.c b/trunk/drivers/input/tablet/wacom_wac.c similarity index 99% rename from trunk/drivers/usb/input/wacom_wac.c rename to trunk/drivers/input/tablet/wacom_wac.c index 4f3e9bc7177d..7661f03a2db2 100644 --- a/trunk/drivers/usb/input/wacom_wac.c +++ b/trunk/drivers/input/tablet/wacom_wac.c @@ -1,5 +1,5 @@ /* - * drivers/usb/input/wacom_wac.c + * drivers/input/tablet/wacom_wac.c * * USB Wacom Graphire and Wacom Intuos tablet support - Wacom specific code * diff --git a/trunk/drivers/usb/input/wacom_wac.h b/trunk/drivers/input/tablet/wacom_wac.h similarity index 93% rename from trunk/drivers/usb/input/wacom_wac.h rename to trunk/drivers/input/tablet/wacom_wac.h index a23022287248..a5e12e8756de 100644 --- a/trunk/drivers/usb/input/wacom_wac.h +++ b/trunk/drivers/input/tablet/wacom_wac.h @@ -1,5 +1,5 @@ /* - * drivers/usb/input/wacom_wac.h + * drivers/input/tablet/wacom_wac.h * * 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 @@ -39,7 +39,7 @@ struct wacom_features { }; struct wacom_wac { - signed char *data; + unsigned char *data; int tool[2]; int id[2]; __u32 serial[2]; diff --git a/trunk/drivers/input/touchscreen/Kconfig b/trunk/drivers/input/touchscreen/Kconfig index 971618059a6f..5e640aeb03cd 100644 --- a/trunk/drivers/input/touchscreen/Kconfig +++ b/trunk/drivers/input/touchscreen/Kconfig @@ -1,5 +1,5 @@ # -# Mouse driver configuration +# Touchscreen driver configuration # menuconfig INPUT_TOUCHSCREEN bool "Touchscreens" @@ -44,9 +44,9 @@ config TOUCHSCREEN_BITSY config TOUCHSCREEN_CORGI tristate "SharpSL (Corgi and Spitz series) touchscreen driver" depends on PXA_SHARPSL - default y + default y help - Say Y here to enable the driver for the touchscreen on the + Say Y here to enable the driver for the touchscreen on the Sharp SL-C7xx and SL-Cxx00 series of PDAs. If unsure, say N. @@ -164,4 +164,58 @@ config TOUCHSCREEN_UCB1400 To compile this driver as a module, choose M here: the module will be called ucb1400_ts. +config TOUCHSCREEN_USB_COMPOSITE + tristate "USB Touchscreen Driver" + select USB + help + USB Touchscreen driver for: + - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700) + - PanJit TouchSet USB + - 3M MicroTouch USB (EX II series) + - ITM + - some other eTurboTouch + - Gunze AHL61 + - DMC TSC-10/25 + + Have a look at for + a usage description and the required user-space stuff. + + To compile this driver as a module, choose M here: the + module will be called usbtouchscreen. + +config TOUCHSCREEN_USB_EGALAX + default y + bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + +config TOUCHSCREEN_USB_PANJIT + default y + bool "PanJit device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + +config TOUCHSCREEN_USB_3M + default y + bool "3M/Microtouch EX II series device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + +config TOUCHSCREEN_USB_ITM + default y + bool "ITM device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + +config TOUCHSCREEN_USB_ETURBO + default y + bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + +config TOUCHSCREEN_USB_GUNZE + default y + bool "Gunze AHL61 device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + +config TOUCHSCREEN_USB_DMC_TSC10 + default y + bool "DMC TSC-10/25 device support" if EMBEDDED + depends on TOUCHSCREEN_USB_COMPOSITE + endif diff --git a/trunk/drivers/input/touchscreen/Makefile b/trunk/drivers/input/touchscreen/Makefile index 30e6e2217a15..2f86d6ad06d3 100644 --- a/trunk/drivers/input/touchscreen/Makefile +++ b/trunk/drivers/input/touchscreen/Makefile @@ -1,17 +1,18 @@ # -# Makefile for the mouse drivers. +# Makefile for the touchscreen drivers. # # Each configuration option enables a list of files. obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o -obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o -obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o -obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o -obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o -obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o -obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o -obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o +obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o +obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o +obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o +obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o +obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o +obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o +obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o +obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o diff --git a/trunk/drivers/input/touchscreen/hp680_ts_input.c b/trunk/drivers/input/touchscreen/hp680_ts_input.c index 249087472740..61c15024c2a0 100644 --- a/trunk/drivers/input/touchscreen/hp680_ts_input.c +++ b/trunk/drivers/input/touchscreen/hp680_ts_input.c @@ -21,7 +21,7 @@ static void do_softint(void *data); static struct input_dev *hp680_ts_dev; -static DECLARE_WORK(work, do_softint, 0); +static DECLARE_WORK(work, do_softint); static void do_softint(void *data) { diff --git a/trunk/drivers/usb/input/usbtouchscreen.c b/trunk/drivers/input/touchscreen/usbtouchscreen.c similarity index 99% rename from trunk/drivers/usb/input/usbtouchscreen.c rename to trunk/drivers/input/touchscreen/usbtouchscreen.c index e0829413336b..8e18e6c64777 100644 --- a/trunk/drivers/usb/input/usbtouchscreen.c +++ b/trunk/drivers/input/touchscreen/usbtouchscreen.c @@ -668,9 +668,8 @@ static void usbtouch_close(struct input_dev *input) static void usbtouch_free_buffers(struct usb_device *udev, struct usbtouch_usb *usbtouch) { - if (usbtouch->data) - usb_buffer_free(udev, usbtouch->type->rept_size, - usbtouch->data, usbtouch->data_dma); + usb_buffer_free(udev, usbtouch->type->rept_size, + usbtouch->data, usbtouch->data_dma); kfree(usbtouch->buffer); } diff --git a/trunk/drivers/input/tsdev.c b/trunk/drivers/input/tsdev.c index 5e5b5c91d75b..8238b13874c2 100644 --- a/trunk/drivers/input/tsdev.c +++ b/trunk/drivers/input/tsdev.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/isdn/capi/capi.c b/trunk/drivers/isdn/capi/capi.c index db1260f73f10..81661b8bd3a8 100644 --- a/trunk/drivers/isdn/capi/capi.c +++ b/trunk/drivers/isdn/capi/capi.c @@ -18,8 +18,8 @@ #include #include #include +#include #include -#include #include #include #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -147,7 +147,7 @@ struct capidev { struct capincci *nccis; - struct semaphore ncci_list_sem; + struct mutex ncci_list_mtx; }; /* -------- global variables ---------------------------------------- */ @@ -395,7 +395,7 @@ static struct capidev *capidev_alloc(void) if (!cdev) return NULL; - init_MUTEX(&cdev->ncci_list_sem); + mutex_init(&cdev->ncci_list_mtx); skb_queue_head_init(&cdev->recvqueue); init_waitqueue_head(&cdev->recvwait); write_lock_irqsave(&capidev_list_lock, flags); @@ -414,9 +414,9 @@ static void capidev_free(struct capidev *cdev) } skb_queue_purge(&cdev->recvqueue); - down(&cdev->ncci_list_sem); + mutex_lock(&cdev->ncci_list_mtx); capincci_free(cdev, 0xffffffff); - up(&cdev->ncci_list_sem); + mutex_unlock(&cdev->ncci_list_mtx); write_lock_irqsave(&capidev_list_lock, flags); list_del(&cdev->list); @@ -603,15 +603,15 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) { u16 info = CAPIMSG_U16(skb->data, 12); // Info field if (info == 0) { - down(&cdev->ncci_list_sem); + mutex_lock(&cdev->ncci_list_mtx); capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); - up(&cdev->ncci_list_sem); + mutex_unlock(&cdev->ncci_list_mtx); } } if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) { - down(&cdev->ncci_list_sem); + mutex_lock(&cdev->ncci_list_mtx); capincci_alloc(cdev, CAPIMSG_NCCI(skb->data)); - up(&cdev->ncci_list_sem); + mutex_unlock(&cdev->ncci_list_mtx); } spin_lock_irqsave(&workaround_lock, flags); if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) { @@ -752,9 +752,9 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos CAPIMSG_SETAPPID(skb->data, cdev->ap.applid); if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) { - down(&cdev->ncci_list_sem); + mutex_lock(&cdev->ncci_list_mtx); capincci_free(cdev, CAPIMSG_NCCI(skb->data)); - up(&cdev->ncci_list_sem); + mutex_unlock(&cdev->ncci_list_mtx); } cdev->errcode = capi20_put_message(&cdev->ap, skb); @@ -939,9 +939,9 @@ capi_ioctl(struct inode *inode, struct file *file, if (copy_from_user(&ncci, argp, sizeof(ncci))) return -EFAULT; - down(&cdev->ncci_list_sem); + mutex_lock(&cdev->ncci_list_mtx); if ((nccip = capincci_find(cdev, (u32) ncci)) == 0) { - up(&cdev->ncci_list_sem); + mutex_unlock(&cdev->ncci_list_mtx); return 0; } #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -949,7 +949,7 @@ capi_ioctl(struct inode *inode, struct file *file, count += atomic_read(&mp->ttyopencount); } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - up(&cdev->ncci_list_sem); + mutex_unlock(&cdev->ncci_list_mtx); return count; } return 0; @@ -964,14 +964,14 @@ capi_ioctl(struct inode *inode, struct file *file, if (copy_from_user(&ncci, argp, sizeof(ncci))) return -EFAULT; - down(&cdev->ncci_list_sem); + mutex_lock(&cdev->ncci_list_mtx); nccip = capincci_find(cdev, (u32) ncci); if (!nccip || (mp = nccip->minorp) == 0) { - up(&cdev->ncci_list_sem); + mutex_unlock(&cdev->ncci_list_mtx); return -ESRCH; } unit = mp->minor; - up(&cdev->ncci_list_sem); + mutex_unlock(&cdev->ncci_list_mtx); return unit; } return 0; diff --git a/trunk/drivers/isdn/capi/capiutil.c b/trunk/drivers/isdn/capi/capiutil.c index ad1e2702c2d1..22379b94e88f 100644 --- a/trunk/drivers/isdn/capi/capiutil.c +++ b/trunk/drivers/isdn/capi/capiutil.c @@ -855,7 +855,7 @@ static _cdebbuf *g_debbuf; static u_long g_debbuf_lock; static _cmsg *g_cmsg; -_cdebbuf *cdebbuf_alloc(void) +static _cdebbuf *cdebbuf_alloc(void) { _cdebbuf *cdb; @@ -989,11 +989,6 @@ _cdebbuf *capi_cmsg2str(_cmsg * cmsg) return &g_debbuf; } -_cdebbuf *cdebbuf_alloc(void) -{ - return &g_debbuf; -} - void cdebbuf_free(_cdebbuf *cdb) { } @@ -1009,7 +1004,6 @@ void __exit cdebug_exit(void) #endif -EXPORT_SYMBOL(cdebbuf_alloc); EXPORT_SYMBOL(cdebbuf_free); EXPORT_SYMBOL(capi_cmsg2message); EXPORT_SYMBOL(capi_message2cmsg); diff --git a/trunk/drivers/isdn/divert/divert_procfs.c b/trunk/drivers/isdn/divert/divert_procfs.c index 53a189003355..be77ee625bb7 100644 --- a/trunk/drivers/isdn/divert/divert_procfs.c +++ b/trunk/drivers/isdn/divert/divert_procfs.c @@ -11,7 +11,6 @@ #include #include -#include #ifdef CONFIG_PROC_FS #include #else diff --git a/trunk/drivers/isdn/hardware/eicon/capimain.c b/trunk/drivers/isdn/hardware/eicon/capimain.c index 7a74ed35b1bf..98fcdfc7ca55 100644 --- a/trunk/drivers/isdn/hardware/eicon/capimain.c +++ b/trunk/drivers/isdn/hardware/eicon/capimain.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "os_capi.h" diff --git a/trunk/drivers/isdn/hardware/eicon/dbgioctl.h b/trunk/drivers/isdn/hardware/eicon/dbgioctl.h deleted file mode 100644 index 0fb6f5e88b60..000000000000 --- a/trunk/drivers/isdn/hardware/eicon/dbgioctl.h +++ /dev/null @@ -1,198 +0,0 @@ - -/* - * - Copyright (c) Eicon Technology Corporation, 2000. - * - This source file is supplied for the use with Eicon - Technology Corporation's range of DIVA Server Adapters. - * - 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 OF ANY KIND WHATSOEVER INCLUDING ANY - 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. - * - */ -/*------------------------------------------------------------------*/ -/* file: dbgioctl.h */ -/*------------------------------------------------------------------*/ - -#if !defined(__DBGIOCTL_H__) - -#define __DBGIOCTL_H__ - -#ifdef NOT_YET_NEEDED -/* - * The requested operation is passed in arg0 of DbgIoctlArgs, - * additional arguments (if any) in arg1, arg2 and arg3. - */ - -typedef struct -{ ULONG arg0 ; - ULONG arg1 ; - ULONG arg2 ; - ULONG arg3 ; -} DbgIoctlArgs ; - -#define DBG_COPY_LOGS 0 /* copy debugs to user until buffer full */ - /* arg1: size threshold */ - /* arg2: timeout in milliseconds */ - -#define DBG_FLUSH_LOGS 1 /* flush pending debugs to user buffer */ - /* arg1: internal driver id */ - -#define DBG_LIST_DRVS 2 /* return the list of registered drivers */ - -#define DBG_GET_MASK 3 /* get current debug mask of driver */ - /* arg1: internal driver id */ - -#define DBG_SET_MASK 4 /* set/change debug mask of driver */ - /* arg1: internal driver id */ - /* arg2: new debug mask */ - -#define DBG_GET_BUFSIZE 5 /* get current buffer size of driver */ - /* arg1: internal driver id */ - /* arg2: new debug mask */ - -#define DBG_SET_BUFSIZE 6 /* set new buffer size of driver */ - /* arg1: new buffer size */ - -/* - * common internal debug message structure - */ - -typedef struct -{ unsigned short id ; /* virtual driver id */ - unsigned short type ; /* special message type */ - unsigned long seq ; /* sequence number of message */ - unsigned long size ; /* size of message in bytes */ - unsigned long next ; /* offset to next buffered message */ - LARGE_INTEGER NTtime ; /* 100 ns since 1.1.1601 */ - unsigned char data[4] ;/* message data */ -} OldDbgMessage ; - -typedef struct -{ LARGE_INTEGER NTtime ; /* 100 ns since 1.1.1601 */ - unsigned short size ; /* size of message in bytes */ - unsigned short ffff ; /* always 0xffff to indicate new msg */ - unsigned short id ; /* virtual driver id */ - unsigned short type ; /* special message type */ - unsigned long seq ; /* sequence number of message */ - unsigned char data[4] ;/* message data */ -} DbgMessage ; - -#endif - -#define DRV_ID_UNKNOWN 0x0C /* for messages via prtComp() */ - -#define MSG_PROC_FLAG 0x80 -#define MSG_PROC_NO_GET(x) (((x) & MSG_PROC_FLAG) ? (((x) >> 4) & 7) : -1) -#define MSG_PROC_NO_SET(x) (MSG_PROC_FLAG | (((x) & 7) << 4)) - -#define MSG_TYPE_DRV_ID 0x0001 -#define MSG_TYPE_FLAGS 0x0002 -#define MSG_TYPE_STRING 0x0003 -#define MSG_TYPE_BINARY 0x0004 - -#define MSG_HEAD_SIZE ((unsigned long)&(((DbgMessage *)0)->data[0])) -#define MSG_ALIGN(len) (((unsigned long)(len) + MSG_HEAD_SIZE + 3) & ~3) -#define MSG_SIZE(pMsg) MSG_ALIGN((pMsg)->size) -#define MSG_NEXT(pMsg) ((DbgMessage *)( ((char *)(pMsg)) + MSG_SIZE(pMsg) )) - -#define OLD_MSG_HEAD_SIZE ((unsigned long)&(((OldDbgMessage *)0)->data[0])) -#define OLD_MSG_ALIGN(len) (((unsigned long)(len)+OLD_MSG_HEAD_SIZE+3) & ~3) - -/* - * manifest constants - */ - -#define MSG_FRAME_MAX_SIZE 2150 /* maximum size of B1 frame */ -#define MSG_TEXT_MAX_SIZE 1024 /* maximum size of msg text */ -#define MSG_MAX_SIZE MSG_ALIGN(MSG_FRAME_MAX_SIZE) -#define DBG_MIN_BUFFER_SIZE 0x00008000 /* minimal total buffer size 32 KB */ -#define DBG_DEF_BUFFER_SIZE 0x00020000 /* default total buffer size 128 KB */ -#define DBG_MAX_BUFFER_SIZE 0x00400000 /* maximal total buffer size 4 MB */ - -#define DBGDRV_NAME "Diehl_DIMAINT" -#define UNIDBG_DRIVER L"\\Device\\Diehl_DIMAINT" /* UNICODE name for kernel */ -#define DEBUG_DRIVER "\\\\.\\" DBGDRV_NAME /* traditional string for apps */ -#define DBGVXD_NAME "DIMAINT" -#define DEBUG_VXD "\\\\.\\" DBGVXD_NAME /* traditional string for apps */ - -/* - * Special IDI interface debug construction - */ - -#define DBG_IDI_SIG_REQ (unsigned long)0xF479C402 -#define DBG_IDI_SIG_IND (unsigned long)0xF479C403 -#define DBG_IDI_NL_REQ (unsigned long)0xF479C404 -#define DBG_IDI_NL_IND (unsigned long)0xF479C405 - -typedef struct -{ unsigned long magic_type ; - unsigned short data_len ; - unsigned char layer_ID ; - unsigned char entity_ID ; - unsigned char request ; - unsigned char ret_code ; - unsigned char indication ; - unsigned char complete ; - unsigned char data[4] ; -} DbgIdiAct, *DbgIdiAction ; - -/* - * We want to use the same IOCTL codes in Win95 and WinNT. - * The official constructor for IOCTL codes is the CTL_CODE macro - * from ( in WinNT DDK environment). - * The problem here is that we don't know how to get - * working in a Win95 DDK environment! - */ - -# ifdef CTL_CODE /*{*/ - -/* Assert that we have the same idea of the CTL_CODE macro. */ - -#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ - ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ -) - -# else /* !CTL_CODE */ /*}{*/ - -/* Use the definitions stolen from . */ - -#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ - ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ -) - -#define METHOD_BUFFERED 0 -#define METHOD_IN_DIRECT 1 -#define METHOD_OUT_DIRECT 2 -#define METHOD_NEITHER 3 - -#define FILE_ANY_ACCESS 0 -#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe -#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe - -# endif /* CTL_CODE */ /*}*/ - -/* - * Now we can define WinNT/Win95 DeviceIoControl codes. - * - * These codes are defined in di_defs.h too, a possible mismatch will be - * detected when the dbgtool is compiled. - */ - -#define IOCTL_DRIVER_LNK \ - CTL_CODE(0x8001U,0x701,METHOD_OUT_DIRECT,FILE_ANY_ACCESS) -#define IOCTL_DRIVER_DBG \ - CTL_CODE(0x8001U,0x702,METHOD_OUT_DIRECT,FILE_ANY_ACCESS) - -#endif /* __DBGIOCTL_H__ */ diff --git a/trunk/drivers/isdn/hardware/eicon/divamnt.c b/trunk/drivers/isdn/hardware/eicon/divamnt.c index 4aba5c502d8e..c90928974249 100644 --- a/trunk/drivers/isdn/hardware/eicon/divamnt.c +++ b/trunk/drivers/isdn/hardware/eicon/divamnt.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/isdn/hardware/eicon/divasi.c b/trunk/drivers/isdn/hardware/eicon/divasi.c index 556b19615bc7..78f141e77466 100644 --- a/trunk/drivers/isdn/hardware/eicon/divasi.c +++ b/trunk/drivers/isdn/hardware/eicon/divasi.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/isdn/hardware/eicon/divasmain.c b/trunk/drivers/isdn/hardware/eicon/divasmain.c index 5e862e244117..6d39f9360766 100644 --- a/trunk/drivers/isdn/hardware/eicon/divasmain.c +++ b/trunk/drivers/isdn/hardware/eicon/divasmain.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/isdn/hardware/eicon/main_if.h b/trunk/drivers/isdn/hardware/eicon/main_if.h deleted file mode 100644 index 0ea339afd424..000000000000 --- a/trunk/drivers/isdn/hardware/eicon/main_if.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - Copyright (c) Eicon Technology Corporation, 2000. - * - This source file is supplied for the use with Eicon - Technology Corporation's range of DIVA Server Adapters. - * - 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 OF ANY KIND WHATSOEVER INCLUDING ANY - 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. - * - */ -/*------------------------------------------------------------------*/ -/* file: main_if.h */ -/*------------------------------------------------------------------*/ -# ifndef MAIN_IF___H -# define MAIN_IF___H - -# include "debug_if.h" - -void DI_lock (void) ; -void DI_unlock (void) ; - -#ifdef NOT_YET_NEEDED -void DI_nttime (LARGE_INTEGER *NTtime) ; -void DI_ntlcltime(LARGE_INTEGER *NTtime, LARGE_INTEGER *lclNTtime) ; -void DI_nttimefields(LARGE_INTEGER *NTtime, TIME_FIELDS *TimeFields); -unsigned long DI_wintime(LARGE_INTEGER *NTtime) ; - -unsigned short DiInsertProcessorNumber (int type) ; -void DiProcessEventLog (unsigned short id, unsigned long msgID, va_list ap); - -void StartIoctlTimer (void (*Handler)(void), unsigned long msec) ; -void StopIoctlTimer (void) ; -void UnpendIoctl (DbgRequest *pDbgReq) ; -#endif - -void add_to_q(int, char* , unsigned int); -# endif /* MAIN_IF___H */ - diff --git a/trunk/drivers/isdn/hardware/eicon/platform.h b/trunk/drivers/isdn/hardware/eicon/platform.h index ff09f07f440a..15d4942de53b 100644 --- a/trunk/drivers/isdn/hardware/eicon/platform.h +++ b/trunk/drivers/isdn/hardware/eicon/platform.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/isdn/hisax/hfc_usb.c b/trunk/drivers/isdn/hisax/hfc_usb.c index 9f44d3e69fb0..99e70d4103b6 100644 --- a/trunk/drivers/isdn/hisax/hfc_usb.c +++ b/trunk/drivers/isdn/hisax/hfc_usb.c @@ -37,7 +37,6 @@ #include #include #include -#include #include "hisax.h" #include "hisax_if.h" #include "hfc_usb.h" diff --git a/trunk/drivers/isdn/hysdn/boardergo.c b/trunk/drivers/isdn/hysdn/boardergo.c index 84dccd526ac0..6cdbad3a9926 100644 --- a/trunk/drivers/isdn/hysdn/boardergo.c +++ b/trunk/drivers/isdn/hysdn/boardergo.c @@ -443,7 +443,7 @@ ergo_inithardware(hysdn_card * card) card->waitpofready = ergo_waitpofready; card->set_errlog_state = ergo_set_errlog_state; INIT_WORK(&card->irq_queue, ergo_irq_bh); - card->hysdn_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&card->hysdn_lock); return (0); } /* ergo_inithardware */ diff --git a/trunk/drivers/isdn/hysdn/hysdn_proclog.c b/trunk/drivers/isdn/hysdn/hysdn_proclog.c index 4c7dedac0e51..27b3991fb0ec 100644 --- a/trunk/drivers/isdn/hysdn/hysdn_proclog.c +++ b/trunk/drivers/isdn/hysdn/hysdn_proclog.c @@ -297,8 +297,6 @@ hysdn_log_close(struct inode *ino, struct file *filep) struct procdata *pd; hysdn_card *card; int retval = 0; - unsigned long flags; - spinlock_t hysdn_lock = SPIN_LOCK_UNLOCKED; lock_kernel(); if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { @@ -308,7 +306,6 @@ hysdn_log_close(struct inode *ino, struct file *filep) /* read access -> log/debug read, mark one further file as closed */ pd = NULL; - spin_lock_irqsave(&hysdn_lock, flags); inf = *((struct log_data **) filep->private_data); /* get first log entry */ if (inf) pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ @@ -331,7 +328,6 @@ hysdn_log_close(struct inode *ino, struct file *filep) inf->usage_cnt--; /* decrement usage count for buffers */ inf = inf->next; } - spin_unlock_irqrestore(&hysdn_lock, flags); if (pd) if (pd->if_used <= 0) /* delete buffers if last file closed */ diff --git a/trunk/drivers/isdn/isdnloop/isdnloop.c b/trunk/drivers/isdn/isdnloop/isdnloop.c index e93ad59f60bf..bb92e3cd9334 100644 --- a/trunk/drivers/isdn/isdnloop/isdnloop.c +++ b/trunk/drivers/isdn/isdnloop/isdnloop.c @@ -1462,7 +1462,7 @@ isdnloop_initcard(char *id) skb_queue_head_init(&card->bqueue[i]); } skb_queue_head_init(&card->dqueue); - card->isdnloop_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&card->isdnloop_lock); card->next = cards; cards = card; if (!register_isdn(&card->interface)) { diff --git a/trunk/drivers/kvm/kvm.h b/trunk/drivers/kvm/kvm.h index 0d122bf889db..41634fde8e13 100644 --- a/trunk/drivers/kvm/kvm.h +++ b/trunk/drivers/kvm/kvm.h @@ -51,16 +51,19 @@ #define UNMAPPED_GVA (~(gpa_t)0) #define KVM_MAX_VCPUS 1 +#define KVM_ALIAS_SLOTS 4 #define KVM_MEMORY_SLOTS 4 #define KVM_NUM_MMU_PAGES 256 #define KVM_MIN_FREE_MMU_PAGES 5 #define KVM_REFILL_PAGES 25 +#define KVM_MAX_CPUID_ENTRIES 40 #define FX_IMAGE_SIZE 512 #define FX_IMAGE_ALIGN 16 #define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN) #define DE_VECTOR 0 +#define NM_VECTOR 7 #define DF_VECTOR 8 #define TS_VECTOR 10 #define NP_VECTOR 11 @@ -73,6 +76,8 @@ #define IOPL_SHIFT 12 +#define KVM_PIO_PAGE_OFFSET 1 + /* * Address types: * @@ -106,6 +111,7 @@ struct kvm_pte_chain { * bits 4:7 - page table level for this shadow (1-4) * bits 8:9 - page table quadrant for 2-level guests * bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode) + * bits 17:18 - "access" - the user and writable bits of a huge page pde */ union kvm_mmu_page_role { unsigned word; @@ -115,6 +121,7 @@ union kvm_mmu_page_role { unsigned quadrant : 2; unsigned pad_for_nice_hex_output : 6; unsigned metaphysical : 1; + unsigned hugepage_access : 2; }; }; @@ -133,7 +140,6 @@ struct kvm_mmu_page { unsigned long slot_bitmap; /* One bit set per slot which has memory * in this shadow page. */ - int global; /* Set if all ptes in this page are global */ int multimapped; /* More than one parent_pte? */ int root_count; /* Currently serving as active root */ union { @@ -219,6 +225,34 @@ enum { VCPU_SREG_LDTR, }; +struct kvm_pio_request { + unsigned long count; + int cur_count; + struct page *guest_pages[2]; + unsigned guest_page_offset; + int in; + int size; + int string; + int down; + int rep; +}; + +struct kvm_stat { + u32 pf_fixed; + u32 pf_guest; + u32 tlb_flush; + u32 invlpg; + + u32 exits; + u32 io_exits; + u32 mmio_exits; + u32 signal_exits; + u32 irq_window_exits; + u32 halt_exits; + u32 request_irq_exits; + u32 irq_exits; +}; + struct kvm_vcpu { struct kvm *kvm; union { @@ -228,6 +262,8 @@ struct kvm_vcpu { struct mutex mutex; int cpu; int launched; + u64 host_tsc; + struct kvm_run *run; int interrupt_window_open; unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long) @@ -266,6 +302,7 @@ struct kvm_vcpu { char fx_buf[FX_BUF_SIZE]; char *host_fx_image; char *guest_fx_image; + int fpu_active; int mmio_needed; int mmio_read_completed; @@ -273,6 +310,14 @@ struct kvm_vcpu { int mmio_size; unsigned char mmio_data[8]; gpa_t mmio_phys_addr; + gva_t mmio_fault_cr2; + struct kvm_pio_request pio; + void *pio_data; + + int sigset_active; + sigset_t sigset; + + struct kvm_stat stat; struct { int active; @@ -284,6 +329,15 @@ struct kvm_vcpu { u32 ar; } tr, es, ds, fs, gs; } rmode; + + int cpuid_nent; + struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES]; +}; + +struct kvm_mem_alias { + gfn_t base_gfn; + unsigned long npages; + gfn_t target_gfn; }; struct kvm_memory_slot { @@ -296,6 +350,8 @@ struct kvm_memory_slot { struct kvm { spinlock_t lock; /* protects everything except vcpus */ + int naliases; + struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS]; int nmemslots; struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS]; /* @@ -312,22 +368,6 @@ struct kvm { struct file *filp; }; -struct kvm_stat { - u32 pf_fixed; - u32 pf_guest; - u32 tlb_flush; - u32 invlpg; - - u32 exits; - u32 io_exits; - u32 mmio_exits; - u32 signal_exits; - u32 irq_window_exits; - u32 halt_exits; - u32 request_irq_exits; - u32 irq_exits; -}; - struct descriptor_table { u16 limit; unsigned long base; @@ -358,10 +398,8 @@ struct kvm_arch_ops { void (*set_segment)(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l); - void (*decache_cr0_cr4_guest_bits)(struct kvm_vcpu *vcpu); + void (*decache_cr4_guest_bits)(struct kvm_vcpu *vcpu); void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0); - void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu, - unsigned long cr0); void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3); void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4); void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer); @@ -391,7 +429,6 @@ struct kvm_arch_ops { unsigned char *hypercall_addr); }; -extern struct kvm_stat kvm_stat; extern struct kvm_arch_ops *kvm_arch_ops; #define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt) @@ -400,28 +437,29 @@ extern struct kvm_arch_ops *kvm_arch_ops; int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module); void kvm_exit_arch(void); +int kvm_mmu_module_init(void); +void kvm_mmu_module_exit(void); + void kvm_mmu_destroy(struct kvm_vcpu *vcpu); int kvm_mmu_create(struct kvm_vcpu *vcpu); int kvm_mmu_setup(struct kvm_vcpu *vcpu); int kvm_mmu_reset_context(struct kvm_vcpu *vcpu); void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot); +void kvm_mmu_zap_all(struct kvm_vcpu *vcpu); hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa); #define HPA_MSB ((sizeof(hpa_t) * 8) - 1) #define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB) static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva); +struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva); void kvm_emulator_want_group7_invlpg(void); extern hpa_t bad_page_address; -static inline struct page *gfn_to_page(struct kvm_memory_slot *slot, gfn_t gfn) -{ - return slot->phys_mem[gfn - slot->base_gfn]; -} - +struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn); void mark_page_dirty(struct kvm *kvm, gfn_t gfn); @@ -444,6 +482,10 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value, struct x86_emulate_ctxt; +int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned long count, int string, int down, + gva_t address, int rep, unsigned port); +void kvm_emulate_cpuid(struct kvm_vcpu *vcpu); int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); int emulate_clts(struct kvm_vcpu *vcpu); int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, @@ -493,12 +535,6 @@ static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, return vcpu->mmu.page_fault(vcpu, gva, error_code); } -static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn) -{ - struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn); - return (slot) ? slot->phys_mem[gfn - slot->base_gfn] : NULL; -} - static inline int is_long_mode(struct kvm_vcpu *vcpu) { #ifdef CONFIG_X86_64 diff --git a/trunk/drivers/kvm/kvm_main.c b/trunk/drivers/kvm/kvm_main.c index dc7a8c78cbf9..c8b8cfa332bb 100644 --- a/trunk/drivers/kvm/kvm_main.c +++ b/trunk/drivers/kvm/kvm_main.c @@ -51,27 +51,27 @@ static DEFINE_SPINLOCK(kvm_lock); static LIST_HEAD(vm_list); struct kvm_arch_ops *kvm_arch_ops; -struct kvm_stat kvm_stat; -EXPORT_SYMBOL_GPL(kvm_stat); + +#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x) static struct kvm_stats_debugfs_item { const char *name; - u32 *data; + int offset; struct dentry *dentry; } debugfs_entries[] = { - { "pf_fixed", &kvm_stat.pf_fixed }, - { "pf_guest", &kvm_stat.pf_guest }, - { "tlb_flush", &kvm_stat.tlb_flush }, - { "invlpg", &kvm_stat.invlpg }, - { "exits", &kvm_stat.exits }, - { "io_exits", &kvm_stat.io_exits }, - { "mmio_exits", &kvm_stat.mmio_exits }, - { "signal_exits", &kvm_stat.signal_exits }, - { "irq_window", &kvm_stat.irq_window_exits }, - { "halt_exits", &kvm_stat.halt_exits }, - { "request_irq", &kvm_stat.request_irq_exits }, - { "irq_exits", &kvm_stat.irq_exits }, - { NULL, NULL } + { "pf_fixed", STAT_OFFSET(pf_fixed) }, + { "pf_guest", STAT_OFFSET(pf_guest) }, + { "tlb_flush", STAT_OFFSET(tlb_flush) }, + { "invlpg", STAT_OFFSET(invlpg) }, + { "exits", STAT_OFFSET(exits) }, + { "io_exits", STAT_OFFSET(io_exits) }, + { "mmio_exits", STAT_OFFSET(mmio_exits) }, + { "signal_exits", STAT_OFFSET(signal_exits) }, + { "irq_window", STAT_OFFSET(irq_window_exits) }, + { "halt_exits", STAT_OFFSET(halt_exits) }, + { "request_irq", STAT_OFFSET(request_irq_exits) }, + { "irq_exits", STAT_OFFSET(irq_exits) }, + { NULL } }; static struct dentry *debugfs_dir; @@ -346,6 +346,17 @@ static void kvm_free_physmem(struct kvm *kvm) kvm_free_physmem_slot(&kvm->memslots[i], NULL); } +static void free_pio_guest_pages(struct kvm_vcpu *vcpu) +{ + int i; + + for (i = 0; i < 2; ++i) + if (vcpu->pio.guest_pages[i]) { + __free_page(vcpu->pio.guest_pages[i]); + vcpu->pio.guest_pages[i] = NULL; + } +} + static void kvm_free_vcpu(struct kvm_vcpu *vcpu) { if (!vcpu->vmcs) @@ -355,6 +366,11 @@ static void kvm_free_vcpu(struct kvm_vcpu *vcpu) kvm_mmu_destroy(vcpu); vcpu_put(vcpu); kvm_arch_ops->vcpu_free(vcpu); + free_page((unsigned long)vcpu->run); + vcpu->run = NULL; + free_page((unsigned long)vcpu->pio_data); + vcpu->pio_data = NULL; + free_pio_guest_pages(vcpu); } static void kvm_free_vcpus(struct kvm *kvm) @@ -404,12 +420,12 @@ static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) u64 pdpte; u64 *pdpt; int ret; - struct kvm_memory_slot *memslot; + struct page *page; spin_lock(&vcpu->kvm->lock); - memslot = gfn_to_memslot(vcpu->kvm, pdpt_gfn); - /* FIXME: !memslot - emulate? 0xff? */ - pdpt = kmap_atomic(gfn_to_page(memslot, pdpt_gfn), KM_USER0); + page = gfn_to_page(vcpu->kvm, pdpt_gfn); + /* FIXME: !page - emulate? 0xff? */ + pdpt = kmap_atomic(page, KM_USER0); ret = 1; for (i = 0; i < 4; ++i) { @@ -494,7 +510,6 @@ EXPORT_SYMBOL_GPL(set_cr0); void lmsw(struct kvm_vcpu *vcpu, unsigned long msw) { - kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu); set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f)); } EXPORT_SYMBOL_GPL(lmsw); @@ -830,7 +845,73 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, return r; } -struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) +/* + * Set a new alias region. Aliases map a portion of physical memory into + * another portion. This is useful for memory windows, for example the PC + * VGA region. + */ +static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, + struct kvm_memory_alias *alias) +{ + int r, n; + struct kvm_mem_alias *p; + + r = -EINVAL; + /* General sanity checks */ + if (alias->memory_size & (PAGE_SIZE - 1)) + goto out; + if (alias->guest_phys_addr & (PAGE_SIZE - 1)) + goto out; + if (alias->slot >= KVM_ALIAS_SLOTS) + goto out; + if (alias->guest_phys_addr + alias->memory_size + < alias->guest_phys_addr) + goto out; + if (alias->target_phys_addr + alias->memory_size + < alias->target_phys_addr) + goto out; + + spin_lock(&kvm->lock); + + p = &kvm->aliases[alias->slot]; + p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; + p->npages = alias->memory_size >> PAGE_SHIFT; + p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT; + + for (n = KVM_ALIAS_SLOTS; n > 0; --n) + if (kvm->aliases[n - 1].npages) + break; + kvm->naliases = n; + + spin_unlock(&kvm->lock); + + vcpu_load(&kvm->vcpus[0]); + spin_lock(&kvm->lock); + kvm_mmu_zap_all(&kvm->vcpus[0]); + spin_unlock(&kvm->lock); + vcpu_put(&kvm->vcpus[0]); + + return 0; + +out: + return r; +} + +static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) +{ + int i; + struct kvm_mem_alias *alias; + + for (i = 0; i < kvm->naliases; ++i) { + alias = &kvm->aliases[i]; + if (gfn >= alias->base_gfn + && gfn < alias->base_gfn + alias->npages) + return alias->target_gfn + gfn - alias->base_gfn; + } + return gfn; +} + +static struct kvm_memory_slot *__gfn_to_memslot(struct kvm *kvm, gfn_t gfn) { int i; @@ -843,7 +924,24 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) } return NULL; } -EXPORT_SYMBOL_GPL(gfn_to_memslot); + +struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) +{ + gfn = unalias_gfn(kvm, gfn); + return __gfn_to_memslot(kvm, gfn); +} + +struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) +{ + struct kvm_memory_slot *slot; + + gfn = unalias_gfn(kvm, gfn); + slot = __gfn_to_memslot(kvm, gfn); + if (!slot) + return NULL; + return slot->phys_mem[gfn - slot->base_gfn]; +} +EXPORT_SYMBOL_GPL(gfn_to_page); void mark_page_dirty(struct kvm *kvm, gfn_t gfn) { @@ -871,7 +969,7 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn) } static int emulator_read_std(unsigned long addr, - unsigned long *val, + void *val, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { @@ -883,20 +981,20 @@ static int emulator_read_std(unsigned long addr, unsigned offset = addr & (PAGE_SIZE-1); unsigned tocopy = min(bytes, (unsigned)PAGE_SIZE - offset); unsigned long pfn; - struct kvm_memory_slot *memslot; - void *page; + struct page *page; + void *page_virt; if (gpa == UNMAPPED_GVA) return X86EMUL_PROPAGATE_FAULT; pfn = gpa >> PAGE_SHIFT; - memslot = gfn_to_memslot(vcpu->kvm, pfn); - if (!memslot) + page = gfn_to_page(vcpu->kvm, pfn); + if (!page) return X86EMUL_UNHANDLEABLE; - page = kmap_atomic(gfn_to_page(memslot, pfn), KM_USER0); + page_virt = kmap_atomic(page, KM_USER0); - memcpy(data, page + offset, tocopy); + memcpy(data, page_virt + offset, tocopy); - kunmap_atomic(page, KM_USER0); + kunmap_atomic(page_virt, KM_USER0); bytes -= tocopy; data += tocopy; @@ -907,7 +1005,7 @@ static int emulator_read_std(unsigned long addr, } static int emulator_write_std(unsigned long addr, - unsigned long val, + const void *val, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { @@ -917,7 +1015,7 @@ static int emulator_write_std(unsigned long addr, } static int emulator_read_emulated(unsigned long addr, - unsigned long *val, + void *val, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { @@ -945,37 +1043,37 @@ static int emulator_read_emulated(unsigned long addr, } static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, - unsigned long val, int bytes) + const void *val, int bytes) { - struct kvm_memory_slot *m; struct page *page; void *virt; if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT)) return 0; - m = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT); - if (!m) + page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); + if (!page) return 0; - page = gfn_to_page(m, gpa >> PAGE_SHIFT); kvm_mmu_pre_write(vcpu, gpa, bytes); mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT); virt = kmap_atomic(page, KM_USER0); - memcpy(virt + offset_in_page(gpa), &val, bytes); + memcpy(virt + offset_in_page(gpa), val, bytes); kunmap_atomic(virt, KM_USER0); kvm_mmu_post_write(vcpu, gpa, bytes); return 1; } static int emulator_write_emulated(unsigned long addr, - unsigned long val, + const void *val, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { struct kvm_vcpu *vcpu = ctxt->vcpu; gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); - if (gpa == UNMAPPED_GVA) + if (gpa == UNMAPPED_GVA) { + kvm_arch_ops->inject_page_fault(vcpu, addr, 2); return X86EMUL_PROPAGATE_FAULT; + } if (emulator_write_phys(vcpu, gpa, val, bytes)) return X86EMUL_CONTINUE; @@ -984,14 +1082,14 @@ static int emulator_write_emulated(unsigned long addr, vcpu->mmio_phys_addr = gpa; vcpu->mmio_size = bytes; vcpu->mmio_is_write = 1; - memcpy(vcpu->mmio_data, &val, bytes); + memcpy(vcpu->mmio_data, val, bytes); return X86EMUL_CONTINUE; } static int emulator_cmpxchg_emulated(unsigned long addr, - unsigned long old, - unsigned long new, + const void *old, + const void *new, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { @@ -1004,30 +1102,6 @@ static int emulator_cmpxchg_emulated(unsigned long addr, return emulator_write_emulated(addr, new, bytes, ctxt); } -#ifdef CONFIG_X86_32 - -static int emulator_cmpxchg8b_emulated(unsigned long addr, - unsigned long old_lo, - unsigned long old_hi, - unsigned long new_lo, - unsigned long new_hi, - struct x86_emulate_ctxt *ctxt) -{ - static int reported; - int r; - - if (!reported) { - reported = 1; - printk(KERN_WARNING "kvm: emulating exchange8b as write\n"); - } - r = emulator_write_emulated(addr, new_lo, 4, ctxt); - if (r != X86EMUL_CONTINUE) - return r; - return emulator_write_emulated(addr+4, new_hi, 4, ctxt); -} - -#endif - static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) { return kvm_arch_ops->get_segment_base(vcpu, seg); @@ -1042,7 +1116,6 @@ int emulate_clts(struct kvm_vcpu *vcpu) { unsigned long cr0; - kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu); cr0 = vcpu->cr0 & ~CR0_TS_MASK; kvm_arch_ops->set_cr0(vcpu, cr0); return X86EMUL_CONTINUE; @@ -1102,9 +1175,6 @@ struct x86_emulate_ops emulate_ops = { .read_emulated = emulator_read_emulated, .write_emulated = emulator_write_emulated, .cmpxchg_emulated = emulator_cmpxchg_emulated, -#ifdef CONFIG_X86_32 - .cmpxchg8b_emulated = emulator_cmpxchg8b_emulated, -#endif }; int emulate_instruction(struct kvm_vcpu *vcpu, @@ -1116,6 +1186,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu, int r; int cs_db, cs_l; + vcpu->mmio_fault_cr2 = cr2; kvm_arch_ops->cache_regs(vcpu); kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); @@ -1166,8 +1237,10 @@ int emulate_instruction(struct kvm_vcpu *vcpu, kvm_arch_ops->decache_regs(vcpu); kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags); - if (vcpu->mmio_is_write) + if (vcpu->mmio_is_write) { + vcpu->mmio_needed = 0; return EMULATE_DO_MMIO; + } return EMULATE_DONE; } @@ -1177,7 +1250,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run) { unsigned long nr, a0, a1, a2, a3, a4, a5, ret; - kvm_arch_ops->decache_regs(vcpu); + kvm_arch_ops->cache_regs(vcpu); ret = -KVM_EINVAL; #ifdef CONFIG_X86_64 if (is_long_mode(vcpu)) { @@ -1201,10 +1274,19 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run) } switch (nr) { default: - ; + run->hypercall.args[0] = a0; + run->hypercall.args[1] = a1; + run->hypercall.args[2] = a2; + run->hypercall.args[3] = a3; + run->hypercall.args[4] = a4; + run->hypercall.args[5] = a5; + run->hypercall.ret = ret; + run->hypercall.longmode = is_long_mode(vcpu); + kvm_arch_ops->decache_regs(vcpu); + return 0; } vcpu->regs[VCPU_REGS_RAX] = ret; - kvm_arch_ops->cache_regs(vcpu); + kvm_arch_ops->decache_regs(vcpu); return 1; } EXPORT_SYMBOL_GPL(kvm_hypercall); @@ -1237,7 +1319,7 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) { - kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu); + kvm_arch_ops->decache_cr4_guest_bits(vcpu); switch (cr) { case 0: return vcpu->cr0; @@ -1442,6 +1524,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n", __FUNCTION__, data); break; + case MSR_IA32_MCG_STATUS: + printk(KERN_WARNING "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n", + __FUNCTION__, data); + break; case MSR_IA32_UCODE_REV: case MSR_IA32_UCODE_WRITE: case 0x200 ... 0x2ff: /* MTRRs */ @@ -1478,6 +1564,8 @@ static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) void kvm_resched(struct kvm_vcpu *vcpu) { + if (!need_resched()) + return; vcpu_put(vcpu); cond_resched(); vcpu_load(vcpu); @@ -1502,29 +1590,250 @@ void save_msrs(struct vmx_msr_entry *e, int n) } EXPORT_SYMBOL_GPL(save_msrs); +void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) +{ + int i; + u32 function; + struct kvm_cpuid_entry *e, *best; + + kvm_arch_ops->cache_regs(vcpu); + function = vcpu->regs[VCPU_REGS_RAX]; + vcpu->regs[VCPU_REGS_RAX] = 0; + vcpu->regs[VCPU_REGS_RBX] = 0; + vcpu->regs[VCPU_REGS_RCX] = 0; + vcpu->regs[VCPU_REGS_RDX] = 0; + best = NULL; + for (i = 0; i < vcpu->cpuid_nent; ++i) { + e = &vcpu->cpuid_entries[i]; + if (e->function == function) { + best = e; + break; + } + /* + * Both basic or both extended? + */ + if (((e->function ^ function) & 0x80000000) == 0) + if (!best || e->function > best->function) + best = e; + } + if (best) { + vcpu->regs[VCPU_REGS_RAX] = best->eax; + vcpu->regs[VCPU_REGS_RBX] = best->ebx; + vcpu->regs[VCPU_REGS_RCX] = best->ecx; + vcpu->regs[VCPU_REGS_RDX] = best->edx; + } + kvm_arch_ops->decache_regs(vcpu); + kvm_arch_ops->skip_emulated_instruction(vcpu); +} +EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); + +static int pio_copy_data(struct kvm_vcpu *vcpu) +{ + void *p = vcpu->pio_data; + void *q; + unsigned bytes; + int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1; + + kvm_arch_ops->vcpu_put(vcpu); + q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE, + PAGE_KERNEL); + if (!q) { + kvm_arch_ops->vcpu_load(vcpu); + free_pio_guest_pages(vcpu); + return -ENOMEM; + } + q += vcpu->pio.guest_page_offset; + bytes = vcpu->pio.size * vcpu->pio.cur_count; + if (vcpu->pio.in) + memcpy(q, p, bytes); + else + memcpy(p, q, bytes); + q -= vcpu->pio.guest_page_offset; + vunmap(q); + kvm_arch_ops->vcpu_load(vcpu); + free_pio_guest_pages(vcpu); + return 0; +} + +static int complete_pio(struct kvm_vcpu *vcpu) +{ + struct kvm_pio_request *io = &vcpu->pio; + long delta; + int r; + + kvm_arch_ops->cache_regs(vcpu); + + if (!io->string) { + if (io->in) + memcpy(&vcpu->regs[VCPU_REGS_RAX], vcpu->pio_data, + io->size); + } else { + if (io->in) { + r = pio_copy_data(vcpu); + if (r) { + kvm_arch_ops->cache_regs(vcpu); + return r; + } + } + + delta = 1; + if (io->rep) { + delta *= io->cur_count; + /* + * The size of the register should really depend on + * current address size. + */ + vcpu->regs[VCPU_REGS_RCX] -= delta; + } + if (io->down) + delta = -delta; + delta *= io->size; + if (io->in) + vcpu->regs[VCPU_REGS_RDI] += delta; + else + vcpu->regs[VCPU_REGS_RSI] += delta; + } + + kvm_arch_ops->decache_regs(vcpu); + + io->count -= io->cur_count; + io->cur_count = 0; + + if (!io->count) + kvm_arch_ops->skip_emulated_instruction(vcpu); + return 0; +} + +int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, + int size, unsigned long count, int string, int down, + gva_t address, int rep, unsigned port) +{ + unsigned now, in_page; + int i; + int nr_pages = 1; + struct page *page; + + vcpu->run->exit_reason = KVM_EXIT_IO; + vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; + vcpu->run->io.size = size; + vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; + vcpu->run->io.count = count; + vcpu->run->io.port = port; + vcpu->pio.count = count; + vcpu->pio.cur_count = count; + vcpu->pio.size = size; + vcpu->pio.in = in; + vcpu->pio.string = string; + vcpu->pio.down = down; + vcpu->pio.guest_page_offset = offset_in_page(address); + vcpu->pio.rep = rep; + + if (!string) { + kvm_arch_ops->cache_regs(vcpu); + memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4); + kvm_arch_ops->decache_regs(vcpu); + return 0; + } + + if (!count) { + kvm_arch_ops->skip_emulated_instruction(vcpu); + return 1; + } + + now = min(count, PAGE_SIZE / size); + + if (!down) + in_page = PAGE_SIZE - offset_in_page(address); + else + in_page = offset_in_page(address) + size; + now = min(count, (unsigned long)in_page / size); + if (!now) { + /* + * String I/O straddles page boundary. Pin two guest pages + * so that we satisfy atomicity constraints. Do just one + * transaction to avoid complexity. + */ + nr_pages = 2; + now = 1; + } + if (down) { + /* + * String I/O in reverse. Yuck. Kill the guest, fix later. + */ + printk(KERN_ERR "kvm: guest string pio down\n"); + inject_gp(vcpu); + return 1; + } + vcpu->run->io.count = now; + vcpu->pio.cur_count = now; + + for (i = 0; i < nr_pages; ++i) { + spin_lock(&vcpu->kvm->lock); + page = gva_to_page(vcpu, address + i * PAGE_SIZE); + if (page) + get_page(page); + vcpu->pio.guest_pages[i] = page; + spin_unlock(&vcpu->kvm->lock); + if (!page) { + inject_gp(vcpu); + free_pio_guest_pages(vcpu); + return 1; + } + } + + if (!vcpu->pio.in) + return pio_copy_data(vcpu); + return 0; +} +EXPORT_SYMBOL_GPL(kvm_setup_pio); + static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { int r; + sigset_t sigsaved; vcpu_load(vcpu); + if (vcpu->sigset_active) + sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); + /* re-sync apic's tpr */ vcpu->cr8 = kvm_run->cr8; - if (kvm_run->emulated) { - kvm_arch_ops->skip_emulated_instruction(vcpu); - kvm_run->emulated = 0; + if (vcpu->pio.cur_count) { + r = complete_pio(vcpu); + if (r) + goto out; } - if (kvm_run->mmio_completed) { + if (vcpu->mmio_needed) { memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); vcpu->mmio_read_completed = 1; + vcpu->mmio_needed = 0; + r = emulate_instruction(vcpu, kvm_run, + vcpu->mmio_fault_cr2, 0); + if (r == EMULATE_DO_MMIO) { + /* + * Read-modify-write. Back to userspace. + */ + kvm_run->exit_reason = KVM_EXIT_MMIO; + r = 0; + goto out; + } } - vcpu->mmio_needed = 0; + if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) { + kvm_arch_ops->cache_regs(vcpu); + vcpu->regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret; + kvm_arch_ops->decache_regs(vcpu); + } r = kvm_arch_ops->run(vcpu, kvm_run); +out: + if (vcpu->sigset_active) + sigprocmask(SIG_SETMASK, &sigsaved, NULL); + vcpu_put(vcpu); return r; } @@ -1633,7 +1942,7 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, sregs->gdt.limit = dt.limit; sregs->gdt.base = dt.base; - kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu); + kvm_arch_ops->decache_cr4_guest_bits(vcpu); sregs->cr0 = vcpu->cr0; sregs->cr2 = vcpu->cr2; sregs->cr3 = vcpu->cr3; @@ -1665,16 +1974,6 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, vcpu_load(vcpu); - set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); - set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); - set_segment(vcpu, &sregs->es, VCPU_SREG_ES); - set_segment(vcpu, &sregs->fs, VCPU_SREG_FS); - set_segment(vcpu, &sregs->gs, VCPU_SREG_GS); - set_segment(vcpu, &sregs->ss, VCPU_SREG_SS); - - set_segment(vcpu, &sregs->tr, VCPU_SREG_TR); - set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); - dt.limit = sregs->idt.limit; dt.base = sregs->idt.base; kvm_arch_ops->set_idt(vcpu, &dt); @@ -1694,10 +1993,10 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, #endif vcpu->apic_base = sregs->apic_base; - kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu); + kvm_arch_ops->decache_cr4_guest_bits(vcpu); mmu_reset_needed |= vcpu->cr0 != sregs->cr0; - kvm_arch_ops->set_cr0_no_modeswitch(vcpu, sregs->cr0); + kvm_arch_ops->set_cr0(vcpu, sregs->cr0); mmu_reset_needed |= vcpu->cr4 != sregs->cr4; kvm_arch_ops->set_cr4(vcpu, sregs->cr4); @@ -1714,6 +2013,16 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, if (vcpu->irq_pending[i]) __set_bit(i, &vcpu->irq_summary); + set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); + set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); + set_segment(vcpu, &sregs->es, VCPU_SREG_ES); + set_segment(vcpu, &sregs->fs, VCPU_SREG_FS); + set_segment(vcpu, &sregs->gs, VCPU_SREG_GS); + set_segment(vcpu, &sregs->ss, VCPU_SREG_SS); + + set_segment(vcpu, &sregs->tr, VCPU_SREG_TR); + set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); + vcpu_put(vcpu); return 0; @@ -1887,6 +2196,36 @@ static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, return r; } +static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type) +{ + struct kvm_vcpu *vcpu = vma->vm_file->private_data; + unsigned long pgoff; + struct page *page; + + *type = VM_FAULT_MINOR; + pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + if (pgoff == 0) + page = virt_to_page(vcpu->run); + else if (pgoff == KVM_PIO_PAGE_OFFSET) + page = virt_to_page(vcpu->pio_data); + else + return NOPAGE_SIGBUS; + get_page(page); + return page; +} + +static struct vm_operations_struct kvm_vcpu_vm_ops = { + .nopage = kvm_vcpu_nopage, +}; + +static int kvm_vcpu_mmap(struct file *file, struct vm_area_struct *vma) +{ + vma->vm_ops = &kvm_vcpu_vm_ops; + return 0; +} + static int kvm_vcpu_release(struct inode *inode, struct file *filp) { struct kvm_vcpu *vcpu = filp->private_data; @@ -1899,6 +2238,7 @@ static struct file_operations kvm_vcpu_fops = { .release = kvm_vcpu_release, .unlocked_ioctl = kvm_vcpu_ioctl, .compat_ioctl = kvm_vcpu_ioctl, + .mmap = kvm_vcpu_mmap, }; /* @@ -1947,6 +2287,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) { int r; struct kvm_vcpu *vcpu; + struct page *page; r = -EINVAL; if (!valid_vcpu(n)) @@ -1961,9 +2302,22 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) return -EEXIST; } + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + r = -ENOMEM; + if (!page) + goto out_unlock; + vcpu->run = page_address(page); + + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + r = -ENOMEM; + if (!page) + goto out_free_run; + vcpu->pio_data = page_address(page); + vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf, FX_IMAGE_ALIGN); vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE; + vcpu->cr0 = 0x10; r = kvm_arch_ops->vcpu_create(vcpu); if (r < 0) @@ -1990,11 +2344,107 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) out_free_vcpus: kvm_free_vcpu(vcpu); +out_free_run: + free_page((unsigned long)vcpu->run); + vcpu->run = NULL; +out_unlock: mutex_unlock(&vcpu->mutex); out: return r; } +static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu, + struct kvm_cpuid *cpuid, + struct kvm_cpuid_entry __user *entries) +{ + int r; + + r = -E2BIG; + if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) + goto out; + r = -EFAULT; + if (copy_from_user(&vcpu->cpuid_entries, entries, + cpuid->nent * sizeof(struct kvm_cpuid_entry))) + goto out; + vcpu->cpuid_nent = cpuid->nent; + return 0; + +out: + return r; +} + +static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset) +{ + if (sigset) { + sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP)); + vcpu->sigset_active = 1; + vcpu->sigset = *sigset; + } else + vcpu->sigset_active = 0; + return 0; +} + +/* + * fxsave fpu state. Taken from x86_64/processor.h. To be killed when + * we have asm/x86/processor.h + */ +struct fxsave { + u16 cwd; + u16 swd; + u16 twd; + u16 fop; + u64 rip; + u64 rdp; + u32 mxcsr; + u32 mxcsr_mask; + u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ +#ifdef CONFIG_X86_64 + u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */ +#else + u32 xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ +#endif +}; + +static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) +{ + struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image; + + vcpu_load(vcpu); + + memcpy(fpu->fpr, fxsave->st_space, 128); + fpu->fcw = fxsave->cwd; + fpu->fsw = fxsave->swd; + fpu->ftwx = fxsave->twd; + fpu->last_opcode = fxsave->fop; + fpu->last_ip = fxsave->rip; + fpu->last_dp = fxsave->rdp; + memcpy(fpu->xmm, fxsave->xmm_space, sizeof fxsave->xmm_space); + + vcpu_put(vcpu); + + return 0; +} + +static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) +{ + struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image; + + vcpu_load(vcpu); + + memcpy(fxsave->st_space, fpu->fpr, 128); + fxsave->cwd = fpu->fcw; + fxsave->swd = fpu->fsw; + fxsave->twd = fpu->ftwx; + fxsave->fop = fpu->last_opcode; + fxsave->rip = fpu->last_ip; + fxsave->rdp = fpu->last_dp; + memcpy(fxsave->xmm_space, fpu->xmm, sizeof fxsave->xmm_space); + + vcpu_put(vcpu); + + return 0; +} + static long kvm_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -2003,21 +2453,12 @@ static long kvm_vcpu_ioctl(struct file *filp, int r = -EINVAL; switch (ioctl) { - case KVM_RUN: { - struct kvm_run kvm_run; - - r = -EFAULT; - if (copy_from_user(&kvm_run, argp, sizeof kvm_run)) + case KVM_RUN: + r = -EINVAL; + if (arg) goto out; - r = kvm_vcpu_ioctl_run(vcpu, &kvm_run); - if (r < 0 && r != -EINTR) - goto out; - if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) { - r = -EFAULT; - goto out; - } + r = kvm_vcpu_ioctl_run(vcpu, vcpu->run); break; - } case KVM_GET_REGS: { struct kvm_regs kvm_regs; @@ -2113,6 +2554,66 @@ static long kvm_vcpu_ioctl(struct file *filp, case KVM_SET_MSRS: r = msr_io(vcpu, argp, do_set_msr, 0); break; + case KVM_SET_CPUID: { + struct kvm_cpuid __user *cpuid_arg = argp; + struct kvm_cpuid cpuid; + + r = -EFAULT; + if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) + goto out; + r = kvm_vcpu_ioctl_set_cpuid(vcpu, &cpuid, cpuid_arg->entries); + if (r) + goto out; + break; + } + case KVM_SET_SIGNAL_MASK: { + struct kvm_signal_mask __user *sigmask_arg = argp; + struct kvm_signal_mask kvm_sigmask; + sigset_t sigset, *p; + + p = NULL; + if (argp) { + r = -EFAULT; + if (copy_from_user(&kvm_sigmask, argp, + sizeof kvm_sigmask)) + goto out; + r = -EINVAL; + if (kvm_sigmask.len != sizeof sigset) + goto out; + r = -EFAULT; + if (copy_from_user(&sigset, sigmask_arg->sigset, + sizeof sigset)) + goto out; + p = &sigset; + } + r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); + break; + } + case KVM_GET_FPU: { + struct kvm_fpu fpu; + + memset(&fpu, 0, sizeof fpu); + r = kvm_vcpu_ioctl_get_fpu(vcpu, &fpu); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &fpu, sizeof fpu)) + goto out; + r = 0; + break; + } + case KVM_SET_FPU: { + struct kvm_fpu fpu; + + r = -EFAULT; + if (copy_from_user(&fpu, argp, sizeof fpu)) + goto out; + r = kvm_vcpu_ioctl_set_fpu(vcpu, &fpu); + if (r) + goto out; + r = 0; + break; + } default: ; } @@ -2155,6 +2656,17 @@ static long kvm_vm_ioctl(struct file *filp, goto out; break; } + case KVM_SET_MEMORY_ALIAS: { + struct kvm_memory_alias alias; + + r = -EFAULT; + if (copy_from_user(&alias, argp, sizeof alias)) + goto out; + r = kvm_vm_ioctl_set_memory_alias(kvm, &alias); + if (r) + goto out; + break; + } default: ; } @@ -2168,15 +2680,11 @@ static struct page *kvm_vm_nopage(struct vm_area_struct *vma, { struct kvm *kvm = vma->vm_file->private_data; unsigned long pgoff; - struct kvm_memory_slot *slot; struct page *page; *type = VM_FAULT_MINOR; pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - slot = gfn_to_memslot(kvm, pgoff); - if (!slot) - return NOPAGE_SIGBUS; - page = gfn_to_page(slot, pgoff); + page = gfn_to_page(kvm, pgoff); if (!page) return NOPAGE_SIGBUS; get_page(page); @@ -2248,13 +2756,19 @@ static long kvm_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { void __user *argp = (void __user *)arg; - int r = -EINVAL; + long r = -EINVAL; switch (ioctl) { case KVM_GET_API_VERSION: + r = -EINVAL; + if (arg) + goto out; r = KVM_API_VERSION; break; case KVM_CREATE_VM: + r = -EINVAL; + if (arg) + goto out; r = kvm_dev_ioctl_create_vm(); break; case KVM_GET_MSR_INDEX_LIST: { @@ -2284,6 +2798,18 @@ static long kvm_dev_ioctl(struct file *filp, r = 0; break; } + case KVM_CHECK_EXTENSION: + /* + * No extensions defined at present. + */ + r = 0; + break; + case KVM_GET_VCPU_MMAP_SIZE: + r = -EINVAL; + if (arg) + goto out; + r = 2 * PAGE_SIZE; + break; default: ; } @@ -2299,7 +2825,7 @@ static struct file_operations kvm_chardev_ops = { }; static struct miscdevice kvm_dev = { - MISC_DYNAMIC_MINOR, + KVM_MINOR, "kvm", &kvm_chardev_ops, }; @@ -2385,14 +2911,39 @@ static struct notifier_block kvm_cpu_notifier = { .priority = 20, /* must be > scheduler priority */ }; +static u64 stat_get(void *_offset) +{ + unsigned offset = (long)_offset; + u64 total = 0; + struct kvm *kvm; + struct kvm_vcpu *vcpu; + int i; + + spin_lock(&kvm_lock); + list_for_each_entry(kvm, &vm_list, vm_list) + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + vcpu = &kvm->vcpus[i]; + total += *(u32 *)((void *)vcpu + offset); + } + spin_unlock(&kvm_lock); + return total; +} + +static void stat_set(void *offset, u64 val) +{ +} + +DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, stat_set, "%llu\n"); + static __init void kvm_init_debug(void) { struct kvm_stats_debugfs_item *p; debugfs_dir = debugfs_create_dir("kvm", NULL); for (p = debugfs_entries; p->name; ++p) - p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir, - p->data); + p->dentry = debugfs_create_file(p->name, 0444, debugfs_dir, + (void *)(long)p->offset, + &stat_fops); } static void kvm_exit_debug(void) @@ -2522,6 +3073,10 @@ static __init int kvm_init(void) static struct page *bad_page; int r; + r = kvm_mmu_module_init(); + if (r) + goto out4; + r = register_filesystem(&kvm_fs_type); if (r) goto out3; @@ -2550,6 +3105,8 @@ static __init int kvm_init(void) out2: unregister_filesystem(&kvm_fs_type); out3: + kvm_mmu_module_exit(); +out4: return r; } @@ -2559,6 +3116,7 @@ static __exit void kvm_exit(void) __free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT)); mntput(kvmfs_mnt); unregister_filesystem(&kvm_fs_type); + kvm_mmu_module_exit(); } module_init(kvm_init) diff --git a/trunk/drivers/kvm/kvm_svm.h b/trunk/drivers/kvm/kvm_svm.h index 624f1ca48657..a869983d683d 100644 --- a/trunk/drivers/kvm/kvm_svm.h +++ b/trunk/drivers/kvm/kvm_svm.h @@ -9,17 +9,15 @@ #include "svm.h" #include "kvm.h" -static const u32 host_save_msrs[] = { +static const u32 host_save_user_msrs[] = { #ifdef CONFIG_X86_64 MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE, - MSR_FS_BASE, MSR_GS_BASE, + MSR_FS_BASE, #endif MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, - MSR_IA32_DEBUGCTLMSR, /*MSR_IA32_LASTBRANCHFROMIP, - MSR_IA32_LASTBRANCHTOIP, MSR_IA32_LASTINTFROMIP,MSR_IA32_LASTINTTOIP,*/ }; -#define NR_HOST_SAVE_MSRS ARRAY_SIZE(host_save_msrs) +#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs) #define NUM_DB_REGS 4 struct vcpu_svm { @@ -28,13 +26,12 @@ struct vcpu_svm { struct svm_cpu_data *svm_data; uint64_t asid_generation; - unsigned long cr0; - unsigned long cr4; unsigned long db_regs[NUM_DB_REGS]; u64 next_rip; - u64 host_msrs[NR_HOST_SAVE_MSRS]; + u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS]; + u64 host_gs_base; unsigned long host_cr2; unsigned long host_db_regs[NUM_DB_REGS]; unsigned long host_dr6; diff --git a/trunk/drivers/kvm/kvm_vmx.h b/trunk/drivers/kvm/kvm_vmx.h deleted file mode 100644 index d139f73fb6e1..000000000000 --- a/trunk/drivers/kvm/kvm_vmx.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __KVM_VMX_H -#define __KVM_VMX_H - -#ifdef CONFIG_X86_64 -/* - * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt - * mechanism (cpu bug AA24) - */ -#define NR_BAD_MSRS 2 -#else -#define NR_BAD_MSRS 0 -#endif - -#endif diff --git a/trunk/drivers/kvm/mmu.c b/trunk/drivers/kvm/mmu.c index cab26f301eab..e8e228118de9 100644 --- a/trunk/drivers/kvm/mmu.c +++ b/trunk/drivers/kvm/mmu.c @@ -52,11 +52,15 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {} static int dbg = 1; #endif +#ifndef MMU_DEBUG +#define ASSERT(x) do { } while (0) +#else #define ASSERT(x) \ if (!(x)) { \ printk(KERN_WARNING "assertion failed %s:%d: %s\n", \ __FILE__, __LINE__, #x); \ } +#endif #define PT64_PT_BITS 9 #define PT64_ENT_PER_PAGE (1 << PT64_PT_BITS) @@ -159,6 +163,9 @@ struct kvm_rmap_desc { struct kvm_rmap_desc *more; }; +static struct kmem_cache *pte_chain_cache; +static struct kmem_cache *rmap_desc_cache; + static int is_write_protection(struct kvm_vcpu *vcpu) { return vcpu->cr0 & CR0_WP_MASK; @@ -196,14 +203,15 @@ static int is_rmap_pte(u64 pte) } static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, - size_t objsize, int min) + struct kmem_cache *base_cache, int min, + gfp_t gfp_flags) { void *obj; if (cache->nobjs >= min) return 0; while (cache->nobjs < ARRAY_SIZE(cache->objects)) { - obj = kzalloc(objsize, GFP_NOWAIT); + obj = kmem_cache_zalloc(base_cache, gfp_flags); if (!obj) return -ENOMEM; cache->objects[cache->nobjs++] = obj; @@ -217,20 +225,35 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc) kfree(mc->objects[--mc->nobjs]); } -static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) +static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags) { int r; r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache, - sizeof(struct kvm_pte_chain), 4); + pte_chain_cache, 4, gfp_flags); if (r) goto out; r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache, - sizeof(struct kvm_rmap_desc), 1); + rmap_desc_cache, 1, gfp_flags); out: return r; } +static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) +{ + int r; + + r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT); + if (r < 0) { + spin_unlock(&vcpu->kvm->lock); + kvm_arch_ops->vcpu_put(vcpu); + r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL); + kvm_arch_ops->vcpu_load(vcpu); + spin_lock(&vcpu->kvm->lock); + } + return r; +} + static void mmu_free_memory_caches(struct kvm_vcpu *vcpu) { mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache); @@ -390,13 +413,11 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn) { struct kvm *kvm = vcpu->kvm; struct page *page; - struct kvm_memory_slot *slot; struct kvm_rmap_desc *desc; u64 *spte; - slot = gfn_to_memslot(kvm, gfn); - BUG_ON(!slot); - page = gfn_to_page(slot, gfn); + page = gfn_to_page(kvm, gfn); + BUG_ON(!page); while (page_private(page)) { if (!(page_private(page) & 1)) @@ -417,6 +438,7 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn) } } +#ifdef MMU_DEBUG static int is_empty_shadow_page(hpa_t page_hpa) { u64 *pos; @@ -431,15 +453,15 @@ static int is_empty_shadow_page(hpa_t page_hpa) } return 1; } +#endif static void kvm_mmu_free_page(struct kvm_vcpu *vcpu, hpa_t page_hpa) { struct kvm_mmu_page *page_head = page_header(page_hpa); ASSERT(is_empty_shadow_page(page_hpa)); - list_del(&page_head->link); page_head->page_hpa = page_hpa; - list_add(&page_head->link, &vcpu->free_pages); + list_move(&page_head->link, &vcpu->free_pages); ++vcpu->kvm->n_free_mmu_pages; } @@ -457,11 +479,9 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, return NULL; page = list_entry(vcpu->free_pages.next, struct kvm_mmu_page, link); - list_del(&page->link); - list_add(&page->link, &vcpu->kvm->active_mmu_pages); + list_move(&page->link, &vcpu->kvm->active_mmu_pages); ASSERT(is_empty_shadow_page(page->page_hpa)); page->slot_bitmap = 0; - page->global = 1; page->multimapped = 0; page->parent_pte = parent_pte; --vcpu->kvm->n_free_mmu_pages; @@ -569,6 +589,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gva_t gaddr, unsigned level, int metaphysical, + unsigned hugepage_access, u64 *parent_pte) { union kvm_mmu_page_role role; @@ -582,6 +603,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, role.glevels = vcpu->mmu.root_level; role.level = level; role.metaphysical = metaphysical; + role.hugepage_access = hugepage_access; if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) { quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; @@ -669,10 +691,8 @@ static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu, if (!page->root_count) { hlist_del(&page->hash_link); kvm_mmu_free_page(vcpu, page->page_hpa); - } else { - list_del(&page->link); - list_add(&page->link, &vcpu->kvm->active_mmu_pages); - } + } else + list_move(&page->link, &vcpu->kvm->active_mmu_pages); } static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn) @@ -714,14 +734,12 @@ hpa_t safe_gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa) hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa) { - struct kvm_memory_slot *slot; struct page *page; ASSERT((gpa & HPA_ERR_MASK) == 0); - slot = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT); - if (!slot) + page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); + if (!page) return gpa | HPA_ERR_MASK; - page = gfn_to_page(slot, gpa >> PAGE_SHIFT); return ((hpa_t)page_to_pfn(page) << PAGE_SHIFT) | (gpa & (PAGE_SIZE-1)); } @@ -735,6 +753,15 @@ hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva) return gpa_to_hpa(vcpu, gpa); } +struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva) +{ + gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva); + + if (gpa == UNMAPPED_GVA) + return NULL; + return pfn_to_page(gpa_to_hpa(vcpu, gpa) >> PAGE_SHIFT); +} + static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) { } @@ -772,7 +799,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p) >> PAGE_SHIFT; new_table = kvm_mmu_get_page(vcpu, pseudo_gfn, v, level - 1, - 1, &table[index]); + 1, 0, &table[index]); if (!new_table) { pgprintk("nonpaging_map: ENOMEM\n"); return -ENOMEM; @@ -804,10 +831,12 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu) for (i = 0; i < 4; ++i) { hpa_t root = vcpu->mmu.pae_root[i]; - ASSERT(VALID_PAGE(root)); - root &= PT64_BASE_ADDR_MASK; - page = page_header(root); - --page->root_count; + if (root) { + ASSERT(VALID_PAGE(root)); + root &= PT64_BASE_ADDR_MASK; + page = page_header(root); + --page->root_count; + } vcpu->mmu.pae_root[i] = INVALID_PAGE; } vcpu->mmu.root_hpa = INVALID_PAGE; @@ -827,7 +856,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) ASSERT(!VALID_PAGE(root)); page = kvm_mmu_get_page(vcpu, root_gfn, 0, - PT64_ROOT_LEVEL, 0, NULL); + PT64_ROOT_LEVEL, 0, 0, NULL); root = page->page_hpa; ++page->root_count; vcpu->mmu.root_hpa = root; @@ -838,13 +867,17 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu) hpa_t root = vcpu->mmu.pae_root[i]; ASSERT(!VALID_PAGE(root)); - if (vcpu->mmu.root_level == PT32E_ROOT_LEVEL) + if (vcpu->mmu.root_level == PT32E_ROOT_LEVEL) { + if (!is_present_pte(vcpu->pdptrs[i])) { + vcpu->mmu.pae_root[i] = 0; + continue; + } root_gfn = vcpu->pdptrs[i] >> PAGE_SHIFT; - else if (vcpu->mmu.root_level == 0) + } else if (vcpu->mmu.root_level == 0) root_gfn = 0; page = kvm_mmu_get_page(vcpu, root_gfn, i << 30, PT32_ROOT_LEVEL, !is_paging(vcpu), - NULL); + 0, NULL); root = page->page_hpa; ++page->root_count; vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK; @@ -903,7 +936,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu) static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu) { - ++kvm_stat.tlb_flush; + ++vcpu->stat.tlb_flush; kvm_arch_ops->tlb_flush(vcpu); } @@ -918,11 +951,6 @@ static void paging_new_cr3(struct kvm_vcpu *vcpu) kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa); } -static void mark_pagetable_nonglobal(void *shadow_pte) -{ - page_header(__pa(shadow_pte))->global = 0; -} - static inline void set_pte_common(struct kvm_vcpu *vcpu, u64 *shadow_pte, gpa_t gaddr, @@ -940,9 +968,6 @@ static inline void set_pte_common(struct kvm_vcpu *vcpu, *shadow_pte |= access_bits; - if (!(*shadow_pte & PT_GLOBAL_MASK)) - mark_pagetable_nonglobal(shadow_pte); - if (is_error_hpa(paddr)) { *shadow_pte |= gaddr; *shadow_pte |= PT_SHADOW_IO_MARK; @@ -1316,6 +1341,51 @@ void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot) } } +void kvm_mmu_zap_all(struct kvm_vcpu *vcpu) +{ + destroy_kvm_mmu(vcpu); + + while (!list_empty(&vcpu->kvm->active_mmu_pages)) { + struct kvm_mmu_page *page; + + page = container_of(vcpu->kvm->active_mmu_pages.next, + struct kvm_mmu_page, link); + kvm_mmu_zap_page(vcpu, page); + } + + mmu_free_memory_caches(vcpu); + kvm_arch_ops->tlb_flush(vcpu); + init_kvm_mmu(vcpu); +} + +void kvm_mmu_module_exit(void) +{ + if (pte_chain_cache) + kmem_cache_destroy(pte_chain_cache); + if (rmap_desc_cache) + kmem_cache_destroy(rmap_desc_cache); +} + +int kvm_mmu_module_init(void) +{ + pte_chain_cache = kmem_cache_create("kvm_pte_chain", + sizeof(struct kvm_pte_chain), + 0, 0, NULL, NULL); + if (!pte_chain_cache) + goto nomem; + rmap_desc_cache = kmem_cache_create("kvm_rmap_desc", + sizeof(struct kvm_rmap_desc), + 0, 0, NULL, NULL); + if (!rmap_desc_cache) + goto nomem; + + return 0; + +nomem: + kvm_mmu_module_exit(); + return -ENOMEM; +} + #ifdef AUDIT static const char *audit_msg; @@ -1338,7 +1408,7 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) { u64 ent = pt[i]; - if (!ent & PT_PRESENT_MASK) + if (!(ent & PT_PRESENT_MASK)) continue; va = canonicalize(va); @@ -1360,7 +1430,7 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, static void audit_mappings(struct kvm_vcpu *vcpu) { - int i; + unsigned i; if (vcpu->mmu.root_level == 4) audit_mappings_page(vcpu, vcpu->mmu.root_hpa, 0, 4); diff --git a/trunk/drivers/kvm/paging_tmpl.h b/trunk/drivers/kvm/paging_tmpl.h index f3bcee904651..73ffbffb1097 100644 --- a/trunk/drivers/kvm/paging_tmpl.h +++ b/trunk/drivers/kvm/paging_tmpl.h @@ -148,8 +148,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker, break; } - if (walker->level != 3 || is_long_mode(vcpu)) - walker->inherited_ar &= walker->table[index]; + walker->inherited_ar &= walker->table[index]; table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT; paddr = safe_gpa_to_hpa(vcpu, *ptep & PT_BASE_ADDR_MASK); kunmap_atomic(walker->table, KM_USER0); @@ -248,6 +247,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, u64 shadow_pte; int metaphysical; gfn_t table_gfn; + unsigned hugepage_access = 0; if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) { if (level == PT_PAGE_TABLE_LEVEL) @@ -277,6 +277,9 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, if (level - 1 == PT_PAGE_TABLE_LEVEL && walker->level == PT_DIRECTORY_LEVEL) { metaphysical = 1; + hugepage_access = *guest_ent; + hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK; + hugepage_access >>= PT_WRITABLE_SHIFT; table_gfn = (*guest_ent & PT_BASE_ADDR_MASK) >> PAGE_SHIFT; } else { @@ -284,7 +287,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, table_gfn = walker->table_gfn[level - 2]; } shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1, - metaphysical, shadow_ent); + metaphysical, hugepage_access, + shadow_ent); shadow_addr = shadow_page->page_hpa; shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_WRITABLE_MASK | PT_USER_MASK; @@ -444,7 +448,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, if (is_io_pte(*shadow_pte)) return 1; - ++kvm_stat.pf_fixed; + ++vcpu->stat.pf_fixed; kvm_mmu_audit(vcpu, "post page fault (fixed)"); return write_pt; diff --git a/trunk/drivers/kvm/svm.c b/trunk/drivers/kvm/svm.c index 3d8ea7ac2ecc..9c15f32eea18 100644 --- a/trunk/drivers/kvm/svm.c +++ b/trunk/drivers/kvm/svm.c @@ -44,6 +44,10 @@ MODULE_LICENSE("GPL"); #define KVM_EFER_LMA (1 << 10) #define KVM_EFER_LME (1 << 8) +#define SVM_FEATURE_NPT (1 << 0) +#define SVM_FEATURE_LBRV (1 << 1) +#define SVM_DEATURE_SVML (1 << 2) + unsigned long iopm_base; unsigned long msrpm_base; @@ -59,15 +63,16 @@ struct kvm_ldttss_desc { struct svm_cpu_data { int cpu; - uint64_t asid_generation; - uint32_t max_asid; - uint32_t next_asid; + u64 asid_generation; + u32 max_asid; + u32 next_asid; struct kvm_ldttss_desc *tss_desc; struct page *save_area; }; static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data); +static uint32_t svm_features; struct svm_init_data { int cpu; @@ -82,6 +87,11 @@ static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000}; #define MAX_INST_SIZE 15 +static inline u32 svm_has(u32 feat) +{ + return svm_features & feat; +} + static unsigned get_addr_size(struct kvm_vcpu *vcpu) { struct vmcb_save_area *sa = &vcpu->svm->vmcb->save; @@ -203,13 +213,6 @@ static void inject_ud(struct kvm_vcpu *vcpu) UD_VECTOR; } -static void inject_db(struct kvm_vcpu *vcpu) -{ - vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | - SVM_EVTINJ_TYPE_EXEPT | - DB_VECTOR; -} - static int is_page_fault(uint32_t info) { info &= SVM_EVTINJ_VEC_MASK | SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID; @@ -309,6 +312,7 @@ static void svm_hardware_enable(void *garbage) svm_data->asid_generation = 1; svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1; svm_data->next_asid = svm_data->max_asid + 1; + svm_features = cpuid_edx(SVM_CPUID_FUNC); asm volatile ( "sgdt %0" : "=m"(gdt_descr) ); gdt = (struct desc_struct *)gdt_descr.address; @@ -459,7 +463,6 @@ static void init_vmcb(struct vmcb *vmcb) { struct vmcb_control_area *control = &vmcb->control; struct vmcb_save_area *save = &vmcb->save; - u64 tsc; control->intercept_cr_read = INTERCEPT_CR0_MASK | INTERCEPT_CR3_MASK | @@ -511,12 +514,13 @@ static void init_vmcb(struct vmcb *vmcb) (1ULL << INTERCEPT_VMSAVE) | (1ULL << INTERCEPT_STGI) | (1ULL << INTERCEPT_CLGI) | - (1ULL << INTERCEPT_SKINIT); + (1ULL << INTERCEPT_SKINIT) | + (1ULL << INTERCEPT_MONITOR) | + (1ULL << INTERCEPT_MWAIT); control->iopm_base_pa = iopm_base; control->msrpm_base_pa = msrpm_base; - rdtscll(tsc); - control->tsc_offset = -tsc; + control->tsc_offset = 0; control->int_ctl = V_INTR_MASKING_MASK; init_seg(&save->es); @@ -576,12 +580,15 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu) vcpu->svm->vmcb = page_address(page); memset(vcpu->svm->vmcb, 0, PAGE_SIZE); vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; - vcpu->svm->cr0 = 0x00000010; vcpu->svm->asid_generation = 0; memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs)); init_vmcb(vcpu->svm->vmcb); fx_init(vcpu); + vcpu->fpu_active = 1; + vcpu->apic_base = 0xfee00000 | + /*for vcpu 0*/ MSR_IA32_APICBASE_BSP | + MSR_IA32_APICBASE_ENABLE; return 0; @@ -602,11 +609,34 @@ static void svm_free_vcpu(struct kvm_vcpu *vcpu) static void svm_vcpu_load(struct kvm_vcpu *vcpu) { - get_cpu(); + int cpu, i; + + cpu = get_cpu(); + if (unlikely(cpu != vcpu->cpu)) { + u64 tsc_this, delta; + + /* + * Make sure that the guest sees a monotonically + * increasing TSC. + */ + rdtscll(tsc_this); + delta = vcpu->host_tsc - tsc_this; + vcpu->svm->vmcb->control.tsc_offset += delta; + vcpu->cpu = cpu; + } + + for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) + rdmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]); } static void svm_vcpu_put(struct kvm_vcpu *vcpu) { + int i; + + for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) + wrmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]); + + rdtscll(vcpu->host_tsc); put_cpu(); } @@ -714,7 +744,7 @@ static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) vcpu->svm->vmcb->save.gdtr.base = dt->base ; } -static void svm_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu) +static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) { } @@ -733,9 +763,15 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) } } #endif - vcpu->svm->cr0 = cr0; - vcpu->svm->vmcb->save.cr0 = cr0 | CR0_PG_MASK | CR0_WP_MASK; + if ((vcpu->cr0 & CR0_TS_MASK) && !(cr0 & CR0_TS_MASK)) { + vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); + vcpu->fpu_active = 1; + } + vcpu->cr0 = cr0; + cr0 |= CR0_PG_MASK | CR0_WP_MASK; + cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK); + vcpu->svm->vmcb->save.cr0 = cr0; } static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) @@ -785,18 +821,16 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) static void load_host_msrs(struct kvm_vcpu *vcpu) { - int i; - - for ( i = 0; i < NR_HOST_SAVE_MSRS; i++) - wrmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]); +#ifdef CONFIG_X86_64 + wrmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base); +#endif } static void save_host_msrs(struct kvm_vcpu *vcpu) { - int i; - - for ( i = 0; i < NR_HOST_SAVE_MSRS; i++) - rdmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]); +#ifdef CONFIG_X86_64 + rdmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base); +#endif } static void new_asid(struct kvm_vcpu *vcpu, struct svm_cpu_data *svm_data) @@ -890,7 +924,7 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) case EMULATE_DONE: return 1; case EMULATE_DO_MMIO: - ++kvm_stat.mmio_exits; + ++vcpu->stat.mmio_exits; kvm_run->exit_reason = KVM_EXIT_MMIO; return 0; case EMULATE_FAIL: @@ -904,6 +938,16 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } +static int nm_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); + if (!(vcpu->cr0 & CR0_TS_MASK)) + vcpu->svm->vmcb->save.cr0 &= ~CR0_TS_MASK; + vcpu->fpu_active = 1; + + return 1; +} + static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { /* @@ -981,7 +1025,7 @@ static int io_get_override(struct kvm_vcpu *vcpu, return 0; } -static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, u64 *address) +static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, gva_t *address) { unsigned long addr_mask; unsigned long *reg; @@ -1025,38 +1069,38 @@ static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, u64 *address) static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug? - int _in = io_info & SVM_IOIO_TYPE_MASK; + int size, down, in, string, rep; + unsigned port; + unsigned long count; + gva_t address = 0; - ++kvm_stat.io_exits; + ++vcpu->stat.io_exits; vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2; - kvm_run->exit_reason = KVM_EXIT_IO; - kvm_run->io.port = io_info >> 16; - kvm_run->io.direction = (_in) ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; - kvm_run->io.size = ((io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT); - kvm_run->io.string = (io_info & SVM_IOIO_STR_MASK) != 0; - kvm_run->io.rep = (io_info & SVM_IOIO_REP_MASK) != 0; + in = (io_info & SVM_IOIO_TYPE_MASK) != 0; + port = io_info >> 16; + size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT; + string = (io_info & SVM_IOIO_STR_MASK) != 0; + rep = (io_info & SVM_IOIO_REP_MASK) != 0; + count = 1; + down = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0; - if (kvm_run->io.string) { + if (string) { unsigned addr_mask; - addr_mask = io_adress(vcpu, _in, &kvm_run->io.address); + addr_mask = io_adress(vcpu, in, &address); if (!addr_mask) { printk(KERN_DEBUG "%s: get io address failed\n", __FUNCTION__); return 1; } - if (kvm_run->io.rep) { - kvm_run->io.count - = vcpu->regs[VCPU_REGS_RCX] & addr_mask; - kvm_run->io.string_down = (vcpu->svm->vmcb->save.rflags - & X86_EFLAGS_DF) != 0; - } - } else - kvm_run->io.value = vcpu->svm->vmcb->save.rax; - return 0; + if (rep) + count = vcpu->regs[VCPU_REGS_RCX] & addr_mask; + } + return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down, + address, rep, port); } static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) @@ -1072,13 +1116,14 @@ static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 1; kvm_run->exit_reason = KVM_EXIT_HLT; - ++kvm_stat.halt_exits; + ++vcpu->stat.halt_exits; return 0; } static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - vcpu->svm->vmcb->save.rip += 3; + vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 3; + skip_emulated_instruction(vcpu); return kvm_hypercall(vcpu, kvm_run); } @@ -1098,8 +1143,8 @@ static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_r static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2; - kvm_run->exit_reason = KVM_EXIT_CPUID; - return 0; + kvm_emulate_cpuid(vcpu); + return 1; } static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) @@ -1239,7 +1284,7 @@ static int interrupt_window_interception(struct kvm_vcpu *vcpu, */ if (kvm_run->request_interrupt_window && !vcpu->irq_summary) { - ++kvm_stat.irq_window_exits; + ++vcpu->stat.irq_window_exits; kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; return 0; } @@ -1267,6 +1312,7 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, [SVM_EXIT_WRITE_DR5] = emulate_on_interception, [SVM_EXIT_WRITE_DR7] = emulate_on_interception, [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, + [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, [SVM_EXIT_INTR] = nop_on_interception, [SVM_EXIT_NMI] = nop_on_interception, [SVM_EXIT_SMI] = nop_on_interception, @@ -1288,6 +1334,8 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, [SVM_EXIT_STGI] = invalid_op_interception, [SVM_EXIT_CLGI] = invalid_op_interception, [SVM_EXIT_SKINIT] = invalid_op_interception, + [SVM_EXIT_MONITOR] = invalid_op_interception, + [SVM_EXIT_MWAIT] = invalid_op_interception, }; @@ -1295,8 +1343,6 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { u32 exit_code = vcpu->svm->vmcb->control.exit_code; - kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT; - if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) && exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR) printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " @@ -1307,12 +1353,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (exit_code >= ARRAY_SIZE(svm_exit_handlers) || svm_exit_handlers[exit_code] == 0) { kvm_run->exit_reason = KVM_EXIT_UNKNOWN; - printk(KERN_ERR "%s: 0x%x @ 0x%llx cr0 0x%lx rflags 0x%llx\n", - __FUNCTION__, - exit_code, - vcpu->svm->vmcb->save.rip, - vcpu->cr0, - vcpu->svm->vmcb->save.rflags); + kvm_run->hw.hardware_exit_reason = exit_code; return 0; } @@ -1461,8 +1502,10 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) load_db_regs(vcpu->svm->db_regs); } - fx_save(vcpu->host_fx_image); - fx_restore(vcpu->guest_fx_image); + if (vcpu->fpu_active) { + fx_save(vcpu->host_fx_image); + fx_restore(vcpu->guest_fx_image); + } asm volatile ( #ifdef CONFIG_X86_64 @@ -1573,8 +1616,10 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) #endif : "cc", "memory" ); - fx_save(vcpu->guest_fx_image); - fx_restore(vcpu->host_fx_image); + if (vcpu->fpu_active) { + fx_save(vcpu->guest_fx_image); + fx_restore(vcpu->host_fx_image); + } if ((vcpu->svm->vmcb->save.dr7 & 0xff)) load_db_regs(vcpu->svm->host_db_regs); @@ -1606,8 +1651,9 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) vcpu->svm->next_rip = 0; if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) { - kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY; - kvm_run->exit_reason = vcpu->svm->vmcb->control.exit_code; + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry.hardware_entry_failure_reason + = vcpu->svm->vmcb->control.exit_code; post_kvm_run_save(vcpu, kvm_run); return 0; } @@ -1615,14 +1661,16 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) r = handle_exit(vcpu, kvm_run); if (r > 0) { if (signal_pending(current)) { - ++kvm_stat.signal_exits; + ++vcpu->stat.signal_exits; post_kvm_run_save(vcpu, kvm_run); + kvm_run->exit_reason = KVM_EXIT_INTR; return -EINTR; } if (dm_request_for_irq_injection(vcpu, kvm_run)) { - ++kvm_stat.request_irq_exits; + ++vcpu->stat.request_irq_exits; post_kvm_run_save(vcpu, kvm_run); + kvm_run->exit_reason = KVM_EXIT_INTR; return -EINTR; } kvm_resched(vcpu); @@ -1641,6 +1689,12 @@ static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) { vcpu->svm->vmcb->save.cr3 = root; force_new_asid(vcpu); + + if (vcpu->fpu_active) { + vcpu->svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); + vcpu->svm->vmcb->save.cr0 |= CR0_TS_MASK; + vcpu->fpu_active = 0; + } } static void svm_inject_page_fault(struct kvm_vcpu *vcpu, @@ -1649,7 +1703,7 @@ static void svm_inject_page_fault(struct kvm_vcpu *vcpu, { uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info; - ++kvm_stat.pf_guest; + ++vcpu->stat.pf_guest; if (is_page_fault(exit_int_info)) { @@ -1709,9 +1763,8 @@ static struct kvm_arch_ops svm_arch_ops = { .get_segment = svm_get_segment, .set_segment = svm_set_segment, .get_cs_db_l_bits = svm_get_cs_db_l_bits, - .decache_cr0_cr4_guest_bits = svm_decache_cr0_cr4_guest_bits, + .decache_cr4_guest_bits = svm_decache_cr4_guest_bits, .set_cr0 = svm_set_cr0, - .set_cr0_no_modeswitch = svm_set_cr0, .set_cr3 = svm_set_cr3, .set_cr4 = svm_set_cr4, .set_efer = svm_set_efer, diff --git a/trunk/drivers/kvm/svm.h b/trunk/drivers/kvm/svm.h index df731c3fb588..5e93814400ce 100644 --- a/trunk/drivers/kvm/svm.h +++ b/trunk/drivers/kvm/svm.h @@ -44,6 +44,9 @@ enum { INTERCEPT_RDTSCP, INTERCEPT_ICEBP, INTERCEPT_WBINVD, + INTERCEPT_MONITOR, + INTERCEPT_MWAIT, + INTERCEPT_MWAIT_COND, }; @@ -298,6 +301,9 @@ struct __attribute__ ((__packed__)) vmcb { #define SVM_EXIT_RDTSCP 0x087 #define SVM_EXIT_ICEBP 0x088 #define SVM_EXIT_WBINVD 0x089 +#define SVM_EXIT_MONITOR 0x08a +#define SVM_EXIT_MWAIT 0x08b +#define SVM_EXIT_MWAIT_COND 0x08c #define SVM_EXIT_NPF 0x400 #define SVM_EXIT_ERR -1 diff --git a/trunk/drivers/kvm/vmx.c b/trunk/drivers/kvm/vmx.c index fbbf9d6b299f..724db0027f00 100644 --- a/trunk/drivers/kvm/vmx.c +++ b/trunk/drivers/kvm/vmx.c @@ -17,7 +17,6 @@ #include "kvm.h" #include "vmx.h" -#include "kvm_vmx.h" #include #include #include @@ -70,6 +69,10 @@ static struct kvm_vmx_segment_field { VMX_SEGMENT_FIELD(LDTR), }; +/* + * Keep MSR_K6_STAR at the end, as setup_msrs() will try to optimize it + * away by decrementing the array size. + */ static const u32 vmx_msr_index[] = { #ifdef CONFIG_X86_64 MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, MSR_KERNEL_GS_BASE, @@ -78,6 +81,19 @@ static const u32 vmx_msr_index[] = { }; #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index) +#ifdef CONFIG_X86_64 +static unsigned msr_offset_kernel_gs_base; +#define NR_64BIT_MSRS 4 +/* + * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt + * mechanism (cpu bug AA24) + */ +#define NR_BAD_MSRS 2 +#else +#define NR_64BIT_MSRS 0 +#define NR_BAD_MSRS 0 +#endif + static inline int is_page_fault(u32 intr_info) { return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | @@ -85,6 +101,13 @@ static inline int is_page_fault(u32 intr_info) (INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK); } +static inline int is_no_device(u32 intr_info) +{ + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | + INTR_INFO_VALID_MASK)) == + (INTR_TYPE_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK); +} + static inline int is_external_interrupt(u32 intr_info) { return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) @@ -200,6 +223,16 @@ static void vmcs_write64(unsigned long field, u64 value) #endif } +static void vmcs_clear_bits(unsigned long field, u32 mask) +{ + vmcs_writel(field, vmcs_readl(field) & ~mask); +} + +static void vmcs_set_bits(unsigned long field, u32 mask) +{ + vmcs_writel(field, vmcs_readl(field) | mask); +} + /* * Switches to specified vcpu, until a matching vcpu_put(), but assumes * vcpu mutex is already taken. @@ -296,6 +329,44 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) INTR_INFO_VALID_MASK); } +/* + * Set up the vmcs to automatically save and restore system + * msrs. Don't touch the 64-bit msrs if the guest is in legacy + * mode, as fiddling with msrs is very expensive. + */ +static void setup_msrs(struct kvm_vcpu *vcpu) +{ + int nr_skip, nr_good_msrs; + + if (is_long_mode(vcpu)) + nr_skip = NR_BAD_MSRS; + else + nr_skip = NR_64BIT_MSRS; + nr_good_msrs = vcpu->nmsrs - nr_skip; + + /* + * MSR_K6_STAR is only needed on long mode guests, and only + * if efer.sce is enabled. + */ + if (find_msr_entry(vcpu, MSR_K6_STAR)) { + --nr_good_msrs; +#ifdef CONFIG_X86_64 + if (is_long_mode(vcpu) && (vcpu->shadow_efer & EFER_SCE)) + ++nr_good_msrs; +#endif + } + + vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR, + virt_to_phys(vcpu->guest_msrs + nr_skip)); + vmcs_writel(VM_EXIT_MSR_STORE_ADDR, + virt_to_phys(vcpu->guest_msrs + nr_skip)); + vmcs_writel(VM_EXIT_MSR_LOAD_ADDR, + virt_to_phys(vcpu->host_msrs + nr_skip)); + vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */ + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */ + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */ +} + /* * reads and returns guest's timestamp counter "register" * guest_tsc = host_tsc + tsc_offset -- 21.3 @@ -712,6 +783,8 @@ static void enter_rmode(struct kvm_vcpu *vcpu) vmcs_write32(GUEST_CS_AR_BYTES, 0xf3); vmcs_write32(GUEST_CS_LIMIT, 0xffff); + if (vmcs_readl(GUEST_CS_BASE) == 0xffff0000) + vmcs_writel(GUEST_CS_BASE, 0xf0000); vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4); fix_rmode_seg(VCPU_SREG_ES, &vcpu->rmode.es); @@ -754,11 +827,8 @@ static void exit_lmode(struct kvm_vcpu *vcpu) #endif -static void vmx_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu) +static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) { - vcpu->cr0 &= KVM_GUEST_CR0_MASK; - vcpu->cr0 |= vmcs_readl(GUEST_CR0) & ~KVM_GUEST_CR0_MASK; - vcpu->cr4 &= KVM_GUEST_CR4_MASK; vcpu->cr4 |= vmcs_readl(GUEST_CR4) & ~KVM_GUEST_CR4_MASK; } @@ -780,22 +850,11 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) } #endif - vmcs_writel(CR0_READ_SHADOW, cr0); - vmcs_writel(GUEST_CR0, - (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON); - vcpu->cr0 = cr0; -} - -/* - * Used when restoring the VM to avoid corrupting segment registers - */ -static void vmx_set_cr0_no_modeswitch(struct kvm_vcpu *vcpu, unsigned long cr0) -{ - if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK)) - enter_rmode(vcpu); + if (!(cr0 & CR0_TS_MASK)) { + vcpu->fpu_active = 1; + vmcs_clear_bits(EXCEPTION_BITMAP, CR0_TS_MASK); + } - vcpu->rmode.active = ((cr0 & CR0_PE_MASK) == 0); - update_exception_bitmap(vcpu); vmcs_writel(CR0_READ_SHADOW, cr0); vmcs_writel(GUEST_CR0, (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON); @@ -805,6 +864,12 @@ static void vmx_set_cr0_no_modeswitch(struct kvm_vcpu *vcpu, unsigned long cr0) static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) { vmcs_writel(GUEST_CR3, cr3); + + if (!(vcpu->cr0 & CR0_TS_MASK)) { + vcpu->fpu_active = 0; + vmcs_set_bits(GUEST_CR0, CR0_TS_MASK); + vmcs_set_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR); + } } static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) @@ -835,6 +900,7 @@ static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) msr->data = efer & ~EFER_LME; } + setup_msrs(vcpu); } #endif @@ -878,7 +944,14 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu, vmcs_writel(sf->base, var->base); vmcs_write32(sf->limit, var->limit); vmcs_write16(sf->selector, var->selector); - if (var->unusable) + if (vcpu->rmode.active && var->s) { + /* + * Hack real-mode segments into vm86 compatibility. + */ + if (var->base == 0xffff0000 && var->selector == 0xf000) + vmcs_writel(sf->base, 0xf0000); + ar = 0xf3; + } else if (var->unusable) ar = 1 << 16; else { ar = var->type & 15; @@ -933,9 +1006,9 @@ static int init_rmode_tss(struct kvm* kvm) gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT; char *page; - p1 = _gfn_to_page(kvm, fn++); - p2 = _gfn_to_page(kvm, fn++); - p3 = _gfn_to_page(kvm, fn); + p1 = gfn_to_page(kvm, fn++); + p2 = gfn_to_page(kvm, fn++); + p3 = gfn_to_page(kvm, fn); if (!p1 || !p2 || !p3) { kvm_printf(kvm,"%s: gfn_to_page failed\n", __FUNCTION__); @@ -991,7 +1064,6 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) struct descriptor_table dt; int i; int ret = 0; - int nr_good_msrs; extern asmlinkage void kvm_vmx_return(void); if (!init_rmode_tss(vcpu->kvm)) { @@ -1136,23 +1208,17 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) vcpu->host_msrs[j].reserved = 0; vcpu->host_msrs[j].data = data; vcpu->guest_msrs[j] = vcpu->host_msrs[j]; +#ifdef CONFIG_X86_64 + if (index == MSR_KERNEL_GS_BASE) + msr_offset_kernel_gs_base = j; +#endif ++vcpu->nmsrs; } - printk(KERN_DEBUG "kvm: msrs: %d\n", vcpu->nmsrs); - nr_good_msrs = vcpu->nmsrs - NR_BAD_MSRS; - vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR, - virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS)); - vmcs_writel(VM_EXIT_MSR_STORE_ADDR, - virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS)); - vmcs_writel(VM_EXIT_MSR_LOAD_ADDR, - virt_to_phys(vcpu->host_msrs + NR_BAD_MSRS)); + setup_msrs(vcpu); + vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS, (HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */ - vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */ - vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */ - vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */ - /* 22.2.1, 20.8.1 */ vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS, @@ -1164,7 +1230,7 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu) vmcs_writel(TPR_THRESHOLD, 0); #endif - vmcs_writel(CR0_GUEST_HOST_MASK, KVM_GUEST_CR0_MASK); + vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL); vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK); vcpu->cr0 = 0x60000010; @@ -1190,7 +1256,7 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) u16 sp = vmcs_readl(GUEST_RSP); u32 ss_limit = vmcs_read32(GUEST_SS_LIMIT); - if (sp > ss_limit || sp - 6 > sp) { + if (sp > ss_limit || sp < 6 ) { vcpu_printf(vcpu, "%s: #SS, rsp 0x%lx ss 0x%lx limit 0x%x\n", __FUNCTION__, vmcs_readl(GUEST_RSP), @@ -1330,6 +1396,15 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) asm ("int $2"); return 1; } + + if (is_no_device(intr_info)) { + vcpu->fpu_active = 1; + vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR); + if (!(vcpu->cr0 & CR0_TS_MASK)) + vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK); + return 1; + } + error_code = 0; rip = vmcs_readl(GUEST_RIP); if (intr_info & INTR_INFO_DELIEVER_CODE_MASK) @@ -1355,7 +1430,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) case EMULATE_DONE: return 1; case EMULATE_DO_MMIO: - ++kvm_stat.mmio_exits; + ++vcpu->stat.mmio_exits; kvm_run->exit_reason = KVM_EXIT_MMIO; return 0; case EMULATE_FAIL: @@ -1384,7 +1459,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) static int handle_external_interrupt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - ++kvm_stat.irq_exits; + ++vcpu->stat.irq_exits; return 1; } @@ -1394,7 +1469,7 @@ static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } -static int get_io_count(struct kvm_vcpu *vcpu, u64 *count) +static int get_io_count(struct kvm_vcpu *vcpu, unsigned long *count) { u64 inst; gva_t rip; @@ -1439,33 +1514,35 @@ static int get_io_count(struct kvm_vcpu *vcpu, u64 *count) done: countr_size *= 8; *count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size)); + //printk("cx: %lx\n", vcpu->regs[VCPU_REGS_RCX]); return 1; } static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { u64 exit_qualification; + int size, down, in, string, rep; + unsigned port; + unsigned long count; + gva_t address; - ++kvm_stat.io_exits; + ++vcpu->stat.io_exits; exit_qualification = vmcs_read64(EXIT_QUALIFICATION); - kvm_run->exit_reason = KVM_EXIT_IO; - if (exit_qualification & 8) - kvm_run->io.direction = KVM_EXIT_IO_IN; - else - kvm_run->io.direction = KVM_EXIT_IO_OUT; - kvm_run->io.size = (exit_qualification & 7) + 1; - kvm_run->io.string = (exit_qualification & 16) != 0; - kvm_run->io.string_down - = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; - kvm_run->io.rep = (exit_qualification & 32) != 0; - kvm_run->io.port = exit_qualification >> 16; - if (kvm_run->io.string) { - if (!get_io_count(vcpu, &kvm_run->io.count)) + in = (exit_qualification & 8) != 0; + size = (exit_qualification & 7) + 1; + string = (exit_qualification & 16) != 0; + down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; + count = 1; + rep = (exit_qualification & 32) != 0; + port = exit_qualification >> 16; + address = 0; + if (string) { + if (rep && !get_io_count(vcpu, &count)) return 1; - kvm_run->io.address = vmcs_readl(GUEST_LINEAR_ADDRESS); - } else - kvm_run->io.value = vcpu->regs[VCPU_REGS_RAX]; /* rax */ - return 0; + address = vmcs_readl(GUEST_LINEAR_ADDRESS); + } + return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down, + address, rep, port); } static void @@ -1514,6 +1591,15 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 1; }; break; + case 2: /* clts */ + vcpu_load_rsp_rip(vcpu); + vcpu->fpu_active = 1; + vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR); + vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK); + vcpu->cr0 &= ~CR0_TS_MASK; + vmcs_writel(CR0_READ_SHADOW, vcpu->cr0); + skip_emulated_instruction(vcpu); + return 1; case 1: /*mov from cr*/ switch (cr) { case 3: @@ -1523,8 +1609,6 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) skip_emulated_instruction(vcpu); return 1; case 8: - printk(KERN_DEBUG "handle_cr: read CR8 " - "cpu erratum AA15\n"); vcpu_load_rsp_rip(vcpu); vcpu->regs[reg] = vcpu->cr8; vcpu_put_rsp_rip(vcpu); @@ -1583,8 +1667,8 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - kvm_run->exit_reason = KVM_EXIT_CPUID; - return 0; + kvm_emulate_cpuid(vcpu); + return 1; } static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) @@ -1639,7 +1723,7 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu, if (kvm_run->request_interrupt_window && !vcpu->irq_summary) { kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; - ++kvm_stat.irq_window_exits; + ++vcpu->stat.irq_window_exits; return 0; } return 1; @@ -1652,13 +1736,13 @@ static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 1; kvm_run->exit_reason = KVM_EXIT_HLT; - ++kvm_stat.halt_exits; + ++vcpu->stat.halt_exits; return 0; } static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - vmcs_writel(GUEST_RIP, vmcs_readl(GUEST_RIP)+3); + skip_emulated_instruction(vcpu); return kvm_hypercall(vcpu, kvm_run); } @@ -1699,7 +1783,6 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) exit_reason != EXIT_REASON_EXCEPTION_NMI ) printk(KERN_WARNING "%s: unexpected, valid vectoring info and " "exit reason is 0x%x\n", __FUNCTION__, exit_reason); - kvm_run->instruction_length = vmcs_read32(VM_EXIT_INSTRUCTION_LEN); if (exit_reason < kvm_vmx_max_exit_handlers && kvm_vmx_exit_handlers[exit_reason]) return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run); @@ -1763,11 +1846,21 @@ static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (vcpu->guest_debug.enabled) kvm_guest_debug_pre(vcpu); - fx_save(vcpu->host_fx_image); - fx_restore(vcpu->guest_fx_image); + if (vcpu->fpu_active) { + fx_save(vcpu->host_fx_image); + fx_restore(vcpu->guest_fx_image); + } + /* + * Loading guest fpu may have cleared host cr0.ts + */ + vmcs_writel(HOST_CR0, read_cr0()); - save_msrs(vcpu->host_msrs, vcpu->nmsrs); - load_msrs(vcpu->guest_msrs, NR_BAD_MSRS); +#ifdef CONFIG_X86_64 + if (is_long_mode(vcpu)) { + save_msrs(vcpu->host_msrs + msr_offset_kernel_gs_base, 1); + load_msrs(vcpu->guest_msrs, NR_BAD_MSRS); + } +#endif asm ( /* Store host registers */ @@ -1909,21 +2002,28 @@ static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) reload_tss(); } - ++kvm_stat.exits; + ++vcpu->stat.exits; - save_msrs(vcpu->guest_msrs, NR_BAD_MSRS); - load_msrs(vcpu->host_msrs, NR_BAD_MSRS); +#ifdef CONFIG_X86_64 + if (is_long_mode(vcpu)) { + save_msrs(vcpu->guest_msrs, NR_BAD_MSRS); + load_msrs(vcpu->host_msrs, NR_BAD_MSRS); + } +#endif + + if (vcpu->fpu_active) { + fx_save(vcpu->guest_fx_image); + fx_restore(vcpu->host_fx_image); + } - fx_save(vcpu->guest_fx_image); - fx_restore(vcpu->host_fx_image); vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); - kvm_run->exit_type = 0; if (fail) { - kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY; - kvm_run->exit_reason = vmcs_read32(VM_INSTRUCTION_ERROR); + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry.hardware_entry_failure_reason + = vmcs_read32(VM_INSTRUCTION_ERROR); r = 0; } else { /* @@ -1933,19 +2033,20 @@ static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP)); vcpu->launched = 1; - kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT; r = kvm_handle_exit(kvm_run, vcpu); if (r > 0) { /* Give scheduler a change to reschedule. */ if (signal_pending(current)) { - ++kvm_stat.signal_exits; + ++vcpu->stat.signal_exits; post_kvm_run_save(vcpu, kvm_run); + kvm_run->exit_reason = KVM_EXIT_INTR; return -EINTR; } if (dm_request_for_irq_injection(vcpu, kvm_run)) { - ++kvm_stat.request_irq_exits; + ++vcpu->stat.request_irq_exits; post_kvm_run_save(vcpu, kvm_run); + kvm_run->exit_reason = KVM_EXIT_INTR; return -EINTR; } @@ -1969,7 +2070,7 @@ static void vmx_inject_page_fault(struct kvm_vcpu *vcpu, { u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); - ++kvm_stat.pf_guest; + ++vcpu->stat.pf_guest; if (is_page_fault(vect_info)) { printk(KERN_DEBUG "inject_page_fault: " @@ -2026,6 +2127,7 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu) vmcs_clear(vmcs); vcpu->vmcs = vmcs; vcpu->launched = 0; + vcpu->fpu_active = 1; return 0; @@ -2062,9 +2164,8 @@ static struct kvm_arch_ops vmx_arch_ops = { .get_segment = vmx_get_segment, .set_segment = vmx_set_segment, .get_cs_db_l_bits = vmx_get_cs_db_l_bits, - .decache_cr0_cr4_guest_bits = vmx_decache_cr0_cr4_guest_bits, + .decache_cr4_guest_bits = vmx_decache_cr4_guest_bits, .set_cr0 = vmx_set_cr0, - .set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch, .set_cr3 = vmx_set_cr3, .set_cr4 = vmx_set_cr4, #ifdef CONFIG_X86_64 diff --git a/trunk/drivers/kvm/x86_emulate.c b/trunk/drivers/kvm/x86_emulate.c index 7513cddb929f..7ade09086aa5 100644 --- a/trunk/drivers/kvm/x86_emulate.c +++ b/trunk/drivers/kvm/x86_emulate.c @@ -833,8 +833,9 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) dst.ptr = (unsigned long *)cr2; dst.bytes = (d & ByteOp) ? 1 : op_bytes; if (d & BitOp) { - dst.ptr += src.val / BITS_PER_LONG; - dst.bytes = sizeof(long); + unsigned long mask = ~(dst.bytes * 8 - 1); + + dst.ptr = (void *)dst.ptr + (src.val & mask) / 8; } if (!(d & Mov) && /* optimisation - avoid slow emulated read */ ((rc = ops->read_emulated((unsigned long)dst.ptr, @@ -1044,7 +1045,7 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) if ((rc = ops->write_std( register_address(ctxt->ss_base, _regs[VCPU_REGS_RSP]), - dst.val, dst.bytes, ctxt)) != 0) + &dst.val, dst.bytes, ctxt)) != 0) goto done; dst.val = dst.orig_val; /* skanky: disable writeback */ break; @@ -1077,12 +1078,12 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) case OP_MEM: if (lock_prefix) rc = ops->cmpxchg_emulated((unsigned long)dst. - ptr, dst.orig_val, - dst.val, dst.bytes, + ptr, &dst.orig_val, + &dst.val, dst.bytes, ctxt); else rc = ops->write_emulated((unsigned long)dst.ptr, - dst.val, dst.bytes, + &dst.val, dst.bytes, ctxt); if (rc != 0) goto done; @@ -1320,36 +1321,8 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags); break; case 0xc7: /* Grp9 (cmpxchg8b) */ -#if defined(__i386__) - { - unsigned long old_lo, old_hi; - if (((rc = ops->read_emulated(cr2 + 0, &old_lo, 4, - ctxt)) != 0) - || ((rc = ops->read_emulated(cr2 + 4, &old_hi, 4, - ctxt)) != 0)) - goto done; - if ((old_lo != _regs[VCPU_REGS_RAX]) - || (old_hi != _regs[VCPU_REGS_RDX])) { - _regs[VCPU_REGS_RAX] = old_lo; - _regs[VCPU_REGS_RDX] = old_hi; - _eflags &= ~EFLG_ZF; - } else if (ops->cmpxchg8b_emulated == NULL) { - rc = X86EMUL_UNHANDLEABLE; - goto done; - } else { - if ((rc = ops->cmpxchg8b_emulated(cr2, old_lo, - old_hi, - _regs[VCPU_REGS_RBX], - _regs[VCPU_REGS_RCX], - ctxt)) != 0) - goto done; - _eflags |= EFLG_ZF; - } - break; - } -#elif defined(CONFIG_X86_64) { - unsigned long old, new; + u64 old, new; if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0) goto done; if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) || @@ -1358,15 +1331,15 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) _regs[VCPU_REGS_RDX] = (u32) (old >> 32); _eflags &= ~EFLG_ZF; } else { - new = (_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX]; - if ((rc = ops->cmpxchg_emulated(cr2, old, - new, 8, ctxt)) != 0) + new = ((u64)_regs[VCPU_REGS_RCX] << 32) + | (u32) _regs[VCPU_REGS_RBX]; + if ((rc = ops->cmpxchg_emulated(cr2, &old, + &new, 8, ctxt)) != 0) goto done; _eflags |= EFLG_ZF; } break; } -#endif } goto writeback; diff --git a/trunk/drivers/kvm/x86_emulate.h b/trunk/drivers/kvm/x86_emulate.h index 5d41bd55125e..ea3407d7feee 100644 --- a/trunk/drivers/kvm/x86_emulate.h +++ b/trunk/drivers/kvm/x86_emulate.h @@ -59,8 +59,7 @@ struct x86_emulate_ops { * @val: [OUT] Value read from memory, zero-extended to 'u_long'. * @bytes: [IN ] Number of bytes to read from memory. */ - int (*read_std)(unsigned long addr, - unsigned long *val, + int (*read_std)(unsigned long addr, void *val, unsigned int bytes, struct x86_emulate_ctxt * ctxt); /* @@ -71,8 +70,7 @@ struct x86_emulate_ops { * required). * @bytes: [IN ] Number of bytes to write to memory. */ - int (*write_std)(unsigned long addr, - unsigned long val, + int (*write_std)(unsigned long addr, const void *val, unsigned int bytes, struct x86_emulate_ctxt * ctxt); /* @@ -82,7 +80,7 @@ struct x86_emulate_ops { * @bytes: [IN ] Number of bytes to read from memory. */ int (*read_emulated) (unsigned long addr, - unsigned long *val, + void *val, unsigned int bytes, struct x86_emulate_ctxt * ctxt); @@ -94,7 +92,7 @@ struct x86_emulate_ops { * @bytes: [IN ] Number of bytes to write to memory. */ int (*write_emulated) (unsigned long addr, - unsigned long val, + const void *val, unsigned int bytes, struct x86_emulate_ctxt * ctxt); @@ -107,29 +105,11 @@ struct x86_emulate_ops { * @bytes: [IN ] Number of bytes to access using CMPXCHG. */ int (*cmpxchg_emulated) (unsigned long addr, - unsigned long old, - unsigned long new, + const void *old, + const void *new, unsigned int bytes, struct x86_emulate_ctxt * ctxt); - /* - * cmpxchg8b_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an - * emulated/special memory area. - * @addr: [IN ] Linear address to access. - * @old: [IN ] Value expected to be current at @addr. - * @new: [IN ] Value to write to @addr. - * NOTES: - * 1. This function is only ever called when emulating a real CMPXCHG8B. - * 2. This function is *never* called on x86/64 systems. - * 2. Not defining this function (i.e., specifying NULL) is equivalent - * to defining a function that always returns X86EMUL_UNHANDLEABLE. - */ - int (*cmpxchg8b_emulated) (unsigned long addr, - unsigned long old_lo, - unsigned long old_hi, - unsigned long new_lo, - unsigned long new_hi, - struct x86_emulate_ctxt * ctxt); }; struct cpu_user_regs; diff --git a/trunk/drivers/macintosh/Kconfig b/trunk/drivers/macintosh/Kconfig index 1a86387e23be..a32c91e27b3c 100644 --- a/trunk/drivers/macintosh/Kconfig +++ b/trunk/drivers/macintosh/Kconfig @@ -1,6 +1,10 @@ -menu "Macintosh device drivers" +menuconfig MACINTOSH_DRIVERS + bool "Macintosh device drivers" depends on PPC || MAC || X86 + default y + +if MACINTOSH_DRIVERS config ADB bool "Apple Desktop Bus (ADB) support" @@ -109,7 +113,9 @@ config PMAC_SMU config PMAC_APM_EMU tristate "APM emulation" - depends on PPC_PMAC && PPC32 && PM && ADB_PMU + select SYS_SUPPORTS_APM_EMULATION + select APM_EMULATION + depends on ADB_PMU && PM config PMAC_MEDIABAY bool "Support PowerBook hotswap media bay" @@ -234,4 +240,4 @@ config PMAC_RACKMETER This driver procides some support to control the front panel blue LEDs "vu-meter" of the XServer macs. -endmenu +endif # MACINTOSH_DRIVERS diff --git a/trunk/drivers/macintosh/apm_emu.c b/trunk/drivers/macintosh/apm_emu.c index cdb0bead9917..9821e6361e60 100644 --- a/trunk/drivers/macintosh/apm_emu.c +++ b/trunk/drivers/macintosh/apm_emu.c @@ -1,9 +1,7 @@ -/* APM emulation layer for PowerMac - * - * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org) +/* + * APM emulation for PMU-based machines * - * Lots of code inherited from apm.c, see appropriate notice in - * arch/i386/kernel/apm.c + * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org) * * 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 @@ -18,429 +16,39 @@ * */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include - +#include +#include #include #include -#include -#include -#include - -#undef DEBUG - -#ifdef DEBUG -#define DBG(args...) printk(KERN_DEBUG args) -//#define DBG(args...) xmon_printf(args) -#else -#define DBG(args...) do { } while (0) -#endif - -/* - * The apm_bios device is one of the misc char devices. - * This is its minor number. - */ -#define APM_MINOR_DEV 134 - -/* - * Maximum number of events stored - */ -#define APM_MAX_EVENTS 20 - -#define FAKE_APM_BIOS_VERSION 0x0101 - -#define APM_USER_NOTIFY_TIMEOUT (5*HZ) - -/* - * The per-file APM data - */ -struct apm_user { - int magic; - struct apm_user * next; - int suser: 1; - int suspend_waiting: 1; - int suspends_pending; - int suspends_read; - int event_head; - int event_tail; - apm_event_t events[APM_MAX_EVENTS]; -}; - -/* - * The magic number in apm_user - */ -#define APM_BIOS_MAGIC 0x4101 - -/* - * Local variables - */ -static int suspends_pending; - -static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); -static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); -static struct apm_user * user_list; - -static void apm_notify_sleep(struct pmu_sleep_notifier *self, int when); -static struct pmu_sleep_notifier apm_sleep_notifier = { - apm_notify_sleep, - SLEEP_LEVEL_USERLAND, -}; - -static const char driver_version[] = "0.5"; /* no spaces */ - -#ifdef DEBUG -static char * apm_event_name[] = { - "system standby", - "system suspend", - "normal resume", - "critical resume", - "low battery", - "power status change", - "update time", - "critical suspend", - "user standby", - "user suspend", - "system standby resume", - "capabilities change" -}; -#define NR_APM_EVENT_NAME \ - (sizeof(apm_event_name) / sizeof(apm_event_name[0])) - -#endif - -static int queue_empty(struct apm_user *as) -{ - return as->event_head == as->event_tail; -} - -static apm_event_t get_queued_event(struct apm_user *as) -{ - as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; - return as->events[as->event_tail]; -} - -static void queue_event(apm_event_t event, struct apm_user *sender) -{ - struct apm_user * as; - - DBG("apm_emu: queue_event(%s)\n", apm_event_name[event-1]); - if (user_list == NULL) - return; - for (as = user_list; as != NULL; as = as->next) { - if (as == sender) - continue; - as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; - if (as->event_head == as->event_tail) { - static int notified; - - if (notified++ == 0) - printk(KERN_ERR "apm_emu: an event queue overflowed\n"); - as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; - } - as->events[as->event_head] = event; - if (!as->suser) - continue; - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - as->suspends_pending++; - suspends_pending++; - break; - case APM_NORMAL_RESUME: - as->suspend_waiting = 0; - break; - } - } - wake_up_interruptible(&apm_waitqueue); -} - -static int check_apm_user(struct apm_user *as, const char *func) -{ - if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { - printk(KERN_ERR "apm_emu: %s passed bad filp\n", func); - return 1; - } - return 0; -} - -static ssize_t do_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos) -{ - struct apm_user * as; - size_t i; - apm_event_t event; - DECLARE_WAITQUEUE(wait, current); - - as = fp->private_data; - if (check_apm_user(as, "read")) - return -EIO; - if (count < sizeof(apm_event_t)) - return -EINVAL; - if (queue_empty(as)) { - if (fp->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&apm_waitqueue, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (queue_empty(as) && !signal_pending(current)) { - schedule(); - goto repeat; - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&apm_waitqueue, &wait); - } - i = count; - while ((i >= sizeof(event)) && !queue_empty(as)) { - event = get_queued_event(as); - DBG("apm_emu: do_read, returning: %s\n", apm_event_name[event-1]); - if (copy_to_user(buf, &event, sizeof(event))) { - if (i < count) - break; - return -EFAULT; - } - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - as->suspends_read++; - break; - } - buf += sizeof(event); - i -= sizeof(event); - } - if (i < count) - return count - i; - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -static unsigned int do_poll(struct file *fp, poll_table * wait) -{ - struct apm_user * as; - - as = fp->private_data; - if (check_apm_user(as, "poll")) - return 0; - poll_wait(fp, &apm_waitqueue, wait); - if (!queue_empty(as)) - return POLLIN | POLLRDNORM; - return 0; -} - -static int do_ioctl(struct inode * inode, struct file *filp, - u_int cmd, u_long arg) -{ - struct apm_user * as; - DECLARE_WAITQUEUE(wait, current); - - as = filp->private_data; - if (check_apm_user(as, "ioctl")) - return -EIO; - if (!as->suser) - return -EPERM; - switch (cmd) { - case APM_IOC_SUSPEND: - /* If a suspend message was sent to userland, we - * consider this as a confirmation message - */ - if (as->suspends_read > 0) { - as->suspends_read--; - as->suspends_pending--; - suspends_pending--; - } else { - // Route to PMU suspend ? - break; - } - as->suspend_waiting = 1; - add_wait_queue(&apm_waitqueue, &wait); - DBG("apm_emu: ioctl waking up sleep waiter !\n"); - wake_up(&apm_suspend_waitqueue); - mb(); - while(as->suspend_waiting && !signal_pending(current)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&apm_waitqueue, &wait); - break; - default: - return -EINVAL; - } - return 0; -} - -static int do_release(struct inode * inode, struct file * filp) -{ - struct apm_user * as; - - as = filp->private_data; - if (check_apm_user(as, "release")) - return 0; - filp->private_data = NULL; - lock_kernel(); - if (as->suspends_pending > 0) { - suspends_pending -= as->suspends_pending; - if (suspends_pending <= 0) - wake_up(&apm_suspend_waitqueue); - } - if (user_list == as) - user_list = as->next; - else { - struct apm_user * as1; - - for (as1 = user_list; - (as1 != NULL) && (as1->next != as); - as1 = as1->next) - ; - if (as1 == NULL) - printk(KERN_ERR "apm: filp not in user list\n"); - else - as1->next = as->next; - } - unlock_kernel(); - kfree(as); - return 0; -} - -static int do_open(struct inode * inode, struct file * filp) -{ - struct apm_user * as; - - as = kmalloc(sizeof(*as), GFP_KERNEL); - if (as == NULL) { - printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n", - sizeof(*as)); - return -ENOMEM; - } - as->magic = APM_BIOS_MAGIC; - as->event_tail = as->event_head = 0; - as->suspends_pending = 0; - as->suspends_read = 0; - /* - * XXX - this is a tiny bit broken, when we consider BSD - * process accounting. If the device is opened by root, we - * instantly flag that we used superuser privs. Who knows, - * we might close the device immediately without doing a - * privileged operation -- cevans - */ - as->suser = capable(CAP_SYS_ADMIN); - as->next = user_list; - user_list = as; - filp->private_data = as; - - DBG("apm_emu: opened by %s, suser: %d\n", current->comm, (int)as->suser); - - return 0; -} - -/* Wait for all clients to ack the suspend request. APM API - * doesn't provide a way to NAK, but this could be added - * here. - */ -static void wait_all_suspend(void) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&apm_suspend_waitqueue, &wait); - DBG("apm_emu: wait_all_suspend(), suspends_pending: %d\n", suspends_pending); - while(suspends_pending > 0) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&apm_suspend_waitqueue, &wait); - - DBG("apm_emu: wait_all_suspend() - complete !\n"); -} - -static void apm_notify_sleep(struct pmu_sleep_notifier *self, int when) -{ - switch(when) { - case PBOOK_SLEEP_REQUEST: - queue_event(APM_SYS_SUSPEND, NULL); - wait_all_suspend(); - break; - case PBOOK_WAKE: - queue_event(APM_NORMAL_RESUME, NULL); - break; - } -} - #define APM_CRITICAL 10 #define APM_LOW 30 -static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length) +static void pmu_apm_get_power_status(struct apm_power_info *info) { - /* Arguments, with symbols from linux/apm_bios.h. Information is - from the Get Power Status (0x0a) call unless otherwise noted. + int percentage = -1; + int batteries = 0; + int time_units = -1; + int real_count = 0; + int i; + char charging = 0; + long charge = -1; + long amperage = 0; + unsigned long btype = 0; + + info->battery_status = APM_BATTERY_STATUS_UNKNOWN; + info->battery_flag = APM_BATTERY_FLAG_UNKNOWN; + info->units = APM_UNITS_MINS; + + if (pmu_power_flags & PMU_PWR_AC_PRESENT) + info->ac_line_status = APM_AC_ONLINE; + else + info->ac_line_status = APM_AC_OFFLINE; - 0) Linux driver version (this will change if format changes) - 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. - 2) APM flags from APM Installation Check (0x00): - bit 0: APM_16_BIT_SUPPORT - bit 1: APM_32_BIT_SUPPORT - bit 2: APM_IDLE_SLOWS_CLOCK - bit 3: APM_BIOS_DISABLED - bit 4: APM_BIOS_DISENGAGED - 3) AC line status - 0x00: Off-line - 0x01: On-line - 0x02: On backup power (BIOS >= 1.1 only) - 0xff: Unknown - 4) Battery status - 0x00: High - 0x01: Low - 0x02: Critical - 0x03: Charging - 0x04: Selected battery not present (BIOS >= 1.2 only) - 0xff: Unknown - 5) Battery flag - bit 0: High - bit 1: Low - bit 2: Critical - bit 3: Charging - bit 7: No system battery - 0xff: Unknown - 6) Remaining battery life (percentage of charge): - 0-100: valid - -1: Unknown - 7) Remaining battery life (time units): - Number of remaining minutes or seconds - -1: Unknown - 8) min = minutes; sec = seconds */ - - unsigned short ac_line_status; - unsigned short battery_status = 0; - unsigned short battery_flag = 0xff; - int percentage = -1; - int time_units = -1; - int real_count = 0; - int i; - char * p = buf; - char charging = 0; - long charge = -1; - long amperage = 0; - unsigned long btype = 0; - - ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0); for (i=0; iac_line_status = APM_AC_ONLINE; + if (real_count) { if (amperage < 0) { if (btype == PMU_BATT_TYPE_SMART) @@ -468,85 +76,44 @@ static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length) } percentage /= real_count; if (charging > 0) { - battery_status = 0x03; - battery_flag = 0x08; + info->battery_status = APM_BATTERY_STATUS_CHARGING; + info->battery_flag = APM_BATTERY_FLAG_CHARGING; } else if (percentage <= APM_CRITICAL) { - battery_status = 0x02; - battery_flag = 0x04; + info->battery_status = APM_BATTERY_STATUS_CRITICAL; + info->battery_flag = APM_BATTERY_FLAG_CRITICAL; } else if (percentage <= APM_LOW) { - battery_status = 0x01; - battery_flag = 0x02; + info->battery_status = APM_BATTERY_STATUS_LOW; + info->battery_flag = APM_BATTERY_FLAG_LOW; } else { - battery_status = 0x00; - battery_flag = 0x01; + info->battery_status = APM_BATTERY_STATUS_HIGH; + info->battery_flag = APM_BATTERY_FLAG_HIGH; } } - p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", - driver_version, - (FAKE_APM_BIOS_VERSION >> 8) & 0xff, - FAKE_APM_BIOS_VERSION & 0xff, - 0, - ac_line_status, - battery_status, - battery_flag, - percentage, - time_units, - "min"); - return p - buf; + info->battery_life = percentage; + info->time = time_units; } -static const struct file_operations apm_bios_fops = { - .owner = THIS_MODULE, - .read = do_read, - .poll = do_poll, - .ioctl = do_ioctl, - .open = do_open, - .release = do_release, -}; - -static struct miscdevice apm_device = { - APM_MINOR_DEV, - "apm_bios", - &apm_bios_fops -}; - static int __init apm_emu_init(void) { - struct proc_dir_entry *apm_proc; - - if (sys_ctrler != SYS_CTRLER_PMU) { - printk(KERN_INFO "apm_emu: Requires a machine with a PMU.\n"); - return -ENODEV; - } - - apm_proc = create_proc_info_entry("apm", 0, NULL, apm_emu_get_info); - if (apm_proc) - apm_proc->owner = THIS_MODULE; + apm_get_power_status = pmu_apm_get_power_status; - if (misc_register(&apm_device) != 0) - printk(KERN_INFO "Could not create misc. device for apm\n"); - - pmu_register_sleep_notifier(&apm_sleep_notifier); - - printk(KERN_INFO "apm_emu: APM Emulation %s initialized.\n", driver_version); + printk(KERN_INFO "apm_emu: PMU APM Emulation initialized.\n"); return 0; } static void __exit apm_emu_exit(void) { - pmu_unregister_sleep_notifier(&apm_sleep_notifier); - misc_deregister(&apm_device); - remove_proc_entry("apm", NULL); + if (apm_get_power_status == pmu_apm_get_power_status) + apm_get_power_status = NULL; - printk(KERN_INFO "apm_emu: APM Emulation removed.\n"); + printk(KERN_INFO "apm_emu: PMU APM Emulation removed.\n"); } module_init(apm_emu_init); module_exit(apm_emu_exit); MODULE_AUTHOR("Benjamin Herrenschmidt"); -MODULE_DESCRIPTION("APM emulation layer for PowerMac"); +MODULE_DESCRIPTION("APM emulation for PowerMac"); MODULE_LICENSE("GPL"); - diff --git a/trunk/drivers/macintosh/mac_hid.c b/trunk/drivers/macintosh/mac_hid.c index 1599dc34f15f..76c1e8e4a487 100644 --- a/trunk/drivers/macintosh/mac_hid.c +++ b/trunk/drivers/macintosh/mac_hid.c @@ -24,7 +24,7 @@ static int mouse_last_keycode; #if defined(CONFIG_SYSCTL) /* file(s) in /proc/sys/dev/mac_hid */ -ctl_table mac_hid_files[] = { +static ctl_table mac_hid_files[] = { { .ctl_name = DEV_MAC_HID_MOUSE_BUTTON_EMULATION, .procname = "mouse_button_emulation", @@ -53,7 +53,7 @@ ctl_table mac_hid_files[] = { }; /* dir in /proc/sys/dev */ -ctl_table mac_hid_dir[] = { +static ctl_table mac_hid_dir[] = { { .ctl_name = DEV_MAC_HID, .procname = "mac_hid", @@ -65,7 +65,7 @@ ctl_table mac_hid_dir[] = { }; /* /proc/sys/dev itself, in case that is not there yet */ -ctl_table mac_hid_root_dir[] = { +static ctl_table mac_hid_root_dir[] = { { .ctl_name = CTL_DEV, .procname = "dev", @@ -127,7 +127,7 @@ static int emumousebtn_input_register(void) return ret; } -int __init mac_hid_init(void) +static int __init mac_hid_init(void) { int err; diff --git a/trunk/drivers/macintosh/macio_sysfs.c b/trunk/drivers/macintosh/macio_sysfs.c index cc8267912656..112e5ef728f1 100644 --- a/trunk/drivers/macintosh/macio_sysfs.c +++ b/trunk/drivers/macintosh/macio_sysfs.c @@ -41,28 +41,15 @@ compatible_show (struct device *dev, struct device_attribute *attr, char *buf) static ssize_t modalias_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct of_device *of; - const char *compat; - int cplen; - int length; + struct of_device *ofdev = to_of_device(dev); + int len; - of = &to_macio_device (dev)->ofdev; - compat = of_get_property(of->node, "compatible", &cplen); - if (!compat) compat = "", cplen = 1; - length = sprintf (buf, "of:N%sT%s", of->node->name, of->node->type); - buf += length; - while (cplen > 0) { - int l; - l = sprintf (buf, "C%s", compat); - length += l; - buf += l; - l = strlen (compat) + 1; - compat += l; - cplen -= l; - } - length += sprintf(buf, "\n"); + len = of_device_get_modalias(ofdev, buf, PAGE_SIZE); - return length; + buf[len] = '\n'; + buf[len+1] = 0; + + return len+1; } macio_config_of_attr (name, "%s\n"); diff --git a/trunk/drivers/macintosh/smu.c b/trunk/drivers/macintosh/smu.c index a98a328b1cfc..f8e1a135bf9d 100644 --- a/trunk/drivers/macintosh/smu.c +++ b/trunk/drivers/macintosh/smu.c @@ -606,7 +606,7 @@ static void smu_expose_childs(struct work_struct *unused) struct device_node *np; for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;) - if (device_is_compatible(np, "smu-sensors")) + if (of_device_is_compatible(np, "smu-sensors")) of_platform_device_create(np, "smu-sensors", &smu->of_dev->dev); } diff --git a/trunk/drivers/macintosh/therm_adt746x.c b/trunk/drivers/macintosh/therm_adt746x.c index 228903403cfc..bd55e6ab99fc 100644 --- a/trunk/drivers/macintosh/therm_adt746x.c +++ b/trunk/drivers/macintosh/therm_adt746x.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -560,9 +559,9 @@ thermostat_init(void) np = of_find_node_by_name(NULL, "fan"); if (!np) return -ENODEV; - if (device_is_compatible(np, "adt7460")) + if (of_device_is_compatible(np, "adt7460")) therm_type = ADT7460; - else if (device_is_compatible(np, "adt7467")) + else if (of_device_is_compatible(np, "adt7467")) therm_type = ADT7467; else return -ENODEV; diff --git a/trunk/drivers/macintosh/therm_pm72.c b/trunk/drivers/macintosh/therm_pm72.c index 78ff18617139..dbb22403979f 100644 --- a/trunk/drivers/macintosh/therm_pm72.c +++ b/trunk/drivers/macintosh/therm_pm72.c @@ -117,7 +117,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/macintosh/via-pmu-led.c b/trunk/drivers/macintosh/via-pmu-led.c index fc89a7047cd0..55ad95671387 100644 --- a/trunk/drivers/macintosh/via-pmu-led.c +++ b/trunk/drivers/macintosh/via-pmu-led.c @@ -31,7 +31,6 @@ static spinlock_t pmu_blink_lock; static struct adb_request pmu_blink_req; /* -1: no change, 0: request off, 1: request on */ static int requested_change; -static int sleeping; static void pmu_req_done(struct adb_request * req) { @@ -41,7 +40,7 @@ static void pmu_req_done(struct adb_request * req) /* if someone requested a change in the meantime * (we only see the last one which is fine) * then apply it now */ - if (requested_change != -1 && !sleeping) + if (requested_change != -1 && !pmu_sys_suspended) pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change); /* reset requested change */ requested_change = -1; @@ -66,7 +65,7 @@ static void pmu_led_set(struct led_classdev *led_cdev, break; } /* if request isn't done, then don't do anything */ - if (pmu_blink_req.complete && !sleeping) + if (pmu_blink_req.complete && !pmu_sys_suspended) pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change); out: spin_unlock_irqrestore(&pmu_blink_lock, flags); @@ -80,32 +79,6 @@ static struct led_classdev pmu_led = { .brightness_set = pmu_led_set, }; -#ifdef CONFIG_PM -static void pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when) -{ - unsigned long flags; - - spin_lock_irqsave(&pmu_blink_lock, flags); - - switch (when) { - case PBOOK_SLEEP_REQUEST: - sleeping = 1; - break; - case PBOOK_WAKE: - sleeping = 0; - break; - default: - /* do nothing */ - break; - } - spin_unlock_irqrestore(&pmu_blink_lock, flags); -} - -static struct pmu_sleep_notifier via_pmu_led_sleep_notif = { - .notifier_call = pmu_led_sleep_call, -}; -#endif - static int __init via_pmu_led_init(void) { struct device_node *dt; @@ -135,9 +108,7 @@ static int __init via_pmu_led_init(void) /* no outstanding req */ pmu_blink_req.complete = 1; pmu_blink_req.done = pmu_req_done; -#ifdef CONFIG_PM - pmu_register_sleep_notifier(&via_pmu_led_sleep_notif); -#endif + return led_classdev_register(NULL, &pmu_led); } diff --git a/trunk/drivers/macintosh/via-pmu.c b/trunk/drivers/macintosh/via-pmu.c index 1729d3fd7a11..157080b3b468 100644 --- a/trunk/drivers/macintosh/via-pmu.c +++ b/trunk/drivers/macintosh/via-pmu.c @@ -310,14 +310,14 @@ int __init find_via_pmu(void) PMU_INT_TICK; if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0) - || device_is_compatible(vias->parent, "ohare"))) + || of_device_is_compatible(vias->parent, "ohare"))) pmu_kind = PMU_OHARE_BASED; - else if (device_is_compatible(vias->parent, "paddington")) + else if (of_device_is_compatible(vias->parent, "paddington")) pmu_kind = PMU_PADDINGTON_BASED; - else if (device_is_compatible(vias->parent, "heathrow")) + else if (of_device_is_compatible(vias->parent, "heathrow")) pmu_kind = PMU_HEATHROW_BASED; - else if (device_is_compatible(vias->parent, "Keylargo") - || device_is_compatible(vias->parent, "K2-Keylargo")) { + else if (of_device_is_compatible(vias->parent, "Keylargo") + || of_device_is_compatible(vias->parent, "K2-Keylargo")) { struct device_node *gpiop; struct device_node *adbp; u64 gaddr = OF_BAD_ADDR; @@ -2759,7 +2759,7 @@ pmu_polled_request(struct adb_request *req) #if defined(CONFIG_PM) && defined(CONFIG_PPC32) -static int pmu_sys_suspended; +int pmu_sys_suspended; static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state) { diff --git a/trunk/drivers/macintosh/windfarm_core.c b/trunk/drivers/macintosh/windfarm_core.c index 94c117ef20c1..192b26e97777 100644 --- a/trunk/drivers/macintosh/windfarm_core.c +++ b/trunk/drivers/macintosh/windfarm_core.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/macintosh/windfarm_lm75_sensor.c b/trunk/drivers/macintosh/windfarm_lm75_sensor.c index ab4d1b63f63e..a0fabf3c2008 100644 --- a/trunk/drivers/macintosh/windfarm_lm75_sensor.c +++ b/trunk/drivers/macintosh/windfarm_lm75_sensor.c @@ -188,10 +188,10 @@ static int wf_lm75_attach(struct i2c_adapter *adapter) if (loc == NULL || addr == 0) continue; /* real lm75 */ - if (device_is_compatible(dev, "lm75")) + if (of_device_is_compatible(dev, "lm75")) wf_lm75_create(adapter, addr, 0, loc); /* ds1775 (compatible, better resolution */ - else if (device_is_compatible(dev, "ds1775")) + else if (of_device_is_compatible(dev, "ds1775")) wf_lm75_create(adapter, addr, 1, loc); } return 0; diff --git a/trunk/drivers/macintosh/windfarm_max6690_sensor.c b/trunk/drivers/macintosh/windfarm_max6690_sensor.c index eaa74afa175b..5f03aab9fb5d 100644 --- a/trunk/drivers/macintosh/windfarm_max6690_sensor.c +++ b/trunk/drivers/macintosh/windfarm_max6690_sensor.c @@ -131,7 +131,7 @@ static int wf_max6690_attach(struct i2c_adapter *adapter) */ if (!pmac_i2c_match_adapter(dev, adapter)) continue; - if (!device_is_compatible(dev, "max6690")) + if (!of_device_is_compatible(dev, "max6690")) continue; addr = pmac_i2c_get_dev_addr(dev); loc = of_get_property(dev, "hwsensor-location", NULL); diff --git a/trunk/drivers/macintosh/windfarm_smu_controls.c b/trunk/drivers/macintosh/windfarm_smu_controls.c index ff398adc0283..58c2590f05ec 100644 --- a/trunk/drivers/macintosh/windfarm_smu_controls.c +++ b/trunk/drivers/macintosh/windfarm_smu_controls.c @@ -263,7 +263,7 @@ static int __init smu_controls_init(void) /* Look for RPM fans */ for (fans = NULL; (fans = of_get_next_child(smu, fans)) != NULL;) if (!strcmp(fans->name, "rpm-fans") || - device_is_compatible(fans, "smu-rpm-fans")) + of_device_is_compatible(fans, "smu-rpm-fans")) break; for (fan = NULL; fans && (fan = of_get_next_child(fans, fan)) != NULL;) { diff --git a/trunk/drivers/macintosh/windfarm_smu_sat.c b/trunk/drivers/macintosh/windfarm_smu_sat.c index 9a6c2cf8fd0e..1043b39aa123 100644 --- a/trunk/drivers/macintosh/windfarm_smu_sat.c +++ b/trunk/drivers/macintosh/windfarm_smu_sat.c @@ -380,7 +380,7 @@ static int wf_sat_attach(struct i2c_adapter *adapter) busnode = pmac_i2c_get_bus_node(bus); while ((dev = of_get_next_child(busnode, dev)) != NULL) - if (device_is_compatible(dev, "smu-sat")) + if (of_device_is_compatible(dev, "smu-sat")) wf_sat_create(adapter, dev); return 0; } diff --git a/trunk/drivers/md/bitmap.c b/trunk/drivers/md/bitmap.c index e61e0efe9ec7..5a4a74c1097c 100644 --- a/trunk/drivers/md/bitmap.c +++ b/trunk/drivers/md/bitmap.c @@ -1456,10 +1456,10 @@ int bitmap_create(mddev_t *mddev) bitmap->offset = mddev->bitmap_offset; if (file) { get_file(file); - do_sync_file_range(file, 0, LLONG_MAX, - SYNC_FILE_RANGE_WAIT_BEFORE | - SYNC_FILE_RANGE_WRITE | - SYNC_FILE_RANGE_WAIT_AFTER); + do_sync_mapping_range(file->f_mapping, 0, LLONG_MAX, + SYNC_FILE_RANGE_WAIT_BEFORE | + SYNC_FILE_RANGE_WRITE | + SYNC_FILE_RANGE_WAIT_AFTER); } /* read superblock from bitmap file (this sets bitmap->chunksize) */ err = bitmap_read_sb(bitmap); diff --git a/trunk/drivers/md/md.c b/trunk/drivers/md/md.c index 509171ca7fa8..2b4315d7e5d6 100644 --- a/trunk/drivers/md/md.c +++ b/trunk/drivers/md/md.c @@ -3080,7 +3080,7 @@ static int do_md_run(mddev_t * mddev) if (test_bit(Faulty, &rdev->flags)) continue; sync_blockdev(rdev->bdev); - invalidate_bdev(rdev->bdev, 0); + invalidate_bdev(rdev->bdev); } md_probe(mddev->unit, NULL, NULL); diff --git a/trunk/drivers/media/dvb/bt8xx/dst_common.h b/trunk/drivers/media/dvb/bt8xx/dst_common.h index 3bf084f2e522..87623d203a89 100644 --- a/trunk/drivers/media/dvb/bt8xx/dst_common.h +++ b/trunk/drivers/media/dvb/bt8xx/dst_common.h @@ -22,7 +22,6 @@ #ifndef DST_COMMON_H #define DST_COMMON_H -#include #include #include #include diff --git a/trunk/drivers/media/dvb/ttpci/av7110_av.c b/trunk/drivers/media/dvb/ttpci/av7110_av.c index 654c9e919e04..58678c05aa53 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_av.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_av.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include "av7110.h" diff --git a/trunk/drivers/media/dvb/ttpci/av7110_ca.c b/trunk/drivers/media/dvb/ttpci/av7110_ca.c index e9b4e88e7932..e1c1294bb767 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_ca.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_ca.c @@ -34,7 +34,6 @@ #include #include #include -#include #include "av7110.h" #include "av7110_hw.h" diff --git a/trunk/drivers/media/dvb/ttpci/av7110_hw.c b/trunk/drivers/media/dvb/ttpci/av7110_hw.c index 4d7150e15d1e..70aee4eb5da4 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_hw.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_hw.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include "av7110.h" diff --git a/trunk/drivers/media/dvb/ttpci/av7110_v4l.c b/trunk/drivers/media/dvb/ttpci/av7110_v4l.c index cde5d3ae7ec7..fcd9994058d0 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_v4l.c @@ -31,7 +31,6 @@ #include #include #include -#include #include "av7110.h" #include "av7110_hw.h" diff --git a/trunk/drivers/media/radio/dsbr100.c b/trunk/drivers/media/radio/dsbr100.c index df8d0520d1d1..449df1bb00d3 100644 --- a/trunk/drivers/media/radio/dsbr100.c +++ b/trunk/drivers/media/radio/dsbr100.c @@ -79,7 +79,6 @@ #include #include #include -#include /* * Version Information diff --git a/trunk/drivers/media/video/cpia.h b/trunk/drivers/media/video/cpia.h index 6eaa692021c5..78392fb6f94e 100644 --- a/trunk/drivers/media/video/cpia.h +++ b/trunk/drivers/media/video/cpia.h @@ -47,7 +47,6 @@ #include #include #include -#include #include struct cpia_camera_ops diff --git a/trunk/drivers/media/video/cpia_pp.c b/trunk/drivers/media/video/cpia_pp.c index 19711aaf9a3e..c431df8248d6 100644 --- a/trunk/drivers/media/video/cpia_pp.c +++ b/trunk/drivers/media/video/cpia_pp.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/media/video/cx88/cx88-alsa.c b/trunk/drivers/media/video/cx88/cx88-alsa.c index 3956c257556c..2d666b56020c 100644 --- a/trunk/drivers/media/video/cx88/cx88-alsa.c +++ b/trunk/drivers/media/video/cx88/cx88-alsa.c @@ -27,6 +27,8 @@ #include #include #include +#include + #include #include #include diff --git a/trunk/drivers/media/video/cx88/cx88-mpeg.c b/trunk/drivers/media/video/cx88/cx88-mpeg.c index b2eb32e01aee..2ebde2fdbcbe 100644 --- a/trunk/drivers/media/video/cx88/cx88-mpeg.c +++ b/trunk/drivers/media/video/cx88/cx88-mpeg.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/media/video/cx88/cx88-tvaudio.c b/trunk/drivers/media/video/cx88/cx88-tvaudio.c index e627062fde3a..259ea08e784f 100644 --- a/trunk/drivers/media/video/cx88/cx88-tvaudio.c +++ b/trunk/drivers/media/video/cx88/cx88-tvaudio.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/media/video/cx88/cx88-video.c b/trunk/drivers/media/video/cx88/cx88-video.c index fbce1d50578b..b94ef8ab28c1 100644 --- a/trunk/drivers/media/video/cx88/cx88-video.c +++ b/trunk/drivers/media/video/cx88/cx88-video.c @@ -1,4 +1,3 @@ - /* * * device driver for Conexant 2388x based TV cards @@ -34,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/dabusb.c b/trunk/drivers/media/video/dabusb.c index ff4b238090ac..a5731f90be0f 100644 --- a/trunk/drivers/media/video/dabusb.c +++ b/trunk/drivers/media/video/dabusb.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include "dabusb.h" diff --git a/trunk/drivers/media/video/ov511.h b/trunk/drivers/media/video/ov511.h index 68b082bcee1d..18c64222dd11 100644 --- a/trunk/drivers/media/video/ov511.h +++ b/trunk/drivers/media/video/ov511.h @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-main.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-main.c index e976c484c058..9ea41c6699bb 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/media/video/saa7134/saa7134-tvaudio.c b/trunk/drivers/media/video/saa7134/saa7134-tvaudio.c index dd759d6d8d25..7b56041186dc 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/trunk/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include "saa7134-reg.h" diff --git a/trunk/drivers/media/video/se401.h b/trunk/drivers/media/video/se401.h index c0891b3e0018..835ef872e803 100644 --- a/trunk/drivers/media/video/se401.h +++ b/trunk/drivers/media/video/se401.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #define se401_DEBUG /* Turn on debug messages */ diff --git a/trunk/drivers/media/video/tvaudio.c b/trunk/drivers/media/video/tvaudio.c index a2da5d2affff..c9bf9dbc2ea3 100644 --- a/trunk/drivers/media/video/tvaudio.c +++ b/trunk/drivers/media/video/tvaudio.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/media/video/usbvideo/usbvideo.c b/trunk/drivers/media/video/usbvideo/usbvideo.c index 687f026753b2..37ce36b9e587 100644 --- a/trunk/drivers/media/video/usbvideo/usbvideo.c +++ b/trunk/drivers/media/video/usbvideo/usbvideo.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/media/video/usbvision/usbvision-core.c b/trunk/drivers/media/video/usbvision/usbvision-core.c index bcb551adb7e6..9118a6227ea6 100644 --- a/trunk/drivers/media/video/usbvision/usbvision-core.c +++ b/trunk/drivers/media/video/usbvision/usbvision-core.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/media/video/usbvision/usbvision-video.c b/trunk/drivers/media/video/usbvision/usbvision-video.c index 216704170a4c..aa3258bbb4af 100644 --- a/trunk/drivers/media/video/usbvision/usbvision-video.c +++ b/trunk/drivers/media/video/usbvision/usbvision-video.c @@ -52,7 +52,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/media/video/v4l1-compat.c b/trunk/drivers/media/video/v4l1-compat.c index d2c1ae0dbfba..a861e150865e 100644 --- a/trunk/drivers/media/video/v4l1-compat.c +++ b/trunk/drivers/media/video/v4l1-compat.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/media/video/v4l2-common.c b/trunk/drivers/media/video/v4l2-common.c index 49f1df74aa21..13ee550d3215 100644 --- a/trunk/drivers/media/video/v4l2-common.c +++ b/trunk/drivers/media/video/v4l2-common.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/media/video/videodev.c b/trunk/drivers/media/video/videodev.c index 80ac5f86d9e5..5263b50463e1 100644 --- a/trunk/drivers/media/video/videodev.c +++ b/trunk/drivers/media/video/videodev.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/media/video/zoran_driver.c b/trunk/drivers/media/video/zoran_driver.c index 074323733352..cf0ed6cbb0e3 100644 --- a/trunk/drivers/media/video/zoran_driver.c +++ b/trunk/drivers/media/video/zoran_driver.c @@ -2034,7 +2034,7 @@ zoran_do_ioctl (struct inode *inode, * but moving the free code outside the munmap() handler fixes * all this... If someone knows why, please explain me (Ronald) */ - if (!!mutex_trylock(&zr->resource_lock)) { + if (mutex_trylock(&zr->resource_lock)) { /* we obtained it! Let's try to free some things */ if (fh->jpg_buffers.ready_to_be_freed) jpg_fbuffer_free(file); diff --git a/trunk/drivers/message/i2o/i2o_lan.h b/trunk/drivers/message/i2o/i2o_lan.h deleted file mode 100644 index 6502b817df58..000000000000 --- a/trunk/drivers/message/i2o/i2o_lan.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * i2o_lan.h I2O LAN Class definitions - * - * I2O LAN CLASS OSM May 26th 2000 - * - * (C) Copyright 1999, 2000 University of Helsinki, - * Department of Computer Science - * - * This code is still under development / test. - * - * Author: Auvo Häkkinen - * Juha Sievänen - * Taneli Vähäkangas - */ - -#ifndef _I2O_LAN_H -#define _I2O_LAN_H - -/* Default values for tunable parameters first */ - -#define I2O_LAN_MAX_BUCKETS_OUT 96 -#define I2O_LAN_BUCKET_THRESH 18 /* 9 buckets in one message */ -#define I2O_LAN_RX_COPYBREAK 200 -#define I2O_LAN_TX_TIMEOUT (1*HZ) -#define I2O_LAN_TX_BATCH_MODE 2 /* 2=automatic, 1=on, 0=off */ -#define I2O_LAN_EVENT_MASK 0 /* 0=None, 0xFFC00002=All */ - -/* LAN types */ -#define I2O_LAN_ETHERNET 0x0030 -#define I2O_LAN_100VG 0x0040 -#define I2O_LAN_TR 0x0050 -#define I2O_LAN_FDDI 0x0060 -#define I2O_LAN_FIBRE_CHANNEL 0x0070 -#define I2O_LAN_UNKNOWN 0x00000000 - -/* Connector types */ - -/* Ethernet */ -#define I2O_LAN_AUI (I2O_LAN_ETHERNET << 4) + 0x00000001 -#define I2O_LAN_10BASE5 (I2O_LAN_ETHERNET << 4) + 0x00000002 -#define I2O_LAN_FIORL (I2O_LAN_ETHERNET << 4) + 0x00000003 -#define I2O_LAN_10BASE2 (I2O_LAN_ETHERNET << 4) + 0x00000004 -#define I2O_LAN_10BROAD36 (I2O_LAN_ETHERNET << 4) + 0x00000005 -#define I2O_LAN_10BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000006 -#define I2O_LAN_10BASE_FP (I2O_LAN_ETHERNET << 4) + 0x00000007 -#define I2O_LAN_10BASE_FB (I2O_LAN_ETHERNET << 4) + 0x00000008 -#define I2O_LAN_10BASE_FL (I2O_LAN_ETHERNET << 4) + 0x00000009 -#define I2O_LAN_100BASE_TX (I2O_LAN_ETHERNET << 4) + 0x0000000A -#define I2O_LAN_100BASE_FX (I2O_LAN_ETHERNET << 4) + 0x0000000B -#define I2O_LAN_100BASE_T4 (I2O_LAN_ETHERNET << 4) + 0x0000000C -#define I2O_LAN_1000BASE_SX (I2O_LAN_ETHERNET << 4) + 0x0000000D -#define I2O_LAN_1000BASE_LX (I2O_LAN_ETHERNET << 4) + 0x0000000E -#define I2O_LAN_1000BASE_CX (I2O_LAN_ETHERNET << 4) + 0x0000000F -#define I2O_LAN_1000BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000010 - -/* AnyLAN */ -#define I2O_LAN_100VG_ETHERNET (I2O_LAN_100VG << 4) + 0x00000001 -#define I2O_LAN_100VG_TR (I2O_LAN_100VG << 4) + 0x00000002 - -/* Token Ring */ -#define I2O_LAN_4MBIT (I2O_LAN_TR << 4) + 0x00000001 -#define I2O_LAN_16MBIT (I2O_LAN_TR << 4) + 0x00000002 - -/* FDDI */ -#define I2O_LAN_125MBAUD (I2O_LAN_FDDI << 4) + 0x00000001 - -/* Fibre Channel */ -#define I2O_LAN_POINT_POINT (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000001 -#define I2O_LAN_ARB_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000002 -#define I2O_LAN_PUBLIC_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000003 -#define I2O_LAN_FABRIC (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000004 - -#define I2O_LAN_EMULATION 0x00000F00 -#define I2O_LAN_OTHER 0x00000F01 -#define I2O_LAN_DEFAULT 0xFFFFFFFF - -/* LAN class functions */ - -#define LAN_PACKET_SEND 0x3B -#define LAN_SDU_SEND 0x3D -#define LAN_RECEIVE_POST 0x3E -#define LAN_RESET 0x35 -#define LAN_SUSPEND 0x37 - -/* LAN DetailedStatusCode defines */ -#define I2O_LAN_DSC_SUCCESS 0x00 -#define I2O_LAN_DSC_DEVICE_FAILURE 0x01 -#define I2O_LAN_DSC_DESTINATION_NOT_FOUND 0x02 -#define I2O_LAN_DSC_TRANSMIT_ERROR 0x03 -#define I2O_LAN_DSC_TRANSMIT_ABORTED 0x04 -#define I2O_LAN_DSC_RECEIVE_ERROR 0x05 -#define I2O_LAN_DSC_RECEIVE_ABORTED 0x06 -#define I2O_LAN_DSC_DMA_ERROR 0x07 -#define I2O_LAN_DSC_BAD_PACKET_DETECTED 0x08 -#define I2O_LAN_DSC_OUT_OF_MEMORY 0x09 -#define I2O_LAN_DSC_BUCKET_OVERRUN 0x0A -#define I2O_LAN_DSC_IOP_INTERNAL_ERROR 0x0B -#define I2O_LAN_DSC_CANCELED 0x0C -#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT 0x0D -#define I2O_LAN_DSC_DEST_ADDRESS_DETECTED 0x0E -#define I2O_LAN_DSC_DEST_ADDRESS_OMITTED 0x0F -#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x10 -#define I2O_LAN_DSC_SUSPENDED 0x11 - -struct i2o_packet_info { - u32 offset:24; - u32 flags:8; - u32 len:24; - u32 status:8; -}; - -struct i2o_bucket_descriptor { - u32 context; /* FIXME: 64bit support */ - struct i2o_packet_info packet_info[1]; -}; - -/* Event Indicator Mask Flags for LAN OSM */ - -#define I2O_LAN_EVT_LINK_DOWN 0x01 -#define I2O_LAN_EVT_LINK_UP 0x02 -#define I2O_LAN_EVT_MEDIA_CHANGE 0x04 - -#include -#include - -struct i2o_lan_local { - u8 unit; - struct i2o_device *i2o_dev; - - struct fddi_statistics stats; /* see also struct net_device_stats */ - unsigned short (*type_trans) (struct sk_buff *, struct net_device *); - atomic_t buckets_out; /* nbr of unused buckets on DDM */ - atomic_t tx_out; /* outstanding TXes */ - u8 tx_count; /* packets in one TX message frame */ - u16 tx_max_out; /* DDM's Tx queue len */ - u8 sgl_max; /* max SGLs in one message frame */ - u32 m; /* IOP address of the batch msg frame */ - - struct work_struct i2o_batch_send_task; - int send_active; - struct sk_buff **i2o_fbl; /* Free bucket list (to reuse skbs) */ - int i2o_fbl_tail; - spinlock_t fbl_lock; - - spinlock_t tx_lock; - - u32 max_size_mc_table; /* max number of multicast addresses */ - - /* LAN OSM configurable parameters are here: */ - - u16 max_buckets_out; /* max nbr of buckets to send to DDM */ - u16 bucket_thresh; /* send more when this many used */ - u16 rx_copybreak; - - u8 tx_batch_mode; /* Set when using batch mode sends */ - u32 i2o_event_mask; /* To turn on interesting event flags */ -}; - -#endif /* _I2O_LAN_H */ diff --git a/trunk/drivers/mfd/ucb1x00-ts.c b/trunk/drivers/mfd/ucb1x00-ts.c index ce1a48108210..cb8c264eaff0 100644 --- a/trunk/drivers/mfd/ucb1x00-ts.c +++ b/trunk/drivers/mfd/ucb1x00-ts.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/misc/Kconfig b/trunk/drivers/misc/Kconfig index a3c525b2616a..877e7909a0e5 100644 --- a/trunk/drivers/misc/Kconfig +++ b/trunk/drivers/misc/Kconfig @@ -25,6 +25,15 @@ config IBM_ASM information on the specific driver level and support statement for your IBM server. +config PHANTOM + tristate "Sensable PHANToM" + depends on PCI + help + Say Y here if you want to build a driver for Sensable PHANToM device. + + If you choose to build module, its name will be phantom. If unsure, + say N here. + If unsure, say N. @@ -178,4 +187,13 @@ config THINKPAD_ACPI_BAY If you are not sure, say Y here. +config BLINK + tristate "Keyboard blink driver" + help + Driver that when loaded will blink the keyboard LEDs continuously. + This is useful for debugging and for kernels that cannot necessarily + output something to the screen like kexec kernels to give the user + a visual indication that the kernel is doing something. + + endmenu diff --git a/trunk/drivers/misc/Makefile b/trunk/drivers/misc/Makefile index e32516459138..5b6d46de005c 100644 --- a/trunk/drivers/misc/Makefile +++ b/trunk/drivers/misc/Makefile @@ -7,9 +7,11 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o +obj-$(CONFIG_BLINK) += blink.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o +obj-$(CONFIG_PHANTOM) += phantom.o obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o diff --git a/trunk/drivers/misc/blink.c b/trunk/drivers/misc/blink.c new file mode 100644 index 000000000000..634431ce1184 --- /dev/null +++ b/trunk/drivers/misc/blink.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +static void do_blink(unsigned long data); + +static DEFINE_TIMER(blink_timer, do_blink, 0 ,0); + +static void do_blink(unsigned long data) +{ + static long count; + if (panic_blink) + panic_blink(count++); + blink_timer.expires = jiffies + msecs_to_jiffies(1); + add_timer(&blink_timer); +} + +static int blink_init(void) +{ + printk(KERN_INFO "Enabling keyboard blinking\n"); + do_blink(0); + return 0; +} + +module_init(blink_init); + diff --git a/trunk/drivers/misc/phantom.c b/trunk/drivers/misc/phantom.c new file mode 100644 index 000000000000..35b139b0e5f2 --- /dev/null +++ b/trunk/drivers/misc/phantom.c @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2005-2007 Jiri Slaby + * + * 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. + * + * You need an userspace library to cooperate with this driver. It (and other + * info) may be obtained here: + * http://www.fi.muni.cz/~xslaby/phantom.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define PHANTOM_VERSION "n0.9.5" + +#define PHANTOM_MAX_MINORS 8 + +#define PHN_IRQCTL 0x4c /* irq control in caddr space */ + +#define PHB_RUNNING 1 + +static struct class *phantom_class; +static int phantom_major; + +struct phantom_device { + unsigned int opened; + void __iomem *caddr; + u32 __iomem *iaddr; + u32 __iomem *oaddr; + unsigned long status; + atomic_t counter; + + wait_queue_head_t wait; + struct cdev cdev; + + struct mutex open_lock; +}; + +static unsigned char phantom_devices[PHANTOM_MAX_MINORS]; + +static int phantom_status(struct phantom_device *dev, unsigned long newstat) +{ + pr_debug("phantom_status %lx %lx\n", dev->status, newstat); + + if (!(dev->status & PHB_RUNNING) && (newstat & PHB_RUNNING)) { + atomic_set(&dev->counter, 0); + iowrite32(PHN_CTL_IRQ, dev->iaddr + PHN_CONTROL); + iowrite32(0x43, dev->caddr + PHN_IRQCTL); + } else if ((dev->status & PHB_RUNNING) && !(newstat & PHB_RUNNING)) + iowrite32(0, dev->caddr + PHN_IRQCTL); + + dev->status = newstat; + + return 0; +} + +/* + * File ops + */ + +static int phantom_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg) +{ + struct phantom_device *dev = file->private_data; + struct phm_regs rs; + struct phm_reg r; + void __user *argp = (void __user *)arg; + unsigned int i; + + if (_IOC_TYPE(cmd) != PH_IOC_MAGIC || + _IOC_NR(cmd) > PH_IOC_MAXNR) + return -ENOTTY; + + switch (cmd) { + case PHN_SET_REG: + if (copy_from_user(&r, argp, sizeof(r))) + return -EFAULT; + + if (r.reg > 7) + return -EINVAL; + + if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) && + phantom_status(dev, dev->status | PHB_RUNNING)) + return -ENODEV; + + pr_debug("phantom: writing %x to %u\n", r.value, r.reg); + iowrite32(r.value, dev->iaddr + r.reg); + + if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ)) + phantom_status(dev, dev->status & ~PHB_RUNNING); + break; + case PHN_SET_REGS: + if (copy_from_user(&rs, argp, sizeof(rs))) + return -EFAULT; + + pr_debug("phantom: SRS %u regs %x\n", rs.count, rs.mask); + for (i = 0; i < min(rs.count, 8U); i++) + if ((1 << i) & rs.mask) + iowrite32(rs.values[i], dev->oaddr + i); + break; + case PHN_GET_REG: + if (copy_from_user(&r, argp, sizeof(r))) + return -EFAULT; + + if (r.reg > 7) + return -EINVAL; + + r.value = ioread32(dev->iaddr + r.reg); + + if (copy_to_user(argp, &r, sizeof(r))) + return -EFAULT; + break; + case PHN_GET_REGS: + if (copy_from_user(&rs, argp, sizeof(rs))) + return -EFAULT; + + pr_debug("phantom: GRS %u regs %x\n", rs.count, rs.mask); + for (i = 0; i < min(rs.count, 8U); i++) + if ((1 << i) & rs.mask) + rs.values[i] = ioread32(dev->iaddr + i); + + if (copy_to_user(argp, &rs, sizeof(rs))) + return -EFAULT; + break; + default: + return -ENOTTY; + } + + return 0; +} + +static int phantom_open(struct inode *inode, struct file *file) +{ + struct phantom_device *dev = container_of(inode->i_cdev, + struct phantom_device, cdev); + + nonseekable_open(inode, file); + + if (mutex_lock_interruptible(&dev->open_lock)) + return -ERESTARTSYS; + + if (dev->opened) { + mutex_unlock(&dev->open_lock); + return -EINVAL; + } + + file->private_data = dev; + + dev->opened++; + mutex_unlock(&dev->open_lock); + + return 0; +} + +static int phantom_release(struct inode *inode, struct file *file) +{ + struct phantom_device *dev = file->private_data; + + mutex_lock(&dev->open_lock); + + dev->opened = 0; + phantom_status(dev, dev->status & ~PHB_RUNNING); + + mutex_unlock(&dev->open_lock); + + return 0; +} + +static unsigned int phantom_poll(struct file *file, poll_table *wait) +{ + struct phantom_device *dev = file->private_data; + unsigned int mask = 0; + + pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter)); + poll_wait(file, &dev->wait, wait); + if (atomic_read(&dev->counter)) { + mask = POLLIN | POLLRDNORM; + atomic_dec(&dev->counter); + } else if ((dev->status & PHB_RUNNING) == 0) + mask = POLLIN | POLLRDNORM | POLLERR; + pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter)); + + return mask; +} + +static struct file_operations phantom_file_ops = { + .open = phantom_open, + .release = phantom_release, + .ioctl = phantom_ioctl, + .poll = phantom_poll, +}; + +static irqreturn_t phantom_isr(int irq, void *data) +{ + struct phantom_device *dev = data; + + if (!(ioread32(dev->iaddr + PHN_CONTROL) & PHN_CTL_IRQ)) + return IRQ_NONE; + + iowrite32(0, dev->iaddr); + iowrite32(0xc0, dev->iaddr); + + atomic_inc(&dev->counter); + wake_up_interruptible(&dev->wait); + + return IRQ_HANDLED; +} + +/* + * Init and deinit driver + */ + +static unsigned int __devinit phantom_get_free(void) +{ + unsigned int i; + + for (i = 0; i < PHANTOM_MAX_MINORS; i++) + if (phantom_devices[i] == 0) + break; + + return i; +} + +static int __devinit phantom_probe(struct pci_dev *pdev, + const struct pci_device_id *pci_id) +{ + struct phantom_device *pht; + unsigned int minor; + int retval; + + retval = pci_enable_device(pdev); + if (retval) + goto err; + + minor = phantom_get_free(); + if (minor == PHANTOM_MAX_MINORS) { + dev_err(&pdev->dev, "too many devices found!\n"); + retval = -EIO; + goto err_dis; + } + + phantom_devices[minor] = 1; + + retval = pci_request_regions(pdev, "phantom"); + if (retval) + goto err_null; + + retval = -ENOMEM; + pht = kzalloc(sizeof(*pht), GFP_KERNEL); + if (pht == NULL) { + dev_err(&pdev->dev, "unable to allocate device\n"); + goto err_reg; + } + + pht->caddr = pci_iomap(pdev, 0, 0); + if (pht->caddr == NULL) { + dev_err(&pdev->dev, "can't remap conf space\n"); + goto err_fr; + } + pht->iaddr = pci_iomap(pdev, 2, 0); + if (pht->iaddr == NULL) { + dev_err(&pdev->dev, "can't remap input space\n"); + goto err_unmc; + } + pht->oaddr = pci_iomap(pdev, 3, 0); + if (pht->oaddr == NULL) { + dev_err(&pdev->dev, "can't remap output space\n"); + goto err_unmi; + } + + mutex_init(&pht->open_lock); + init_waitqueue_head(&pht->wait); + cdev_init(&pht->cdev, &phantom_file_ops); + pht->cdev.owner = THIS_MODULE; + + iowrite32(0, pht->caddr + PHN_IRQCTL); + retval = request_irq(pdev->irq, phantom_isr, + IRQF_SHARED | IRQF_DISABLED, "phantom", pht); + if (retval) { + dev_err(&pdev->dev, "can't establish ISR\n"); + goto err_unmo; + } + + retval = cdev_add(&pht->cdev, MKDEV(phantom_major, minor), 1); + if (retval) { + dev_err(&pdev->dev, "chardev registration failed\n"); + goto err_irq; + } + + if (IS_ERR(device_create(phantom_class, &pdev->dev, MKDEV(phantom_major, + minor), "phantom%u", minor))) + dev_err(&pdev->dev, "can't create device\n"); + + pci_set_drvdata(pdev, pht); + + return 0; +err_irq: + free_irq(pdev->irq, pht); +err_unmo: + pci_iounmap(pdev, pht->oaddr); +err_unmi: + pci_iounmap(pdev, pht->iaddr); +err_unmc: + pci_iounmap(pdev, pht->caddr); +err_fr: + kfree(pht); +err_reg: + pci_release_regions(pdev); +err_null: + phantom_devices[minor] = 0; +err_dis: + pci_disable_device(pdev); +err: + return retval; +} + +static void __devexit phantom_remove(struct pci_dev *pdev) +{ + struct phantom_device *pht = pci_get_drvdata(pdev); + unsigned int minor = MINOR(pht->cdev.dev); + + device_destroy(phantom_class, MKDEV(phantom_major, minor)); + + cdev_del(&pht->cdev); + + iowrite32(0, pht->caddr + PHN_IRQCTL); + free_irq(pdev->irq, pht); + + pci_iounmap(pdev, pht->oaddr); + pci_iounmap(pdev, pht->iaddr); + pci_iounmap(pdev, pht->caddr); + + kfree(pht); + + pci_release_regions(pdev); + + phantom_devices[minor] = 0; + + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int phantom_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct phantom_device *dev = pci_get_drvdata(pdev); + + iowrite32(0, dev->caddr + PHN_IRQCTL); + + return 0; +} + +static int phantom_resume(struct pci_dev *pdev) +{ + struct phantom_device *dev = pci_get_drvdata(pdev); + + iowrite32(0, dev->caddr + PHN_IRQCTL); + + return 0; +} +#else +#define phantom_suspend NULL +#define phantom_resume NULL +#endif + +static struct pci_device_id phantom_pci_tbl[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050), + .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, phantom_pci_tbl); + +static struct pci_driver phantom_pci_driver = { + .name = "phantom", + .id_table = phantom_pci_tbl, + .probe = phantom_probe, + .remove = __devexit_p(phantom_remove), + .suspend = phantom_suspend, + .resume = phantom_resume +}; + +static ssize_t phantom_show_version(struct class *cls, char *buf) +{ + return sprintf(buf, PHANTOM_VERSION "\n"); +} + +static CLASS_ATTR(version, 0444, phantom_show_version, NULL); + +static int __init phantom_init(void) +{ + int retval; + dev_t dev; + + phantom_class = class_create(THIS_MODULE, "phantom"); + if (IS_ERR(phantom_class)) { + retval = PTR_ERR(phantom_class); + printk(KERN_ERR "phantom: can't register phantom class\n"); + goto err; + } + retval = class_create_file(phantom_class, &class_attr_version); + if (retval) { + printk(KERN_ERR "phantom: can't create sysfs version file\n"); + goto err_class; + } + + retval = alloc_chrdev_region(&dev, 0, PHANTOM_MAX_MINORS, "phantom"); + if (retval) { + printk(KERN_ERR "phantom: can't register character device\n"); + goto err_attr; + } + phantom_major = MAJOR(dev); + + retval = pci_register_driver(&phantom_pci_driver); + if (retval) { + printk(KERN_ERR "phantom: can't register pci driver\n"); + goto err_unchr; + } + + printk(KERN_INFO "Phantom Linux Driver, version " PHANTOM_VERSION ", " + "init OK\n"); + + return 0; +err_unchr: + unregister_chrdev_region(dev, PHANTOM_MAX_MINORS); +err_attr: + class_remove_file(phantom_class, &class_attr_version); +err_class: + class_destroy(phantom_class); +err: + return retval; +} + +static void __exit phantom_exit(void) +{ + pci_unregister_driver(&phantom_pci_driver); + + unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS); + + class_remove_file(phantom_class, &class_attr_version); + class_destroy(phantom_class); + + pr_debug("phantom: module successfully removed\n"); +} + +module_init(phantom_init); +module_exit(phantom_exit); + +MODULE_AUTHOR("Jiri Slaby "); +MODULE_DESCRIPTION("Sensable Phantom driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(PHANTOM_VERSION); diff --git a/trunk/drivers/misc/tifm_7xx1.c b/trunk/drivers/misc/tifm_7xx1.c index 1ba6c085419a..c08ad8f823d2 100644 --- a/trunk/drivers/misc/tifm_7xx1.c +++ b/trunk/drivers/misc/tifm_7xx1.c @@ -105,7 +105,8 @@ static unsigned char tifm_7xx1_toggle_sock_power(char __iomem *sock_addr) == TIFM_TYPE_XD) msleep(40); - writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL); + writel((s_state & TIFM_CTRL_POWER_MASK) | 0x0c00, + sock_addr + SOCK_CONTROL); /* wait for power to stabilize */ msleep(20); for (cnt = 16; cnt <= 256; cnt <<= 1) { @@ -122,6 +123,12 @@ static unsigned char tifm_7xx1_toggle_sock_power(char __iomem *sock_addr) return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7; } +inline static void tifm_7xx1_sock_power_off(char __iomem *sock_addr) +{ + writel((~TIFM_CTRL_POWER_MASK) & readl(sock_addr + SOCK_CONTROL), + sock_addr + SOCK_CONTROL); +} + inline static char __iomem * tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) { @@ -133,6 +140,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work) struct tifm_adapter *fm = container_of(work, struct tifm_adapter, media_switcher); struct tifm_dev *sock; + char __iomem *sock_addr; unsigned long flags; unsigned char media_id; unsigned int socket_change_set, cnt; @@ -158,11 +166,12 @@ static void tifm_7xx1_switch_media(struct work_struct *work) "%s : demand removing card from socket %u:%u\n", fm->cdev.class_id, fm->id, cnt); fm->sockets[cnt] = NULL; + sock_addr = sock->addr; spin_unlock_irqrestore(&fm->lock, flags); device_unregister(&sock->dev); spin_lock_irqsave(&fm->lock, flags); - writel(0x0e00, tifm_7xx1_sock_addr(fm->addr, cnt) - + SOCK_CONTROL); + tifm_7xx1_sock_power_off(sock_addr); + writel(0x0e00, sock_addr + SOCK_CONTROL); } spin_unlock_irqrestore(&fm->lock, flags); @@ -205,8 +214,16 @@ static void tifm_7xx1_switch_media(struct work_struct *work) static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) { + struct tifm_adapter *fm = pci_get_drvdata(dev); + int cnt; + dev_dbg(&dev->dev, "suspending host\n"); + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (fm->sockets[cnt]) + tifm_7xx1_sock_power_off(fm->sockets[cnt]->addr); + } + pci_save_state(dev); pci_enable_wake(dev, pci_choose_state(dev, state), 0); pci_disable_device(dev); @@ -357,6 +374,7 @@ static int tifm_7xx1_probe(struct pci_dev *dev, static void tifm_7xx1_remove(struct pci_dev *dev) { struct tifm_adapter *fm = pci_get_drvdata(dev); + int cnt; fm->eject = tifm_7xx1_dummy_eject; writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); @@ -365,6 +383,9 @@ static void tifm_7xx1_remove(struct pci_dev *dev) tifm_remove_adapter(fm); + for (cnt = 0; cnt < fm->num_sockets; cnt++) + tifm_7xx1_sock_power_off(tifm_7xx1_sock_addr(fm->addr, cnt)); + pci_set_drvdata(dev, NULL); iounmap(fm->addr); diff --git a/trunk/drivers/mmc/Kconfig b/trunk/drivers/mmc/Kconfig index 6c97491543db..45b7d53b949c 100644 --- a/trunk/drivers/mmc/Kconfig +++ b/trunk/drivers/mmc/Kconfig @@ -2,10 +2,8 @@ # MMC subsystem configuration # -menu "MMC/SD Card support" - -config MMC - tristate "MMC support" +menuconfig MMC + tristate "MMC/SD card support" help MMC is the "multi-media card" bus protocol. @@ -19,10 +17,12 @@ config MMC_DEBUG This is an option for use by developers; most people should say N here. This enables MMC core and driver debugging. +if MMC + source "drivers/mmc/core/Kconfig" source "drivers/mmc/card/Kconfig" source "drivers/mmc/host/Kconfig" -endmenu +endif # MMC diff --git a/trunk/drivers/mmc/card/Kconfig b/trunk/drivers/mmc/card/Kconfig index 01a9fd376a1f..9320a8c73239 100644 --- a/trunk/drivers/mmc/card/Kconfig +++ b/trunk/drivers/mmc/card/Kconfig @@ -3,11 +3,10 @@ # comment "MMC/SD Card Drivers" - depends MMC config MMC_BLOCK tristate "MMC block device driver" - depends on MMC && BLOCK + depends on BLOCK default y help Say Y here to enable the MMC block device driver support. diff --git a/trunk/drivers/mmc/core/Kconfig b/trunk/drivers/mmc/core/Kconfig index 94222b9a15ea..ab37a6d9d32a 100644 --- a/trunk/drivers/mmc/core/Kconfig +++ b/trunk/drivers/mmc/core/Kconfig @@ -4,7 +4,6 @@ config MMC_UNSAFE_RESUME bool "Allow unsafe resume (DANGEROUS)" - depends on MMC != n help If you say Y here, the MMC layer will assume that all cards stayed in their respective slots during the suspend. The diff --git a/trunk/drivers/mmc/core/core.c b/trunk/drivers/mmc/core/core.c index 72c7cf4a9f9d..b6c16704aaab 100644 --- a/trunk/drivers/mmc/core/core.c +++ b/trunk/drivers/mmc/core/core.c @@ -500,9 +500,10 @@ void __mmc_release_bus(struct mmc_host *host) void mmc_detect_change(struct mmc_host *host, unsigned long delay) { #ifdef CONFIG_MMC_DEBUG - mmc_claim_host(host); + unsigned long flags; + spin_lock_irqsave(host->lock, flags); BUG_ON(host->removed); - mmc_release_host(host); + spin_unlock_irqrestore(host->lock, flags); #endif mmc_schedule_delayed_work(&host->detect, delay); @@ -625,9 +626,10 @@ EXPORT_SYMBOL(mmc_add_host); void mmc_remove_host(struct mmc_host *host) { #ifdef CONFIG_MMC_DEBUG - mmc_claim_host(host); + unsigned long flags; + spin_lock_irqsave(&host->lock, flags); host->removed = 1; - mmc_release_host(host); + spin_unlock_irqrestore(&host->lock, flags); #endif mmc_flush_scheduled_work(); diff --git a/trunk/drivers/mmc/host/Kconfig b/trunk/drivers/mmc/host/Kconfig index ed4deab2203d..e23082fe88d0 100644 --- a/trunk/drivers/mmc/host/Kconfig +++ b/trunk/drivers/mmc/host/Kconfig @@ -3,11 +3,10 @@ # comment "MMC/SD Host Controller Drivers" - depends on MMC config MMC_ARMMMCI tristate "ARM AMBA Multimedia Card Interface support" - depends on ARM_AMBA && MMC + depends on ARM_AMBA help This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card Interface (PL180 and PL181) support. If you have an ARM(R) @@ -17,7 +16,7 @@ config MMC_ARMMMCI config MMC_PXA tristate "Intel PXA25x/26x/27x Multimedia Card Interface support" - depends on ARCH_PXA && MMC + depends on ARCH_PXA help This selects the Intel(R) PXA(R) Multimedia card Interface. If you have a PXA(R) platform with a Multimedia Card slot, @@ -27,7 +26,7 @@ config MMC_PXA config MMC_SDHCI tristate "Secure Digital Host Controller Interface support (EXPERIMENTAL)" - depends on PCI && MMC && EXPERIMENTAL + depends on PCI && EXPERIMENTAL help This select the generic Secure Digital Host Controller Interface. It is used by manufacturers such as Texas Instruments(R), Ricoh(R) @@ -38,7 +37,7 @@ config MMC_SDHCI config MMC_OMAP tristate "TI OMAP Multimedia Card Interface support" - depends on ARCH_OMAP && MMC + depends on ARCH_OMAP select TPS65010 if MACH_OMAP_H2 help This selects the TI OMAP Multimedia card Interface. @@ -49,7 +48,7 @@ config MMC_OMAP config MMC_WBSD tristate "Winbond W83L51xD SD/MMC Card Interface support" - depends on MMC && ISA_DMA_API + depends on ISA_DMA_API help This selects the Winbond(R) W83L51xD Secure digital and Multimedia card Interface. @@ -60,7 +59,7 @@ config MMC_WBSD config MMC_AU1X tristate "Alchemy AU1XX0 MMC Card Interface support" - depends on MMC && SOC_AU1200 + depends on SOC_AU1200 help This selects the AMD Alchemy(R) Multimedia card interface. If you have a Alchemy platform with a MMC slot, say Y or M here. @@ -69,7 +68,7 @@ config MMC_AU1X config MMC_AT91 tristate "AT91 SD/MMC Card Interface support" - depends on ARCH_AT91 && MMC + depends on ARCH_AT91 help This selects the AT91 MCI controller. @@ -77,7 +76,7 @@ config MMC_AT91 config MMC_IMX tristate "Motorola i.MX Multimedia Card Interface support" - depends on ARCH_IMX && MMC + depends on ARCH_IMX help This selects the Motorola i.MX Multimedia card Interface. If you have a i.MX platform with a Multimedia Card slot, @@ -87,7 +86,7 @@ config MMC_IMX config MMC_TIFM_SD tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)" - depends on MMC && EXPERIMENTAL && PCI + depends on EXPERIMENTAL && PCI select TIFM_CORE help Say Y here if you want to be able to access MMC/SD cards with diff --git a/trunk/drivers/mmc/host/pxamci.c b/trunk/drivers/mmc/host/pxamci.c index a98ff98fa567..d97d3864b57f 100644 --- a/trunk/drivers/mmc/host/pxamci.c +++ b/trunk/drivers/mmc/host/pxamci.c @@ -368,14 +368,14 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (CLOCKRATE / clk > ios->clock) clk <<= 1; host->clkrt = fls(clk) - 1; - pxa_set_cken(CKEN12_MMC, 1); + pxa_set_cken(CKEN_MMC, 1); /* * we write clkrt on the next command */ } else { pxamci_stop_clock(host); - pxa_set_cken(CKEN12_MMC, 0); + pxa_set_cken(CKEN_MMC, 0); } if (host->power_mode != ios->power_mode) { diff --git a/trunk/drivers/mmc/host/tifm_sd.c b/trunk/drivers/mmc/host/tifm_sd.c index 7511f961c67b..8b736e968447 100644 --- a/trunk/drivers/mmc/host/tifm_sd.c +++ b/trunk/drivers/mmc/host/tifm_sd.c @@ -1021,10 +1021,6 @@ static void tifm_sd_remove(struct tifm_dev *sock) mmc_remove_host(mmc); dev_dbg(&sock->dev, "after remove\n"); - /* The meaning of the bit majority in this constant is unknown. */ - writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - mmc_free_host(mmc); } @@ -1032,14 +1028,7 @@ static void tifm_sd_remove(struct tifm_dev *sock) static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state) { - struct mmc_host *mmc = tifm_get_drvdata(sock); - int rc; - - rc = mmc_suspend_host(mmc, state); - /* The meaning of the bit majority in this constant is unknown. */ - writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); - return rc; + return mmc_suspend_host(tifm_get_drvdata(sock), state); } static int tifm_sd_resume(struct tifm_dev *sock) diff --git a/trunk/drivers/mtd/devices/Kconfig b/trunk/drivers/mtd/devices/Kconfig index 690c94236d7f..ff642f8fbee7 100644 --- a/trunk/drivers/mtd/devices/Kconfig +++ b/trunk/drivers/mtd/devices/Kconfig @@ -49,8 +49,8 @@ config MTD_MS02NV If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read . The module will - be called ms02-nv.o. + say M here and read . + The module will be called ms02-nv.ko. config MTD_DATAFLASH tristate "Support for AT45xxx DataFlash" diff --git a/trunk/drivers/mtd/devices/block2mtd.c b/trunk/drivers/mtd/devices/block2mtd.c index ce47544dc120..fc4cc8ba9e29 100644 --- a/trunk/drivers/mtd/devices/block2mtd.c +++ b/trunk/drivers/mtd/devices/block2mtd.c @@ -40,13 +40,11 @@ struct block2mtd_dev { static LIST_HEAD(blkmtd_device_list); -static struct page* page_read(struct address_space *mapping, int index) +static struct page *page_read(struct address_space *mapping, int index) { - filler_t *filler = (filler_t*)mapping->a_ops->readpage; - return read_cache_page(mapping, index, filler, NULL); + return read_mapping_page(mapping, index, NULL); } - /* erase a specified part of the device */ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len) { diff --git a/trunk/drivers/mtd/maps/physmap_of.c b/trunk/drivers/mtd/maps/physmap_of.c index 7efe744ad31e..72107dc06d67 100644 --- a/trunk/drivers/mtd/maps/physmap_of.c +++ b/trunk/drivers/mtd/maps/physmap_of.c @@ -48,7 +48,7 @@ static int parse_flash_partitions(struct device_node *node, const u32 *part; const char *name; - part = get_property(node, "partitions", &plen); + part = of_get_property(node, "partitions", &plen); if (part == NULL) goto err; @@ -59,7 +59,7 @@ static int parse_flash_partitions(struct device_node *node, goto err; } - name = get_property(node, "partition-names", &plen); + name = of_get_property(node, "partition-names", &plen); for (i = 0; i < retval; i++) { (*parts)[i].offset = *part++; @@ -153,7 +153,7 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev goto err_out; } - width = get_property(dp, "bank-width", NULL); + width = of_get_property(dp, "bank-width", NULL); if (width == NULL) { dev_err(&dev->dev, "Can't get the flash bank width!\n"); err = -EINVAL; @@ -174,7 +174,7 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev simple_map_init(&info->map); - of_probe = get_property(dp, "probe-type", NULL); + of_probe = of_get_property(dp, "probe-type", NULL); if (of_probe == NULL) { probe_type = rom_probe_types; for (; info->mtd == NULL && *probe_type != NULL; probe_type++) diff --git a/trunk/drivers/mtd/mtd_blkdevs.c b/trunk/drivers/mtd/mtd_blkdevs.c index 524b83b5ebf5..51bc7e2f1f22 100644 --- a/trunk/drivers/mtd/mtd_blkdevs.c +++ b/trunk/drivers/mtd/mtd_blkdevs.c @@ -216,7 +216,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) int last_devnum = -1; struct gendisk *gd; - if (!!mutex_trylock(&mtd_table_mutex)) { + if (mutex_trylock(&mtd_table_mutex)) { mutex_unlock(&mtd_table_mutex); BUG(); } @@ -294,7 +294,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) { - if (!!mutex_trylock(&mtd_table_mutex)) { + if (mutex_trylock(&mtd_table_mutex)) { mutex_unlock(&mtd_table_mutex); BUG(); } diff --git a/trunk/drivers/mtd/ubi/eba.c b/trunk/drivers/mtd/ubi/eba.c index d847ee1da3d9..3dba5733ed1f 100644 --- a/trunk/drivers/mtd/ubi/eba.c +++ b/trunk/drivers/mtd/ubi/eba.c @@ -940,8 +940,7 @@ static void ltree_entry_ctor(void *obj, struct kmem_cache *cache, { struct ltree_entry *le = obj; - if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) != - SLAB_CTOR_CONSTRUCTOR) + if (flags & SLAB_CTOR_CONSTRUCTOR) return; le->users = 0; diff --git a/trunk/drivers/net/Kconfig b/trunk/drivers/net/Kconfig index 69dba62e0bad..b86ccd2ecd5b 100644 --- a/trunk/drivers/net/Kconfig +++ b/trunk/drivers/net/Kconfig @@ -822,7 +822,7 @@ config SMC91X tristate "SMC 91C9x/91C1xxx support" select CRC32 select MII - depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00) + depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00 || BFIN) help This is a driver for SMC's 91x series of Ethernet chipsets, including the SMC91C94 and the SMC91C111. Say Y if you want it @@ -833,8 +833,8 @@ config SMC91X This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called smc91x. If you want to compile it as a - module, say M here and read as well - as . + module, say M here and read + as well as . config SMC9194 tristate "SMC 9194 support" @@ -889,7 +889,7 @@ config SMC911X This driver is also available as a module. The module will be called smc911x. If you want to compile it as a module, say M - here and read + here and read config NET_VENDOR_RACAL bool "Racal-Interlan (Micom) NI cards" @@ -1104,7 +1104,7 @@ config ETH16I config NE2000 tristate "NE2000/NE1000 support" - depends on NET_ISA || (Q40 && m) || M32R + depends on NET_ISA || (Q40 && m) || M32R || TOSHIBA_RBTX4927 || TOSHIBA_RBTX4938 select CRC32 ---help--- If you have a network (Ethernet) card of this type, say Y and read @@ -2488,6 +2488,7 @@ config NETXEN_NIC config PASEMI_MAC tristate "PA Semi 1/10Gbit MAC" depends on PPC64 && PCI + select PHYLIB help This driver supports the on-chip 1/10Gbit Ethernet controller on PA Semi's PWRficient line of chips. diff --git a/trunk/drivers/net/arm/at91_ether.c b/trunk/drivers/net/arm/at91_ether.c index 152fa7a042b8..ef2cc80256a3 100644 --- a/trunk/drivers/net/arm/at91_ether.c +++ b/trunk/drivers/net/arm/at91_ether.c @@ -225,6 +225,16 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id) if (!(phy & ((1 << 2) | 1))) goto done; } + else if (lp->phy_type == MII_T78Q21x3_ID) { /* ack interrupt in Teridian PHY */ + read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy); + if (!(phy & ((1 << 2) | 1))) + goto done; + } + else if (lp->phy_type == MII_DP83848_ID) { + read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy); /* ack interrupt in DP83848 PHY */ + if (!(phy & (1 << 7))) + goto done; + } update_linkspeed(dev, 0); @@ -280,6 +290,19 @@ static void enable_phyirq(struct net_device *dev) dsintr = (1 << 10) | ( 1 << 8); write_phy(lp->phy_address, MII_TPISTATUS, dsintr); } + else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */ + read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr); + dsintr = dsintr | 0x500; /* set bits 8, 10 */ + write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr); + } + else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */ + read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr); + dsintr = dsintr | 0x3c; /* set bits 2..5 */ + write_phy(lp->phy_address, MII_DPMISR_REG, dsintr); + read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr); + dsintr = dsintr | 0x3; /* set bits 0,1 */ + write_phy(lp->phy_address, MII_DPMICR_REG, dsintr); + } disable_mdi(); spin_unlock_irq(&lp->lock); @@ -323,6 +346,19 @@ static void disable_phyirq(struct net_device *dev) dsintr = ~((1 << 10) | (1 << 8)); write_phy(lp->phy_address, MII_TPISTATUS, dsintr); } + else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */ + read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr); + dsintr = dsintr & ~0x500; /* clear bits 8, 10 */ + write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr); + } + else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */ + read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr); + dsintr = dsintr & ~0x3; /* clear bits 0, 1 */ + write_phy(lp->phy_address, MII_DPMICR_REG, dsintr); + read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr); + dsintr = dsintr & ~0x3c; /* clear bits 2..5 */ + write_phy(lp->phy_address, MII_DPMISR_REG, dsintr); + } disable_mdi(); spin_unlock_irq(&lp->lock); @@ -535,8 +571,8 @@ static void at91ether_sethashtable(struct net_device *dev) mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); } - at91_emac_write(AT91_EMAC_HSH, mc_filter[0]); - at91_emac_write(AT91_EMAC_HSL, mc_filter[1]); + at91_emac_write(AT91_EMAC_HSL, mc_filter[0]); + at91_emac_write(AT91_EMAC_HSH, mc_filter[1]); } /* @@ -1062,10 +1098,16 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name); else if (phy_type == MII_DP83847_ID) printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name); + else if (phy_type == MII_DP83848_ID) + printk(KERN_INFO "%s: National Semiconductor DP83848 PHY\n", dev->name); else if (phy_type == MII_AC101L_ID) printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name); else if (phy_type == MII_KS8721_ID) printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name); + else if (phy_type == MII_T78Q21x3_ID) + printk(KERN_INFO "%s: Teridian 78Q21x3 PHY\n", dev->name); + else if (phy_type == MII_LAN83C185_ID) + printk(KERN_INFO "%s: SMSC LAN83C185 PHY\n", dev->name); return 0; } @@ -1103,8 +1145,11 @@ static int __init at91ether_probe(struct platform_device *pdev) case MII_RTL8201_ID: /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */ case MII_BCM5221_ID: /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */ case MII_DP83847_ID: /* National Semiconductor DP83847: */ + case MII_DP83848_ID: /* National Semiconductor DP83848: */ case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */ case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */ + case MII_T78Q21x3_ID: /* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */ + case MII_LAN83C185_ID: /* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */ detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk); break; } diff --git a/trunk/drivers/net/arm/at91_ether.h b/trunk/drivers/net/arm/at91_ether.h index b6b665de2ea0..a38fd2d053a6 100644 --- a/trunk/drivers/net/arm/at91_ether.h +++ b/trunk/drivers/net/arm/at91_ether.h @@ -17,39 +17,46 @@ /* Davicom 9161 PHY */ -#define MII_DM9161_ID 0x0181b880 -#define MII_DM9161A_ID 0x0181b8a0 - -/* Davicom specific registers */ -#define MII_DSCR_REG 16 -#define MII_DSCSR_REG 17 -#define MII_DSINTR_REG 21 +#define MII_DM9161_ID 0x0181b880 +#define MII_DM9161A_ID 0x0181b8a0 +#define MII_DSCR_REG 16 +#define MII_DSCSR_REG 17 +#define MII_DSINTR_REG 21 /* Intel LXT971A PHY */ -#define MII_LXT971A_ID 0x001378E0 - -/* Intel specific registers */ -#define MII_ISINTE_REG 18 -#define MII_ISINTS_REG 19 -#define MII_LEDCTRL_REG 20 +#define MII_LXT971A_ID 0x001378E0 +#define MII_ISINTE_REG 18 +#define MII_ISINTS_REG 19 +#define MII_LEDCTRL_REG 20 /* Realtek RTL8201 PHY */ -#define MII_RTL8201_ID 0x00008200 +#define MII_RTL8201_ID 0x00008200 /* Broadcom BCM5221 PHY */ -#define MII_BCM5221_ID 0x004061e0 - -/* Broadcom specific registers */ -#define MII_BCMINTR_REG 26 +#define MII_BCM5221_ID 0x004061e0 +#define MII_BCMINTR_REG 26 /* National Semiconductor DP83847 */ -#define MII_DP83847_ID 0x20005c30 +#define MII_DP83847_ID 0x20005c30 + +/* National Semiconductor DP83848 */ +#define MII_DP83848_ID 0x20005c90 +#define MII_DPPHYSTS_REG 16 +#define MII_DPMICR_REG 17 +#define MII_DPMISR_REG 18 /* Altima AC101L PHY */ -#define MII_AC101L_ID 0x00225520 +#define MII_AC101L_ID 0x00225520 /* Micrel KS8721 PHY */ -#define MII_KS8721_ID 0x00221610 +#define MII_KS8721_ID 0x00221610 + +/* Teridian 78Q2123/78Q2133 */ +#define MII_T78Q21x3_ID 0x000e7230 +#define MII_T78Q21INT_REG 17 + +/* SMSC LAN83C185 */ +#define MII_LAN83C185_ID 0x0007C0A0 /* ........................................................................ */ diff --git a/trunk/drivers/net/atl1/atl1_ethtool.c b/trunk/drivers/net/atl1/atl1_ethtool.c index c11c27798e5c..1f616c5c1473 100644 --- a/trunk/drivers/net/atl1/atl1_ethtool.c +++ b/trunk/drivers/net/atl1/atl1_ethtool.c @@ -156,8 +156,7 @@ static int atl1_set_settings(struct net_device *netdev, u16 old_media_type = hw->media_type; if (netif_running(adapter->netdev)) { - printk(KERN_DEBUG "%s: ethtool shutting down adapter\n", - atl1_driver_name); + dev_dbg(&adapter->pdev->dev, "ethtool shutting down adapter\n"); atl1_down(adapter); } @@ -166,9 +165,8 @@ static int atl1_set_settings(struct net_device *netdev, else { if (ecmd->speed == SPEED_1000) { if (ecmd->duplex != DUPLEX_FULL) { - printk(KERN_WARNING - "%s: can't force to 1000M half duplex\n", - atl1_driver_name); + dev_warn(&adapter->pdev->dev, + "can't force to 1000M half duplex\n"); ret_val = -EINVAL; goto exit_sset; } @@ -206,9 +204,8 @@ static int atl1_set_settings(struct net_device *netdev, } if (atl1_phy_setup_autoneg_adv(hw)) { ret_val = -EINVAL; - printk(KERN_WARNING - "%s: invalid ethtool speed/duplex setting\n", - atl1_driver_name); + dev_warn(&adapter->pdev->dev, + "invalid ethtool speed/duplex setting\n"); goto exit_sset; } if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || @@ -239,12 +236,10 @@ static int atl1_set_settings(struct net_device *netdev, hw->media_type = old_media_type; if (netif_running(adapter->netdev)) { - printk(KERN_DEBUG "%s: ethtool starting adapter\n", - atl1_driver_name); + dev_dbg(&adapter->pdev->dev, "ethtool starting adapter\n"); atl1_up(adapter); } else if (!ret_val) { - printk(KERN_DEBUG "%s: ethtool resetting adapter\n", - atl1_driver_name); + dev_dbg(&adapter->pdev->dev, "ethtool resetting adapter\n"); atl1_reset(adapter); } return ret_val; diff --git a/trunk/drivers/net/atl1/atl1_hw.c b/trunk/drivers/net/atl1/atl1_hw.c index 69482e0d849b..ef886bdeac13 100644 --- a/trunk/drivers/net/atl1/atl1_hw.c +++ b/trunk/drivers/net/atl1/atl1_hw.c @@ -2,20 +2,20 @@ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. * Copyright(c) 2006 Chris Snook * Copyright(c) 2006 Jay Cliburn - * + * * Derived from Intel e1000 driver * Copyright(c) 1999 - 2005 Intel Corporation. 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. @@ -38,12 +38,13 @@ */ s32 atl1_reset_hw(struct atl1_hw *hw) { + struct pci_dev *pdev = hw->back->pdev; u32 icr; int i; - /* + /* * Clear Interrupt mask to stop board from generating - * interrupts & Clear any pending interrupt events + * interrupts & Clear any pending interrupt events */ /* * iowrite32(0, hw->hw_addr + REG_IMR); @@ -74,7 +75,7 @@ s32 atl1_reset_hw(struct atl1_hw *hw) } if (icr) { - printk (KERN_DEBUG "icr = %x\n", icr); + dev_dbg(&pdev->dev, "ICR = 0x%x\n", icr); return icr; } @@ -136,8 +137,8 @@ s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data) int i; val = ((u32) (reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT | - MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 << - MDIO_CLK_SEL_SHIFT; + MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 << + MDIO_CLK_SEL_SHIFT; iowrite32(val, hw->hw_addr + REG_MDIO_CTRL); ioread32(hw->hw_addr + REG_MDIO_CTRL); @@ -204,7 +205,7 @@ static bool atl1_spi_read(struct atl1_hw *hw, u32 addr, u32 *buf) /* * get_permanent_address - * return 0 if get valid mac address, + * return 0 if get valid mac address, */ static int atl1_get_permanent_address(struct atl1_hw *hw) { @@ -301,7 +302,7 @@ static int atl1_get_permanent_address(struct atl1_hw *hw) } /* - * Reads the adapter's MAC address from the EEPROM + * Reads the adapter's MAC address from the EEPROM * hw - Struct containing variables accessed by shared code */ s32 atl1_read_mac_addr(struct atl1_hw *hw) @@ -437,6 +438,7 @@ s32 atl1_phy_enter_power_saving(struct atl1_hw *hw) */ static s32 atl1_phy_reset(struct atl1_hw *hw) { + struct pci_dev *pdev = hw->back->pdev; s32 ret_val; u16 phy_data; @@ -468,8 +470,7 @@ static s32 atl1_phy_reset(struct atl1_hw *hw) u32 val; int i; /* pcie serdes link may be down! */ - printk(KERN_DEBUG "%s: autoneg caused pcie phy link down\n", - atl1_driver_name); + dev_dbg(&pdev->dev, "pcie phy link down\n"); for (i = 0; i < 25; i++) { msleep(1); @@ -479,9 +480,7 @@ static s32 atl1_phy_reset(struct atl1_hw *hw) } if ((val & (MDIO_START | MDIO_BUSY)) != 0) { - printk(KERN_WARNING - "%s: pcie link down at least for 25ms\n", - atl1_driver_name); + dev_warn(&pdev->dev, "pcie link down at least 25ms\n"); return ret_val; } } @@ -571,6 +570,7 @@ s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw) */ static s32 atl1_setup_link(struct atl1_hw *hw) { + struct pci_dev *pdev = hw->back->pdev; s32 ret_val; /* @@ -581,15 +581,13 @@ static s32 atl1_setup_link(struct atl1_hw *hw) */ ret_val = atl1_phy_setup_autoneg_adv(hw); if (ret_val) { - printk(KERN_DEBUG "%s: error setting up autonegotiation\n", - atl1_driver_name); + dev_dbg(&pdev->dev, "error setting up autonegotiation\n"); return ret_val; } /* SW.Reset , En-Auto-Neg if needed */ ret_val = atl1_phy_reset(hw); if (ret_val) { - printk(KERN_DEBUG "%s: error resetting the phy\n", - atl1_driver_name); + dev_dbg(&pdev->dev, "error resetting phy\n"); return ret_val; } hw->phy_configured = true; @@ -631,7 +629,7 @@ static void atl1_init_flash_opcode(struct atl1_hw *hw) * Performs basic configuration of the adapter. * hw - Struct containing variables accessed by shared code * Assumes that the controller has previously been reset and is in a - * post-reset uninitialized state. Initializes multicast table, + * post-reset uninitialized state. Initializes multicast table, * and Calls routines to setup link * Leaves the transmit and receive units disabled and uninitialized. */ @@ -669,6 +667,7 @@ s32 atl1_init_hw(struct atl1_hw *hw) */ s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex) { + struct pci_dev *pdev = hw->back->pdev; s32 ret_val; u16 phy_data; @@ -691,8 +690,7 @@ s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex) *speed = SPEED_10; break; default: - printk(KERN_DEBUG "%s: error getting speed\n", - atl1_driver_name); + dev_dbg(&pdev->dev, "error getting speed\n"); return ATL1_ERR_PHY_SPEED; break; } diff --git a/trunk/drivers/net/atl1/atl1_main.c b/trunk/drivers/net/atl1/atl1_main.c index 4b1d4d153ecf..d28f88bbdd5f 100644 --- a/trunk/drivers/net/atl1/atl1_main.c +++ b/trunk/drivers/net/atl1/atl1_main.c @@ -188,8 +188,7 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter) size = sizeof(struct atl1_buffer) * (tpd_ring->count + rfd_ring->count); tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL); if (unlikely(!tpd_ring->buffer_info)) { - printk(KERN_WARNING "%s: kzalloc failed , size = D%d\n", - atl1_driver_name, size); + dev_err(&pdev->dev, "kzalloc failed , size = D%d\n", size); goto err_nomem; } rfd_ring->buffer_info = @@ -207,9 +206,7 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter) ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, &ring_header->dma); if (unlikely(!ring_header->desc)) { - printk(KERN_WARNING - "%s: pci_alloc_consistent failed, size = D%d\n", - atl1_driver_name, size); + dev_err(&pdev->dev, "pci_alloc_consistent failed\n"); goto err_nomem; } @@ -373,8 +370,7 @@ static void atl1_rx_checksum(struct atl1_adapter *adapter, if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC | ERR_FLAG_CODE | ERR_FLAG_OV)) { adapter->hw_csum_err++; - printk(KERN_DEBUG "%s: rx checksum error\n", - atl1_driver_name); + dev_dbg(&adapter->pdev->dev, "rx checksum error\n"); return; } } @@ -393,8 +389,9 @@ static void atl1_rx_checksum(struct atl1_adapter *adapter, } /* IPv4, but hardware thinks its checksum is wrong */ - printk(KERN_DEBUG "%s: hw csum wrong pkt_flag:%x, err_flag:%x\n", - atl1_driver_name, rrd->pkt_flg, rrd->err_flg); + dev_dbg(&adapter->pdev->dev, + "hw csum wrong, pkt_flag:%x, err_flag:%x\n", + rrd->pkt_flg, rrd->err_flg); skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum); adapter->hw_csum_err++; @@ -507,14 +504,13 @@ static void atl1_intr_rx(struct atl1_adapter *adapter) /* rrd seems to be bad */ if (unlikely(i-- > 0)) { /* rrd may not be DMAed completely */ - printk(KERN_DEBUG - "%s: RRD may not be DMAed completely\n", - atl1_driver_name); + dev_dbg(&adapter->pdev->dev, + "incomplete RRD DMA transfer\n"); udelay(1); goto chk_rrd; } /* bad rrd */ - printk(KERN_DEBUG "%s: bad RRD\n", atl1_driver_name); + dev_dbg(&adapter->pdev->dev, "bad RRD\n"); /* see if update RFD index */ if (rrd->num_buf > 1) { u16 num_buf; @@ -685,8 +681,8 @@ static void atl1_check_for_link(struct atl1_adapter *adapter) /* notify upper layer link down ASAP */ if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */ if (netif_carrier_ok(netdev)) { /* old link state: Up */ - printk(KERN_INFO "%s: %s link is down\n", - atl1_driver_name, netdev->name); + dev_info(&adapter->pdev->dev, "%s link is down\n", + netdev->name); adapter->link_speed = SPEED_0; netif_carrier_off(netdev); netif_stop_queue(netdev); @@ -731,8 +727,8 @@ static irqreturn_t atl1_intr(int irq, void *data) /* check if PCIE PHY Link down */ if (status & ISR_PHY_LINKDOWN) { - printk(KERN_DEBUG "%s: pcie phy link down %x\n", - atl1_driver_name, status); + dev_dbg(&adapter->pdev->dev, "pcie phy link down %x\n", + status); if (netif_running(adapter->netdev)) { /* reset MAC */ iowrite32(0, adapter->hw.hw_addr + REG_IMR); schedule_work(&adapter->pcie_dma_to_rst_task); @@ -742,9 +738,9 @@ static irqreturn_t atl1_intr(int irq, void *data) /* check if DMA read/write error ? */ if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { - printk(KERN_DEBUG - "%s: pcie DMA r/w error (status = 0x%x)\n", - atl1_driver_name, status); + dev_dbg(&adapter->pdev->dev, + "pcie DMA r/w error (status = 0x%x)\n", + status); iowrite32(0, adapter->hw.hw_addr + REG_IMR); schedule_work(&adapter->pcie_dma_to_rst_task); return IRQ_HANDLED; @@ -762,14 +758,13 @@ static irqreturn_t atl1_intr(int irq, void *data) /* rx exception */ if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN | + ISR_RRD_OV | ISR_HOST_RFD_UNRUN | + ISR_HOST_RRD_OV | ISR_CMB_RX))) { + if (status & (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV | ISR_HOST_RFD_UNRUN | - ISR_HOST_RRD_OV | ISR_CMB_RX))) { - if (status & - (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV | - ISR_HOST_RFD_UNRUN | ISR_HOST_RRD_OV)) - printk(KERN_INFO - "%s: rx exception: status = 0x%x\n", - atl1_driver_name, status); + ISR_HOST_RRD_OV)) + dev_dbg(&adapter->pdev->dev, + "rx exception, ISR = 0x%x\n", status); atl1_intr_rx(adapter); } @@ -874,8 +869,7 @@ static u32 atl1_check_link(struct atl1_adapter *adapter) atl1_read_phy_reg(hw, MII_BMSR, &phy_data); if (!(phy_data & BMSR_LSTATUS)) { /* link down */ if (netif_carrier_ok(netdev)) { /* old link state: Up */ - printk(KERN_INFO "%s: link is down\n", - atl1_driver_name); + dev_info(&adapter->pdev->dev, "link is down\n"); adapter->link_speed = SPEED_0; netif_carrier_off(netdev); netif_stop_queue(netdev); @@ -918,11 +912,11 @@ static u32 atl1_check_link(struct atl1_adapter *adapter) adapter->link_speed = speed; adapter->link_duplex = duplex; atl1_setup_mac_ctrl(adapter); - printk(KERN_INFO "%s: %s link is up %d Mbps %s\n", - atl1_driver_name, netdev->name, - adapter->link_speed, - adapter->link_duplex == - FULL_DUPLEX ? "full duplex" : "half duplex"); + dev_info(&adapter->pdev->dev, + "%s link is up %d Mbps %s\n", + netdev->name, adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? + "full duplex" : "half duplex"); } if (!netif_carrier_ok(netdev)) { /* Link down -> Up */ netif_carrier_on(netdev); @@ -1330,8 +1324,8 @@ static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb, cso = skb_transport_offset(skb); css = cso + skb->csum_offset; if (unlikely(cso & 0x1)) { - printk(KERN_DEBUG "%s: payload offset != even number\n", - atl1_driver_name); + dev_dbg(&adapter->pdev->dev, + "payload offset not an even number\n"); return -1; } csum->csumpl |= (cso & CSUM_PARAM_PLOADOFFSET_MASK) << @@ -1579,7 +1573,7 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (!spin_trylock(&adapter->lock)) { /* Can't get lock - tell upper layer to requeue */ local_irq_restore(flags); - printk(KERN_DEBUG "%s: TX locked\n", atl1_driver_name); + dev_dbg(&adapter->pdev->dev, "tx locked\n"); return NETDEV_TX_LOCKED; } @@ -1587,7 +1581,7 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* not enough descriptors */ netif_stop_queue(netdev); spin_unlock_irqrestore(&adapter->lock, flags); - printk(KERN_DEBUG "%s: TX busy\n", atl1_driver_name); + dev_dbg(&adapter->pdev->dev, "tx busy\n"); return NETDEV_TX_BUSY; } @@ -1841,8 +1835,7 @@ static int atl1_change_mtu(struct net_device *netdev, int new_mtu) if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || (max_frame > MAX_JUMBO_FRAME_SIZE)) { - printk(KERN_WARNING "%s: invalid MTU setting\n", - atl1_driver_name); + dev_warn(&adapter->pdev->dev, "invalid MTU setting\n"); return -EINVAL; } @@ -2136,9 +2129,7 @@ static int __devinit atl1_probe(struct pci_dev *pdev, if (err) { err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (err) { - printk(KERN_DEBUG - "%s: no usable DMA configuration, aborting\n", - atl1_driver_name); + dev_err(&pdev->dev, "no usable DMA configuration\n"); goto err_dma; } pci_using_64 = false; @@ -2175,7 +2166,9 @@ static int __devinit atl1_probe(struct pci_dev *pdev, goto err_pci_iomap; } /* get device revision number */ - adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2)); + adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + + (REG_MASTER_CTRL + 2)); + dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); /* set default ring resource counts */ adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD; @@ -2466,8 +2459,6 @@ static void __exit atl1_exit_module(void) */ static int __init atl1_init_module(void) { - printk(KERN_INFO "%s - version %s\n", atl1_driver_string, DRIVER_VERSION); - printk(KERN_INFO "%s\n", atl1_copyright); return pci_register_driver(&atl1_driver); } diff --git a/trunk/drivers/net/atl1/atl1_param.c b/trunk/drivers/net/atl1/atl1_param.c index bcd0bd891722..4246bb9bd50e 100644 --- a/trunk/drivers/net/atl1/atl1_param.c +++ b/trunk/drivers/net/atl1/atl1_param.c @@ -23,6 +23,7 @@ #include #include +#include #include "atl1.h" /* @@ -93,7 +94,7 @@ struct atl1_option { } arg; }; -static int __devinit atl1_validate_option(int *value, struct atl1_option *opt) +static int __devinit atl1_validate_option(int *value, struct atl1_option *opt, struct pci_dev *pdev) { if (*value == OPTION_UNSET) { *value = opt->def; @@ -104,19 +105,17 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt) case enable_option: switch (*value) { case OPTION_ENABLED: - printk(KERN_INFO "%s: %s Enabled\n", atl1_driver_name, - opt->name); + dev_info(&pdev->dev, "%s enabled\n", opt->name); return 0; case OPTION_DISABLED: - printk(KERN_INFO "%s: %s Disabled\n", atl1_driver_name, - opt->name); + dev_info(&pdev->dev, "%s disabled\n", opt->name); return 0; } break; case range_option: if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { - printk(KERN_INFO "%s: %s set to %i\n", - atl1_driver_name, opt->name, *value); + dev_info(&pdev->dev, "%s set to %i\n", opt->name, + *value); return 0; } break; @@ -128,8 +127,8 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt) ent = &opt->arg.l.p[i]; if (*value == ent->i) { if (ent->str[0] != '\0') - printk(KERN_INFO "%s: %s\n", - atl1_driver_name, ent->str); + dev_info(&pdev->dev, "%s\n", + ent->str); return 0; } } @@ -140,8 +139,8 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt) break; } - printk(KERN_INFO "%s: invalid %s specified (%i) %s\n", - atl1_driver_name, opt->name, *value, opt->err); + dev_info(&pdev->dev, "invalid %s specified (%i) %s\n", + opt->name, *value, opt->err); *value = opt->def; return -1; } @@ -157,12 +156,11 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt) */ void __devinit atl1_check_options(struct atl1_adapter *adapter) { + struct pci_dev *pdev = adapter->pdev; int bd = adapter->bd_number; if (bd >= ATL1_MAX_NIC) { - printk(KERN_NOTICE "%s: warning: no configuration for board #%i\n", - atl1_driver_name, bd); - printk(KERN_NOTICE "%s: using defaults for all values\n", - atl1_driver_name); + dev_notice(&pdev->dev, "no configuration for board#%i\n", bd); + dev_notice(&pdev->dev, "using defaults for all values\n"); } { /* Interrupt Moderate Timer */ struct atl1_option opt = { @@ -177,7 +175,7 @@ void __devinit atl1_check_options(struct atl1_adapter *adapter) int val; if (num_int_mod_timer > bd) { val = int_mod_timer[bd]; - atl1_validate_option(&val, &opt); + atl1_validate_option(&val, &opt, pdev); adapter->imt = (u16) val; } else adapter->imt = (u16) (opt.def); @@ -197,7 +195,7 @@ void __devinit atl1_check_options(struct atl1_adapter *adapter) int val; if (num_flash_vendor > bd) { val = flash_vendor[bd]; - atl1_validate_option(&val, &opt); + atl1_validate_option(&val, &opt, pdev); adapter->hw.flash_vendor = (u8) val; } else adapter->hw.flash_vendor = (u8) (opt.def); diff --git a/trunk/drivers/net/bmac.c b/trunk/drivers/net/bmac.c index 4612725965df..9b8d7d9dbe86 100644 --- a/trunk/drivers/net/bmac.c +++ b/trunk/drivers/net/bmac.c @@ -1260,9 +1260,10 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n"); return -ENODEV; } - prop_addr = get_property(macio_get_of_node(mdev), "mac-address", NULL); + prop_addr = of_get_property(macio_get_of_node(mdev), + "mac-address", NULL); if (prop_addr == NULL) { - prop_addr = get_property(macio_get_of_node(mdev), + prop_addr = of_get_property(macio_get_of_node(mdev), "local-mac-address", NULL); if (prop_addr == NULL) { printk(KERN_ERR "BMAC: Can't get mac-address\n"); diff --git a/trunk/drivers/net/cxgb3/version.h b/trunk/drivers/net/cxgb3/version.h index 042e27e291cd..b112317f033e 100644 --- a/trunk/drivers/net/cxgb3/version.h +++ b/trunk/drivers/net/cxgb3/version.h @@ -38,7 +38,7 @@ #define DRV_VERSION "1.0-ko" /* Firmware version */ -#define FW_VERSION_MAJOR 3 -#define FW_VERSION_MINOR 3 +#define FW_VERSION_MAJOR 4 +#define FW_VERSION_MINOR 0 #define FW_VERSION_MICRO 0 #endif /* __CHELSIO_VERSION_H */ diff --git a/trunk/drivers/net/dm9000.c b/trunk/drivers/net/dm9000.c index 8cc1174e7f64..264fa0e2e075 100644 --- a/trunk/drivers/net/dm9000.c +++ b/trunk/drivers/net/dm9000.c @@ -77,9 +77,6 @@ #define DM9000_PHY 0x40 /* PHY address 0x01 */ -#define TRUE 1 -#define FALSE 0 - #define CARDNAME "dm9000" #define PFX CARDNAME ": " @@ -601,7 +598,7 @@ dm9000_probe(struct platform_device *pdev) printk("%s: not found (%d).\n", CARDNAME, ret); dm9000_release_board(pdev, db); - kfree(ndev); + free_netdev(ndev); return ret; } @@ -896,7 +893,7 @@ dm9000_rx(struct net_device *dev) struct dm9000_rxhdr rxhdr; struct sk_buff *skb; u8 rxbyte, *rdptr; - int GoodPacket; + bool GoodPacket; int RxLen; /* Check packet ready or not */ @@ -918,7 +915,7 @@ dm9000_rx(struct net_device *dev) return; /* A packet ready now & Get status/length */ - GoodPacket = TRUE; + GoodPacket = true; writeb(DM9000_MRCMD, db->io_addr); (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); @@ -927,7 +924,7 @@ dm9000_rx(struct net_device *dev) /* Packet Status check */ if (RxLen < 0x40) { - GoodPacket = FALSE; + GoodPacket = false; PRINTK1("Bad Packet received (runt)\n"); } @@ -936,7 +933,7 @@ dm9000_rx(struct net_device *dev) } if (rxhdr.RxStatus & 0xbf00) { - GoodPacket = FALSE; + GoodPacket = false; if (rxhdr.RxStatus & 0x100) { PRINTK1("fifo error\n"); db->stats.rx_fifo_errors++; @@ -1193,7 +1190,7 @@ dm9000_drv_remove(struct platform_device *pdev) unregister_netdev(ndev); dm9000_release_board(pdev, (board_info_t *) ndev->priv); - kfree(ndev); /* free device structure */ + free_netdev(ndev); /* free device structure */ PRINTK1("clean_module() exit\n"); diff --git a/trunk/drivers/net/ehea/ehea_main.c b/trunk/drivers/net/ehea/ehea_main.c index c7a5614e66c0..f6e0cb1ada1f 100644 --- a/trunk/drivers/net/ehea/ehea_main.c +++ b/trunk/drivers/net/ehea/ehea_main.c @@ -1803,10 +1803,10 @@ static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps) u32 tmp; if ((skb->protocol == htons(ETH_P_IP)) && - (skb->nh.iph->protocol == IPPROTO_TCP)) { - tcp = (struct tcphdr*)(skb->nh.raw + (skb->nh.iph->ihl * 4)); + (ip_hdr(skb)->protocol == IPPROTO_TCP)) { + tcp = (struct tcphdr*)(skb_network_header(skb) + (ip_hdr(skb)->ihl * 4)); tmp = (tcp->source + (tcp->dest << 16)) % 31; - tmp += skb->nh.iph->daddr % 31; + tmp += ip_hdr(skb)->daddr % 31; return tmp % num_qps; } else @@ -2603,14 +2603,13 @@ static int ehea_setup_ports(struct ehea_adapter *adapter) { struct device_node *lhea_dn; struct device_node *eth_dn = NULL; - - u32 *dn_log_port_id; + const u32 *dn_log_port_id; int i = 0; lhea_dn = adapter->ebus_dev->ofdev.node; while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { - dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", + dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no", NULL); if (!dn_log_port_id) { ehea_error("bad device node: eth_dn name=%s", @@ -2645,12 +2644,12 @@ static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, { struct device_node *lhea_dn; struct device_node *eth_dn = NULL; - u32 *dn_log_port_id; + const u32 *dn_log_port_id; lhea_dn = adapter->ebus_dev->ofdev.node; while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { - dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", + dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no", NULL); if (dn_log_port_id) if (*dn_log_port_id == logical_port_id) @@ -2774,7 +2773,7 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, const struct of_device_id *id) { struct ehea_adapter *adapter; - u64 *adapter_handle; + const u64 *adapter_handle; int ret; if (!dev || !dev->ofdev.node) { @@ -2791,7 +2790,7 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, adapter->ebus_dev = dev; - adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle", + adapter_handle = of_get_property(dev->ofdev.node, "ibm,hea-handle", NULL); if (adapter_handle) adapter->handle = *adapter_handle; diff --git a/trunk/drivers/net/irda/pxaficp_ir.c b/trunk/drivers/net/irda/pxaficp_ir.c index fb196fd91855..55ff0fbe525a 100644 --- a/trunk/drivers/net/irda/pxaficp_ir.c +++ b/trunk/drivers/net/irda/pxaficp_ir.c @@ -134,7 +134,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed) DCSR(si->rxdma) &= ~DCSR_RUN; /* disable FICP */ ICCR0 = 0; - pxa_set_cken(CKEN13_FICP, 0); + pxa_set_cken(CKEN_FICP, 0); /* set board transceiver to SIR mode */ si->pdata->transceiver_mode(si->dev, IR_SIRMODE); @@ -144,7 +144,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed) pxa_gpio_mode(GPIO47_STTXD_MD); /* enable the STUART clock */ - pxa_set_cken(CKEN5_STUART, 1); + pxa_set_cken(CKEN_STUART, 1); } /* disable STUART first */ @@ -169,7 +169,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed) /* disable STUART */ STIER = 0; STISR = 0; - pxa_set_cken(CKEN5_STUART, 0); + pxa_set_cken(CKEN_STUART, 0); /* disable FICP first */ ICCR0 = 0; @@ -182,7 +182,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed) pxa_gpio_mode(GPIO47_ICPTXD_MD); /* enable the FICP clock */ - pxa_set_cken(CKEN13_FICP, 1); + pxa_set_cken(CKEN_FICP, 1); si->speed = speed; pxa_irda_fir_dma_rx_start(si); @@ -593,7 +593,7 @@ static void pxa_irda_shutdown(struct pxa_irda *si) /* disable STUART SIR mode */ STISR = 0; /* disable the STUART clock */ - pxa_set_cken(CKEN5_STUART, 0); + pxa_set_cken(CKEN_STUART, 0); /* disable DMA */ DCSR(si->txdma) &= ~DCSR_RUN; @@ -601,7 +601,7 @@ static void pxa_irda_shutdown(struct pxa_irda *si) /* disable FICP */ ICCR0 = 0; /* disable the FICP clock */ - pxa_set_cken(CKEN13_FICP, 0); + pxa_set_cken(CKEN_FICP, 0); DRCMR17 = 0; DRCMR18 = 0; diff --git a/trunk/drivers/net/irda/sir_dev.c b/trunk/drivers/net/irda/sir_dev.c index 17b0c3ab6201..9d6c8f391b2d 100644 --- a/trunk/drivers/net/irda/sir_dev.c +++ b/trunk/drivers/net/irda/sir_dev.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/net/irda/sir_dongle.c b/trunk/drivers/net/irda/sir_dongle.c index d7e32d9554fc..25d5b8a96bdc 100644 --- a/trunk/drivers/net/irda/sir_dongle.c +++ b/trunk/drivers/net/irda/sir_dongle.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/net/irda/smsc-ircc2.c b/trunk/drivers/net/irda/smsc-ircc2.c index 198bf3bfa70f..9043bf4aa49e 100644 --- a/trunk/drivers/net/irda/smsc-ircc2.c +++ b/trunk/drivers/net/irda/smsc-ircc2.c @@ -79,11 +79,17 @@ MODULE_AUTHOR("Daniele Peri "); MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver"); MODULE_LICENSE("GPL"); -static int ircc_dma = 255; +static int smsc_nopnp; +module_param_named(nopnp, smsc_nopnp, bool, 0); +MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); + +#define DMA_INVAL 255 +static int ircc_dma = DMA_INVAL; module_param(ircc_dma, int, 0); MODULE_PARM_DESC(ircc_dma, "DMA channel"); -static int ircc_irq = 255; +#define IRQ_INVAL 255 +static int ircc_irq = IRQ_INVAL; module_param(ircc_irq, int, 0); MODULE_PARM_DESC(ircc_irq, "IRQ line"); @@ -360,7 +366,6 @@ static inline void register_bank(int iobase, int bank) iobase + IRCC_MASTER); } -#ifdef CONFIG_PNP /* PNP hotplug support */ static const struct pnp_device_id smsc_ircc_pnp_table[] = { { .id = "SMCf010", .driver_data = 0 }, @@ -368,7 +373,35 @@ static const struct pnp_device_id smsc_ircc_pnp_table[] = { { } }; MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table); -#endif + +static int pnp_driver_registered; + +static int __init smsc_ircc_pnp_probe(struct pnp_dev *dev, + const struct pnp_device_id *dev_id) +{ + unsigned int firbase, sirbase; + u8 dma, irq; + + if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && + pnp_dma_valid(dev, 0) && pnp_irq_valid(dev, 0))) + return -EINVAL; + + sirbase = pnp_port_start(dev, 0); + firbase = pnp_port_start(dev, 1); + dma = pnp_dma(dev, 0); + irq = pnp_irq(dev, 0); + + if (smsc_ircc_open(firbase, sirbase, dma, irq)) + return -ENODEV; + + return 0; +} + +static struct pnp_driver smsc_ircc_pnp_driver = { + .name = "smsc-ircc2", + .id_table = smsc_ircc_pnp_table, + .probe = smsc_ircc_pnp_probe, +}; /******************************************************************************* @@ -379,6 +412,35 @@ MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table); * *******************************************************************************/ +static int __init smsc_ircc_legacy_probe(void) +{ + int ret = 0; + + if (ircc_fir > 0 && ircc_sir > 0) { + IRDA_MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir); + IRDA_MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir); + + if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq)) + ret = -ENODEV; + } else { + ret = -ENODEV; + + /* try user provided configuration register base address */ + if (ircc_cfg > 0) { + IRDA_MESSAGE(" Overriding configuration address " + "0x%04x\n", ircc_cfg); + if (!smsc_superio_fdc(ircc_cfg)) + ret = 0; + if (!smsc_superio_lpc(ircc_cfg)) + ret = 0; + } + + if (smsc_ircc_look_for_chips() > 0) + ret = 0; + } + return ret; +} + /* * Function smsc_ircc_init () * @@ -406,31 +468,20 @@ static int __init smsc_ircc_init(void) dev_count = 0; - if (ircc_fir > 0 && ircc_sir > 0) { - IRDA_MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir); - IRDA_MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir); - - if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq)) - ret = -ENODEV; + if (smsc_nopnp || !pnp_platform_devices || + ircc_cfg || ircc_fir || ircc_sir || + ircc_dma != DMA_INVAL || ircc_irq != IRQ_INVAL) { + ret = smsc_ircc_legacy_probe(); } else { - ret = -ENODEV; - - /* try user provided configuration register base address */ - if (ircc_cfg > 0) { - IRDA_MESSAGE(" Overriding configuration address " - "0x%04x\n", ircc_cfg); - if (!smsc_superio_fdc(ircc_cfg)) - ret = 0; - if (!smsc_superio_lpc(ircc_cfg)) - ret = 0; - } - - if (smsc_ircc_look_for_chips() > 0) - ret = 0; + if (pnp_register_driver(&smsc_ircc_pnp_driver) == 0) + pnp_driver_registered = 1; } - if (ret) + if (ret) { + if (pnp_driver_registered) + pnp_unregister_driver(&smsc_ircc_pnp_driver); platform_driver_unregister(&smsc_ircc_driver); + } return ret; } @@ -646,7 +697,7 @@ static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, self->io.fifo_size = SMSC_IRCC2_FIFO_SIZE; self->io.speed = SMSC_IRCC2_C_IRDA_FALLBACK_SPEED; - if (irq < 255) { + if (irq != IRQ_INVAL) { if (irq != chip_irq) IRDA_MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n", driver_name, chip_irq, irq); @@ -654,7 +705,7 @@ static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, } else self->io.irq = chip_irq; - if (dma < 255) { + if (dma != DMA_INVAL) { if (dma != chip_dma) IRDA_MESSAGE("%s, Overriding DMA - chip says %d, using %d\n", driver_name, chip_dma, dma); @@ -1840,6 +1891,9 @@ static void __exit smsc_ircc_cleanup(void) smsc_ircc_close(dev_self[i]); } + if (pnp_driver_registered) + pnp_unregister_driver(&smsc_ircc_pnp_driver); + platform_driver_unregister(&smsc_ircc_driver); } @@ -2836,9 +2890,9 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, tmpconf.fir_io = ircc_fir; if (ircc_sir != 0) tmpconf.sir_io = ircc_sir; - if (ircc_dma != 0xff) + if (ircc_dma != DMA_INVAL) tmpconf.fir_dma = ircc_dma; - if (ircc_irq != 0xff) + if (ircc_irq != IRQ_INVAL) tmpconf.fir_irq = ircc_irq; IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name); diff --git a/trunk/drivers/net/irda/vlsi_ir.c b/trunk/drivers/net/irda/vlsi_ir.c index c4be973867a6..bf78ef1120ad 100644 --- a/trunk/drivers/net/irda/vlsi_ir.c +++ b/trunk/drivers/net/irda/vlsi_ir.c @@ -44,7 +44,6 @@ MODULE_LICENSE("GPL"); #include #include #include -#include #include #include diff --git a/trunk/drivers/net/mace.c b/trunk/drivers/net/mace.c index b3bd62394958..52b9332810c5 100644 --- a/trunk/drivers/net/mace.c +++ b/trunk/drivers/net/mace.c @@ -110,9 +110,9 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i return -ENODEV; } - addr = get_property(mace, "mac-address", NULL); + addr = of_get_property(mace, "mac-address", NULL); if (addr == NULL) { - addr = get_property(mace, "local-mac-address", NULL); + addr = of_get_property(mace, "local-mac-address", NULL); if (addr == NULL) { printk(KERN_ERR "Can't get mac-address for MACE %s\n", mace->full_name); diff --git a/trunk/drivers/net/myri10ge/myri10ge.c b/trunk/drivers/net/myri10ge/myri10ge.c index 16e3c4315e82..5d14be7405a3 100644 --- a/trunk/drivers/net/myri10ge/myri10ge.c +++ b/trunk/drivers/net/myri10ge/myri10ge.c @@ -290,6 +290,8 @@ MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n"); #define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8) +static void myri10ge_set_multicast_list(struct net_device *dev); + static inline void put_be32(__be32 val, __be32 __iomem * p) { __raw_writel((__force __u32) val, (__force void __iomem *)p); @@ -353,6 +355,8 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, return 0; } else if (result == MXGEFW_CMD_UNKNOWN) { return -ENOSYS; + } else if (result == MXGEFW_CMD_ERROR_UNALIGNED) { + return -E2BIG; } else { dev_err(&mgp->pdev->dev, "command %d failed, result = %d\n", @@ -712,14 +716,78 @@ myri10ge_change_promisc(struct myri10ge_priv *mgp, int promisc, int atomic) mgp->dev->name); } -static int myri10ge_reset(struct myri10ge_priv *mgp) +static int myri10ge_dma_test(struct myri10ge_priv *mgp, int test_type) { struct myri10ge_cmd cmd; int status; - size_t bytes; u32 len; struct page *dmatest_page; dma_addr_t dmatest_bus; + char *test = " "; + + dmatest_page = alloc_page(GFP_KERNEL); + if (!dmatest_page) + return -ENOMEM; + dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE, + DMA_BIDIRECTIONAL); + + /* Run a small DMA test. + * The magic multipliers to the length tell the firmware + * to do DMA read, write, or read+write tests. The + * results are returned in cmd.data0. The upper 16 + * bits or the return is the number of transfers completed. + * The lower 16 bits is the time in 0.5us ticks that the + * transfers took to complete. + */ + + len = mgp->tx.boundary; + + cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); + cmd.data2 = len * 0x10000; + status = myri10ge_send_cmd(mgp, test_type, &cmd, 0); + if (status != 0) { + test = "read"; + goto abort; + } + mgp->read_dma = ((cmd.data0 >> 16) * len * 2) / (cmd.data0 & 0xffff); + cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); + cmd.data2 = len * 0x1; + status = myri10ge_send_cmd(mgp, test_type, &cmd, 0); + if (status != 0) { + test = "write"; + goto abort; + } + mgp->write_dma = ((cmd.data0 >> 16) * len * 2) / (cmd.data0 & 0xffff); + + cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); + cmd.data2 = len * 0x10001; + status = myri10ge_send_cmd(mgp, test_type, &cmd, 0); + if (status != 0) { + test = "read/write"; + goto abort; + } + mgp->read_write_dma = ((cmd.data0 >> 16) * len * 2 * 2) / + (cmd.data0 & 0xffff); + +abort: + pci_unmap_page(mgp->pdev, dmatest_bus, PAGE_SIZE, DMA_BIDIRECTIONAL); + put_page(dmatest_page); + + if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST) + dev_warn(&mgp->pdev->dev, "DMA %s benchmark failed: %d\n", + test, status); + + return status; +} + +static int myri10ge_reset(struct myri10ge_priv *mgp) +{ + struct myri10ge_cmd cmd; + int status; + size_t bytes; /* try to send a reset command to the card to see if it * is alive */ @@ -729,11 +797,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) dev_err(&mgp->pdev->dev, "failed reset\n"); return -ENXIO; } - dmatest_page = alloc_page(GFP_KERNEL); - if (!dmatest_page) - return -ENOMEM; - dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE, - DMA_BIDIRECTIONAL); + + (void)myri10ge_dma_test(mgp, MXGEFW_DMA_TEST); /* Now exchange information about interrupts */ @@ -761,52 +826,6 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) } put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); - /* Run a small DMA test. - * The magic multipliers to the length tell the firmware - * to do DMA read, write, or read+write tests. The - * results are returned in cmd.data0. The upper 16 - * bits or the return is the number of transfers completed. - * The lower 16 bits is the time in 0.5us ticks that the - * transfers took to complete. - */ - - len = mgp->tx.boundary; - - cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); - cmd.data2 = len * 0x10000; - status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0); - if (status == 0) - mgp->read_dma = ((cmd.data0 >> 16) * len * 2) / - (cmd.data0 & 0xffff); - else - dev_warn(&mgp->pdev->dev, "DMA read benchmark failed: %d\n", - status); - cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); - cmd.data2 = len * 0x1; - status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0); - if (status == 0) - mgp->write_dma = ((cmd.data0 >> 16) * len * 2) / - (cmd.data0 & 0xffff); - else - dev_warn(&mgp->pdev->dev, "DMA write benchmark failed: %d\n", - status); - - cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); - cmd.data2 = len * 0x10001; - status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0); - if (status == 0) - mgp->read_write_dma = ((cmd.data0 >> 16) * len * 2 * 2) / - (cmd.data0 & 0xffff); - else - dev_warn(&mgp->pdev->dev, - "DMA read/write benchmark failed: %d\n", status); - - pci_unmap_page(mgp->pdev, dmatest_bus, PAGE_SIZE, DMA_BIDIRECTIONAL); - put_page(dmatest_page); - memset(mgp->rx_done.entry, 0, bytes); /* reset mcp/driver shared state back to 0 */ @@ -820,10 +839,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) mgp->rx_done.cnt = 0; mgp->link_changes = 0; status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr); - myri10ge_change_promisc(mgp, 0, 0); myri10ge_change_pause(mgp, mgp->pause); - if (mgp->adopted_rx_filter_bug) - (void)myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1); + myri10ge_set_multicast_list(mgp->dev); return status; } @@ -1355,7 +1372,9 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = { "tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt", "wake_queue", "stop_queue", "watchdog_resets", "tx_linearized", "link_changes", "link_up", "dropped_link_overflow", - "dropped_link_error_or_filtered", "dropped_multicast_filtered", + "dropped_link_error_or_filtered", + "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32", + "dropped_unicast_filtered", "dropped_multicast_filtered", "dropped_runt", "dropped_overrun", "dropped_no_small_buffer", "dropped_no_big_buffer" }; @@ -1412,6 +1431,11 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_overflow); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_error_or_filtered); + data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_pause); + data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_bad_phy); + data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_bad_crc32); + data[i++] = + (unsigned int)ntohl(mgp->fw_stats->dropped_unicast_filtered); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_multicast_filtered); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt); @@ -2276,7 +2300,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev) myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1); /* This firmware is known to not support multicast */ - if (!mgp->fw_multicast_support || mgp->adopted_rx_filter_bug) + if (!mgp->fw_multicast_support) return; /* Disable multicast filtering */ @@ -2288,7 +2312,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev) goto abort; } - if (dev->flags & IFF_ALLMULTI) { + if ((dev->flags & IFF_ALLMULTI) || mgp->adopted_rx_filter_bug) { /* request to disable multicast filtering, so quit here */ return; } @@ -2461,8 +2485,6 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp) err_cap |= PCI_ERR_CAP_ECRC_GENE; pci_write_config_dword(bridge, cap + PCI_ERR_CAP, err_cap); dev_info(dev, "Enabled ECRC on upstream bridge %s\n", pci_name(bridge)); - mgp->tx.boundary = 4096; - mgp->fw_name = myri10ge_fw_aligned; } /* @@ -2484,22 +2506,70 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp) * firmware image, and set tx.boundary to 4KB. */ -#define PCI_DEVICE_ID_INTEL_E5000_PCIE23 0x25f7 -#define PCI_DEVICE_ID_INTEL_E5000_PCIE47 0x25fa -#define PCI_DEVICE_ID_INTEL_6300ESB_PCIEE1 0x3510 -#define PCI_DEVICE_ID_INTEL_6300ESB_PCIEE4 0x351b -#define PCI_DEVICE_ID_INTEL_E3000_PCIE 0x2779 -#define PCI_DEVICE_ID_INTEL_E3010_PCIE 0x277a -#define PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_FIRST 0x140 -#define PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_LAST 0x142 - -static void myri10ge_select_firmware(struct myri10ge_priv *mgp) +static void myri10ge_firmware_probe(struct myri10ge_priv *mgp) { - struct pci_dev *bridge = mgp->pdev->bus->self; + struct pci_dev *pdev = mgp->pdev; + struct device *dev = &pdev->dev; + int cap, status; + u16 val; + + mgp->tx.boundary = 4096; + /* + * Verify the max read request size was set to 4KB + * before trying the test with 4KB. + */ + cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (cap < 64) { + dev_err(dev, "Bad PCI_CAP_ID_EXP location %d\n", cap); + goto abort; + } + status = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &val); + if (status != 0) { + dev_err(dev, "Couldn't read max read req size: %d\n", status); + goto abort; + } + if ((val & (5 << 12)) != (5 << 12)) { + dev_warn(dev, "Max Read Request size != 4096 (0x%x)\n", val); + mgp->tx.boundary = 2048; + } + /* + * load the optimized firmware (which assumes aligned PCIe + * completions) in order to see if it works on this host. + */ + mgp->fw_name = myri10ge_fw_aligned; + status = myri10ge_load_firmware(mgp); + if (status != 0) { + goto abort; + } + + /* + * Enable ECRC if possible + */ + myri10ge_enable_ecrc(mgp); + + /* + * Run a DMA test which watches for unaligned completions and + * aborts on the first one seen. + */ + status = myri10ge_dma_test(mgp, MXGEFW_CMD_UNALIGNED_TEST); + if (status == 0) + return; /* keep the aligned firmware */ + + if (status != -E2BIG) + dev_warn(dev, "DMA test failed: %d\n", status); + if (status == -ENOSYS) + dev_warn(dev, "Falling back to ethp! " + "Please install up to date fw\n"); +abort: + /* fall back to using the unaligned firmware */ mgp->tx.boundary = 2048; mgp->fw_name = myri10ge_fw_unaligned; +} + +static void myri10ge_select_firmware(struct myri10ge_priv *mgp) +{ if (myri10ge_force_firmware == 0) { int link_width, exp_cap; u16 lnk; @@ -2508,8 +2578,6 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp) pci_read_config_word(mgp->pdev, exp_cap + PCI_EXP_LNKSTA, &lnk); link_width = (lnk >> 4) & 0x3f; - myri10ge_enable_ecrc(mgp); - /* Check to see if Link is less than 8 or if the * upstream bridge is known to provide aligned * completions */ @@ -2518,46 +2586,8 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp) link_width); mgp->tx.boundary = 4096; mgp->fw_name = myri10ge_fw_aligned; - } else if (bridge && - /* ServerWorks HT2000/HT1000 */ - ((bridge->vendor == PCI_VENDOR_ID_SERVERWORKS - && bridge->device == - PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE) - /* ServerWorks HT2100 */ - || (bridge->vendor == PCI_VENDOR_ID_SERVERWORKS - && bridge->device >= - PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_FIRST - && bridge->device <= - PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_LAST) - /* All Intel E3000/E3010 PCIE ports */ - || (bridge->vendor == PCI_VENDOR_ID_INTEL - && (bridge->device == - PCI_DEVICE_ID_INTEL_E3000_PCIE - || bridge->device == - PCI_DEVICE_ID_INTEL_E3010_PCIE)) - /* All Intel 6310/6311/6321ESB PCIE ports */ - || (bridge->vendor == PCI_VENDOR_ID_INTEL - && bridge->device >= - PCI_DEVICE_ID_INTEL_6300ESB_PCIEE1 - && bridge->device <= - PCI_DEVICE_ID_INTEL_6300ESB_PCIEE4) - /* All Intel E5000 PCIE ports */ - || (bridge->vendor == PCI_VENDOR_ID_INTEL - && bridge->device >= - PCI_DEVICE_ID_INTEL_E5000_PCIE23 - && bridge->device <= - PCI_DEVICE_ID_INTEL_E5000_PCIE47))) { - dev_info(&mgp->pdev->dev, - "Assuming aligned completions (0x%x:0x%x)\n", - bridge->vendor, bridge->device); - mgp->tx.boundary = 4096; - mgp->fw_name = myri10ge_fw_aligned; - } else if (bridge && - bridge->vendor == PCI_VENDOR_ID_SGI && - bridge->device == 0x4002 /* TIOCE pcie-port */ ) { - /* this pcie bridge does not support 4K rdma request */ - mgp->tx.boundary = 2048; - mgp->fw_name = myri10ge_fw_aligned; + } else { + myri10ge_firmware_probe(mgp); } } else { if (myri10ge_force_firmware == 1) { @@ -2825,7 +2855,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) status = -ENODEV; goto abort_with_netdev; } - myri10ge_select_firmware(mgp); /* Find the vendor-specific cap so we can check * the reboot register later on */ @@ -2919,6 +2948,8 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto abort_with_ioremap; memset(mgp->rx_done.entry, 0, bytes); + myri10ge_select_firmware(mgp); + status = myri10ge_load_firmware(mgp); if (status != 0) { dev_err(&pdev->dev, "failed to load firmware\n"); diff --git a/trunk/drivers/net/myri10ge/myri10ge_mcp.h b/trunk/drivers/net/myri10ge/myri10ge_mcp.h index 29463b301a84..a1d2a22296a9 100644 --- a/trunk/drivers/net/myri10ge/myri10ge_mcp.h +++ b/trunk/drivers/net/myri10ge/myri10ge_mcp.h @@ -200,6 +200,13 @@ enum myri10ge_mcp_cmd_type { /* data0, data1 = bus addr, * data2 = sizeof(struct mcp_irq_data) from driver point of view, allows * adding new stuff to mcp_irq_data without changing the ABI */ + + MXGEFW_CMD_UNALIGNED_TEST, + /* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned + * chipset */ + + MXGEFW_CMD_UNALIGNED_STATUS + /* return data = boolean, true if the chipset is known to be unaligned */ }; enum myri10ge_mcp_cmd_status { @@ -212,18 +219,27 @@ enum myri10ge_mcp_cmd_status { MXGEFW_CMD_ERROR_HASH_ERROR, MXGEFW_CMD_ERROR_BAD_PORT, MXGEFW_CMD_ERROR_RESOURCES, - MXGEFW_CMD_ERROR_MULTICAST + MXGEFW_CMD_ERROR_MULTICAST, + MXGEFW_CMD_ERROR_UNALIGNED }; #define MXGEFW_OLD_IRQ_DATA_LEN 40 struct mcp_irq_data { /* add new counters at the beginning */ - __be32 future_use[5]; + __be32 future_use[1]; + __be32 dropped_pause; + __be32 dropped_unicast_filtered; + __be32 dropped_bad_crc32; + __be32 dropped_bad_phy; __be32 dropped_multicast_filtered; /* 40 Bytes */ __be32 send_done_count; +#define MXGEFW_LINK_DOWN 0 +#define MXGEFW_LINK_UP 1 +#define MXGEFW_LINK_MYRINET 2 +#define MXGEFW_LINK_UNKNOWN 3 __be32 link_up; __be32 dropped_link_overflow; __be32 dropped_link_error_or_filtered; diff --git a/trunk/drivers/net/natsemi.c b/trunk/drivers/net/natsemi.c index a8d7ff2c96ac..223e0e6264ba 100644 --- a/trunk/drivers/net/natsemi.c +++ b/trunk/drivers/net/natsemi.c @@ -81,6 +81,8 @@ static const int multicast_filter_limit = 100; Setting to > 1518 effectively disables this feature. */ static int rx_copybreak; +static int dspcfg_workaround = 1; + /* Used to pass the media type, etc. Both 'options[]' and 'full_duplex[]' should exist for driver interoperability. @@ -139,12 +141,14 @@ MODULE_LICENSE("GPL"); module_param(mtu, int, 0); module_param(debug, int, 0); module_param(rx_copybreak, int, 0); +module_param(dspcfg_workaround, int, 1); module_param_array(options, int, NULL, 0); module_param_array(full_duplex, int, NULL, 0); MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); MODULE_PARM_DESC(debug, "DP8381x default debug level"); MODULE_PARM_DESC(rx_copybreak, "DP8381x copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(dspcfg_workaround, "DP8381x: control DspCfg workaround"); MODULE_PARM_DESC(options, "DP8381x: Bits 0-3: media type, bit 17: full duplex"); MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)"); @@ -590,6 +594,7 @@ struct netdev_private { u32 srr; /* expected DSPCFG value */ u16 dspcfg; + int dspcfg_workaround; /* parms saved in ethtool format */ u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */ u8 duplex; /* Duplex, half or full */ @@ -656,6 +661,56 @@ static int netdev_get_regs(struct net_device *dev, u8 *buf); static int netdev_get_eeprom(struct net_device *dev, u8 *buf); static const struct ethtool_ops ethtool_ops; +#define NATSEMI_ATTR(_name) \ +static ssize_t natsemi_show_##_name(struct device *dev, \ + struct device_attribute *attr, char *buf); \ + static ssize_t natsemi_set_##_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count); \ + static DEVICE_ATTR(_name, 0644, natsemi_show_##_name, natsemi_set_##_name) + +#define NATSEMI_CREATE_FILE(_dev, _name) \ + device_create_file(&_dev->dev, &dev_attr_##_name) +#define NATSEMI_REMOVE_FILE(_dev, _name) \ + device_create_file(&_dev->dev, &dev_attr_##_name) + +NATSEMI_ATTR(dspcfg_workaround); + +static ssize_t natsemi_show_dspcfg_workaround(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct netdev_private *np = netdev_priv(to_net_dev(dev)); + + return sprintf(buf, "%s\n", np->dspcfg_workaround ? "on" : "off"); +} + +static ssize_t natsemi_set_dspcfg_workaround(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct netdev_private *np = netdev_priv(to_net_dev(dev)); + int new_setting; + u32 flags; + + /* Find out the new setting */ + 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)) + new_setting = 0; + else + return count; + + spin_lock_irqsave(&np->lock, flags); + + np->dspcfg_workaround = new_setting; + + spin_unlock_irqrestore(&np->lock, flags); + + return count; +} + static inline void __iomem *ns_ioaddr(struct net_device *dev) { return (void __iomem *) dev->base_addr; @@ -820,6 +875,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, np->ignore_phy = 1; else np->ignore_phy = 0; + np->dspcfg_workaround = dspcfg_workaround; /* Initial port: * - If configured to ignore the PHY set up for external. @@ -899,6 +955,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, if (i) goto err_register_netdev; + if (NATSEMI_CREATE_FILE(pdev, dspcfg_workaround)) + goto err_create_file; + if (netif_msg_drv(np)) { printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ", dev->name, natsemi_pci_info[chip_idx].name, iostart, @@ -915,6 +974,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, } return 0; + err_create_file: + unregister_netdev(dev); + err_register_netdev: iounmap(ioaddr); @@ -1727,7 +1789,8 @@ static void init_registers(struct net_device *dev) * It seems that a reference set for this chip went out with incorrect info, * and there exist boards that aren't quite right. An unexpected voltage * drop can cause the PHY to get itself in a weird state (basically reset). - * NOTE: this only seems to affect revC chips. + * NOTE: this only seems to affect revC chips. The user can disable + * this check via dspcfg_workaround sysfs option. * 3) check of death of the RX path due to OOM */ static void netdev_timer(unsigned long data) @@ -1753,10 +1816,10 @@ static void netdev_timer(unsigned long data) writew(1, ioaddr+PGSEL); dspcfg = readw(ioaddr+DSPCFG); writew(0, ioaddr+PGSEL); - if (dspcfg != np->dspcfg) { + if (np->dspcfg_workaround && dspcfg != np->dspcfg) { if (!netif_queue_stopped(dev)) { spin_unlock_irq(&np->lock); - if (netif_msg_hw(np)) + if (netif_msg_drv(np)) printk(KERN_NOTICE "%s: possible phy reset: " "re-initializing\n", dev->name); disable_irq(dev->irq); @@ -3157,6 +3220,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); void __iomem * ioaddr = ns_ioaddr(dev); + NATSEMI_REMOVE_FILE(pdev, dspcfg_workaround); unregister_netdev (dev); pci_release_regions (pdev); iounmap(ioaddr); diff --git a/trunk/drivers/net/ne.c b/trunk/drivers/net/ne.c index a5c4199e2754..c9f74bf5f491 100644 --- a/trunk/drivers/net/ne.c +++ b/trunk/drivers/net/ne.c @@ -51,14 +51,11 @@ static const char version2[] = #include #include #include +#include #include #include -#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) -#include -#endif - #include "8390.h" #define DRV_NAME "ne" @@ -77,8 +74,13 @@ static const char version2[] = /* Do we have a non std. amount of memory? (in units of 256 byte pages) */ /* #define PACKETBUF_MEMSIZE 0x40 */ +#if !defined(MODULE) && (defined(CONFIG_ISA) || defined(CONFIG_M32R)) +/* Do we need a portlist for the ISA auto-probe ? */ +#define NEEDS_PORTLIST +#endif + /* A zero-terminated list of I/O addresses to be probed at boot. */ -#ifndef MODULE +#ifdef NEEDS_PORTLIST static unsigned int netcard_portlist[] __initdata = { 0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0 }; @@ -146,7 +148,7 @@ bad_clone_list[] __initdata = { # define DCR_VAL 0x49 #endif -static int ne_probe1(struct net_device *dev, int ioaddr); +static int ne_probe1(struct net_device *dev, unsigned long ioaddr); static int ne_probe_isapnp(struct net_device *dev); static int ne_open(struct net_device *dev); @@ -184,8 +186,8 @@ static void ne_block_output(struct net_device *dev, const int count, static int __init do_ne_probe(struct net_device *dev) { - unsigned int base_addr = dev->base_addr; -#ifndef MODULE + unsigned long base_addr = dev->base_addr; +#ifdef NEEDS_PORTLIST int orig_irq = dev->irq; #endif @@ -201,7 +203,7 @@ static int __init do_ne_probe(struct net_device *dev) if (isapnp_present() && (ne_probe_isapnp(dev) == 0)) return 0; -#ifndef MODULE +#ifdef NEEDS_PORTLIST /* Last resort. The semi-risky ISA auto-probe. */ for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) { int ioaddr = netcard_portlist[base_addr]; @@ -226,10 +228,6 @@ struct net_device * __init ne_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); -#ifdef CONFIG_TOSHIBA_RBTX4938 - dev->base_addr = RBTX4938_RTL_8019_BASE; - dev->irq = RBTX4938_RTL_8019_IRQ; -#endif err = do_ne_probe(dev); if (err) goto out; @@ -285,7 +283,7 @@ static int __init ne_probe_isapnp(struct net_device *dev) return -ENODEV; } -static int __init ne_probe1(struct net_device *dev, int ioaddr) +static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) { int i; unsigned char SA_prom[32]; @@ -324,7 +322,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) if (ei_debug && version_printed++ == 0) printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); - printk(KERN_INFO "NE*000 ethercard probe at %#3x:", ioaddr); + printk(KERN_INFO "NE*000 ethercard probe at %#3lx:", ioaddr); /* A user with a poor card that fails to ack the reset, or that does not have a valid 0x57,0x57 signature can still use this @@ -516,8 +514,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) } #endif - printk("\n%s: %s found at %#x, using IRQ %d.\n", - dev->name, name, ioaddr, dev->irq); + printk("\n"); ei_status.name = name; ei_status.tx_start_page = start_page; @@ -547,6 +544,8 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) ret = register_netdev(dev); if (ret) goto out_irq; + printk(KERN_INFO "%s: %s found at %#lx, using IRQ %d.\n", + dev->name, name, ioaddr, dev->irq); return 0; out_irq: @@ -807,6 +806,87 @@ static void ne_block_output(struct net_device *dev, int count, return; } +static int __init ne_drv_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct resource *res; + int err, irq; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + irq = platform_get_irq(pdev, 0); + if (!res || irq < 0) + return -ENODEV; + + dev = alloc_ei_netdev(); + if (!dev) + return -ENOMEM; + dev->irq = irq; + dev->base_addr = res->start; + err = do_ne_probe(dev); + if (err) { + free_netdev(dev); + return err; + } + platform_set_drvdata(pdev, dev); + return 0; +} + +static int __exit ne_drv_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + + unregister_netdev(dev); + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); + free_netdev(dev); + return 0; +} + +#ifdef CONFIG_PM +static int ne_drv_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *dev = platform_get_drvdata(pdev); + + if (netif_running(dev)) + netif_device_detach(dev); + return 0; +} + +static int ne_drv_resume(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + + if (netif_running(dev)) { + ne_reset_8390(dev); + NS8390_init(dev, 1); + netif_device_attach(dev); + } + return 0; +} +#else +#define ne_drv_suspend NULL +#define ne_drv_resume NULL +#endif + +static struct platform_driver ne_driver = { + .remove = __exit_p(ne_drv_remove), + .suspend = ne_drv_suspend, + .resume = ne_drv_resume, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init ne_init(void) +{ + return platform_driver_probe(&ne_driver, ne_drv_probe); +} + +static void __exit ne_exit(void) +{ + platform_driver_unregister(&ne_driver); +} #ifdef MODULE #define MAX_NE_CARDS 4 /* Max number of NE cards per module */ @@ -832,6 +912,7 @@ ISA device autoprobes on a running machine are not recommended anyway. */ int __init init_module(void) { int this_dev, found = 0; + int plat_found = !ne_init(); for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { struct net_device *dev = alloc_ei_netdev(); @@ -845,7 +926,7 @@ int __init init_module(void) continue; } free_netdev(dev); - if (found) + if (found || plat_found) break; if (io[this_dev] != 0) printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]); @@ -853,7 +934,7 @@ int __init init_module(void) printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); return -ENXIO; } - if (found) + if (found || plat_found) return 0; return -ENODEV; } @@ -871,6 +952,7 @@ void __exit cleanup_module(void) { int this_dev; + ne_exit(); for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { struct net_device *dev = dev_ne[this_dev]; if (dev) { @@ -880,4 +962,7 @@ void __exit cleanup_module(void) } } } +#else /* MODULE */ +module_init(ne_init); +module_exit(ne_exit); #endif /* MODULE */ diff --git a/trunk/drivers/net/ns83820.c b/trunk/drivers/net/ns83820.c index 6a32338623f1..3439f8c649f9 100644 --- a/trunk/drivers/net/ns83820.c +++ b/trunk/drivers/net/ns83820.c @@ -104,7 +104,6 @@ #include #include #include -#include #include #include #include /* for iph */ diff --git a/trunk/drivers/net/pasemi_mac.c b/trunk/drivers/net/pasemi_mac.c index 76fe9dd8e841..bc7f3dee6e5b 100644 --- a/trunk/drivers/net/pasemi_mac.c +++ b/trunk/drivers/net/pasemi_mac.c @@ -33,6 +33,8 @@ #include #include +#include + #include "pasemi_mac.h" @@ -51,6 +53,16 @@ #define RX_RING_SIZE 512 #define TX_RING_SIZE 512 +#define DEFAULT_MSG_ENABLE \ + (NETIF_MSG_DRV | \ + NETIF_MSG_PROBE | \ + NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | \ + NETIF_MSG_IFDOWN | \ + NETIF_MSG_IFUP | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) + #define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)]) #define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)]) #define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)]) @@ -59,11 +71,13 @@ #define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ -/* XXXOJN these should come out of the device tree some day */ -#define PAS_DMA_CAP_BASE 0xe00d0040 -#define PAS_DMA_CAP_SIZE 0x100 -#define PAS_DMA_COM_BASE 0xe00d0100 -#define PAS_DMA_COM_SIZE 0x100 +MODULE_LICENSE("GPL"); +MODULE_AUTHOR ("Olof Johansson "); +MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); + +static int debug = -1; /* -1 == use DEFAULT_MSG_ENABLE as value */ +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); static struct pasdma_status *dma_status; @@ -80,7 +94,12 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac) return -ENOENT; } - maddr = get_property(dn, "mac-address", NULL); + maddr = of_get_property(dn, "local-mac-address", NULL); + + /* Fall back to mac-address for older firmware */ + if (maddr == NULL) + maddr = of_get_property(dn, "mac-address", NULL); + if (maddr == NULL) { dev_warn(&pdev->dev, "no mac address in device tree, not configuring\n"); @@ -277,8 +296,8 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev) for (i = 0; i < RX_RING_SIZE; i++) { info = &RX_DESC_INFO(mac, i); dp = &RX_DESC(mac, i); - if (info->dma) { - if (info->skb) { + if (info->skb) { + if (info->dma) { pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len, @@ -309,82 +328,120 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev) struct pasemi_mac *mac = netdev_priv(dev); unsigned int i; int start = mac->rx->next_to_fill; - unsigned int count; + unsigned int limit, count; - count = (mac->rx->next_to_clean + RX_RING_SIZE - + limit = (mac->rx->next_to_clean + RX_RING_SIZE - mac->rx->next_to_fill) & (RX_RING_SIZE - 1); /* Check to see if we're doing first-time setup */ if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0)) - count = RX_RING_SIZE; + limit = RX_RING_SIZE; - if (count <= 0) + if (limit <= 0) return; - for (i = start; i < start + count; i++) { + i = start; + for (count = limit; count; count--) { struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i); u64 *buff = &RX_BUFF(mac, i); struct sk_buff *skb; dma_addr_t dma; - skb = dev_alloc_skb(BUF_SIZE); + /* skb might still be in there for recycle on short receives */ + if (info->skb) + skb = info->skb; + else + skb = dev_alloc_skb(BUF_SIZE); - if (!skb) { - count = i - start; + if (unlikely(!skb)) break; - } dma = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_FROMDEVICE); - if (dma_mapping_error(dma)) { + if (unlikely(dma_mapping_error(dma))) { dev_kfree_skb_irq(info->skb); - count = i - start; break; } info->skb = skb; info->dma = dma; *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma); + i++; } wmb(); pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), - count); + limit - count); pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_INCR(mac->dma_if), - count); + limit - count); - mac->rx->next_to_fill += count; + mac->rx->next_to_fill += limit - count; } +static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac) +{ + unsigned int reg, stat; + /* Re-enable packet count interrupts: finally + * ack the packet count interrupt we got in rx_intr. + */ + + pci_read_config_dword(mac->iob_pdev, + PAS_IOB_DMA_RXCH_STAT(mac->dma_rxch), + &stat); + + reg = PAS_IOB_DMA_RXCH_RESET_PCNT(stat & PAS_IOB_DMA_RXCH_STAT_CNTDEL_M) + | PAS_IOB_DMA_RXCH_RESET_PINTC; + + pci_write_config_dword(mac->iob_pdev, + PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), + reg); +} + +static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac) +{ + unsigned int reg, stat; + + /* Re-enable packet count interrupts */ + pci_read_config_dword(mac->iob_pdev, + PAS_IOB_DMA_TXCH_STAT(mac->dma_txch), &stat); + + reg = PAS_IOB_DMA_TXCH_RESET_PCNT(stat & PAS_IOB_DMA_TXCH_STAT_CNTDEL_M) + | PAS_IOB_DMA_TXCH_RESET_PINTC; + + pci_write_config_dword(mac->iob_pdev, + PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg); +} + + static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) { - unsigned int i; - int start, count; + unsigned int n; + int count; + struct pas_dma_xct_descr *dp; + struct pasemi_mac_buffer *info; + struct sk_buff *skb; + unsigned int i, len; + u64 macrx; + dma_addr_t dma; spin_lock(&mac->rx->lock); - start = mac->rx->next_to_clean; - count = 0; + n = mac->rx->next_to_clean; - for (i = start; i < (start + RX_RING_SIZE) && count < limit; i++) { - struct pas_dma_xct_descr *dp; - struct pasemi_mac_buffer *info; - struct sk_buff *skb; - unsigned int j, len; - dma_addr_t dma; + for (count = limit; count; count--) { rmb(); - dp = &RX_DESC(mac, i); + dp = &RX_DESC(mac, n); + macrx = dp->macrx; - if (!(dp->macrx & XCT_MACRX_O)) + if (!(macrx & XCT_MACRX_O)) break; - count++; info = NULL; @@ -396,29 +453,42 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) */ dma = (dp->ptr & XCT_PTR_ADDR_M); - for (j = start; j < (start + RX_RING_SIZE); j++) { - info = &RX_DESC_INFO(mac, j); + for (i = n; i < (n + RX_RING_SIZE); i++) { + info = &RX_DESC_INFO(mac, i); if (info->dma == dma) break; } - BUG_ON(!info); - BUG_ON(info->dma != dma); + skb = info->skb; + info->dma = 0; - pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len, + pci_unmap_single(mac->dma_pdev, dma, skb->len, PCI_DMA_FROMDEVICE); - skb = info->skb; - - len = (dp->macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; + len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; + + if (len < 256) { + struct sk_buff *new_skb = + netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN); + if (new_skb) { + skb_reserve(new_skb, NET_IP_ALIGN); + memcpy(new_skb->data - NET_IP_ALIGN, + skb->data - NET_IP_ALIGN, + len + NET_IP_ALIGN); + /* save the skb in buffer_info as good */ + skb = new_skb; + } + /* else just continue with the old one */ + } else + info->skb = NULL; skb_put(skb, len); skb->protocol = eth_type_trans(skb, mac->netdev); - if ((dp->macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) { + if ((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) { skb->ip_summed = CHECKSUM_COMPLETE; - skb->csum = (dp->macrx & XCT_MACRX_CSUM_M) >> + skb->csum = (macrx & XCT_MACRX_CSUM_M) >> XCT_MACRX_CSUM_S; } else skb->ip_summed = CHECKSUM_NONE; @@ -428,13 +498,13 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) netif_receive_skb(skb); - info->dma = 0; - info->skb = NULL; dp->ptr = 0; dp->macrx = 0; + + n++; } - mac->rx->next_to_clean += count; + mac->rx->next_to_clean += limit - count; pasemi_mac_replenish_rx_ring(mac->netdev); spin_unlock(&mac->rx->lock); @@ -476,6 +546,8 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) mac->tx->next_to_clean += count; spin_unlock_irqrestore(&mac->tx->lock, flags); + netif_wake_queue(mac->netdev); + return count; } @@ -486,18 +558,28 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) struct pasemi_mac *mac = netdev_priv(dev); unsigned int reg; - if (!(*mac->rx_status & PAS_STATUS_INT)) + if (!(*mac->rx_status & PAS_STATUS_CAUSE_M)) return IRQ_NONE; - netif_rx_schedule(dev); - pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, - PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0)); + if (*mac->rx_status & PAS_STATUS_ERROR) + printk("rx_status reported error\n"); + + /* Don't reset packet count so it won't fire again but clear + * all others. + */ + + pci_read_config_dword(mac->dma_pdev, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), ®); - reg = PAS_IOB_DMA_RXCH_RESET_PINTC | PAS_IOB_DMA_RXCH_RESET_SINTC | - PAS_IOB_DMA_RXCH_RESET_DINTC; + reg = 0; + if (*mac->rx_status & PAS_STATUS_SOFT) + reg |= PAS_IOB_DMA_RXCH_RESET_SINTC; + if (*mac->rx_status & PAS_STATUS_ERROR) + reg |= PAS_IOB_DMA_RXCH_RESET_DINTC; if (*mac->rx_status & PAS_STATUS_TIMER) reg |= PAS_IOB_DMA_RXCH_RESET_TINTC; + netif_rx_schedule(dev); + pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); @@ -510,31 +592,137 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) struct net_device *dev = data; struct pasemi_mac *mac = netdev_priv(dev); unsigned int reg; - int was_full; - was_full = mac->tx->next_to_clean - mac->tx->next_to_use == TX_RING_SIZE; - - if (!(*mac->tx_status & PAS_STATUS_INT)) + if (!(*mac->tx_status & PAS_STATUS_CAUSE_M)) return IRQ_NONE; pasemi_mac_clean_tx(mac); - reg = PAS_IOB_DMA_TXCH_RESET_PINTC | PAS_IOB_DMA_TXCH_RESET_SINTC; - if (*mac->tx_status & PAS_STATUS_TIMER) - reg |= PAS_IOB_DMA_TXCH_RESET_TINTC; + reg = PAS_IOB_DMA_TXCH_RESET_PINTC; + + if (*mac->tx_status & PAS_STATUS_SOFT) + reg |= PAS_IOB_DMA_TXCH_RESET_SINTC; + if (*mac->tx_status & PAS_STATUS_ERROR) + reg |= PAS_IOB_DMA_TXCH_RESET_DINTC; pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg); - if (was_full) - netif_wake_queue(dev); - return IRQ_HANDLED; } +static void pasemi_adjust_link(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + int msg; + unsigned int flags; + unsigned int new_flags; + + if (!mac->phydev->link) { + /* If no link, MAC speed settings don't matter. Just report + * link down and return. + */ + if (mac->link && netif_msg_link(mac)) + printk(KERN_INFO "%s: Link is down.\n", dev->name); + + netif_carrier_off(dev); + mac->link = 0; + + return; + } else + netif_carrier_on(dev); + + pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags); + new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M | + PAS_MAC_CFG_PCFG_TSR_M); + + if (!mac->phydev->duplex) + new_flags |= PAS_MAC_CFG_PCFG_HD; + + switch (mac->phydev->speed) { + case 1000: + new_flags |= PAS_MAC_CFG_PCFG_SPD_1G | + PAS_MAC_CFG_PCFG_TSR_1G; + break; + case 100: + new_flags |= PAS_MAC_CFG_PCFG_SPD_100M | + PAS_MAC_CFG_PCFG_TSR_100M; + break; + case 10: + new_flags |= PAS_MAC_CFG_PCFG_SPD_10M | + PAS_MAC_CFG_PCFG_TSR_10M; + break; + default: + printk("Unsupported speed %d\n", mac->phydev->speed); + } + + /* Print on link or speed/duplex change */ + msg = mac->link != mac->phydev->link || flags != new_flags; + + mac->duplex = mac->phydev->duplex; + mac->speed = mac->phydev->speed; + mac->link = mac->phydev->link; + + if (new_flags != flags) + pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, new_flags); + + if (msg && netif_msg_link(mac)) + printk(KERN_INFO "%s: Link is up at %d Mbps, %s duplex.\n", + dev->name, mac->speed, mac->duplex ? "full" : "half"); +} + +static int pasemi_mac_phy_init(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + struct device_node *dn, *phy_dn; + struct phy_device *phydev; + unsigned int phy_id; + const phandle *ph; + const unsigned int *prop; + struct resource r; + int ret; + + dn = pci_device_to_OF_node(mac->pdev); + ph = of_get_property(dn, "phy-handle", NULL); + if (!ph) + return -ENODEV; + phy_dn = of_find_node_by_phandle(*ph); + + prop = of_get_property(phy_dn, "reg", NULL); + ret = of_address_to_resource(phy_dn->parent, 0, &r); + if (ret) + goto err; + + phy_id = *prop; + snprintf(mac->phy_id, BUS_ID_SIZE, PHY_ID_FMT, (int)r.start, phy_id); + + of_node_put(phy_dn); + + mac->link = 0; + mac->speed = 0; + mac->duplex = -1; + + phydev = phy_connect(dev, mac->phy_id, &pasemi_adjust_link, 0, PHY_INTERFACE_MODE_SGMII); + + if (IS_ERR(phydev)) { + printk(KERN_ERR "%s: Could not attach to phy\n", dev->name); + return PTR_ERR(phydev); + } + + mac->phydev = phydev; + + return 0; + +err: + of_node_put(phy_dn); + return -ENODEV; +} + + static int pasemi_mac_open(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); + int base_irq; unsigned int flags; int ret; @@ -558,10 +746,18 @@ static int pasemi_mac_open(struct net_device *dev) flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), - PAS_IOB_DMA_RXCH_CFG_CNTTH(30)); + PAS_IOB_DMA_RXCH_CFG_CNTTH(1)); + pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch), + PAS_IOB_DMA_TXCH_CFG_CNTTH(32)); + + /* Clear out any residual packet count state from firmware */ + pasemi_mac_restart_rx_intr(mac); + pasemi_mac_restart_tx_intr(mac); + + /* 0xffffff is max value, about 16ms */ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, - PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000)); + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff)); pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags); @@ -595,31 +791,50 @@ static int pasemi_mac_open(struct net_device *dev) pasemi_mac_replenish_rx_ring(dev); + ret = pasemi_mac_phy_init(dev); + /* Some configs don't have PHYs (XAUI etc), so don't complain about + * failed init due to -ENODEV. + */ + if (ret && ret != -ENODEV) + dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret); + netif_start_queue(dev); netif_poll_enable(dev); - ret = request_irq(mac->dma_pdev->irq + mac->dma_txch, - &pasemi_mac_tx_intr, IRQF_DISABLED, + /* Interrupts are a bit different for our DMA controller: While + * it's got one a regular PCI device header, the interrupt there + * is really the base of the range it's using. Each tx and rx + * channel has it's own interrupt source. + */ + + base_irq = virq_to_hw(mac->dma_pdev->irq); + + mac->tx_irq = irq_create_mapping(NULL, base_irq + mac->dma_txch); + mac->rx_irq = irq_create_mapping(NULL, base_irq + 20 + mac->dma_txch); + + ret = request_irq(mac->tx_irq, &pasemi_mac_tx_intr, IRQF_DISABLED, mac->tx->irq_name, dev); if (ret) { dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", - mac->dma_pdev->irq + mac->dma_txch, ret); + base_irq + mac->dma_txch, ret); goto out_tx_int; } - ret = request_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, - &pasemi_mac_rx_intr, IRQF_DISABLED, + ret = request_irq(mac->rx_irq, &pasemi_mac_rx_intr, IRQF_DISABLED, mac->rx->irq_name, dev); if (ret) { dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", - mac->dma_pdev->irq + 20 + mac->dma_rxch, ret); + base_irq + 20 + mac->dma_rxch, ret); goto out_rx_int; } + if (mac->phydev) + phy_start(mac->phydev); + return 0; out_rx_int: - free_irq(mac->dma_pdev->irq + mac->dma_txch, dev); + free_irq(mac->tx_irq, dev); out_tx_int: netif_poll_disable(dev); netif_stop_queue(dev); @@ -639,6 +854,11 @@ static int pasemi_mac_close(struct net_device *dev) unsigned int stat; int retries; + if (mac->phydev) { + phy_stop(mac->phydev); + phy_disconnect(mac->phydev); + } + netif_stop_queue(dev); /* Clean out any pending buffers */ @@ -660,40 +880,37 @@ static int pasemi_mac_close(struct net_device *dev) pci_read_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), &stat); - if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) + if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) break; cond_resched(); } - if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) { + if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n"); - } for (retries = 0; retries < MAX_RETRIES; retries++) { pci_read_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), &stat); - if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT) + if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) break; cond_resched(); } - if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) { + if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT) dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n"); - } for (retries = 0; retries < MAX_RETRIES; retries++) { pci_read_config_dword(mac->dma_pdev, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), &stat); - if (stat & PAS_DMA_RXINT_RCMDSTA_ACT) + if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) break; cond_resched(); } - if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) { + if (stat & PAS_DMA_RXINT_RCMDSTA_ACT) dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n"); - } /* Then, disable the channel. This must be done separately from * stopping, since you can't disable when active. @@ -706,8 +923,8 @@ static int pasemi_mac_close(struct net_device *dev) pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); - free_irq(mac->dma_pdev->irq + mac->dma_txch, dev); - free_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, dev); + free_irq(mac->tx_irq, dev); + free_irq(mac->rx_irq, dev); /* Free resources */ pasemi_mac_free_rx_resources(dev); @@ -802,6 +1019,7 @@ static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev) return &mac->stats; } + static void pasemi_mac_set_rx_mode(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); @@ -826,18 +1044,17 @@ static int pasemi_mac_poll(struct net_device *dev, int *budget) pkts = pasemi_mac_clean_rx(mac, limit); + dev->quota -= pkts; + *budget -= pkts; + if (pkts < limit) { /* all done, no more packets present */ netif_rx_complete(dev); - /* re-enable receive interrupts */ - pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, - PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000)); + pasemi_mac_restart_rx_intr(mac); return 0; } else { /* used up our quantum, so reschedule */ - dev->quota -= pkts; - *budget -= pkts; return 1; } } @@ -937,6 +1154,11 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mac->rx_status = &dma_status->rx_sta[mac->dma_rxch]; mac->tx_status = &dma_status->tx_sta[mac->dma_txch]; + mac->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); + + /* Enable most messages by default */ + mac->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; + err = register_netdev(dev); if (err) { @@ -1011,9 +1233,5 @@ int pasemi_mac_init_module(void) return pci_register_driver(&pasemi_mac_driver); } -MODULE_LICENSE("GPL"); -MODULE_AUTHOR ("Olof Johansson "); -MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); - module_init(pasemi_mac_init_module); module_exit(pasemi_mac_cleanup_module); diff --git a/trunk/drivers/net/pasemi_mac.h b/trunk/drivers/net/pasemi_mac.h index c3e37e46a18a..8bc0cea8b145 100644 --- a/trunk/drivers/net/pasemi_mac.h +++ b/trunk/drivers/net/pasemi_mac.h @@ -24,6 +24,7 @@ #include #include #include +#include struct pasemi_mac_txring { spinlock_t lock; @@ -54,6 +55,7 @@ struct pasemi_mac { struct pci_dev *pdev; struct pci_dev *dma_pdev; struct pci_dev *iob_pdev; + struct phy_device *phydev; struct net_device_stats stats; /* Pointer to the cacheable per-channel status registers */ @@ -73,6 +75,14 @@ struct pasemi_mac { struct pasemi_mac_txring *tx; struct pasemi_mac_rxring *rx; + unsigned long tx_irq; + unsigned long rx_irq; + int link; + int speed; + int duplex; + + unsigned int msg_enable; + char phy_id[BUS_ID_SIZE]; }; /* Software status descriptor (desc_info) */ @@ -193,11 +203,15 @@ enum { #define PAS_DMA_RXINT_RCMDSTA(i) (0x200+(i)*_PAS_DMA_RXINT_STRIDE) #define PAS_DMA_RXINT_RCMDSTA_EN 0x00000001 #define PAS_DMA_RXINT_RCMDSTA_ST 0x00000002 -#define PAS_DMA_RXINT_RCMDSTA_OO 0x00000100 -#define PAS_DMA_RXINT_RCMDSTA_BP 0x00000200 -#define PAS_DMA_RXINT_RCMDSTA_DR 0x00000400 +#define PAS_DMA_RXINT_RCMDSTA_MBT 0x00000008 +#define PAS_DMA_RXINT_RCMDSTA_MDR 0x00000010 +#define PAS_DMA_RXINT_RCMDSTA_MOO 0x00000020 +#define PAS_DMA_RXINT_RCMDSTA_MBP 0x00000040 #define PAS_DMA_RXINT_RCMDSTA_BT 0x00000800 -#define PAS_DMA_RXINT_RCMDSTA_TB 0x00001000 +#define PAS_DMA_RXINT_RCMDSTA_DR 0x00001000 +#define PAS_DMA_RXINT_RCMDSTA_OO 0x00002000 +#define PAS_DMA_RXINT_RCMDSTA_BP 0x00004000 +#define PAS_DMA_RXINT_RCMDSTA_TB 0x00008000 #define PAS_DMA_RXINT_RCMDSTA_ACT 0x00010000 #define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000 #define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17 @@ -297,6 +311,7 @@ enum { #define PAS_STATUS_DCNT_S 16 #define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull #define PAS_STATUS_BPCNT_S 32 +#define PAS_STATUS_CAUSE_M 0xf000000000000000ull #define PAS_STATUS_TIMER 0x1000000000000000ull #define PAS_STATUS_ERROR 0x2000000000000000ull #define PAS_STATUS_SOFT 0x4000000000000000ull diff --git a/trunk/drivers/net/pcmcia/xirc2ps_cs.c b/trunk/drivers/net/pcmcia/xirc2ps_cs.c index 809ec440b8eb..258d6f396186 100644 --- a/trunk/drivers/net/pcmcia/xirc2ps_cs.c +++ b/trunk/drivers/net/pcmcia/xirc2ps_cs.c @@ -1420,7 +1420,7 @@ set_addresses(struct net_device *dev) kio_addr_t ioaddr = dev->base_addr; local_info_t *lp = netdev_priv(dev); struct dev_mc_list *dmi = dev->mc_list; - char *addr; + unsigned char *addr; int i,j,k,n; SelectPage(k=0x50); @@ -1429,6 +1429,9 @@ set_addresses(struct net_device *dev) if (++n > 9) break; i = 0; + if (n > 1 && n <= dev->mc_count && dmi) { + dmi = dmi->next; + } } if (j > 15) { j = 8; @@ -1436,10 +1439,9 @@ set_addresses(struct net_device *dev) SelectPage(k); } - if (n && n <= dev->mc_count && dmi) { + if (n && n <= dev->mc_count && dmi) addr = dmi->dmi_addr; - dmi = dmi->next; - } else + else addr = dev->dev_addr; if (lp->mohawk) @@ -1465,10 +1467,10 @@ set_multicast_list(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* snoop */ PutByte(XIRCREG42_SWC1, 0x06); /* set MPE and PME */ } else if (dev->mc_count > 9 || (dev->flags & IFF_ALLMULTI)) { - PutByte(XIRCREG42_SWC1, 0x06); /* set MPE */ + PutByte(XIRCREG42_SWC1, 0x02); /* set MPE */ } else if (dev->mc_count) { /* the chip can filter 9 addresses perfectly */ - PutByte(XIRCREG42_SWC1, 0x00); + PutByte(XIRCREG42_SWC1, 0x01); SelectPage(0x40); PutByte(XIRCREG40_CMD0, Offline); set_addresses(dev); diff --git a/trunk/drivers/net/ppp_generic.c b/trunk/drivers/net/ppp_generic.c index 6d596ca50cfd..541168713f1f 100644 --- a/trunk/drivers/net/ppp_generic.c +++ b/trunk/drivers/net/ppp_generic.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/net/skge.c b/trunk/drivers/net/skge.c index 21afe108d3cb..b07da1054add 100644 --- a/trunk/drivers/net/skge.c +++ b/trunk/drivers/net/skge.c @@ -135,10 +135,13 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs, /* Wake on Lan only supported on Yukon chips with rev 1 or above */ static u32 wol_supported(const struct skge_hw *hw) { - if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0) - return WAKE_MAGIC | WAKE_PHY; - else + if (hw->chip_id == CHIP_ID_GENESIS) return 0; + + if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0) + return 0; + + return WAKE_MAGIC | WAKE_PHY; } static u32 pci_wake_enabled(struct pci_dev *dev) diff --git a/trunk/drivers/net/sky2.c b/trunk/drivers/net/sky2.c index 238c2ca34da6..a307310f13f5 100644 --- a/trunk/drivers/net/sky2.c +++ b/trunk/drivers/net/sky2.c @@ -124,10 +124,7 @@ static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, /* 88E8053 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, /* 88E8055 */ -#ifdef broken - /* This device causes data corruption problems that are not resolved */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, /* 88E8056 */ -#endif { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */ @@ -3581,10 +3578,21 @@ static int __devinit sky2_probe(struct pci_dev *pdev, goto err_out; } + /* Some Gigabyte motherboards have 88e8056 but cause problems + * There is some unresolved hardware related problem that causes + * descriptor errors and receive data corruption. + */ + if (pdev->vendor == PCI_VENDOR_ID_MARVELL && + pdev->device == 0x4364 && pdev->subsystem_vendor == 0x1458) { + dev_err(&pdev->dev, + "88E8056 on Gigabyte motherboards not supported\n"); + goto err_out_disable; + } + err = pci_request_regions(pdev, DRV_NAME); if (err) { dev_err(&pdev->dev, "cannot obtain PCI resources\n"); - goto err_out; + goto err_out_disable; } pci_set_master(pdev); @@ -3721,6 +3729,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, kfree(hw); err_out_free_regions: pci_release_regions(pdev); +err_out_disable: pci_disable_device(pdev); err_out: return err; diff --git a/trunk/drivers/net/smc91x.h b/trunk/drivers/net/smc91x.h index d2767e6584a9..111f23d05764 100644 --- a/trunk/drivers/net/smc91x.h +++ b/trunk/drivers/net/smc91x.h @@ -55,6 +55,53 @@ #define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) #define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) +#elif defined(CONFIG_BFIN) + +#define SMC_IRQ_FLAGS IRQF_TRIGGER_HIGH + +# if defined (CONFIG_BFIN561_EZKIT) +#define SMC_CAN_USE_8BIT 0 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 +#define SMC_IO_SHIFT 0 +#define SMC_NOWAIT 1 +#define SMC_USE_BFIN_DMA 0 + + +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_outsl(a, r, p, l) outsl((unsigned long *)((a) + (r)), p, l) +#define SMC_insl(a, r, p, l) insl ((unsigned long *)((a) + (r)), p, l) +# else +#define SMC_CAN_USE_8BIT 0 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 0 +#define SMC_IO_SHIFT 0 +#define SMC_NOWAIT 1 +#define SMC_USE_BFIN_DMA 0 + + +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_outsw(a, r, p, l) outsw((unsigned long *)((a) + (r)), p, l) +#define SMC_insw(a, r, p, l) insw ((unsigned long *)((a) + (r)), p, l) +# endif +/* check if the mac in reg is valid */ +#define SMC_GET_MAC_ADDR(addr) \ + do { \ + unsigned int __v; \ + __v = SMC_inw(ioaddr, ADDR0_REG); \ + addr[0] = __v; addr[1] = __v >> 8; \ + __v = SMC_inw(ioaddr, ADDR1_REG); \ + addr[2] = __v; addr[3] = __v >> 8; \ + __v = SMC_inw(ioaddr, ADDR2_REG); \ + addr[4] = __v; addr[5] = __v >> 8; \ + if (*(u32 *)(&addr[0]) == 0xFFFFFFFF) { \ + random_ether_addr(addr); \ + } \ + } while (0) #elif defined(CONFIG_REDWOOD_5) || defined(CONFIG_REDWOOD_6) /* We can only do 16-bit reads and writes in the static memory space. */ @@ -232,6 +279,40 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_insw(a, r, p, l) insw((a) + (r), p, l) #define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) +#elif defined(CONFIG_SUPERH) + +#if defined(CONFIG_SH_7780_SOLUTION_ENGINE) || defined(CONFIG_SH_7722_SOLUTION_ENGINE) +#define SMC_CAN_USE_8BIT 0 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 0 +#define SMC_IO_SHIFT 0 +#define SMC_NOWAIT 1 + +#define SMC_inb(a, r) (inw((a) + ((r)&~1)) >> (8*(r%2)))&0xff +#define SMC_inw(a, r) inw((a) + (r)) +#define SMC_outb(v, a, r) outw(((inw((a)+((r)&~1))*(0xff<<8*(r%2)))) | ((v)<<(8*(r&2)))), (a) + ((r)&~1)) + +#define SMC_outw(v, a, r) outw(v, (a) + (r)) +#define SMC_insw(a, r, p, l) insw((a) + (r), p, l) +#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) + +#else /* BOARDS */ + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 + +#define SMC_inb(a, r) inb((a) + (r)) +#define SMC_inw(a, r) inw((a) + (r)) +#define SMC_outb(v, a, r) outb(v, (a) + (r)) +#define SMC_outw(v, a, r) outw(v, (a) + (r)) +#define SMC_insw(a, r, p, l) insw((a) + (r), p, l) +#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) + +#endif /* BOARDS */ + +#define set_irq_type(irq, type) do {} while (0) + #elif defined(CONFIG_M32R) #define SMC_CAN_USE_8BIT 0 diff --git a/trunk/drivers/net/spider_net.c b/trunk/drivers/net/spider_net.c index 230da14b1b68..c15e97253ede 100644 --- a/trunk/drivers/net/spider_net.c +++ b/trunk/drivers/net/spider_net.c @@ -1830,7 +1830,7 @@ spider_net_init_firmware(struct spider_net_card *card) if (!dn) goto out_err; - fw_prop = get_property(dn, "firmware", &fw_size); + fw_prop = of_get_property(dn, "firmware", &fw_size); if (!fw_prop) goto out_err; @@ -2236,7 +2236,7 @@ spider_net_setup_netdev(struct spider_net_card *card) if (!dn) return -EIO; - mac = get_property(dn, "local-mac-address", NULL); + mac = of_get_property(dn, "local-mac-address", NULL); if (!mac) return -EIO; memcpy(addr.sa_data, mac, ETH_ALEN); diff --git a/trunk/drivers/net/sungem.c b/trunk/drivers/net/sungem.c index 5da73212ac91..432803855034 100644 --- a/trunk/drivers/net/sungem.c +++ b/trunk/drivers/net/sungem.c @@ -2903,7 +2903,7 @@ static int __devinit gem_get_device_address(struct gem *gp) struct net_device *dev = gp->dev; const unsigned char *addr; - addr = get_property(gp->of_node, "local-mac-address", NULL); + addr = of_get_property(gp->of_node, "local-mac-address", NULL); if (addr == NULL) { #ifdef CONFIG_SPARC addr = idprom->id_ethaddr; diff --git a/trunk/drivers/net/sungem_phy.c b/trunk/drivers/net/sungem_phy.c index 56a110ca5e6f..61843fd57525 100644 --- a/trunk/drivers/net/sungem_phy.c +++ b/trunk/drivers/net/sungem_phy.c @@ -451,7 +451,7 @@ static int bcm5421_init(struct mii_phy* phy) if (phy->platform_data) { struct device_node *np = of_get_parent(phy->platform_data); int can_low_power = 1; - if (np == NULL || get_property(np, "no-autolowpower", NULL)) + if (np == NULL || of_get_property(np, "no-autolowpower", NULL)) can_low_power = 0; if (can_low_power) { /* Enable automatic low-power */ diff --git a/trunk/drivers/net/tc35815.c b/trunk/drivers/net/tc35815.c index f1e2dfc795a2..463d600ed83d 100644 --- a/trunk/drivers/net/tc35815.c +++ b/trunk/drivers/net/tc35815.c @@ -540,7 +540,6 @@ static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev, skb = dev_alloc_skb(RX_BUF_SIZE); if (!skb) return NULL; - skb->dev = dev; *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(*dma_handle)) { diff --git a/trunk/drivers/net/tg3.c b/trunk/drivers/net/tg3.c index 59d6e74a4a5f..e5e901ecd808 100644 --- a/trunk/drivers/net/tg3.c +++ b/trunk/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.75" -#define DRV_MODULE_RELDATE "March 23, 2007" +#define DRV_MODULE_VERSION "3.76" +#define DRV_MODULE_RELDATE "May 5, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -3019,6 +3019,16 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) } } + if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) { + u32 val = tr32(PCIE_PWR_MGMT_THRESH); + if (!netif_carrier_ok(tp->dev)) + val = (val & ~PCIE_PWR_MGMT_L1_THRESH_MSK) | + tp->pwrmgmt_thresh; + else + val |= PCIE_PWR_MGMT_L1_THRESH_MSK; + tw32(PCIE_PWR_MGMT_THRESH, val); + } + return err; } @@ -3580,8 +3590,12 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) * Writing non-zero to intr-mbox-0 additional tells the * NIC to stop sending us irqs, engaging "in-intr-handler" * event coalescing. + * + * Flush the mailbox to de-assert the IRQ immediately to prevent + * spurious interrupts. The flush impacts performance but + * excessive spurious interrupts can be worse in some cases. */ - tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (tg3_irq_sync(tp)) goto out; sblk->status &= ~SD_STATUS_UPDATED; @@ -3625,8 +3639,12 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * writing non-zero to intr-mbox-0 additional tells the * NIC to stop sending us irqs, engaging "in-intr-handler" * event coalescing. + * + * Flush the mailbox to de-assert the IRQ immediately to prevent + * spurious interrupts. The flush impacts performance but + * excessive spurious interrupts can be worse in some cases. */ - tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (tg3_irq_sync(tp)) goto out; if (netif_rx_schedule_prep(dev)) { @@ -10004,6 +10022,8 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; tp->tg3_flags2 |= TG3_FLG2_IS_NIC; } + if (tr32(VCPU_CFGSHDW) & VCPU_CFGSHDW_ASPM_DBNC) + tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; return; } @@ -10131,6 +10151,14 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) /* bootcode if bit 18 is set */ if (cfg2 & (1 << 18)) tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS; + + if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + u32 cfg3; + + tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3); + if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE) + tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; + } } } @@ -10998,6 +11026,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE; + if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) + tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) & + PCIE_PWR_MGMT_L1_THRESH_MSK; + return err; } diff --git a/trunk/drivers/net/tg3.h b/trunk/drivers/net/tg3.h index dcdfc084966c..4d334cf5a243 100644 --- a/trunk/drivers/net/tg3.h +++ b/trunk/drivers/net/tg3.h @@ -1150,6 +1150,9 @@ #define VCPU_STATUS_INIT_DONE 0x04000000 #define VCPU_STATUS_DRV_RESET 0x08000000 +#define VCPU_CFGSHDW 0x00005104 +#define VCPU_CFGSHDW_ASPM_DBNC 0x00001000 + /* Mailboxes */ #define GRCMBOX_BASE 0x00005600 #define GRCMBOX_INTERRUPT_0 0x00005800 /* 64-bit */ @@ -1507,6 +1510,8 @@ #define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000 #define PCIE_TRANS_CFG_LOM 0x00000020 +#define PCIE_PWR_MGMT_THRESH 0x00007d28 +#define PCIE_PWR_MGMT_L1_THRESH_MSK 0x0000ff00 #define TG3_EEPROM_MAGIC 0x669955aa #define TG3_EEPROM_MAGIC_FW 0xa5000000 @@ -1593,6 +1598,9 @@ #define SHASTA_EXT_LED_MAC 0x00010000 #define SHASTA_EXT_LED_COMBO 0x00018000 +#define NIC_SRAM_DATA_CFG_3 0x00000d3c +#define NIC_SRAM_ASPM_DEBOUNCE 0x00000002 + #define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000 #define NIC_SRAM_DMA_DESC_POOL_BASE 0x00002000 @@ -2200,6 +2208,7 @@ struct tg3 { #define TG3_FLAG_USE_LINKCHG_REG 0x00000008 #define TG3_FLAG_USE_MI_INTERRUPT 0x00000010 #define TG3_FLAG_ENABLE_ASF 0x00000020 +#define TG3_FLAG_ASPM_WORKAROUND 0x00000040 #define TG3_FLAG_POLL_SERDES 0x00000080 #define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100 #define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200 @@ -2288,6 +2297,7 @@ struct tg3 { u32 grc_local_ctrl; u32 dma_rwctrl; u32 coalesce_mode; + u32 pwrmgmt_thresh; /* PCI block */ u16 pci_chip_rev_id; diff --git a/trunk/drivers/net/tsi108_eth.c b/trunk/drivers/net/tsi108_eth.c index 0bfc2c9c1c08..1aabc91f6458 100644 --- a/trunk/drivers/net/tsi108_eth.c +++ b/trunk/drivers/net/tsi108_eth.c @@ -82,6 +82,7 @@ struct tsi108_prv_data { unsigned int phy; /* Index of PHY for this interface */ unsigned int irq_num; unsigned int id; + unsigned int phy_type; struct timer_list timer;/* Timer that triggers the check phy function */ unsigned int rxtail; /* Next entry in rxring to read */ @@ -1256,11 +1257,11 @@ static void tsi108_init_phy(struct net_device *dev) if (i == 0) printk(KERN_ERR "%s function time out \n", __FUNCTION__); -#if (TSI108_PHY_TYPE == PHY_BCM54XX) /* Broadcom BCM54xx PHY */ - tsi108_write_mii(data, 0x09, 0x0300); - tsi108_write_mii(data, 0x10, 0x1020); - tsi108_write_mii(data, 0x1c, 0x8c00); -#endif + if (data->phy_type == TSI108_PHY_BCM54XX) { + tsi108_write_mii(data, 0x09, 0x0300); + tsi108_write_mii(data, 0x10, 0x1020); + tsi108_write_mii(data, 0x1c, 0x8c00); + } tsi108_write_mii(data, MII_BMCR, @@ -1587,6 +1588,7 @@ tsi108_init_one(struct platform_device *pdev) data->mii_if.supports_gmii = mii_check_gmii_support(&data->mii_if); data->phy = einfo->phy; + data->phy_type = einfo->phy_type; data->irq_num = einfo->irq_num; data->id = pdev->id; dev->open = tsi108_open; diff --git a/trunk/drivers/net/tsi108_eth.h b/trunk/drivers/net/tsi108_eth.h index 77a769df228a..5a77ae6c5f36 100644 --- a/trunk/drivers/net/tsi108_eth.h +++ b/trunk/drivers/net/tsi108_eth.h @@ -42,15 +42,6 @@ #define TSI_READ_PHY(offset) \ in_be32((data->phyregs + (offset))) -/* - * PHY Configuration Options - * - * NOTE: Enable set of definitions corresponding to your board type - */ -#define PHY_MV88E 1 /* Marvel 88Exxxx PHY */ -#define PHY_BCM54XX 2 /* Broardcom BCM54xx PHY */ -#define TSI108_PHY_TYPE PHY_MV88E - /* * TSI108 GIGE port registers */ diff --git a/trunk/drivers/net/ucc_geth.c b/trunk/drivers/net/ucc_geth.c index 16b9acdabbe8..d7aff8189377 100644 --- a/trunk/drivers/net/ucc_geth.c +++ b/trunk/drivers/net/ucc_geth.c @@ -3787,7 +3787,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ugeth_vdbg("%s: IN", __FUNCTION__); - prop = get_property(np, "device-id", NULL); + prop = of_get_property(np, "device-id", NULL); ucc_num = *prop - 1; if ((ucc_num < 0) || (ucc_num > 7)) return -ENODEV; @@ -3795,9 +3795,9 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ug_info = &ugeth_info[ucc_num]; ug_info->uf_info.ucc_num = ucc_num; - prop = get_property(np, "rx-clock", NULL); + prop = of_get_property(np, "rx-clock", NULL); ug_info->uf_info.rx_clock = *prop; - prop = get_property(np, "tx-clock", NULL); + prop = of_get_property(np, "tx-clock", NULL); ug_info->uf_info.tx_clock = *prop; err = of_address_to_resource(np, 0, &res); if (err) @@ -3806,23 +3806,23 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ug_info->uf_info.regs = res.start; ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); - ph = get_property(np, "phy-handle", NULL); + ph = of_get_property(np, "phy-handle", NULL); phy = of_find_node_by_phandle(*ph); if (phy == NULL) return -ENODEV; /* set the PHY address */ - prop = get_property(phy, "reg", NULL); + prop = of_get_property(phy, "reg", NULL); if (prop == NULL) return -1; ug_info->phy_address = *prop; /* get the phy interface type, or default to MII */ - prop = get_property(np, "interface-type", NULL); + prop = of_get_property(np, "interface-type", NULL); if (!prop) { /* handle interface property present in old trees */ - prop = get_property(phy, "interface", NULL); + prop = of_get_property(phy, "interface", NULL); if (prop != NULL) phy_interface = enet_to_phy_interface[*prop]; else @@ -3832,10 +3832,10 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma } /* get speed, or derive from interface */ - prop = get_property(np, "max-speed", NULL); + prop = of_get_property(np, "max-speed", NULL); if (!prop) { /* handle interface property present in old trees */ - prop = get_property(phy, "interface", NULL); + prop = of_get_property(phy, "interface", NULL); if (prop != NULL) max_speed = enet_to_speed[*prop]; } else { diff --git a/trunk/drivers/net/ucc_geth_mii.c b/trunk/drivers/net/ucc_geth_mii.c index 73b5a538e8f4..27a1ef3b7b06 100644 --- a/trunk/drivers/net/ucc_geth_mii.c +++ b/trunk/drivers/net/ucc_geth_mii.c @@ -172,7 +172,7 @@ static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *ma while ((child = of_get_next_child(np, child)) != NULL) { int irq = irq_of_parse_and_map(child, 0); if (irq != NO_IRQ) { - const u32 *id = get_property(child, "reg", NULL); + const u32 *id = of_get_property(child, "reg", NULL); new_bus->irq[*id] = irq; } } @@ -203,7 +203,7 @@ static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *ma if ((res.start >= tempres.start) && (res.end <= tempres.end)) { /* set this UCC to be the MII master */ - const u32 *id = get_property(tempnp, "device-id", NULL); + const u32 *id = of_get_property(tempnp, "device-id", NULL); if (id == NULL) goto bus_register_fail; diff --git a/trunk/drivers/net/wan/cosa.c b/trunk/drivers/net/wan/cosa.c index 23464735fa88..9ef49ce148b2 100644 --- a/trunk/drivers/net/wan/cosa.c +++ b/trunk/drivers/net/wan/cosa.c @@ -90,7 +90,6 @@ #include #include #include -#include #include #undef COSA_SLOW_IO /* for testing purposes only */ diff --git a/trunk/drivers/net/wireless/Kconfig b/trunk/drivers/net/wireless/Kconfig index c4b3dc291a5a..e273347dc606 100644 --- a/trunk/drivers/net/wireless/Kconfig +++ b/trunk/drivers/net/wireless/Kconfig @@ -153,8 +153,8 @@ config IPW2100 If you want to compile the driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called ipw2100.ko. + say M here and read . + The module will be called ipw2100.ko. config IPW2100_MONITOR bool "Enable promiscuous mode" @@ -208,8 +208,8 @@ config IPW2200 If you want to compile the driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called ipw2200.ko. + say M here and read . + The module will be called ipw2200.ko. config IPW2200_MONITOR bool "Enable promiscuous mode" @@ -267,7 +267,7 @@ config IPW2200_DEBUG config LIBERTAS_USB tristate "Marvell Libertas 8388 802.11a/b/g cards" - depends on NET_RADIO && USB + depends on USB && WLAN_80211 select FW_LOADER ---help--- A driver for Marvell Libertas 8388 USB devices. @@ -517,8 +517,8 @@ config PRISM54 If you want to compile the driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called prism54.ko. + say M here and read . + The module will be called prism54.ko. config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" diff --git a/trunk/drivers/net/wireless/airo.c b/trunk/drivers/net/wireless/airo.c index f21bbafcb728..2d3a180dada0 100644 --- a/trunk/drivers/net/wireless/airo.c +++ b/trunk/drivers/net/wireless/airo.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/net/wireless/hostap/hostap_ioctl.c b/trunk/drivers/net/wireless/hostap/hostap_ioctl.c index cb08bc5db2bd..cdea7f71b9eb 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/trunk/drivers/net/wireless/hostap/hostap_ioctl.c @@ -1,7 +1,6 @@ /* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */ #include -#include #include #include diff --git a/trunk/drivers/parisc/lba_pci.c b/trunk/drivers/parisc/lba_pci.c index 21c4c299b3d6..5b86ee5c1eeb 100644 --- a/trunk/drivers/parisc/lba_pci.c +++ b/trunk/drivers/parisc/lba_pci.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/parport/parport_cs.c b/trunk/drivers/parport/parport_cs.c index 316c06f4423c..8b7d84eca05d 100644 --- a/trunk/drivers/parport/parport_cs.c +++ b/trunk/drivers/parport/parport_cs.c @@ -201,7 +201,7 @@ static int parport_config(struct pcmcia_device *link) p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2, link->irq.AssignedIRQ, PARPORT_DMA_NONE, - NULL); + &link->dev); if (p == NULL) { printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at " "0x%3x, irq %u failed\n", link->io.BasePort1, diff --git a/trunk/drivers/parport/parport_mfc3.c b/trunk/drivers/parport/parport_mfc3.c index e5b0a544de40..77726fc49766 100644 --- a/trunk/drivers/parport/parport_mfc3.c +++ b/trunk/drivers/parport/parport_mfc3.c @@ -356,6 +356,7 @@ static int __init parport_mfc3_init(void) if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, IRQF_SHARED, p->name, &pp_mfc3_ops)) goto out_irq; } + p->dev = &z->dev; this_port[pias++] = p; printk(KERN_INFO "%s: Multiface III port using irq\n", p->name); diff --git a/trunk/drivers/parport/parport_pc.c b/trunk/drivers/parport/parport_pc.c index 3de2623afa13..02c0d52c9f76 100644 --- a/trunk/drivers/parport/parport_pc.c +++ b/trunk/drivers/parport/parport_pc.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -620,6 +621,7 @@ static size_t parport_pc_fifo_write_block_dma (struct parport *port, unsigned long dmaflag; size_t left = length; const struct parport_pc_private *priv = port->physport->private_data; + struct device *dev = port->physport->dev; dma_addr_t dma_addr, dma_handle; size_t maxlen = 0x10000; /* max 64k per DMA transfer */ unsigned long start = (unsigned long) buf; @@ -631,8 +633,8 @@ dump_parport_state ("enter fifo_write_block_dma", port); if ((start ^ end) & ~0xffffUL) maxlen = 0x10000 - (start & 0xffff); - dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length, - PCI_DMA_TODEVICE); + dma_addr = dma_handle = dma_map_single(dev, (void *)buf, length, + DMA_TO_DEVICE); } else { /* above 16 MB we use a bounce buffer as ISA-DMA is not possible */ maxlen = PAGE_SIZE; /* sizeof(priv->dma_buf) */ @@ -728,9 +730,9 @@ dump_parport_state ("enter fifo_write_block_dma", port); /* Turn off DMA mode */ frob_econtrol (port, 1<<3, 0); - + if (dma_handle) - pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE); + dma_unmap_single(dev, dma_handle, length, DMA_TO_DEVICE); dump_parport_state ("leave fifo_write_block_dma", port); return length - left; @@ -2146,7 +2148,7 @@ static DEFINE_SPINLOCK(ports_lock); struct parport *parport_pc_probe_port (unsigned long int base, unsigned long int base_hi, int irq, int dma, - struct pci_dev *dev) + struct device *dev) { struct parport_pc_private *priv; struct parport_operations *ops; @@ -2155,6 +2157,17 @@ struct parport *parport_pc_probe_port (unsigned long int base, struct resource *base_res; struct resource *ECR_res = NULL; struct resource *EPP_res = NULL; + struct platform_device *pdev = NULL; + + if (!dev) { + /* We need a physical device to attach to, but none was + * provided. Create our own. */ + pdev = platform_device_register_simple("parport_pc", + base, NULL, 0); + if (IS_ERR(pdev)) + return NULL; + dev = &pdev->dev; + } ops = kmalloc(sizeof (struct parport_operations), GFP_KERNEL); if (!ops) @@ -2180,9 +2193,10 @@ struct parport *parport_pc_probe_port (unsigned long int base, priv->fifo_depth = 0; priv->dma_buf = NULL; priv->dma_handle = 0; - priv->dev = dev; INIT_LIST_HEAD(&priv->list); priv->port = p; + + p->dev = dev; p->base_hi = base_hi; p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT; p->private_data = priv; @@ -2305,9 +2319,10 @@ struct parport *parport_pc_probe_port (unsigned long int base, p->dma = PARPORT_DMA_NONE; } else { priv->dma_buf = - pci_alloc_consistent(priv->dev, + dma_alloc_coherent(dev, PAGE_SIZE, - &priv->dma_handle); + &priv->dma_handle, + GFP_KERNEL); if (! priv->dma_buf) { printk (KERN_WARNING "%s: " "cannot get buffer for DMA, " @@ -2356,6 +2371,8 @@ struct parport *parport_pc_probe_port (unsigned long int base, out2: kfree (ops); out1: + if (pdev) + platform_device_unregister(pdev); return NULL; } @@ -2383,7 +2400,7 @@ void parport_pc_unregister_port (struct parport *p) release_region(p->base_hi, 3); #if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA) if (priv->dma_buf) - pci_free_consistent(priv->dev, PAGE_SIZE, + dma_free_coherent(p->physport->dev, PAGE_SIZE, priv->dma_buf, priv->dma_handle); #endif @@ -2489,7 +2506,7 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq, */ release_resource(base_res); if (parport_pc_probe_port (ite8872_lpt, ite8872_lpthi, - irq, PARPORT_DMA_NONE, NULL)) { + irq, PARPORT_DMA_NONE, &pdev->dev)) { printk (KERN_INFO "parport_pc: ITE 8872 parallel port: io=0x%X", ite8872_lpt); @@ -2672,7 +2689,7 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq, } /* finally, do the probe with values obtained */ - if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) { + if (parport_pc_probe_port (port1, port2, irq, dma, &pdev->dev)) { printk (KERN_INFO "parport_pc: VIA parallel port: io=0x%X", port1); if (irq != PARPORT_IRQ_NONE) @@ -2970,7 +2987,7 @@ static int parport_pc_pci_probe (struct pci_dev *dev, parport_pc_pci_tbl[i + last_sio].device, io_lo, io_hi); data->ports[count] = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, - PARPORT_DMA_NONE, dev); + PARPORT_DMA_NONE, &dev->dev); if (data->ports[count]) count++; } @@ -3077,8 +3094,8 @@ static int parport_pc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id } else dma = PARPORT_DMA_NONE; - printk(KERN_INFO "parport: PnPBIOS parport detected.\n"); - if (!(pdata = parport_pc_probe_port (io_lo, io_hi, irq, dma, NULL))) + dev_info(&dev->dev, "reported by %s\n", dev->protocol->name); + if (!(pdata = parport_pc_probe_port (io_lo, io_hi, irq, dma, &dev->dev))) return -ENODEV; pnp_set_drvdata(dev,pdata); @@ -3103,6 +3120,21 @@ static struct pnp_driver parport_pc_pnp_driver = { }; +static int __devinit parport_pc_platform_probe(struct platform_device *pdev) +{ + /* Always succeed, the actual probing is done in + * parport_pc_probe_port(). */ + return 0; +} + +static struct platform_driver parport_pc_platform_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "parport_pc", + }, + .probe = parport_pc_platform_probe, +}; + /* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */ static int __devinit __attribute__((unused)) parport_pc_find_isa_ports (int autoirq, int autodma) @@ -3378,9 +3410,15 @@ __setup("parport_init_mode=",parport_init_mode_setup); static int __init parport_pc_init(void) { + int err; + if (parse_parport_params()) return -EINVAL; + err = platform_driver_register(&parport_pc_platform_driver); + if (err) + return err; + if (io[0]) { int i; /* Only probe the ports we were given. */ @@ -3405,6 +3443,7 @@ static void __exit parport_pc_exit(void) pci_unregister_driver (&parport_pc_pci_driver); if (pnp_registered_parport) pnp_unregister_driver (&parport_pc_pnp_driver); + platform_driver_unregister(&parport_pc_platform_driver); spin_lock(&ports_lock); while (!list_empty(&ports_list)) { @@ -3413,6 +3452,9 @@ static void __exit parport_pc_exit(void) priv = list_entry(ports_list.next, struct parport_pc_private, list); port = priv->port; + if (port->dev && port->dev->bus == &platform_bus_type) + platform_device_unregister( + to_platform_device(port->dev)); spin_unlock(&ports_lock); parport_pc_unregister_port(port); spin_lock(&ports_lock); diff --git a/trunk/drivers/parport/parport_serial.c b/trunk/drivers/parport/parport_serial.c index 78c0a269a2ba..90ea3b8b99b0 100644 --- a/trunk/drivers/parport/parport_serial.c +++ b/trunk/drivers/parport/parport_serial.c @@ -305,7 +305,7 @@ static int __devinit parport_register (struct pci_dev *dev, dev_dbg(&dev->dev, "PCI parallel port detected: I/O at " "%#lx(%#lx)\n", io_lo, io_hi); port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, - PARPORT_DMA_NONE, dev); + PARPORT_DMA_NONE, &dev->dev); if (port) { priv->port[priv->num_par++] = port; success = 1; @@ -392,6 +392,7 @@ static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state) static int parport_serial_pci_resume(struct pci_dev *dev) { struct parport_serial_private *priv = pci_get_drvdata(dev); + int err; pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); @@ -399,7 +400,12 @@ static int parport_serial_pci_resume(struct pci_dev *dev) /* * The device may have been disabled. Re-enable it. */ - pci_enable_device(dev); + err = pci_enable_device(dev); + if (err) { + printk(KERN_ERR "parport_serial: %s: error enabling " + "device for resume (%d)\n", pci_name(dev), err); + return err; + } if (priv->serial) pciserial_resume_ports(priv->serial); diff --git a/trunk/drivers/parport/parport_sunbpp.c b/trunk/drivers/parport/parport_sunbpp.c index 400bb90084cf..d27019c2f860 100644 --- a/trunk/drivers/parport/parport_sunbpp.c +++ b/trunk/drivers/parport/parport_sunbpp.c @@ -322,6 +322,7 @@ static int __devinit init_one_port(struct sbus_dev *sdev) goto out_free_ops; p->size = size; + p->dev = &sdev->ofdev.dev; if ((err = request_irq(p->irq, parport_sunbpp_interrupt, IRQF_SHARED, p->name, p)) != 0) { diff --git a/trunk/drivers/parport/share.c b/trunk/drivers/parport/share.c index fd9129e424f9..cd66442acfee 100644 --- a/trunk/drivers/parport/share.c +++ b/trunk/drivers/parport/share.c @@ -365,6 +365,11 @@ void parport_announce_port (struct parport *port) parport_daisy_init(port); #endif + if (!port->dev) + printk(KERN_WARNING "%s: fix this legacy " + "no-device port driver!\n", + port->name); + parport_proc_register(port); mutex_lock(®istration_lock); spin_lock_irq(&parportlist_lock); diff --git a/trunk/drivers/pci/hotplug/acpiphp_core.c b/trunk/drivers/pci/hotplug/acpiphp_core.c index 40c79b03c7ef..fa5c0197d571 100644 --- a/trunk/drivers/pci/hotplug/acpiphp_core.c +++ b/trunk/drivers/pci/hotplug/acpiphp_core.c @@ -40,7 +40,6 @@ #include #include #include -#include #include "acpiphp.h" #define MY_NAME "acpiphp" diff --git a/trunk/drivers/pci/hotplug/acpiphp_glue.c b/trunk/drivers/pci/hotplug/acpiphp_glue.c index fca978fb158e..9ef4e989afc4 100644 --- a/trunk/drivers/pci/hotplug/acpiphp_glue.c +++ b/trunk/drivers/pci/hotplug/acpiphp_glue.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include "../pci.h" diff --git a/trunk/drivers/pci/hotplug/ibmphp_core.c b/trunk/drivers/pci/hotplug/ibmphp_core.c index 59392946c2bd..0316eeaaeb29 100644 --- a/trunk/drivers/pci/hotplug/ibmphp_core.c +++ b/trunk/drivers/pci/hotplug/ibmphp_core.c @@ -34,7 +34,6 @@ #include #include #include -#include #include "../pci.h" #include "../../../arch/i386/pci/pci.h" /* for struct irq_routing_table */ #include "ibmphp.h" diff --git a/trunk/drivers/pci/hotplug/ibmphp_hpc.c b/trunk/drivers/pci/hotplug/ibmphp_hpc.c index f55ac3885cb3..46abaa8c41f1 100644 --- a/trunk/drivers/pci/hotplug/ibmphp_hpc.c +++ b/trunk/drivers/pci/hotplug/ibmphp_hpc.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/pci/hotplug/pci_hotplug_core.c b/trunk/drivers/pci/hotplug/pci_hotplug_core.c index 63f3bd1eecc4..bd433ef6bfc6 100644 --- a/trunk/drivers/pci/hotplug/pci_hotplug_core.c +++ b/trunk/drivers/pci/hotplug/pci_hotplug_core.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/pci/hotplug/rpaphp_core.c b/trunk/drivers/pci/hotplug/rpaphp_core.c index 847936fe327e..458c08ef2654 100644 --- a/trunk/drivers/pci/hotplug/rpaphp_core.c +++ b/trunk/drivers/pci/hotplug/rpaphp_core.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include /* for eeh_add_device() */ #include /* rtas_call */ @@ -170,10 +169,10 @@ static int get_children_props(struct device_node *dn, const int **drc_indexes, { const int *indexes, *names, *types, *domains; - indexes = get_property(dn, "ibm,drc-indexes", NULL); - names = get_property(dn, "ibm,drc-names", NULL); - types = get_property(dn, "ibm,drc-types", NULL); - domains = get_property(dn, "ibm,drc-power-domains", NULL); + indexes = of_get_property(dn, "ibm,drc-indexes", NULL); + names = of_get_property(dn, "ibm,drc-names", NULL); + types = of_get_property(dn, "ibm,drc-types", NULL); + domains = of_get_property(dn, "ibm,drc-power-domains", NULL); if (!indexes || !names || !types || !domains) { /* Slot does not have dynamically-removable children */ @@ -206,7 +205,7 @@ int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, char *name_tmp, *type_tmp; int i, rc; - my_index = get_property(dn, "ibm,my-drc-index", NULL); + my_index = of_get_property(dn, "ibm,my-drc-index", NULL); if (!my_index) { /* Node isn't DLPAR/hotplug capable */ return -EINVAL; diff --git a/trunk/drivers/pci/hotplug/shpchp_ctrl.c b/trunk/drivers/pci/hotplug/shpchp_ctrl.c index 2c94d44279a3..d2fc35598cdd 100644 --- a/trunk/drivers/pci/hotplug/shpchp_ctrl.c +++ b/trunk/drivers/pci/hotplug/shpchp_ctrl.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include "../pci.h" diff --git a/trunk/drivers/pci/msi.c b/trunk/drivers/pci/msi.c index 9e1321d0d5e6..e6740d1a0824 100644 --- a/trunk/drivers/pci/msi.c +++ b/trunk/drivers/pci/msi.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/pci/proc.c b/trunk/drivers/pci/proc.c index ed87aa59f0b1..0425a7b7350d 100644 --- a/trunk/drivers/pci/proc.c +++ b/trunk/drivers/pci/proc.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/pcmcia/at91_cf.c b/trunk/drivers/pcmcia/at91_cf.c index 99baabc23599..948efc775a78 100644 --- a/trunk/drivers/pcmcia/at91_cf.c +++ b/trunk/drivers/pcmcia/at91_cf.c @@ -360,7 +360,6 @@ static struct platform_driver at91_cf_driver = { .name = (char *) driver_name, .owner = THIS_MODULE, }, - .probe = at91_cf_probe, .remove = __exit_p(at91_cf_remove), .suspend = at91_cf_suspend, .resume = at91_cf_resume, @@ -370,7 +369,7 @@ static struct platform_driver at91_cf_driver = { static int __init at91_cf_init(void) { - return platform_driver_register(&at91_cf_driver); + return platform_driver_probe(&at91_cf_driver, at91_cf_probe); } module_init(at91_cf_init); diff --git a/trunk/drivers/pcmcia/ds.c b/trunk/drivers/pcmcia/ds.c index 18e111e12339..143c6efc478a 100644 --- a/trunk/drivers/pcmcia/ds.c +++ b/trunk/drivers/pcmcia/ds.c @@ -234,6 +234,89 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) /*======================================================================*/ +struct pcmcia_dynid { + struct list_head node; + struct pcmcia_device_id id; +}; + +/** + * pcmcia_store_new_id - add a new PCMCIA device ID to this driver and re-probe devices + * @driver: target device driver + * @buf: buffer for scanning device ID data + * @count: input size + * + * Adds a new dynamic PCMCIA device ID to this driver, + * and causes the driver to probe for all devices again. + */ +static ssize_t +pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count) +{ + struct pcmcia_dynid *dynid; + struct pcmcia_driver *pdrv = to_pcmcia_drv(driver); + __u16 match_flags, manf_id, card_id; + __u8 func_id, function, device_no; + __u32 prod_id_hash[4] = {0, 0, 0, 0}; + int fields=0; + int retval = 0; + + fields = sscanf(buf, "%hx %hx %hx %hhx %hhx %hhx %x %x %x %x", + &match_flags, &manf_id, &card_id, &func_id, &function, &device_no, + &prod_id_hash[0], &prod_id_hash[1], &prod_id_hash[2], &prod_id_hash[3]); + if (fields < 6) + return -EINVAL; + + dynid = kzalloc(sizeof(struct pcmcia_dynid), GFP_KERNEL); + if (!dynid) + return -ENOMEM; + + INIT_LIST_HEAD(&dynid->node); + dynid->id.match_flags = match_flags; + dynid->id.manf_id = manf_id; + dynid->id.card_id = card_id; + dynid->id.func_id = func_id; + dynid->id.function = function; + dynid->id.device_no = device_no; + memcpy(dynid->id.prod_id_hash, prod_id_hash, sizeof(__u32) * 4); + + spin_lock(&pdrv->dynids.lock); + list_add_tail(&pdrv->dynids.list, &dynid->node); + spin_unlock(&pdrv->dynids.lock); + + if (get_driver(&pdrv->drv)) { + retval = driver_attach(&pdrv->drv); + put_driver(&pdrv->drv); + } + + if (retval) + return retval; + return count; +} +static DRIVER_ATTR(new_id, S_IWUSR, NULL, pcmcia_store_new_id); + +static void +pcmcia_free_dynids(struct pcmcia_driver *drv) +{ + struct pcmcia_dynid *dynid, *n; + + spin_lock(&drv->dynids.lock); + list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { + list_del(&dynid->node); + kfree(dynid); + } + spin_unlock(&drv->dynids.lock); +} + +static int +pcmcia_create_newid_file(struct pcmcia_driver *drv) +{ + int error = 0; + if (drv->probe != NULL) + error = sysfs_create_file(&drv->drv.kobj, + &driver_attr_new_id.attr); + return error; +} + + /** * pcmcia_register_driver - register a PCMCIA driver with the bus core * @@ -241,6 +324,8 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) */ int pcmcia_register_driver(struct pcmcia_driver *driver) { + int error; + if (!driver) return -EINVAL; @@ -249,10 +334,20 @@ int pcmcia_register_driver(struct pcmcia_driver *driver) /* initialize common fields */ driver->drv.bus = &pcmcia_bus_type; driver->drv.owner = driver->owner; + spin_lock_init(&driver->dynids.lock); + INIT_LIST_HEAD(&driver->dynids.list); ds_dbg(3, "registering driver %s\n", driver->drv.name); - return driver_register(&driver->drv); + error = driver_register(&driver->drv); + if (error < 0) + return error; + + error = pcmcia_create_newid_file(driver); + if (error) + driver_unregister(&driver->drv); + + return error; } EXPORT_SYMBOL(pcmcia_register_driver); @@ -263,6 +358,7 @@ void pcmcia_unregister_driver(struct pcmcia_driver *driver) { ds_dbg(3, "unregistering driver %s\n", driver->drv.name); driver_unregister(&driver->drv); + pcmcia_free_dynids(driver); } EXPORT_SYMBOL(pcmcia_unregister_driver); @@ -927,6 +1023,21 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { struct pcmcia_device * p_dev = to_pcmcia_dev(dev); struct pcmcia_driver * p_drv = to_pcmcia_drv(drv); struct pcmcia_device_id *did = p_drv->id_table; + struct pcmcia_dynid *dynid; + + /* match dynamic devices first */ + spin_lock(&p_drv->dynids.lock); + list_for_each_entry(dynid, &p_drv->dynids.list, node) { + ds_dbg(3, "trying to match %s to %s\n", dev->bus_id, + drv->name); + if (pcmcia_devmatch(p_dev, &dynid->id)) { + ds_dbg(0, "matched %s to %s\n", dev->bus_id, + drv->name); + spin_unlock(&p_drv->dynids.lock); + return 1; + } + } + spin_unlock(&p_drv->dynids.lock); #ifdef CONFIG_PCMCIA_IOCTL /* matching by cardmgr */ diff --git a/trunk/drivers/pcmcia/pxa2xx_mainstone.c b/trunk/drivers/pcmcia/pxa2xx_mainstone.c index fda06941e730..383107ba4bd3 100644 --- a/trunk/drivers/pcmcia/pxa2xx_mainstone.c +++ b/trunk/drivers/pcmcia/pxa2xx_mainstone.c @@ -175,6 +175,7 @@ static int __init mst_pcmcia_init(void) if (!mst_pcmcia_device) return -ENOMEM; + mst_pcmcia_device->dev.uevent_suppress = 0; mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; ret = platform_device_add(mst_pcmcia_device); diff --git a/trunk/drivers/pcmcia/pxa2xx_sharpsl.c b/trunk/drivers/pcmcia/pxa2xx_sharpsl.c index b7b9e149c5b9..a2daa3f531b2 100644 --- a/trunk/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/trunk/drivers/pcmcia/pxa2xx_sharpsl.c @@ -261,6 +261,7 @@ static int __init sharpsl_pcmcia_init(void) if (!sharpsl_pcmcia_device) return -ENOMEM; + sharpsl_pcmcia_device->dev.uevent_suppress = 0; sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev; diff --git a/trunk/drivers/pnp/core.c b/trunk/drivers/pnp/core.c index aec83ec5ea23..3e20b1cc7778 100644 --- a/trunk/drivers/pnp/core.c +++ b/trunk/drivers/pnp/core.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "base.h" @@ -22,6 +23,14 @@ static LIST_HEAD(pnp_protocols); LIST_HEAD(pnp_global); DEFINE_SPINLOCK(pnp_lock); +/* + * ACPI or PNPBIOS should tell us about all platform devices, so we can + * skip some blind probes. ISAPNP typically enumerates only plug-in ISA + * devices, not built-in things like COM ports. + */ +int pnp_platform_devices; +EXPORT_SYMBOL(pnp_platform_devices); + void *pnp_alloc(long size) { void *result; @@ -114,6 +123,8 @@ int __pnp_add_device(struct pnp_dev *dev) int ret; pnp_fixup_device(dev); dev->dev.bus = &pnp_bus_type; + dev->dev.dma_mask = &dev->dma_mask; + dev->dma_mask = dev->dev.coherent_dma_mask = DMA_24BIT_MASK; dev->dev.release = &pnp_release_device; dev->status = PNP_READY; spin_lock(&pnp_lock); diff --git a/trunk/drivers/pnp/pnpacpi/core.c b/trunk/drivers/pnp/pnpacpi/core.c index 62eda5d59024..a00548799e98 100644 --- a/trunk/drivers/pnp/pnpacpi/core.c +++ b/trunk/drivers/pnp/pnpacpi/core.c @@ -3,7 +3,7 @@ * * Copyright (c) 2004 Matthieu Castet * Copyright (c) 2004 Li Shaohua - * + * * 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 @@ -18,7 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + #include #include #include @@ -82,7 +82,7 @@ static void __init pnpidacpi_to_pnpid(char *id, char *str) static int pnpacpi_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res) { acpi_status status; - status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data, + status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data, &dev->res); return ACPI_FAILURE(status) ? -ENODEV : 0; } @@ -112,9 +112,9 @@ static int pnpacpi_set_resources(struct pnp_dev * dev, struct pnp_resource_table static int pnpacpi_disable_resources(struct pnp_dev *dev) { acpi_status status; - + /* acpi_unregister_gsi(pnp_irq(dev, 0)); */ - status = acpi_evaluate_object((acpi_handle)dev->data, + status = acpi_evaluate_object((acpi_handle)dev->data, "_DIS", NULL, NULL); return ACPI_FAILURE(status) ? -ENODEV : 0; } @@ -167,7 +167,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device) strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name)); dev->number = num; - + /* set the initial values for the PnP device */ dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); if (!dev_id) @@ -185,14 +185,14 @@ static int __init pnpacpi_add_device(struct acpi_device *device) } if(dev->capabilities & PNP_CONFIGURABLE) { - status = pnpacpi_parse_resource_option_data(device->handle, + status = pnpacpi_parse_resource_option_data(device->handle, dev); if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", dev_id->id); goto err1; } } - + /* parse compatible ids */ if (device->flags.compatible_ids) { struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; @@ -236,6 +236,42 @@ static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle, return AE_OK; } +static int __init acpi_pnp_match(struct device *dev, void *_pnp) +{ + struct acpi_device *acpi = to_acpi_device(dev); + struct pnp_dev *pnp = _pnp; + + /* true means it matched */ + return acpi->flags.hardware_id + && !acpi_get_physical_device(acpi->handle) + && compare_pnp_id(pnp->id, acpi->pnp.hardware_id); +} + +static int __init acpi_pnp_find_device(struct device *dev, acpi_handle *handle) +{ + struct device *adev; + struct acpi_device *acpi; + + adev = bus_find_device(&acpi_bus_type, NULL, + to_pnp_dev(dev), + acpi_pnp_match); + if (!adev) + return -ENODEV; + + acpi = to_acpi_device(adev); + *handle = acpi->handle; + put_device(adev); + return 0; +} + +/* complete initialization of a PNPACPI device includes having + * pnpdev->dev.archdata.acpi_handle point to its ACPI sibling. + */ +static struct acpi_bus_type __initdata acpi_pnp_bus = { + .bus = &pnp_bus_type, + .find_device = acpi_pnp_find_device, +}; + int pnpacpi_disabled __initdata; static int __init pnpacpi_init(void) { @@ -245,8 +281,11 @@ static int __init pnpacpi_init(void) } pnp_info("PnP ACPI init"); pnp_register_protocol(&pnpacpi_protocol); + register_acpi_bus_type(&acpi_pnp_bus); acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL); pnp_info("PnP ACPI: found %d devices", num); + unregister_acpi_bus_type(&acpi_pnp_bus); + pnp_platform_devices = 1; return 0; } subsys_initcall(pnpacpi_init); diff --git a/trunk/drivers/pnp/pnpbios/core.c b/trunk/drivers/pnp/pnpbios/core.c index 95738dbd5d45..3a201b77b963 100644 --- a/trunk/drivers/pnp/pnpbios/core.c +++ b/trunk/drivers/pnp/pnpbios/core.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -159,9 +160,7 @@ static int pnp_dock_thread(void * unused) { static struct pnp_docking_station_info now; int docked = -1, d = 0; - daemonize("kpnpbiosd"); - allow_signal(SIGKILL); - while(!unloading && !signal_pending(current)) + while (!unloading) { int status; @@ -170,11 +169,8 @@ static int pnp_dock_thread(void * unused) */ msleep_interruptible(2000); - if(signal_pending(current)) { - if (try_to_freeze()) - continue; - break; - } + if (try_to_freeze()) + continue; status = pnp_bios_dock_station_info(&now); @@ -574,6 +570,7 @@ static int __init pnpbios_init(void) /* scan for pnpbios devices */ build_devlist(); + pnp_platform_devices = 1; return 0; } @@ -581,6 +578,7 @@ subsys_initcall(pnpbios_init); static int __init pnpbios_thread_init(void) { + struct task_struct *task; #if defined(CONFIG_PPC_MERGE) if (check_legacy_ioport(PNPBIOS_BASE)) return 0; @@ -589,7 +587,8 @@ static int __init pnpbios_thread_init(void) return 0; #ifdef CONFIG_HOTPLUG init_completion(&unload_sem); - if (kernel_thread(pnp_dock_thread, NULL, CLONE_KERNEL) > 0) + task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd"); + if (!IS_ERR(task)) unloading = 0; #endif return 0; diff --git a/trunk/drivers/pnp/quirks.c b/trunk/drivers/pnp/quirks.c index e97ecefe8584..277df50c89ae 100644 --- a/trunk/drivers/pnp/quirks.c +++ b/trunk/drivers/pnp/quirks.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "base.h" @@ -106,6 +107,34 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) return; } +static void quirk_smc_enable(struct pnp_dev *dev) +{ + unsigned int firbase; + + if (!dev->active || !pnp_port_valid(dev, 1)) + return; + + /* + * On the HP/Compaq nw8240 (and probably other similar machines), + * there is an SMCF010 device with two I/O port regions: + * + * 0x3e8-0x3ef SIR + * 0x100-0x10f FIR + * + * _STA reports the device is enabled, but in fact, the BIOS + * neglects to enable the FIR range. Fortunately, it does fully + * enable the device if we call _SRS. + */ + firbase = pnp_port_start(dev, 1); + if (inb(firbase + 0x7 /* IRCC_MASTER */) == 0xff) { + pnp_err("%s (%s) enabled but not responding, disabling and " + "re-enabling", dev->dev.bus_id, pnp_dev_name(dev)); + pnp_disable_dev(dev); + pnp_activate_dev(dev); + } +} + + /* * PnP Quirks * Cards or devices that need some tweaking due to incomplete resource info @@ -126,6 +155,7 @@ static struct pnp_fixup pnp_fixups[] = { { "CTL0043", quirk_sb16audio_resources }, { "CTL0044", quirk_sb16audio_resources }, { "CTL0045", quirk_sb16audio_resources }, + { "SMCf010", quirk_smc_enable }, { "" } }; diff --git a/trunk/drivers/ps3/vuart.c b/trunk/drivers/ps3/vuart.c index 7d7cab1d91b4..ec2d36a1bc67 100644 --- a/trunk/drivers/ps3/vuart.c +++ b/trunk/drivers/ps3/vuart.c @@ -886,12 +886,12 @@ static int ps3_vuart_probe(struct device *_dev) if (++vuart_bus_priv.use_count == 1) { - result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY, + result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY, (void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq); if (result) { dev_dbg(&dev->core, - "%s:%d: ps3_alloc_vuart_irq failed (%d)\n", + "%s:%d: ps3_vuart_irq_setup failed (%d)\n", __func__, __LINE__, result); result = -EPERM; goto fail_alloc_irq; @@ -937,7 +937,7 @@ static int ps3_vuart_probe(struct device *_dev) fail_probe: ps3_vuart_set_interrupt_mask(dev, 0); fail_request_irq: - ps3_free_vuart_irq(vuart_bus_priv.virq); + ps3_vuart_irq_destroy(vuart_bus_priv.virq); vuart_bus_priv.virq = NO_IRQ; fail_alloc_irq: --vuart_bus_priv.use_count; @@ -975,7 +975,7 @@ static int ps3_vuart_remove(struct device *_dev) 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); + ps3_vuart_irq_destroy(vuart_bus_priv.virq); vuart_bus_priv.virq = NO_IRQ; } diff --git a/trunk/drivers/rtc/Kconfig b/trunk/drivers/rtc/Kconfig index 95826b92ca4b..5e439836db2d 100644 --- a/trunk/drivers/rtc/Kconfig +++ b/trunk/drivers/rtc/Kconfig @@ -21,21 +21,31 @@ config RTC_CLASS will be called rtc-class. config RTC_HCTOSYS - bool "Set system time from RTC on startup" + bool "Set system time from RTC on startup and resume" depends on RTC_CLASS = y default y help - If you say yes here, the system time will be set using - the value read from the specified RTC device. This is useful - in order to avoid unnecessary fsck runs. + If you say yes here, the system time (wall clock) will be set using + the value read from a specified RTC device. This is useful to avoid + unnecessary fsck runs at boot time, and to network better. config RTC_HCTOSYS_DEVICE - string "The RTC to read the time from" + string "RTC used to set the system time" depends on RTC_HCTOSYS = y default "rtc0" help - The RTC device that will be used as the source for - the system time, usually rtc0. + The RTC device that will be used to (re)initialize the system + clock, usually rtc0. Initialization is done when the system + starts up, and when it resumes from a low power state. + + This clock should be battery-backed, so that it reads the correct + time when the system boots from a power-off state. Otherwise, your + system will need an external clock source (like an NTP server). + + If the clock you specify here is not battery backed, it may still + be useful to reinitialize system time when resuming from system + sleep states. Do not specify an RTC here unless it stays powered + during all this system's supported sleep states. config RTC_DEBUG bool "RTC debug support" @@ -48,7 +58,7 @@ comment "RTC interfaces" depends on RTC_CLASS config RTC_INTF_SYSFS - tristate "sysfs" + boolean "sysfs" depends on RTC_CLASS && SYSFS default RTC_CLASS help @@ -59,7 +69,7 @@ config RTC_INTF_SYSFS will be called rtc-sysfs. config RTC_INTF_PROC - tristate "proc" + boolean "proc" depends on RTC_CLASS && PROC_FS default RTC_CLASS help @@ -71,7 +81,7 @@ config RTC_INTF_PROC will be called rtc-proc. config RTC_INTF_DEV - tristate "dev" + boolean "dev" depends on RTC_CLASS default RTC_CLASS help @@ -92,44 +102,26 @@ config RTC_INTF_DEV_UIE_EMUL driver does not expose RTC_UIE ioctls. Those requests generate once-per-second update interrupts, used for synchronization. -comment "RTC drivers" +config RTC_DRV_TEST + tristate "Test driver/device" depends on RTC_CLASS - -# this 'CMOS' RTC driver is arch dependent because -# requires defining CMOS_READ/CMOS_WRITE, and a -# global rtc_lock ... it's not yet just another platform_device. - -config RTC_DRV_CMOS - tristate "PC-style 'CMOS' real time clock" - depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \ - || M32R || ATARI || POWERPC) - help - Say "yes" here to get direct support for the real time clock - found in every PC or ACPI-based system, and some other boards. - Specifically the original MC146818, compatibles like those in - PC south bridges, the DS12887 or M48T86, some multifunction - or LPC bus chips, and so on. - - Your system will need to define the platform device used by - this driver, otherwise it won't be accessible. This means - you can safely enable this driver if you don't know whether - or not your board has this kind of hardware. - - This driver can also be built as a module. If so, the module - will be called rtc-cmos. - -config RTC_DRV_X1205 - tristate "Xicor/Intersil X1205" - depends on RTC_CLASS && I2C help If you say yes here you get support for the - Xicor/Intersil X1205 RTC chip. + RTC test driver. It's a software RTC which can be + used to test the RTC subsystem APIs. It gets + the time from the system clock. + You want this driver only if you are doing development + on the RTC subsystem. Please read the source code + for further details. This driver can also be built as a module. If so, the module - will be called rtc-x1205. + will be called rtc-test. + +comment "I2C RTC drivers" + depends on RTC_CLASS config RTC_DRV_DS1307 - tristate "Dallas/Maxim DS1307 and similar I2C RTC chips" + tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00" depends on RTC_CLASS && I2C help If you say yes here you get support for various compatible RTC @@ -146,53 +138,55 @@ config RTC_DRV_DS1307 This driver can also be built as a module. If so, the module will be called rtc-ds1307. -config RTC_DRV_DS1553 - tristate "Dallas DS1553" - depends on RTC_CLASS +config RTC_DRV_DS1672 + tristate "Dallas/Maxim DS1672" + depends on RTC_CLASS && I2C help If you say yes here you get support for the - Dallas DS1553 timekeeping chip. + Dallas/Maxim DS1672 timekeeping chip. This driver can also be built as a module. If so, the module - will be called rtc-ds1553. + will be called rtc-ds1672. -config RTC_DRV_ISL1208 - tristate "Intersil 1208" +config RTC_DRV_MAX6900 + tristate "Maxim 6900" depends on RTC_CLASS && I2C help - If you say yes here you get support for the - Intersil 1208 RTC chip. + If you say yes here you will get support for the + Maxim MAX6900 I2C RTC chip. This driver can also be built as a module. If so, the module - will be called rtc-isl1208. + will be called rtc-max6900. -config RTC_DRV_DS1672 - tristate "Dallas/Maxim DS1672" +config RTC_DRV_RS5C372 + tristate "Ricoh RS5C372A/B" depends on RTC_CLASS && I2C help If you say yes here you get support for the - Dallas/Maxim DS1672 timekeeping chip. + Ricoh RS5C372A and RS5C372B RTC chips. This driver can also be built as a module. If so, the module - will be called rtc-ds1672. + will be called rtc-rs5c372. -config RTC_DRV_DS1742 - tristate "Dallas DS1742/1743" - depends on RTC_CLASS +config RTC_DRV_ISL1208 + tristate "Intersil 1208" + depends on RTC_CLASS && I2C help If you say yes here you get support for the - Dallas DS1742/1743 timekeeping chip. + Intersil 1208 RTC chip. This driver can also be built as a module. If so, the module - will be called rtc-ds1742. + will be called rtc-isl1208. -config RTC_DRV_OMAP - tristate "TI OMAP1" - depends on RTC_CLASS && ( \ - ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 ) +config RTC_DRV_X1205 + tristate "Xicor/Intersil X1205" + depends on RTC_CLASS && I2C help - Say "yes" here to support the real time clock on TI OMAP1 chips. - This driver can also be built as a module called rtc-omap. + If you say yes here you get support for the + Xicor/Intersil X1205 RTC chip. + + This driver can also be built as a module. If so, the module + will be called rtc-x1205. config RTC_DRV_PCF8563 tristate "Philips PCF8563/Epson RTC8564" @@ -207,16 +201,20 @@ config RTC_DRV_PCF8563 config RTC_DRV_PCF8583 tristate "Philips PCF8583" - depends on RTC_CLASS && I2C && ARCH_RPC + depends on RTC_CLASS && I2C help If you say yes here you get support for the Philips PCF8583 - RTC chip found on Acorn RiscPCs. This driver supports the + RTC chip found on Acorn RiscPCs. This driver supports the platform specific method of retrieving the current year from - the RTC's SRAM. + the RTC's SRAM. It will work on other platforms with the same + chip, but the year will probably have to be tweaked. This driver can also be built as a module. If so, the module will be called rtc-pcf8583. +comment "SPI RTC drivers" + depends on RTC_CLASS + config RTC_DRV_RS5C348 tristate "Ricoh RS5C348A/B" depends on RTC_CLASS && SPI @@ -227,15 +225,92 @@ config RTC_DRV_RS5C348 This driver can also be built as a module. If so, the module will be called rtc-rs5c348. -config RTC_DRV_RS5C372 - tristate "Ricoh RS5C372A/B" - depends on RTC_CLASS && I2C +config RTC_DRV_MAX6902 + tristate "Maxim 6902" + depends on RTC_CLASS && SPI + help + If you say yes here you will get support for the + Maxim MAX6902 SPI RTC chip. + + This driver can also be built as a module. If so, the module + will be called rtc-max6902. + +comment "Platform RTC drivers" + depends on RTC_CLASS + +# this 'CMOS' RTC driver is arch dependent because +# requires defining CMOS_READ/CMOS_WRITE, and a +# global rtc_lock ... it's not yet just another platform_device. + +config RTC_DRV_CMOS + tristate "PC-style 'CMOS'" + depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \ + || M32R || ATARI || POWERPC) + help + Say "yes" here to get direct support for the real time clock + found in every PC or ACPI-based system, and some other boards. + Specifically the original MC146818, compatibles like those in + PC south bridges, the DS12887 or M48T86, some multifunction + or LPC bus chips, and so on. + + Your system will need to define the platform device used by + this driver, otherwise it won't be accessible. This means + you can safely enable this driver if you don't know whether + or not your board has this kind of hardware. + + This driver can also be built as a module. If so, the module + will be called rtc-cmos. + +config RTC_DRV_DS1553 + tristate "Dallas DS1553" + depends on RTC_CLASS help If you say yes here you get support for the - Ricoh RS5C372A and RS5C372B RTC chips. + Dallas DS1553 timekeeping chip. This driver can also be built as a module. If so, the module - will be called rtc-rs5c372. + will be called rtc-ds1553. + +config RTC_DRV_DS1742 + tristate "Dallas DS1742/1743" + depends on RTC_CLASS + help + If you say yes here you get support for the + Dallas DS1742/1743 timekeeping chip. + + This driver can also be built as a module. If so, the module + will be called rtc-ds1742. + +config RTC_DRV_M48T86 + tristate "ST M48T86/Dallas DS12887" + depends on RTC_CLASS + help + If you say Y here you will get support for the + ST M48T86 and Dallas DS12887 RTC chips. + + This driver can also be built as a module. If so, the module + will be called rtc-m48t86. + +config RTC_DRV_V3020 + tristate "EM Microelectronic V3020" + depends on RTC_CLASS + help + If you say yes here you will get support for the + EM Microelectronic v3020 RTC chip. + + This driver can also be built as a module. If so, the module + will be called rtc-v3020. + +comment "on-CPU RTC drivers" + depends on RTC_CLASS + +config RTC_DRV_OMAP + tristate "TI OMAP1" + depends on RTC_CLASS && ( \ + ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 ) + help + Say "yes" here to support the real time clock on TI OMAP1 chips. + This driver can also be built as a module called rtc-omap. config RTC_DRV_S3C tristate "Samsung S3C series SoC RTC" @@ -253,16 +328,6 @@ config RTC_DRV_S3C This driver can also be build as a module. If so, the module will be called rtc-s3c. -config RTC_DRV_M48T86 - tristate "ST M48T86/Dallas DS12887" - depends on RTC_CLASS - help - If you say Y here you will get support for the - ST M48T86 and Dallas DS12887 RTC chips. - - This driver can also be built as a module. If so, the module - will be called rtc-m48t86. - config RTC_DRV_EP93XX tristate "Cirrus Logic EP93XX" depends on RTC_CLASS && ARCH_EP93XX @@ -308,7 +373,7 @@ config RTC_DRV_PL031 depends on RTC_CLASS && ARM_AMBA help If you say Y here you will get access to ARM AMBA - PrimeCell PL031 UART found on certain ARM SOCs. + PrimeCell PL031 RTC found on certain ARM SOCs. To compile this driver as a module, choose M here: the module will be called rtc-pl031. @@ -319,39 +384,20 @@ config RTC_DRV_AT91RM9200 help Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock). -config RTC_DRV_TEST - tristate "Test driver/device" - depends on RTC_CLASS - help - If you say yes here you get support for the - RTC test driver. It's a software RTC which can be - used to test the RTC subsystem APIs. It gets - the time from the system clock. - You want this driver only if you are doing development - on the RTC subsystem. Please read the source code - for further details. - - This driver can also be built as a module. If so, the module - will be called rtc-test. - -config RTC_DRV_MAX6902 - tristate "Maxim 6902" - depends on RTC_CLASS && SPI +config RTC_DRV_BFIN + tristate "Blackfin On-Chip RTC" + depends on RTC_CLASS && BFIN help If you say yes here you will get support for the - Maxim MAX6902 spi RTC chip. + Blackfin On-Chip Real Time Clock. This driver can also be built as a module. If so, the module - will be called rtc-max6902. + will be called rtc-bfin. -config RTC_DRV_V3020 - tristate "EM Microelectronic V3020" - depends on RTC_CLASS +config RTC_DRV_RS5C313 + tristate "Ricoh RS5C313" + depends on RTC_CLASS && BROKEN help - If you say yes here you will get support for the - EM Microelectronic v3020 RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-v3020. + If you say yes here you get support for the Ricoh RS5C313 RTC chips. endmenu diff --git a/trunk/drivers/rtc/Makefile b/trunk/drivers/rtc/Makefile index 92bfe1b3a5fa..a1afbc236073 100644 --- a/trunk/drivers/rtc/Makefile +++ b/trunk/drivers/rtc/Makefile @@ -11,9 +11,9 @@ obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o rtc-core-y := class.o interface.o -obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o -obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o -obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o +rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o +rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o +rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o @@ -30,11 +30,14 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o +obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o +obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o +obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o diff --git a/trunk/drivers/rtc/class.c b/trunk/drivers/rtc/class.c index 04aaa6347234..8b3cd31d6a61 100644 --- a/trunk/drivers/rtc/class.c +++ b/trunk/drivers/rtc/class.c @@ -16,19 +16,94 @@ #include #include +#include "rtc-core.h" + + static DEFINE_IDR(rtc_idr); static DEFINE_MUTEX(idr_lock); struct class *rtc_class; -static void rtc_device_release(struct class_device *class_dev) +static void rtc_device_release(struct device *dev) { - struct rtc_device *rtc = to_rtc_device(class_dev); + struct rtc_device *rtc = to_rtc_device(dev); mutex_lock(&idr_lock); idr_remove(&rtc_idr, rtc->id); mutex_unlock(&idr_lock); kfree(rtc); } +#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE) + +/* + * On suspend(), measure the delta between one RTC and the + * system's wall clock; restore it on resume(). + */ + +static struct timespec delta; +static time_t oldtime; + +static int rtc_suspend(struct device *dev, pm_message_t mesg) +{ + struct rtc_device *rtc = to_rtc_device(dev); + struct rtc_time tm; + + if (strncmp(rtc->dev.bus_id, + CONFIG_RTC_HCTOSYS_DEVICE, + BUS_ID_SIZE) != 0) + return 0; + + rtc_read_time(rtc, &tm); + rtc_tm_to_time(&tm, &oldtime); + + /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */ + set_normalized_timespec(&delta, + xtime.tv_sec - oldtime, + xtime.tv_nsec - (NSEC_PER_SEC >> 1)); + + return 0; +} + +static int rtc_resume(struct device *dev) +{ + struct rtc_device *rtc = to_rtc_device(dev); + struct rtc_time tm; + time_t newtime; + struct timespec time; + + if (strncmp(rtc->dev.bus_id, + CONFIG_RTC_HCTOSYS_DEVICE, + BUS_ID_SIZE) != 0) + return 0; + + rtc_read_time(rtc, &tm); + if (rtc_valid_tm(&tm) != 0) { + pr_debug("%s: bogus resume time\n", rtc->dev.bus_id); + return 0; + } + rtc_tm_to_time(&tm, &newtime); + if (newtime <= oldtime) { + if (newtime < oldtime) + pr_debug("%s: time travel!\n", rtc->dev.bus_id); + return 0; + } + + /* restore wall clock using delta against this RTC; + * adjust again for avg 1/2 second RTC sampling error + */ + set_normalized_timespec(&time, + newtime + delta.tv_sec, + (NSEC_PER_SEC >> 1) + delta.tv_nsec); + do_settimeofday(&time); + + return 0; +} + +#else +#define rtc_suspend NULL +#define rtc_resume NULL +#endif + + /** * rtc_device_register - register w/ RTC class * @dev: the device to register @@ -70,23 +145,29 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc->ops = ops; rtc->owner = owner; rtc->max_user_freq = 64; - rtc->class_dev.dev = dev; - rtc->class_dev.class = rtc_class; - rtc->class_dev.release = rtc_device_release; + rtc->dev.parent = dev; + rtc->dev.class = rtc_class; + rtc->dev.release = rtc_device_release; mutex_init(&rtc->ops_lock); spin_lock_init(&rtc->irq_lock); spin_lock_init(&rtc->irq_task_lock); strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); - snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id); + snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id); - err = class_device_register(&rtc->class_dev); + rtc_dev_prepare(rtc); + + err = device_register(&rtc->dev); if (err) goto exit_kfree; + rtc_dev_add_device(rtc); + rtc_sysfs_add_device(rtc); + rtc_proc_add_device(rtc); + dev_info(dev, "rtc core: registered %s as %s\n", - rtc->name, rtc->class_dev.class_id); + rtc->name, rtc->dev.bus_id); return rtc; @@ -113,26 +194,22 @@ EXPORT_SYMBOL_GPL(rtc_device_register); */ void rtc_device_unregister(struct rtc_device *rtc) { - if (class_device_get(&rtc->class_dev) != NULL) { + if (get_device(&rtc->dev) != NULL) { mutex_lock(&rtc->ops_lock); /* remove innards of this RTC, then disable it, before * letting any rtc_class_open() users access it again */ - class_device_unregister(&rtc->class_dev); + rtc_sysfs_del_device(rtc); + rtc_dev_del_device(rtc); + rtc_proc_del_device(rtc); + device_unregister(&rtc->dev); rtc->ops = NULL; mutex_unlock(&rtc->ops_lock); - class_device_put(&rtc->class_dev); + put_device(&rtc->dev); } } EXPORT_SYMBOL_GPL(rtc_device_unregister); -int rtc_interface_register(struct class_interface *intf) -{ - intf->class = rtc_class; - return class_interface_register(intf); -} -EXPORT_SYMBOL_GPL(rtc_interface_register); - static int __init rtc_init(void) { rtc_class = class_create(THIS_MODULE, "rtc"); @@ -140,11 +217,16 @@ static int __init rtc_init(void) printk(KERN_ERR "%s: couldn't create class\n", __FILE__); return PTR_ERR(rtc_class); } + rtc_class->suspend = rtc_suspend; + rtc_class->resume = rtc_resume; + rtc_dev_init(); + rtc_sysfs_init(rtc_class); return 0; } static void __exit rtc_exit(void) { + rtc_dev_exit(); class_destroy(rtc_class); } diff --git a/trunk/drivers/rtc/hctosys.c b/trunk/drivers/rtc/hctosys.c index d02fe9a0001f..178527252c6a 100644 --- a/trunk/drivers/rtc/hctosys.c +++ b/trunk/drivers/rtc/hctosys.c @@ -26,15 +26,15 @@ static int __init rtc_hctosys(void) { int err; struct rtc_time tm; - struct class_device *class_dev = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); - if (class_dev == NULL) { + if (rtc == NULL) { printk("%s: unable to open rtc device (%s)\n", __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); return -ENODEV; } - err = rtc_read_time(class_dev, &tm); + err = rtc_read_time(rtc, &tm); if (err == 0) { err = rtc_valid_tm(&tm); if (err == 0) { @@ -46,7 +46,7 @@ static int __init rtc_hctosys(void) do_settimeofday(&tv); - dev_info(class_dev->dev, + dev_info(rtc->dev.parent, "setting the system clock to " "%d-%02d-%02d %02d:%02d:%02d (%u)\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, @@ -54,14 +54,14 @@ static int __init rtc_hctosys(void) (unsigned int) tv.tv_sec); } else - dev_err(class_dev->dev, + dev_err(rtc->dev.parent, "hctosys: invalid date/time\n"); } else - dev_err(class_dev->dev, + dev_err(rtc->dev.parent, "hctosys: unable to read the hardware clock\n"); - rtc_class_close(class_dev); + rtc_class_close(rtc); return 0; } diff --git a/trunk/drivers/rtc/interface.c b/trunk/drivers/rtc/interface.c index ef40df0f169d..ad66c6ecf365 100644 --- a/trunk/drivers/rtc/interface.c +++ b/trunk/drivers/rtc/interface.c @@ -13,10 +13,9 @@ #include -int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm) +int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) { int err; - struct rtc_device *rtc = to_rtc_device(class_dev); err = mutex_lock_interruptible(&rtc->ops_lock); if (err) @@ -28,7 +27,7 @@ int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm) err = -EINVAL; else { memset(tm, 0, sizeof(struct rtc_time)); - err = rtc->ops->read_time(class_dev->dev, tm); + err = rtc->ops->read_time(rtc->dev.parent, tm); } mutex_unlock(&rtc->ops_lock); @@ -36,10 +35,9 @@ int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm) } EXPORT_SYMBOL_GPL(rtc_read_time); -int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm) +int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) { int err; - struct rtc_device *rtc = to_rtc_device(class_dev); err = rtc_valid_tm(tm); if (err != 0) @@ -54,17 +52,16 @@ int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm) else if (!rtc->ops->set_time) err = -EINVAL; else - err = rtc->ops->set_time(class_dev->dev, tm); + err = rtc->ops->set_time(rtc->dev.parent, tm); mutex_unlock(&rtc->ops_lock); return err; } EXPORT_SYMBOL_GPL(rtc_set_time); -int rtc_set_mmss(struct class_device *class_dev, unsigned long secs) +int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) { int err; - struct rtc_device *rtc = to_rtc_device(class_dev); err = mutex_lock_interruptible(&rtc->ops_lock); if (err) @@ -73,11 +70,11 @@ int rtc_set_mmss(struct class_device *class_dev, unsigned long secs) if (!rtc->ops) err = -ENODEV; else if (rtc->ops->set_mmss) - err = rtc->ops->set_mmss(class_dev->dev, secs); + err = rtc->ops->set_mmss(rtc->dev.parent, secs); else if (rtc->ops->read_time && rtc->ops->set_time) { struct rtc_time new, old; - err = rtc->ops->read_time(class_dev->dev, &old); + err = rtc->ops->read_time(rtc->dev.parent, &old); if (err == 0) { rtc_time_to_tm(secs, &new); @@ -89,7 +86,8 @@ int rtc_set_mmss(struct class_device *class_dev, unsigned long secs) */ if (!((old.tm_hour == 23 && old.tm_min == 59) || (new.tm_hour == 23 && new.tm_min == 59))) - err = rtc->ops->set_time(class_dev->dev, &new); + err = rtc->ops->set_time(rtc->dev.parent, + &new); } } else @@ -101,10 +99,9 @@ int rtc_set_mmss(struct class_device *class_dev, unsigned long secs) } EXPORT_SYMBOL_GPL(rtc_set_mmss); -int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm) +int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; - struct rtc_device *rtc = to_rtc_device(class_dev); err = mutex_lock_interruptible(&rtc->ops_lock); if (err) @@ -116,7 +113,7 @@ int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm) err = -EINVAL; else { memset(alarm, 0, sizeof(struct rtc_wkalrm)); - err = rtc->ops->read_alarm(class_dev->dev, alarm); + err = rtc->ops->read_alarm(rtc->dev.parent, alarm); } mutex_unlock(&rtc->ops_lock); @@ -124,10 +121,13 @@ int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm) } EXPORT_SYMBOL_GPL(rtc_read_alarm); -int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm) +int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; - struct rtc_device *rtc = to_rtc_device(class_dev); + + err = rtc_valid_tm(&alarm->time); + if (err != 0) + return err; err = mutex_lock_interruptible(&rtc->ops_lock); if (err) @@ -138,7 +138,7 @@ int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm) else if (!rtc->ops->set_alarm) err = -EINVAL; else - err = rtc->ops->set_alarm(class_dev->dev, alarm); + err = rtc->ops->set_alarm(rtc->dev.parent, alarm); mutex_unlock(&rtc->ops_lock); return err; @@ -147,16 +147,14 @@ EXPORT_SYMBOL_GPL(rtc_set_alarm); /** * rtc_update_irq - report RTC periodic, alarm, and/or update irqs - * @class_dev: the rtc's class device + * @rtc: the rtc device * @num: how many irqs are being reported (usually one) * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF * Context: in_interrupt(), irqs blocked */ -void rtc_update_irq(struct class_device *class_dev, +void rtc_update_irq(struct rtc_device *rtc, unsigned long num, unsigned long events) { - struct rtc_device *rtc = to_rtc_device(class_dev); - spin_lock(&rtc->irq_lock); rtc->irq_data = (rtc->irq_data + (num << 8)) | events; spin_unlock(&rtc->irq_lock); @@ -171,40 +169,43 @@ void rtc_update_irq(struct class_device *class_dev, } EXPORT_SYMBOL_GPL(rtc_update_irq); -struct class_device *rtc_class_open(char *name) +struct rtc_device *rtc_class_open(char *name) { - struct class_device *class_dev = NULL, - *class_dev_tmp; + struct device *dev; + struct rtc_device *rtc = NULL; down(&rtc_class->sem); - list_for_each_entry(class_dev_tmp, &rtc_class->children, node) { - if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) { - class_dev = class_device_get(class_dev_tmp); + list_for_each_entry(dev, &rtc_class->devices, node) { + if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) { + dev = get_device(dev); + if (dev) + rtc = to_rtc_device(dev); break; } } - if (class_dev) { - if (!try_module_get(to_rtc_device(class_dev)->owner)) - class_dev = NULL; + if (rtc) { + if (!try_module_get(rtc->owner)) { + put_device(dev); + rtc = NULL; + } } up(&rtc_class->sem); - return class_dev; + return rtc; } EXPORT_SYMBOL_GPL(rtc_class_open); -void rtc_class_close(struct class_device *class_dev) +void rtc_class_close(struct rtc_device *rtc) { - module_put(to_rtc_device(class_dev)->owner); - class_device_put(class_dev); + module_put(rtc->owner); + put_device(&rtc->dev); } EXPORT_SYMBOL_GPL(rtc_class_close); -int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task) +int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) { int retval = -EBUSY; - struct rtc_device *rtc = to_rtc_device(class_dev); if (task == NULL || task->func == NULL) return -EINVAL; @@ -220,9 +221,8 @@ int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task) } EXPORT_SYMBOL_GPL(rtc_irq_register); -void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task) +void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) { - struct rtc_device *rtc = to_rtc_device(class_dev); spin_lock_irq(&rtc->irq_task_lock); if (rtc->irq_task == task) @@ -231,11 +231,10 @@ void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task) } EXPORT_SYMBOL_GPL(rtc_irq_unregister); -int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled) +int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled) { int err = 0; unsigned long flags; - struct rtc_device *rtc = to_rtc_device(class_dev); if (rtc->ops->irq_set_state == NULL) return -ENXIO; @@ -246,17 +245,16 @@ int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int spin_unlock_irqrestore(&rtc->irq_task_lock, flags); if (err == 0) - err = rtc->ops->irq_set_state(class_dev->dev, enabled); + err = rtc->ops->irq_set_state(rtc->dev.parent, enabled); return err; } EXPORT_SYMBOL_GPL(rtc_irq_set_state); -int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq) +int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) { int err = 0; unsigned long flags; - struct rtc_device *rtc = to_rtc_device(class_dev); if (rtc->ops->irq_set_freq == NULL) return -ENXIO; @@ -267,7 +265,7 @@ int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int spin_unlock_irqrestore(&rtc->irq_task_lock, flags); if (err == 0) { - err = rtc->ops->irq_set_freq(class_dev->dev, freq); + err = rtc->ops->irq_set_freq(rtc->dev.parent, freq); if (err == 0) rtc->irq_freq = freq; } diff --git a/trunk/drivers/rtc/rtc-at91rm9200.c b/trunk/drivers/rtc/rtc-at91rm9200.c index ac0e68e2f025..33795e5a5595 100644 --- a/trunk/drivers/rtc/rtc-at91rm9200.c +++ b/trunk/drivers/rtc/rtc-at91rm9200.c @@ -263,7 +263,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) at91_sys_write(AT91_RTC_SCCR, rtsr); /* clear status reg */ - rtc_update_irq(&rtc->class_dev, 1, events); + rtc_update_irq(rtc, 1, events); pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__, events >> 8, events & 0x000000FF); @@ -348,21 +348,10 @@ static int __exit at91_rtc_remove(struct platform_device *pdev) /* AT91RM9200 RTC Power management control */ -static struct timespec at91_rtc_delta; static u32 at91_rtc_imr; static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state) { - struct rtc_time tm; - struct timespec time; - - time.tv_nsec = 0; - - /* calculate time delta for suspend */ - at91_rtc_readtime(&pdev->dev, &tm); - rtc_tm_to_time(&tm, &time.tv_sec); - save_time_delta(&at91_rtc_delta, &time); - /* this IRQ is shared with DBGU and other hardware which isn't * necessarily doing PM like we are... */ @@ -374,36 +363,17 @@ static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state) else at91_sys_write(AT91_RTC_IDR, at91_rtc_imr); } - - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, - 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - return 0; } static int at91_rtc_resume(struct platform_device *pdev) { - struct rtc_time tm; - struct timespec time; - - time.tv_nsec = 0; - - at91_rtc_readtime(&pdev->dev, &tm); - rtc_tm_to_time(&tm, &time.tv_sec); - restore_time_delta(&at91_rtc_delta, &time); - if (at91_rtc_imr) { if (device_may_wakeup(&pdev->dev)) disable_irq_wake(AT91_ID_SYS); else at91_sys_write(AT91_RTC_IER, at91_rtc_imr); } - - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, - 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - return 0; } #else diff --git a/trunk/drivers/rtc/rtc-bfin.c b/trunk/drivers/rtc/rtc-bfin.c new file mode 100644 index 000000000000..260ead959918 --- /dev/null +++ b/trunk/drivers/rtc/rtc-bfin.c @@ -0,0 +1,445 @@ +/* + * Blackfin On-Chip Real Time Clock Driver + * Supports BF531/BF532/BF533/BF534/BF536/BF537 + * + * Copyright 2004-2007 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +/* The biggest issue we deal with in this driver is that register writes are + * synced to the RTC frequency of 1Hz. So if you write to a register and + * attempt to write again before the first write has completed, the new write + * is simply discarded. This can easily be troublesome if userspace disables + * one event (say periodic) and then right after enables an event (say alarm). + * Since all events are maintained in the same interrupt mask register, if + * we wrote to it to disable the first event and then wrote to it again to + * enable the second event, that second event would not be enabled as the + * write would be discarded and things quickly fall apart. + * + * To keep this delay from significantly degrading performance (we, in theory, + * would have to sleep for up to 1 second everytime we wanted to write a + * register), we only check the write pending status before we start to issue + * a new write. We bank on the idea that it doesnt matter when the sync + * happens so long as we don't attempt another write before it does. The only + * time userspace would take this penalty is when they try and do multiple + * operations right after another ... but in this case, they need to take the + * sync penalty, so we should be OK. + * + * Also note that the RTC_ISTAT register does not suffer this penalty; its + * writes to clear status registers complete immediately. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __FUNCTION__, __LINE__, ## args) +#define stampit() stamp("here i am") + +struct bfin_rtc { + struct rtc_device *rtc_dev; + struct rtc_time rtc_alarm; + spinlock_t lock; +}; + +/* Bit values for the ISTAT / ICTL registers */ +#define RTC_ISTAT_WRITE_COMPLETE 0x8000 +#define RTC_ISTAT_WRITE_PENDING 0x4000 +#define RTC_ISTAT_ALARM_DAY 0x0040 +#define RTC_ISTAT_24HR 0x0020 +#define RTC_ISTAT_HOUR 0x0010 +#define RTC_ISTAT_MIN 0x0008 +#define RTC_ISTAT_SEC 0x0004 +#define RTC_ISTAT_ALARM 0x0002 +#define RTC_ISTAT_STOPWATCH 0x0001 + +/* Shift values for RTC_STAT register */ +#define DAY_BITS_OFF 17 +#define HOUR_BITS_OFF 12 +#define MIN_BITS_OFF 6 +#define SEC_BITS_OFF 0 + +/* Some helper functions to convert between the common RTC notion of time + * and the internal Blackfin notion that is stored in 32bits. + */ +static inline u32 rtc_time_to_bfin(unsigned long now) +{ + u32 sec = (now % 60); + u32 min = (now % (60 * 60)) / 60; + u32 hour = (now % (60 * 60 * 24)) / (60 * 60); + u32 days = (now / (60 * 60 * 24)); + return (sec << SEC_BITS_OFF) + + (min << MIN_BITS_OFF) + + (hour << HOUR_BITS_OFF) + + (days << DAY_BITS_OFF); +} +static inline unsigned long rtc_bfin_to_time(u32 rtc_bfin) +{ + return (((rtc_bfin >> SEC_BITS_OFF) & 0x003F)) + + (((rtc_bfin >> MIN_BITS_OFF) & 0x003F) * 60) + + (((rtc_bfin >> HOUR_BITS_OFF) & 0x001F) * 60 * 60) + + (((rtc_bfin >> DAY_BITS_OFF) & 0x7FFF) * 60 * 60 * 24); +} +static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm) +{ + rtc_time_to_tm(rtc_bfin_to_time(rtc_bfin), tm); +} + +/* Wait for the previous write to a RTC register to complete. + * Unfortunately, we can't sleep here as that introduces a race condition when + * turning on interrupt events. Consider this: + * - process sets alarm + * - process enables alarm + * - process sleeps while waiting for rtc write to sync + * - interrupt fires while process is sleeping + * - interrupt acks the event by writing to ISTAT + * - interrupt sets the WRITE PENDING bit + * - interrupt handler finishes + * - process wakes up, sees WRITE PENDING bit set, goes to sleep + * - interrupt fires while process is sleeping + * If anyone can point out the obvious solution here, i'm listening :). This + * shouldn't be an issue on an SMP or preempt system as this function should + * only be called with the rtc lock held. + */ +static void rtc_bfin_sync_pending(void) +{ + stampit(); + while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE)) { + if (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING)) + break; + } + bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE); +} + +static void rtc_bfin_reset(struct bfin_rtc *rtc) +{ + /* Initialize the RTC. Enable pre-scaler to scale RTC clock + * to 1Hz and clear interrupt/status registers. */ + spin_lock_irq(&rtc->lock); + rtc_bfin_sync_pending(); + bfin_write_RTC_PREN(0x1); + bfin_write_RTC_ICTL(0); + bfin_write_RTC_SWCNT(0); + bfin_write_RTC_ALARM(0); + bfin_write_RTC_ISTAT(0xFFFF); + spin_unlock_irq(&rtc->lock); +} + +static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = to_platform_device(dev_id); + struct bfin_rtc *rtc = platform_get_drvdata(pdev); + unsigned long events = 0; + u16 rtc_istat; + + stampit(); + + spin_lock_irq(&rtc->lock); + + rtc_istat = bfin_read_RTC_ISTAT(); + + if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) { + bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY); + events |= RTC_AF | RTC_IRQF; + } + + if (rtc_istat & RTC_ISTAT_STOPWATCH) { + bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH); + events |= RTC_PF | RTC_IRQF; + bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); + } + + if (rtc_istat & RTC_ISTAT_SEC) { + bfin_write_RTC_ISTAT(RTC_ISTAT_SEC); + events |= RTC_UF | RTC_IRQF; + } + + rtc_update_irq(rtc->rtc_dev, 1, events); + + spin_unlock_irq(&rtc->lock); + + return IRQ_HANDLED; +} + +static int bfin_rtc_open(struct device *dev) +{ + struct bfin_rtc *rtc = dev_get_drvdata(dev); + int ret; + + stampit(); + + ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_DISABLED, "rtc-bfin", dev); + if (unlikely(ret)) { + dev_err(dev, "request RTC IRQ failed with %d\n", ret); + return ret; + } + + rtc_bfin_reset(rtc); + + return ret; +} + +static void bfin_rtc_release(struct device *dev) +{ + struct bfin_rtc *rtc = dev_get_drvdata(dev); + stampit(); + rtc_bfin_reset(rtc); + free_irq(IRQ_RTC, dev); +} + +static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct bfin_rtc *rtc = dev_get_drvdata(dev); + + stampit(); + + switch (cmd) { + case RTC_PIE_ON: + stampit(); + spin_lock_irq(&rtc->lock); + rtc_bfin_sync_pending(); + bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH); + bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); + bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_STOPWATCH); + spin_unlock_irq(&rtc->lock); + return 0; + case RTC_PIE_OFF: + stampit(); + spin_lock_irq(&rtc->lock); + rtc_bfin_sync_pending(); + bfin_write_RTC_SWCNT(0); + bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_STOPWATCH); + spin_unlock_irq(&rtc->lock); + return 0; + + case RTC_UIE_ON: + stampit(); + spin_lock_irq(&rtc->lock); + rtc_bfin_sync_pending(); + bfin_write_RTC_ISTAT(RTC_ISTAT_SEC); + bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_SEC); + spin_unlock_irq(&rtc->lock); + return 0; + case RTC_UIE_OFF: + stampit(); + spin_lock_irq(&rtc->lock); + rtc_bfin_sync_pending(); + bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_SEC); + spin_unlock_irq(&rtc->lock); + return 0; + + case RTC_AIE_ON: { + unsigned long rtc_alarm; + u16 which_alarm; + int ret = 0; + + stampit(); + + spin_lock_irq(&rtc->lock); + + rtc_bfin_sync_pending(); + if (rtc->rtc_alarm.tm_yday == -1) { + struct rtc_time now; + rtc_bfin_to_tm(bfin_read_RTC_STAT(), &now); + now.tm_sec = rtc->rtc_alarm.tm_sec; + now.tm_min = rtc->rtc_alarm.tm_min; + now.tm_hour = rtc->rtc_alarm.tm_hour; + ret = rtc_tm_to_time(&now, &rtc_alarm); + which_alarm = RTC_ISTAT_ALARM; + } else { + ret = rtc_tm_to_time(&rtc->rtc_alarm, &rtc_alarm); + which_alarm = RTC_ISTAT_ALARM_DAY; + } + if (ret == 0) { + bfin_write_RTC_ISTAT(which_alarm); + bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm)); + bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | which_alarm); + } + + spin_unlock_irq(&rtc->lock); + + return ret; + } + case RTC_AIE_OFF: + stampit(); + spin_lock_irq(&rtc->lock); + rtc_bfin_sync_pending(); + bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); + spin_unlock_irq(&rtc->lock); + return 0; + } + + return -ENOIOCTLCMD; +} + +static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct bfin_rtc *rtc = dev_get_drvdata(dev); + + stampit(); + + spin_lock_irq(&rtc->lock); + rtc_bfin_sync_pending(); + rtc_bfin_to_tm(bfin_read_RTC_STAT(), tm); + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static int bfin_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct bfin_rtc *rtc = dev_get_drvdata(dev); + int ret; + unsigned long now; + + stampit(); + + spin_lock_irq(&rtc->lock); + + ret = rtc_tm_to_time(tm, &now); + if (ret == 0) { + rtc_bfin_sync_pending(); + bfin_write_RTC_STAT(rtc_time_to_bfin(now)); + } + + spin_unlock_irq(&rtc->lock); + + return ret; +} + +static int bfin_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct bfin_rtc *rtc = dev_get_drvdata(dev); + stampit(); + memcpy(&alrm->time, &rtc->rtc_alarm, sizeof(struct rtc_time)); + alrm->pending = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); + return 0; +} + +static int bfin_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct bfin_rtc *rtc = dev_get_drvdata(dev); + stampit(); + memcpy(&rtc->rtc_alarm, &alrm->time, sizeof(struct rtc_time)); + return 0; +} + +static int bfin_rtc_proc(struct device *dev, struct seq_file *seq) +{ +#define yesno(x) (x ? "yes" : "no") + u16 ictl = bfin_read_RTC_ICTL(); + stampit(); + seq_printf(seq, "alarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM)); + seq_printf(seq, "wkalarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM_DAY)); + seq_printf(seq, "seconds_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_SEC)); + seq_printf(seq, "periodic_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_STOPWATCH)); +#ifdef DEBUG + seq_printf(seq, "RTC_STAT\t: 0x%08X\n", bfin_read_RTC_STAT()); + seq_printf(seq, "RTC_ICTL\t: 0x%04X\n", bfin_read_RTC_ICTL()); + seq_printf(seq, "RTC_ISTAT\t: 0x%04X\n", bfin_read_RTC_ISTAT()); + seq_printf(seq, "RTC_SWCNT\t: 0x%04X\n", bfin_read_RTC_SWCNT()); + seq_printf(seq, "RTC_ALARM\t: 0x%08X\n", bfin_read_RTC_ALARM()); + seq_printf(seq, "RTC_PREN\t: 0x%04X\n", bfin_read_RTC_PREN()); +#endif + return 0; +} + +static int bfin_irq_set_freq(struct device *dev, int freq) +{ + struct bfin_rtc *rtc = dev_get_drvdata(dev); + stampit(); + rtc->rtc_dev->irq_freq = freq; + return 0; +} + +static struct rtc_class_ops bfin_rtc_ops = { + .open = bfin_rtc_open, + .release = bfin_rtc_release, + .ioctl = bfin_rtc_ioctl, + .read_time = bfin_rtc_read_time, + .set_time = bfin_rtc_set_time, + .read_alarm = bfin_rtc_read_alarm, + .set_alarm = bfin_rtc_set_alarm, + .proc = bfin_rtc_proc, + .irq_set_freq = bfin_irq_set_freq, +}; + +static int __devinit bfin_rtc_probe(struct platform_device *pdev) +{ + struct bfin_rtc *rtc; + int ret = 0; + + stampit(); + + rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); + if (unlikely(!rtc)) + return -ENOMEM; + + spin_lock_init(&rtc->lock); + + rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE); + if (unlikely(IS_ERR(rtc))) { + ret = PTR_ERR(rtc->rtc_dev); + goto err; + } + rtc->rtc_dev->irq_freq = 0; + rtc->rtc_dev->max_user_freq = (2 << 16); /* stopwatch is an unsigned 16 bit reg */ + + platform_set_drvdata(pdev, rtc); + + return 0; + +err: + kfree(rtc); + return ret; +} + +static int __devexit bfin_rtc_remove(struct platform_device *pdev) +{ + struct bfin_rtc *rtc = platform_get_drvdata(pdev); + + rtc_device_unregister(rtc->rtc_dev); + platform_set_drvdata(pdev, NULL); + kfree(rtc); + + return 0; +} + +static struct platform_driver bfin_rtc_driver = { + .driver = { + .name = "rtc-bfin", + .owner = THIS_MODULE, + }, + .probe = bfin_rtc_probe, + .remove = __devexit_p(bfin_rtc_remove), +}; + +static int __init bfin_rtc_init(void) +{ + stampit(); + return platform_driver_register(&bfin_rtc_driver); +} + +static void __exit bfin_rtc_exit(void) +{ + platform_driver_unregister(&bfin_rtc_driver); +} + +module_init(bfin_rtc_init); +module_exit(bfin_rtc_exit); + +MODULE_DESCRIPTION("Blackfin On-Chip Real Time Clock Driver"); +MODULE_AUTHOR("Mike Frysinger "); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/rtc/rtc-cmos.c b/trunk/drivers/rtc/rtc-cmos.c index 7c0d60910077..6085261aa2c1 100644 --- a/trunk/drivers/rtc/rtc-cmos.c +++ b/trunk/drivers/rtc/rtc-cmos.c @@ -46,6 +46,10 @@ struct cmos_rtc { int irq; struct resource *iomem; + void (*wake_on)(struct device *); + void (*wake_off)(struct device *); + + u8 enabled_wake; u8 suspend_ctrl; /* newer hardware extends the original register set */ @@ -203,7 +207,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) rtc_intr = CMOS_READ(RTC_INTR_FLAGS); rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (is_intr(rtc_intr)) - rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); + rtc_update_irq(cmos->rtc, 1, rtc_intr); /* update alarm */ CMOS_WRITE(hrs, RTC_HOURS_ALARM); @@ -223,7 +227,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) rtc_intr = CMOS_READ(RTC_INTR_FLAGS); rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (is_intr(rtc_intr)) - rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); + rtc_update_irq(cmos->rtc, 1, rtc_intr); } spin_unlock_irq(&rtc_lock); @@ -304,7 +308,7 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) rtc_intr = CMOS_READ(RTC_INTR_FLAGS); rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (is_intr(rtc_intr)) - rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); + rtc_update_irq(cmos->rtc, 1, rtc_intr); spin_unlock_irqrestore(&rtc_lock, flags); return 0; } @@ -379,12 +383,12 @@ static irqreturn_t cmos_interrupt(int irq, void *p) return IRQ_NONE; } -#ifdef CONFIG_PNPACPI -#define is_pnpacpi() 1 +#ifdef CONFIG_PNP +#define is_pnp() 1 #define INITSECTION #else -#define is_pnpacpi() 0 +#define is_pnp() 0 #define INITSECTION __init #endif @@ -405,13 +409,20 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) cmos_rtc.irq = rtc_irq; cmos_rtc.iomem = ports; - /* For ACPI systems the info comes from the FADT. On others, - * board specific setup provides it as appropriate. + /* For ACPI systems extension info comes from the FADT. On others, + * board specific setup provides it as appropriate. Systems where + * the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and + * some almost-clones) can provide hooks to make that behave. */ if (info) { cmos_rtc.day_alrm = info->rtc_day_alarm; cmos_rtc.mon_alrm = info->rtc_mon_alarm; cmos_rtc.century = info->rtc_century; + + if (info->wake_on && info->wake_off) { + cmos_rtc.wake_on = info->wake_on; + cmos_rtc.wake_off = info->wake_off; + } } cmos_rtc.rtc = rtc_device_register(driver_name, dev, @@ -427,14 +438,14 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) * REVISIT for non-x86 systems we may need to handle io memory * resources: ioremap them, and request_mem_region(). */ - if (is_pnpacpi()) { + if (is_pnp()) { retval = request_resource(&ioport_resource, ports); if (retval < 0) { dev_dbg(dev, "i/o registers already in use\n"); goto cleanup0; } } - rename_region(ports, cmos_rtc.rtc->class_dev.class_id); + rename_region(ports, cmos_rtc.rtc->dev.bus_id); spin_lock_irq(&rtc_lock); @@ -470,8 +481,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) if (is_valid_irq(rtc_irq)) retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED, - cmos_rtc.rtc->class_dev.class_id, - &cmos_rtc.rtc->class_dev); + cmos_rtc.rtc->dev.bus_id, + cmos_rtc.rtc); if (retval < 0) { dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); goto cleanup1; @@ -483,7 +494,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) */ pr_info("%s: alarms up to one %s%s\n", - cmos_rtc.rtc->class_dev.class_id, + cmos_rtc.rtc->dev.bus_id, is_valid_irq(rtc_irq) ? (cmos_rtc.mon_alrm ? "year" @@ -520,12 +531,12 @@ static void __exit cmos_do_remove(struct device *dev) cmos_do_shutdown(); - if (is_pnpacpi()) + if (is_pnp()) release_resource(cmos->iomem); rename_region(cmos->iomem, NULL); if (is_valid_irq(cmos->irq)) - free_irq(cmos->irq, &cmos_rtc.rtc->class_dev); + free_irq(cmos->irq, cmos_rtc.rtc); rtc_device_unregister(cmos_rtc.rtc); @@ -555,16 +566,20 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) irqstat = CMOS_READ(RTC_INTR_FLAGS); irqstat &= (tmp & RTC_IRQMASK) | RTC_IRQF; if (is_intr(irqstat)) - rtc_update_irq(&cmos->rtc->class_dev, 1, irqstat); + rtc_update_irq(cmos->rtc, 1, irqstat); } spin_unlock_irq(&rtc_lock); - /* ACPI HOOK: enable ACPI_EVENT_RTC when (tmp & RTC_AIE) - * ... it'd be best if we could do that under rtc_lock. - */ + if (tmp & RTC_AIE) { + cmos->enabled_wake = 1; + if (cmos->wake_on) + cmos->wake_on(dev); + else + enable_irq_wake(cmos->irq); + } pr_debug("%s: suspend%s, ctrl %02x\n", - cmos_rtc.rtc->class_dev.class_id, + cmos_rtc.rtc->dev.bus_id, (tmp & RTC_AIE) ? ", alarm may wake" : "", tmp); @@ -576,26 +591,28 @@ static int cmos_resume(struct device *dev) struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char tmp = cmos->suspend_ctrl; - /* REVISIT: a mechanism to resync the system clock (jiffies) - * on resume should be portable between platforms ... - */ - /* re-enable any irqs previously active */ if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { - /* ACPI HOOK: disable ACPI_EVENT_RTC when (tmp & RTC_AIE) */ + if (cmos->enabled_wake) { + if (cmos->wake_off) + cmos->wake_off(dev); + else + disable_irq_wake(cmos->irq); + cmos->enabled_wake = 0; + } spin_lock_irq(&rtc_lock); CMOS_WRITE(tmp, RTC_CONTROL); tmp = CMOS_READ(RTC_INTR_FLAGS); tmp &= (cmos->suspend_ctrl & RTC_IRQMASK) | RTC_IRQF; if (is_intr(tmp)) - rtc_update_irq(&cmos->rtc->class_dev, 1, tmp); + rtc_update_irq(cmos->rtc, 1, tmp); spin_unlock_irq(&rtc_lock); } pr_debug("%s: resume, ctrl %02x\n", - cmos_rtc.rtc->class_dev.class_id, + cmos_rtc.rtc->dev.bus_id, cmos->suspend_ctrl); @@ -613,7 +630,7 @@ static int cmos_resume(struct device *dev) * the device node will always be created as a PNPACPI device. */ -#ifdef CONFIG_PNPACPI +#ifdef CONFIG_PNP #include @@ -684,11 +701,11 @@ static void __exit cmos_exit(void) } module_exit(cmos_exit); -#else /* no PNPACPI */ +#else /* no PNP */ /*----------------------------------------------------------------*/ -/* Platform setup should have set up an RTC device, when PNPACPI is +/* Platform setup should have set up an RTC device, when PNP is * unavailable ... this could happen even on (older) PCs. */ @@ -734,7 +751,7 @@ static void __exit cmos_exit(void) module_exit(cmos_exit); -#endif /* !PNPACPI */ +#endif /* !PNP */ MODULE_AUTHOR("David Brownell"); MODULE_DESCRIPTION("Driver for PC-style 'CMOS' RTCs"); diff --git a/trunk/drivers/rtc/rtc-core.h b/trunk/drivers/rtc/rtc-core.h new file mode 100644 index 000000000000..5f9df7430a22 --- /dev/null +++ b/trunk/drivers/rtc/rtc-core.h @@ -0,0 +1,70 @@ +#ifdef CONFIG_RTC_INTF_DEV + +extern void __init rtc_dev_init(void); +extern void __exit rtc_dev_exit(void); +extern void rtc_dev_prepare(struct rtc_device *rtc); +extern void rtc_dev_add_device(struct rtc_device *rtc); +extern void rtc_dev_del_device(struct rtc_device *rtc); + +#else + +static inline void rtc_dev_init(void) +{ +} + +static inline void rtc_dev_exit(void) +{ +} + +static inline void rtc_dev_prepare(struct rtc_device *rtc) +{ +} + +static inline void rtc_dev_add_device(struct rtc_device *rtc) +{ +} + +static inline void rtc_dev_del_device(struct rtc_device *rtc) +{ +} + +#endif + +#ifdef CONFIG_RTC_INTF_PROC + +extern void rtc_proc_add_device(struct rtc_device *rtc); +extern void rtc_proc_del_device(struct rtc_device *rtc); + +#else + +static inline void rtc_proc_add_device(struct rtc_device *rtc) +{ +} + +static inline void rtc_proc_del_device(struct rtc_device *rtc) +{ +} + +#endif + +#ifdef CONFIG_RTC_INTF_SYSFS + +extern void __init rtc_sysfs_init(struct class *); +extern void rtc_sysfs_add_device(struct rtc_device *rtc); +extern void rtc_sysfs_del_device(struct rtc_device *rtc); + +#else + +static inline void rtc_sysfs_init(struct class *rtc) +{ +} + +static inline void rtc_sysfs_add_device(struct rtc_device *rtc) +{ +} + +static inline void rtc_sysfs_del_device(struct rtc_device *rtc) +{ +} + +#endif diff --git a/trunk/drivers/rtc/rtc-dev.c b/trunk/drivers/rtc/rtc-dev.c index 137330b8636b..f4e5f0040ff7 100644 --- a/trunk/drivers/rtc/rtc-dev.c +++ b/trunk/drivers/rtc/rtc-dev.c @@ -13,8 +13,8 @@ #include #include +#include "rtc-core.h" -static struct class *rtc_dev_class; static dev_t rtc_devt; #define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */ @@ -32,9 +32,9 @@ static int rtc_dev_open(struct inode *inode, struct file *file) if (!(mutex_trylock(&rtc->char_lock))) return -EBUSY; - file->private_data = &rtc->class_dev; + file->private_data = rtc; - err = ops->open ? ops->open(rtc->class_dev.dev) : 0; + err = ops->open ? ops->open(rtc->dev.parent) : 0; if (err == 0) { spin_lock_irq(&rtc->irq_lock); rtc->irq_data = 0; @@ -61,7 +61,7 @@ static void rtc_uie_task(struct work_struct *work) int num = 0; int err; - err = rtc_read_time(&rtc->class_dev, &tm); + err = rtc_read_time(rtc, &tm); local_irq_disable(); spin_lock(&rtc->irq_lock); @@ -79,7 +79,7 @@ static void rtc_uie_task(struct work_struct *work) } spin_unlock(&rtc->irq_lock); if (num) - rtc_update_irq(&rtc->class_dev, num, RTC_UF | RTC_IRQF); + rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF); local_irq_enable(); } static void rtc_uie_timer(unsigned long data) @@ -121,7 +121,7 @@ static int set_uie(struct rtc_device *rtc) struct rtc_time tm; int err; - err = rtc_read_time(&rtc->class_dev, &tm); + err = rtc_read_time(rtc, &tm); if (err) return err; spin_lock_irq(&rtc->irq_lock); @@ -180,7 +180,7 @@ rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (ret == 0) { /* Check for any data updates */ if (rtc->ops->read_callback) - data = rtc->ops->read_callback(rtc->class_dev.dev, + data = rtc->ops->read_callback(rtc->dev.parent, data); if (sizeof(int) != sizeof(long) && @@ -210,8 +210,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; - struct class_device *class_dev = file->private_data; - struct rtc_device *rtc = to_rtc_device(class_dev); + struct rtc_device *rtc = file->private_data; const struct rtc_class_ops *ops = rtc->ops; struct rtc_time tm; struct rtc_wkalrm alarm; @@ -252,7 +251,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, /* try the driver's ioctl interface */ if (ops->ioctl) { - err = ops->ioctl(class_dev->dev, cmd, arg); + err = ops->ioctl(rtc->dev.parent, cmd, arg); if (err != -ENOIOCTLCMD) return err; } @@ -264,7 +263,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, switch (cmd) { case RTC_ALM_READ: - err = rtc_read_alarm(class_dev, &alarm); + err = rtc_read_alarm(rtc, &alarm); if (err < 0) return err; @@ -278,17 +277,53 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, alarm.enabled = 0; alarm.pending = 0; - alarm.time.tm_mday = -1; - alarm.time.tm_mon = -1; - alarm.time.tm_year = -1; alarm.time.tm_wday = -1; alarm.time.tm_yday = -1; alarm.time.tm_isdst = -1; - err = rtc_set_alarm(class_dev, &alarm); + + /* RTC_ALM_SET alarms may be up to 24 hours in the future. + * Rather than expecting every RTC to implement "don't care" + * for day/month/year fields, just force the alarm to have + * the right values for those fields. + * + * RTC_WKALM_SET should be used instead. Not only does it + * eliminate the need for a separate RTC_AIE_ON call, it + * doesn't have the "alarm 23:59:59 in the future" race. + * + * NOTE: some legacy code may have used invalid fields as + * wildcards, exposing hardware "periodic alarm" capabilities. + * Not supported here. + */ + { + unsigned long now, then; + + err = rtc_read_time(rtc, &tm); + if (err < 0) + return err; + rtc_tm_to_time(&tm, &now); + + alarm.time.tm_mday = tm.tm_mday; + alarm.time.tm_mon = tm.tm_mon; + alarm.time.tm_year = tm.tm_year; + err = rtc_valid_tm(&alarm.time); + if (err < 0) + return err; + rtc_tm_to_time(&alarm.time, &then); + + /* alarm may need to wrap into tomorrow */ + if (then < now) { + rtc_time_to_tm(now + 24 * 60 * 60, &tm); + alarm.time.tm_mday = tm.tm_mday; + alarm.time.tm_mon = tm.tm_mon; + alarm.time.tm_year = tm.tm_year; + } + } + + err = rtc_set_alarm(rtc, &alarm); break; case RTC_RD_TIME: - err = rtc_read_time(class_dev, &tm); + err = rtc_read_time(rtc, &tm); if (err < 0) return err; @@ -300,7 +335,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, if (copy_from_user(&tm, uarg, sizeof(tm))) return -EFAULT; - err = rtc_set_time(class_dev, &tm); + err = rtc_set_time(rtc, &tm); break; case RTC_IRQP_READ: @@ -310,7 +345,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, case RTC_IRQP_SET: if (ops->irq_set_freq) - err = rtc_irq_set_freq(class_dev, rtc->irq_task, arg); + err = rtc_irq_set_freq(rtc, rtc->irq_task, arg); break; #if 0 @@ -336,11 +371,11 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, if (copy_from_user(&alarm, uarg, sizeof(alarm))) return -EFAULT; - err = rtc_set_alarm(class_dev, &alarm); + err = rtc_set_alarm(rtc, &alarm); break; case RTC_WKALM_RD: - err = rtc_read_alarm(class_dev, &alarm); + err = rtc_read_alarm(rtc, &alarm); if (err < 0) return err; @@ -372,7 +407,7 @@ static int rtc_dev_release(struct inode *inode, struct file *file) clear_uie(rtc); #endif if (rtc->ops->release) - rtc->ops->release(rtc->class_dev.dev); + rtc->ops->release(rtc->dev.parent); mutex_unlock(&rtc->char_lock); return 0; @@ -397,17 +432,18 @@ static const struct file_operations rtc_dev_fops = { /* insertion/removal hooks */ -static int rtc_dev_add_device(struct class_device *class_dev, - struct class_interface *class_intf) +void rtc_dev_prepare(struct rtc_device *rtc) { - int err = 0; - struct rtc_device *rtc = to_rtc_device(class_dev); + if (!rtc_devt) + return; if (rtc->id >= RTC_DEV_MAX) { - dev_err(class_dev->dev, "too many RTCs\n"); - return -EINVAL; + pr_debug("%s: too many RTC devices\n", rtc->name); + return; } + rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); + mutex_init(&rtc->char_lock); spin_lock_init(&rtc->irq_lock); init_waitqueue_head(&rtc->irq_queue); @@ -418,100 +454,36 @@ static int rtc_dev_add_device(struct class_device *class_dev, cdev_init(&rtc->char_dev, &rtc_dev_fops); rtc->char_dev.owner = rtc->owner; +} - if (cdev_add(&rtc->char_dev, MKDEV(MAJOR(rtc_devt), rtc->id), 1)) { - dev_err(class_dev->dev, - "failed to add char device %d:%d\n", +void rtc_dev_add_device(struct rtc_device *rtc) +{ + if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1)) + printk(KERN_WARNING "%s: failed to add char device %d:%d\n", + rtc->name, MAJOR(rtc_devt), rtc->id); + else + pr_debug("%s: dev (%d:%d)\n", rtc->name, MAJOR(rtc_devt), rtc->id); - return -ENODEV; - } - - rtc->rtc_dev = class_device_create(rtc_dev_class, NULL, - MKDEV(MAJOR(rtc_devt), rtc->id), - class_dev->dev, "rtc%d", rtc->id); - if (IS_ERR(rtc->rtc_dev)) { - dev_err(class_dev->dev, "cannot create rtc_dev device\n"); - err = PTR_ERR(rtc->rtc_dev); - goto err_cdev_del; - } - - dev_dbg(class_dev->dev, "rtc intf: dev (%d:%d)\n", - MAJOR(rtc->rtc_dev->devt), - MINOR(rtc->rtc_dev->devt)); - - return 0; - -err_cdev_del: - - cdev_del(&rtc->char_dev); - return err; } -static void rtc_dev_remove_device(struct class_device *class_dev, - struct class_interface *class_intf) +void rtc_dev_del_device(struct rtc_device *rtc) { - struct rtc_device *rtc = to_rtc_device(class_dev); - - if (rtc->rtc_dev) { - dev_dbg(class_dev->dev, "removing char %d:%d\n", - MAJOR(rtc->rtc_dev->devt), - MINOR(rtc->rtc_dev->devt)); - - class_device_unregister(rtc->rtc_dev); + if (rtc->dev.devt) cdev_del(&rtc->char_dev); - } } -/* interface registration */ - -static struct class_interface rtc_dev_interface = { - .add = &rtc_dev_add_device, - .remove = &rtc_dev_remove_device, -}; - -static int __init rtc_dev_init(void) +void __init rtc_dev_init(void) { int err; - rtc_dev_class = class_create(THIS_MODULE, "rtc-dev"); - if (IS_ERR(rtc_dev_class)) - return PTR_ERR(rtc_dev_class); - err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); - if (err < 0) { + if (err < 0) printk(KERN_ERR "%s: failed to allocate char dev region\n", __FILE__); - goto err_destroy_class; - } - - err = rtc_interface_register(&rtc_dev_interface); - if (err < 0) { - printk(KERN_ERR "%s: failed to register the interface\n", - __FILE__); - goto err_unregister_chrdev; - } - - return 0; - -err_unregister_chrdev: - unregister_chrdev_region(rtc_devt, RTC_DEV_MAX); - -err_destroy_class: - class_destroy(rtc_dev_class); - - return err; } -static void __exit rtc_dev_exit(void) +void __exit rtc_dev_exit(void) { - class_interface_unregister(&rtc_dev_interface); - class_destroy(rtc_dev_class); - unregister_chrdev_region(rtc_devt, RTC_DEV_MAX); + if (rtc_devt) + unregister_chrdev_region(rtc_devt, RTC_DEV_MAX); } - -subsys_initcall(rtc_dev_init); -module_exit(rtc_dev_exit); - -MODULE_AUTHOR("Alessandro Zummo "); -MODULE_DESCRIPTION("RTC class dev interface"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/rtc/rtc-ds1553.c b/trunk/drivers/rtc/rtc-ds1553.c index e27176c0e18f..afa64c7fa2e2 100644 --- a/trunk/drivers/rtc/rtc-ds1553.c +++ b/trunk/drivers/rtc/rtc-ds1553.c @@ -203,7 +203,7 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id) events |= RTC_UF; else events |= RTC_AF; - rtc_update_irq(&pdata->rtc->class_dev, 1, events); + rtc_update_irq(pdata->rtc, 1, events); return IRQ_HANDLED; } diff --git a/trunk/drivers/rtc/rtc-lib.c b/trunk/drivers/rtc/rtc-lib.c index 7bbc26a34bd2..ba795a4db1e9 100644 --- a/trunk/drivers/rtc/rtc-lib.c +++ b/trunk/drivers/rtc/rtc-lib.c @@ -117,85 +117,4 @@ int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) } EXPORT_SYMBOL(rtc_tm_to_time); - -/* Merge the valid (i.e. non-negative) fields of alarm into the current - * time. If the valid alarm fields are earlier than the equivalent - * fields in the time, carry one into the least significant invalid - * field, so that the alarm expiry is in the future. It assumes that the - * least significant invalid field is more significant than the most - * significant valid field, and that the seconds field is valid. - * - * This is used by alarms that take relative (rather than absolute) - * times, and/or have a simple binary second counter instead of - * day/hour/minute/sec registers. - */ -void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm) -{ - int *alarmp = &alarm->tm_sec; - int *timep = &now->tm_sec; - int carry_into, i; - - /* Ignore everything past the 6th element (tm_year). */ - for (i = 5; i > 0; i--) { - if (alarmp[i] < 0) - alarmp[i] = timep[i]; - else - break; - } - - /* No carry needed if all fields are valid. */ - if (i == 5) - return; - - for (carry_into = i + 1; i >= 0; i--) { - if (alarmp[i] < timep[i]) - break; - - if (alarmp[i] > timep[i]) - return; - } - - switch (carry_into) { - case 1: - alarm->tm_min++; - - if (alarm->tm_min < 60) - return; - - alarm->tm_min = 0; - /* fall-through */ - - case 2: - alarm->tm_hour++; - - if (alarm->tm_hour < 60) - return; - - alarm->tm_hour = 0; - /* fall-through */ - - case 3: - alarm->tm_mday++; - - if (alarm->tm_mday <= rtc_days_in_month[alarm->tm_mon]) - return; - - alarm->tm_mday = 1; - /* fall-through */ - - case 4: - alarm->tm_mon++; - - if (alarm->tm_mon <= 12) - return; - - alarm->tm_mon = 1; - /* fall-through */ - - case 5: - alarm->tm_year++; - } -} -EXPORT_SYMBOL(rtc_merge_alarm); - MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/rtc/rtc-max6900.c b/trunk/drivers/rtc/rtc-max6900.c new file mode 100644 index 000000000000..eee4ee5bb75a --- /dev/null +++ b/trunk/drivers/rtc/rtc-max6900.c @@ -0,0 +1,311 @@ +/* + * rtc class driver for the Maxim MAX6900 chip + * + * Author: Dale Farnsworth + * + * based on previously existing rtc class drivers + * + * 2007 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include + +#define DRV_NAME "max6900" +#define DRV_VERSION "0.1" + +/* + * register indices + */ +#define MAX6900_REG_SC 0 /* seconds 00-59 */ +#define MAX6900_REG_MN 1 /* minutes 00-59 */ +#define MAX6900_REG_HR 2 /* hours 00-23 */ +#define MAX6900_REG_DT 3 /* day of month 00-31 */ +#define MAX6900_REG_MO 4 /* month 01-12 */ +#define MAX6900_REG_DW 5 /* day of week 1-7 */ +#define MAX6900_REG_YR 6 /* year 00-99 */ +#define MAX6900_REG_CT 7 /* control */ +#define MAX6900_REG_LEN 8 + +#define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */ + +/* + * register read/write commands + */ +#define MAX6900_REG_CONTROL_WRITE 0x8e +#define MAX6900_REG_BURST_READ 0xbf +#define MAX6900_REG_BURST_WRITE 0xbe +#define MAX6900_REG_RESERVED_READ 0x96 + +#define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */ + +#define MAX6900_I2C_ADDR 0xa0 + +static unsigned short normal_i2c[] = { + MAX6900_I2C_ADDR >> 1, + I2C_CLIENT_END +}; + +I2C_CLIENT_INSMOD; /* defines addr_data */ + +static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind); + +static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf) +{ + u8 reg_addr[1] = { MAX6900_REG_BURST_READ }; + struct i2c_msg msgs[2] = { + { + .addr = client->addr, + .flags = 0, /* write */ + .len = sizeof(reg_addr), + .buf = reg_addr + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = MAX6900_REG_LEN, + .buf = buf + } + }; + int rc; + + rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (rc != ARRAY_SIZE(msgs)) { + dev_err(&client->dev, "%s: register read failed\n", + __FUNCTION__); + return -EIO; + } + return 0; +} + +static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf) +{ + u8 i2c_buf[MAX6900_REG_LEN + 1] = { MAX6900_REG_BURST_WRITE }; + struct i2c_msg msgs[1] = { + { + .addr = client->addr, + .flags = 0, /* write */ + .len = MAX6900_REG_LEN + 1, + .buf = i2c_buf + } + }; + int rc; + + memcpy(&i2c_buf[1], buf, MAX6900_REG_LEN); + + rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (rc != ARRAY_SIZE(msgs)) { + dev_err(&client->dev, "%s: register write failed\n", + __FUNCTION__); + return -EIO; + } + msleep(MAX6900_IDLE_TIME_AFTER_WRITE); + return 0; +} + +static int max6900_i2c_validate_client(struct i2c_client *client) +{ + u8 regs[MAX6900_REG_LEN]; + u8 zero_mask[MAX6900_REG_LEN] = { + 0x80, /* seconds */ + 0x80, /* minutes */ + 0x40, /* hours */ + 0xc0, /* day of month */ + 0xe0, /* month */ + 0xf8, /* day of week */ + 0x00, /* year */ + 0x7f, /* control */ + }; + int i; + int rc; + int reserved; + + reserved = i2c_smbus_read_byte_data(client, MAX6900_REG_RESERVED_READ); + if (reserved != 0x07) + return -ENODEV; + + rc = max6900_i2c_read_regs(client, regs); + if (rc < 0) + return rc; + + for (i = 0; i < MAX6900_REG_LEN; ++i) { + if (regs[i] & zero_mask[i]) + return -ENODEV; + } + + return 0; +} + +static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) +{ + int rc; + u8 regs[MAX6900_REG_LEN]; + + rc = max6900_i2c_read_regs(client, regs); + if (rc < 0) + return rc; + + tm->tm_sec = BCD2BIN(regs[MAX6900_REG_SC]); + tm->tm_min = BCD2BIN(regs[MAX6900_REG_MN]); + tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f); + tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]); + tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1; + tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + 100; + tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]); + + return 0; +} + +static int max6900_i2c_clear_write_protect(struct i2c_client *client) +{ + int rc; + rc = i2c_smbus_write_byte_data (client, MAX6900_REG_CONTROL_WRITE, 0); + if (rc < 0) { + dev_err(&client->dev, "%s: control register write failed\n", + __FUNCTION__); + return -EIO; + } + return 0; +} + +static int max6900_i2c_set_time(struct i2c_client *client, + struct rtc_time const *tm) +{ + u8 regs[MAX6900_REG_LEN]; + int rc; + + rc = max6900_i2c_clear_write_protect(client); + if (rc < 0) + return rc; + + regs[MAX6900_REG_SC] = BIN2BCD(tm->tm_sec); + regs[MAX6900_REG_MN] = BIN2BCD(tm->tm_min); + regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour); + regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday); + regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1); + regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year - 100); + regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday); + regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP; /* set write protect */ + + rc = max6900_i2c_write_regs(client, regs); + if (rc < 0) + return rc; + + return 0; +} + +static int max6900_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + return max6900_i2c_read_time(to_i2c_client(dev), tm); +} + +static int max6900_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + return max6900_i2c_set_time(to_i2c_client(dev), tm); +} + +static int max6900_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_probe(adapter, &addr_data, max6900_probe); +} + +static int max6900_detach_client(struct i2c_client *client) +{ + struct rtc_device *const rtc = i2c_get_clientdata(client); + + if (rtc) + rtc_device_unregister(rtc); + + return i2c_detach_client(client); +} + +static struct i2c_driver max6900_driver = { + .driver = { + .name = DRV_NAME, + }, + .id = I2C_DRIVERID_MAX6900, + .attach_adapter = max6900_attach_adapter, + .detach_client = max6900_detach_client, +}; + +static const struct rtc_class_ops max6900_rtc_ops = { + .read_time = max6900_rtc_read_time, + .set_time = max6900_rtc_set_time, +}; + +static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind) +{ + int rc = 0; + struct i2c_client *client = NULL; + struct rtc_device *rtc = NULL; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + rc = -ENODEV; + goto failout; + } + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == NULL) { + rc = -ENOMEM; + goto failout; + } + + client->addr = addr; + client->adapter = adapter; + client->driver = &max6900_driver; + strlcpy(client->name, DRV_NAME, I2C_NAME_SIZE); + + if (kind < 0) { + rc = max6900_i2c_validate_client(client); + if (rc < 0) + goto failout; + } + + rc = i2c_attach_client(client); + if (rc < 0) + goto failout; + + dev_info(&client->dev, + "chip found, driver version " DRV_VERSION "\n"); + + rtc = rtc_device_register(max6900_driver.driver.name, + &client->dev, + &max6900_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + rc = PTR_ERR(rtc); + goto failout_detach; + } + + i2c_set_clientdata(client, rtc); + + return 0; + +failout_detach: + i2c_detach_client(client); +failout: + kfree(client); + return rc; +} + +static int __init max6900_init(void) +{ + return i2c_add_driver(&max6900_driver); +} + +static void __exit max6900_exit(void) +{ + i2c_del_driver(&max6900_driver); +} + +MODULE_DESCRIPTION("Maxim MAX6900 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(max6900_init); +module_exit(max6900_exit); diff --git a/trunk/drivers/rtc/rtc-omap.c b/trunk/drivers/rtc/rtc-omap.c index 9de8d67f4f8d..60a8a4bb8bd2 100644 --- a/trunk/drivers/rtc/rtc-omap.c +++ b/trunk/drivers/rtc/rtc-omap.c @@ -124,7 +124,7 @@ static void rtc_wait_not_busy(void) /* now we have ~15 usec to read/write various registers */ } -static irqreturn_t rtc_irq(int irq, void *class_dev) +static irqreturn_t rtc_irq(int irq, void *rtc) { unsigned long events = 0; u8 irq_data; @@ -141,7 +141,7 @@ static irqreturn_t rtc_irq(int irq, void *class_dev) if (irq_data & OMAP_RTC_STATUS_1S_EVENT) events |= RTC_IRQF | RTC_UF; - rtc_update_irq(class_dev, 1, events); + rtc_update_irq(rtc, 1, events); return IRQ_HANDLED; } @@ -289,34 +289,6 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { u8 reg; - /* Much userspace code uses RTC_ALM_SET, thus "don't care" for - * day/month/year specifies alarms up to 24 hours in the future. - * So we need to handle that ... but let's ignore the "don't care" - * values for hours/minutes/seconds. - */ - if (alm->time.tm_mday <= 0 - && alm->time.tm_mon < 0 - && alm->time.tm_year < 0) { - struct rtc_time tm; - unsigned long now, then; - - omap_rtc_read_time(dev, &tm); - rtc_tm_to_time(&tm, &now); - - alm->time.tm_mday = tm.tm_mday; - alm->time.tm_mon = tm.tm_mon; - alm->time.tm_year = tm.tm_year; - rtc_tm_to_time(&alm->time, &then); - - /* sometimes the alarm wraps into tomorrow */ - if (then < now) { - rtc_time_to_tm(now + 24 * 60 * 60, &tm); - alm->time.tm_mday = tm.tm_mday; - alm->time.tm_mon = tm.tm_mon; - alm->time.tm_year = tm.tm_year; - } - } - if (tm2bcd(&alm->time) < 0) return -EINVAL; @@ -399,7 +371,7 @@ static int __devinit omap_rtc_probe(struct platform_device *pdev) goto fail; } platform_set_drvdata(pdev, rtc); - class_set_devdata(&rtc->class_dev, mem); + dev_set_devdata(&rtc->dev, mem); /* clear pending irqs, and set 1/second periodic, * which we'll use instead of update irqs @@ -418,13 +390,13 @@ static int __devinit omap_rtc_probe(struct platform_device *pdev) /* handle periodic and alarm irqs */ if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED, - rtc->class_dev.class_id, &rtc->class_dev)) { + rtc->dev.bus_id, rtc)) { pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n", pdev->name, omap_rtc_timer); goto fail0; } if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED, - rtc->class_dev.class_id, &rtc->class_dev)) { + rtc->dev.bus_id, rtc)) { pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n", pdev->name, omap_rtc_alarm); goto fail1; @@ -481,26 +453,17 @@ static int __devexit omap_rtc_remove(struct platform_device *pdev) free_irq(omap_rtc_timer, rtc); free_irq(omap_rtc_alarm, rtc); - release_resource(class_get_devdata(&rtc->class_dev)); + release_resource(dev_get_devdata(&rtc->dev)); rtc_device_unregister(rtc); return 0; } #ifdef CONFIG_PM -static struct timespec rtc_delta; static u8 irqstat; static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state) { - struct rtc_time rtc_tm; - struct timespec time; - - time.tv_nsec = 0; - omap_rtc_read_time(NULL, &rtc_tm); - rtc_tm_to_time(&rtc_tm, &time.tv_sec); - - save_time_delta(&rtc_delta, &time); irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG); /* FIXME the RTC alarm is not currently acting as a wakeup event @@ -517,14 +480,6 @@ static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state) static int omap_rtc_resume(struct platform_device *pdev) { - struct rtc_time rtc_tm; - struct timespec time; - - time.tv_nsec = 0; - omap_rtc_read_time(NULL, &rtc_tm); - rtc_tm_to_time(&rtc_tm, &time.tv_sec); - - restore_time_delta(&rtc_delta, &time); if (device_may_wakeup(&pdev->dev)) disable_irq_wake(omap_rtc_alarm); else diff --git a/trunk/drivers/rtc/rtc-pl031.c b/trunk/drivers/rtc/rtc-pl031.c index f13daa9fecaa..e4bf68ca96f7 100644 --- a/trunk/drivers/rtc/rtc-pl031.c +++ b/trunk/drivers/rtc/rtc-pl031.c @@ -51,7 +51,7 @@ static irqreturn_t pl031_interrupt(int irq, void *dev_id) { struct rtc_device *rtc = dev_id; - rtc_update_irq(&rtc->class_dev, 1, RTC_AF); + rtc_update_irq(rtc, 1, RTC_AF); return IRQ_HANDLED; } diff --git a/trunk/drivers/rtc/rtc-proc.c b/trunk/drivers/rtc/rtc-proc.c index 1bd624fc685c..8d300e6d0d9e 100644 --- a/trunk/drivers/rtc/rtc-proc.c +++ b/trunk/drivers/rtc/rtc-proc.c @@ -16,18 +16,18 @@ #include #include -static struct class_device *rtc_dev = NULL; -static DEFINE_MUTEX(rtc_lock); +#include "rtc-core.h" + static int rtc_proc_show(struct seq_file *seq, void *offset) { int err; - struct class_device *class_dev = seq->private; - const struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops; + struct rtc_device *rtc = seq->private; + const struct rtc_class_ops *ops = rtc->ops; struct rtc_wkalrm alrm; struct rtc_time tm; - err = rtc_read_time(class_dev, &tm); + err = rtc_read_time(rtc, &tm); if (err == 0) { seq_printf(seq, "rtc_time\t: %02d:%02d:%02d\n" @@ -36,7 +36,7 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); } - err = rtc_read_alarm(class_dev, &alrm); + err = rtc_read_alarm(rtc, &alrm); if (err == 0) { seq_printf(seq, "alrm_time\t: "); if ((unsigned int)alrm.time.tm_hour <= 24) @@ -74,19 +74,19 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) seq_printf(seq, "24hr\t\t: yes\n"); if (ops->proc) - ops->proc(class_dev->dev, seq); + ops->proc(rtc->dev.parent, seq); return 0; } static int rtc_proc_open(struct inode *inode, struct file *file) { - struct class_device *class_dev = PDE(inode)->data; + struct rtc_device *rtc = PDE(inode)->data; if (!try_module_get(THIS_MODULE)) return -ENODEV; - return single_open(file, rtc_proc_show, class_dev); + return single_open(file, rtc_proc_show, rtc); } static int rtc_proc_release(struct inode *inode, struct file *file) @@ -103,62 +103,22 @@ static const struct file_operations rtc_proc_fops = { .release = rtc_proc_release, }; -static int rtc_proc_add_device(struct class_device *class_dev, - struct class_interface *class_intf) +void rtc_proc_add_device(struct rtc_device *rtc) { - mutex_lock(&rtc_lock); - if (rtc_dev == NULL) { + if (rtc->id == 0) { struct proc_dir_entry *ent; - rtc_dev = class_dev; - ent = create_proc_entry("driver/rtc", 0, NULL); if (ent) { - struct rtc_device *rtc = to_rtc_device(class_dev); - ent->proc_fops = &rtc_proc_fops; ent->owner = rtc->owner; - ent->data = class_dev; - - dev_dbg(class_dev->dev, "rtc intf: proc\n"); + ent->data = rtc; } - else - rtc_dev = NULL; } - mutex_unlock(&rtc_lock); - - return 0; } -static void rtc_proc_remove_device(struct class_device *class_dev, - struct class_interface *class_intf) +void rtc_proc_del_device(struct rtc_device *rtc) { - mutex_lock(&rtc_lock); - if (rtc_dev == class_dev) { + if (rtc->id == 0) remove_proc_entry("driver/rtc", NULL); - rtc_dev = NULL; - } - mutex_unlock(&rtc_lock); -} - -static struct class_interface rtc_proc_interface = { - .add = &rtc_proc_add_device, - .remove = &rtc_proc_remove_device, -}; - -static int __init rtc_proc_init(void) -{ - return rtc_interface_register(&rtc_proc_interface); } - -static void __exit rtc_proc_exit(void) -{ - class_interface_unregister(&rtc_proc_interface); -} - -subsys_initcall(rtc_proc_init); -module_exit(rtc_proc_exit); - -MODULE_AUTHOR("Alessandro Zummo "); -MODULE_DESCRIPTION("RTC class proc interface"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/rtc/rtc-rs5c313.c b/trunk/drivers/rtc/rtc-rs5c313.c new file mode 100644 index 000000000000..9d6de371495b --- /dev/null +++ b/trunk/drivers/rtc/rtc-rs5c313.c @@ -0,0 +1,405 @@ +/* + * Ricoh RS5C313 RTC device/driver + * Copyright (C) 2007 Nobuhiro Iwamatsu + * + * 2005-09-19 modifed by kogiidena + * + * Based on the old drivers/char/rs5c313_rtc.c by: + * Copyright (C) 2000 Philipp Rumpf + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka + * + * Based on code written by Paul Gortmaker. + * Copyright (C) 1996 Paul Gortmaker + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Based on other minimal char device drivers, like Alan's + * watchdog, Ted's random, etc. etc. + * + * 1.07 Paul Gortmaker. + * 1.08 Miquel van Smoorenburg: disallow certain things on the + * DEC Alpha as the CMOS clock is also used for other things. + * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. + * 1.09a Pete Zaitcev: Sun SPARC + * 1.09b Jeff Garzik: Modularize, init cleanup + * 1.09c Jeff Garzik: SMP cleanup + * 1.10 Paul Barton-Davis: add support for async I/O + * 1.10a Andrea Arcangeli: Alpha updates + * 1.10b Andrew Morton: SMP lock fix + * 1.10c Cesar Barros: SMP locking fixes and cleanup + * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit + * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness. + * 1.11 Takashi Iwai: Kernel access functions + * rtc_register/rtc_unregister/rtc_control + * 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init + * 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer + * CONFIG_HPET_EMULATE_RTC + * 1.13 Nobuhiro Iwamatsu: Updata driver. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "rs5c313" +#define DRV_VERSION "1.13" + +#ifdef CONFIG_SH_LANDISK +/*****************************************************/ +/* LANDISK dependence part of RS5C313 */ +/*****************************************************/ + +#define SCSMR1 0xFFE00000 +#define SCSCR1 0xFFE00008 +#define SCSMR1_CA 0x80 +#define SCSCR1_CKE 0x03 +#define SCSPTR1 0xFFE0001C +#define SCSPTR1_EIO 0x80 +#define SCSPTR1_SPB1IO 0x08 +#define SCSPTR1_SPB1DT 0x04 +#define SCSPTR1_SPB0IO 0x02 +#define SCSPTR1_SPB0DT 0x01 + +#define SDA_OEN SCSPTR1_SPB1IO +#define SDA SCSPTR1_SPB1DT +#define SCL_OEN SCSPTR1_SPB0IO +#define SCL SCSPTR1_SPB0DT + +/* RICOH RS5C313 CE port */ +#define RS5C313_CE 0xB0000003 + +/* RICOH RS5C313 CE port bit */ +#define RS5C313_CE_RTCCE 0x02 + +/* SCSPTR1 data */ +unsigned char scsptr1_data; + +#define RS5C313_CEENABLE ctrl_outb(RS5C313_CE_RTCCE, RS5C313_CE); +#define RS5C313_CEDISABLE ctrl_outb(0x00, RS5C313_CE) +#define RS5C313_MISCOP ctrl_outb(0x02, 0xB0000008) + +static void rs5c313_init_port(void) +{ + /* Set SCK as I/O port and Initialize SCSPTR1 data & I/O port. */ + ctrl_outb(ctrl_inb(SCSMR1) & ~SCSMR1_CA, SCSMR1); + ctrl_outb(ctrl_inb(SCSCR1) & ~SCSCR1_CKE, SCSCR1); + + /* And Initialize SCL for RS5C313 clock */ + scsptr1_data = ctrl_inb(SCSPTR1) | SCL; /* SCL:H */ + ctrl_outb(scsptr1_data, SCSPTR1); + scsptr1_data = ctrl_inb(SCSPTR1) | SCL_OEN; /* SCL output enable */ + ctrl_outb(scsptr1_data, SCSPTR1); + RS5C313_CEDISABLE; /* CE:L */ +} + +static void rs5c313_write_data(unsigned char data) +{ + int i; + + for (i = 0; i < 8; i++) { + /* SDA:Write Data */ + scsptr1_data = (scsptr1_data & ~SDA) | + ((((0x80 >> i) & data) >> (7 - i)) << 2); + ctrl_outb(scsptr1_data, SCSPTR1); + if (i == 0) { + scsptr1_data |= SDA_OEN; /* SDA:output enable */ + ctrl_outb(scsptr1_data, SCSPTR1); + } + ndelay(700); + scsptr1_data &= ~SCL; /* SCL:L */ + ctrl_outb(scsptr1_data, SCSPTR1); + ndelay(700); + scsptr1_data |= SCL; /* SCL:H */ + ctrl_outb(scsptr1_data, SCSPTR1); + } + + scsptr1_data &= ~SDA_OEN; /* SDA:output disable */ + ctrl_outb(scsptr1_data, SCSPTR1); +} + +static unsigned char rs5c313_read_data(void) +{ + int i; + unsigned char data; + + for (i = 0; i < 8; i++) { + ndelay(700); + /* SDA:Read Data */ + data |= ((ctrl_inb(SCSPTR1) & SDA) >> 2) << (7 - i); + scsptr1_data &= ~SCL; /* SCL:L */ + ctrl_outb(scsptr1_data, SCSPTR1); + ndelay(700); + scsptr1_data |= SCL; /* SCL:H */ + ctrl_outb(scsptr1_data, SCSPTR1); + } + return data & 0x0F; +} + +#endif /* CONFIG_SH_LANDISK */ + +/*****************************************************/ +/* machine independence part of RS5C313 */ +/*****************************************************/ + +/* RICOH RS5C313 address */ +#define RS5C313_ADDR_SEC 0x00 +#define RS5C313_ADDR_SEC10 0x01 +#define RS5C313_ADDR_MIN 0x02 +#define RS5C313_ADDR_MIN10 0x03 +#define RS5C313_ADDR_HOUR 0x04 +#define RS5C313_ADDR_HOUR10 0x05 +#define RS5C313_ADDR_WEEK 0x06 +#define RS5C313_ADDR_INTINTVREG 0x07 +#define RS5C313_ADDR_DAY 0x08 +#define RS5C313_ADDR_DAY10 0x09 +#define RS5C313_ADDR_MON 0x0A +#define RS5C313_ADDR_MON10 0x0B +#define RS5C313_ADDR_YEAR 0x0C +#define RS5C313_ADDR_YEAR10 0x0D +#define RS5C313_ADDR_CNTREG 0x0E +#define RS5C313_ADDR_TESTREG 0x0F + +/* RICOH RS5C313 control register */ +#define RS5C313_CNTREG_ADJ_BSY 0x01 +#define RS5C313_CNTREG_WTEN_XSTP 0x02 +#define RS5C313_CNTREG_12_24 0x04 +#define RS5C313_CNTREG_CTFG 0x08 + +/* RICOH RS5C313 test register */ +#define RS5C313_TESTREG_TEST 0x01 + +/* RICOH RS5C313 control bit */ +#define RS5C313_CNTBIT_READ 0x40 +#define RS5C313_CNTBIT_AD 0x20 +#define RS5C313_CNTBIT_DT 0x10 + +static unsigned char rs5c313_read_reg(unsigned char addr) +{ + + rs5c313_write_data(addr | RS5C313_CNTBIT_READ | RS5C313_CNTBIT_AD); + return rs5c313_read_data(); +} + +static void rs5c313_write_reg(unsigned char addr, unsigned char data) +{ + data &= 0x0f; + rs5c313_write_data(addr | RS5C313_CNTBIT_AD); + rs5c313_write_data(data | RS5C313_CNTBIT_DT); + return; +} + +static inline unsigned char rs5c313_read_cntreg(unsigned char addr) +{ + return rs5c313_read_reg(RS5C313_ADDR_CNTREG); +} + +static inline void rs5c313_write_cntreg(unsigned char data) +{ + rs5c313_write_reg(RS5C313_ADDR_CNTREG, data); +} + +static inline void rs5c313_write_intintvreg(unsigned char data) +{ + rs5c313_write_reg(RS5C313_ADDR_INTINTVREG, data); +} + +static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + int data; + + while (1) { + RS5C313_CEENABLE; /* CE:H */ + + /* Initialize control reg. 24 hour */ + rs5c313_write_cntreg(0x04); + + if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY)) + break; + + RS5C313_CEDISABLE; + ndelay(700); /* CE:L */ + + } + + data = rs5c313_read_reg(RS5C313_ADDR_SEC); + data |= (rs5c313_read_reg(RS5C313_ADDR_SEC10) << 4); + tm->tm_sec = BCD2BIN(data); + + data = rs5c313_read_reg(RS5C313_ADDR_MIN); + data |= (rs5c313_read_reg(RS5C313_ADDR_MIN10) << 4); + tm->tm_min = BCD2BIN(data); + + data = rs5c313_read_reg(RS5C313_ADDR_HOUR); + data |= (rs5c313_read_reg(RS5C313_ADDR_HOUR10) << 4); + tm->tm_hour = BCD2BIN(data); + + data = rs5c313_read_reg(RS5C313_ADDR_DAY); + data |= (rs5c313_read_reg(RS5C313_ADDR_DAY10) << 4); + tm->tm_mday = BCD2BIN(data); + + data = rs5c313_read_reg(RS5C313_ADDR_MON); + data |= (rs5c313_read_reg(RS5C313_ADDR_MON10) << 4); + tm->tm_mon = BCD2BIN(data) - 1; + + data = rs5c313_read_reg(RS5C313_ADDR_YEAR); + data |= (rs5c313_read_reg(RS5C313_ADDR_YEAR10) << 4); + tm->tm_year = BCD2BIN(data); + + if (tm->tm_year < 70) + tm->tm_year += 100; + + data = rs5c313_read_reg(RS5C313_ADDR_WEEK); + tm->tm_wday = BCD2BIN(data); + + RS5C313_CEDISABLE; + ndelay(700); /* CE:L */ + + return 0; +} + +static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + int data; + + /* busy check. */ + while (1) { + RS5C313_CEENABLE; /* CE:H */ + + /* Initiatlize control reg. 24 hour */ + rs5c313_write_cntreg(0x04); + + if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY)) + break; + RS5C313_MISCOP; + RS5C313_CEDISABLE; + ndelay(700); /* CE:L */ + } + + data = BIN2BCD(tm->tm_sec); + rs5c313_write_reg(RS5C313_ADDR_SEC, data); + rs5c313_write_reg(RS5C313_ADDR_SEC10, (data >> 4)); + + data = BIN2BCD(tm->tm_min); + rs5c313_write_reg(RS5C313_ADDR_MIN, data ); + rs5c313_write_reg(RS5C313_ADDR_MIN10, (data >> 4)); + + data = BIN2BCD(tm->tm_hour); + rs5c313_write_reg(RS5C313_ADDR_HOUR, data); + rs5c313_write_reg(RS5C313_ADDR_HOUR10, (data >> 4)); + + data = BIN2BCD(tm->tm_mday); + rs5c313_write_reg(RS5C313_ADDR_DAY, data); + rs5c313_write_reg(RS5C313_ADDR_DAY10, (data>> 4)); + + data = BIN2BCD(tm->tm_mon + 1); + rs5c313_write_reg(RS5C313_ADDR_MON, data); + rs5c313_write_reg(RS5C313_ADDR_MON10, (data >> 4)); + + data = BIN2BCD(tm->tm_year % 100); + rs5c313_write_reg(RS5C313_ADDR_YEAR, data); + rs5c313_write_reg(RS5C313_ADDR_YEAR10, (data >> 4)); + + data = BIN2BCD(tm->tm_wday); + rs5c313_write_reg(RS5C313_ADDR_WEEK, data); + + RS5C313_CEDISABLE; /* CE:H */ + ndelay(700); + + return 0; +} + +static void rs5c313_check_xstp_bit(void) +{ + struct rtc_time tm; + + RS5C313_CEENABLE; /* CE:H */ + if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) { + /* INT interval reg. OFF */ + rs5c313_write_intintvreg(0x00); + /* Initialize control reg. 24 hour & adjust */ + rs5c313_write_cntreg(0x07); + + /* busy check. */ + while (rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY) + RS5C313_MISCOP; + + memset(&tm, 0, sizeof(struct rtc_time)); + tm.tm_mday = 1; + tm.tm_mon = 1; + + rs5c313_rtc_set_time(NULL, &tm); + printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to " + "1 Jan 2000\n"); + } + RS5C313_CEDISABLE; + ndelay(700); /* CE:L */ +} + +static const struct rtc_class_ops rs5c313_rtc_ops = { + .read_time = rs5c313_rtc_read_time, + .set_time = rs5c313_rtc_set_time, +}; + +static int rs5c313_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc = rtc_device_register("rs5c313", &pdev->dev, + &rs5c313_rtc_ops, THIS_MODULE); + + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + platform_set_drvdata(pdev, rtc); + + return err; +} + +static int __devexit rs5c313_rtc_remove(struct platform_device *pdev) +{ + struct rtc_device *rtc = platform_get_drvdata( pdev ); + + rtc_device_unregister(rtc); + + return 0; +} + +static struct platform_driver rs5c313_rtc_platform_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = rs5c313_rtc_probe, + .remove = __devexit_p( rs5c313_rtc_remove ), +}; + +static int __init rs5c313_rtc_init(void) +{ + int err; + + err = platform_driver_register(&rs5c313_rtc_platform_driver); + if (err) + return err; + + rs5c313_init_port(); + rs5c313_check_xstp_bit(); + + return 0; +} + +static void __exit rs5c313_rtc_exit(void) +{ + platform_driver_unregister( &rs5c313_rtc_platform_driver ); +} + +module_init(rs5c313_rtc_init); +module_exit(rs5c313_rtc_exit); + +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR("kogiidena , Nobuhiro Iwamatsu "); +MODULE_DESCRIPTION("Ricoh RS5C313 RTC device driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/rtc/rtc-s3c.c b/trunk/drivers/rtc/rtc-s3c.c index 9a79a24a7487..54b613053468 100644 --- a/trunk/drivers/rtc/rtc-s3c.c +++ b/trunk/drivers/rtc/rtc-s3c.c @@ -50,7 +50,7 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) { struct rtc_device *rdev = id; - rtc_update_irq(&rdev->class_dev, 1, RTC_AF | RTC_IRQF); + rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); return IRQ_HANDLED; } @@ -58,7 +58,7 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id) { struct rtc_device *rdev = id; - rtc_update_irq(&rdev->class_dev, tick_count++, RTC_PF | RTC_IRQF); + rtc_update_irq(rdev, tick_count++, RTC_PF | RTC_IRQF); return IRQ_HANDLED; } @@ -548,37 +548,15 @@ static int ticnt_save; static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) { - struct rtc_time tm; - struct timespec time; - - time.tv_nsec = 0; - /* save TICNT for anyone using periodic interrupts */ - ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); - - /* calculate time delta for suspend */ - - s3c_rtc_gettime(&pdev->dev, &tm); - rtc_tm_to_time(&tm, &time.tv_sec); - save_time_delta(&s3c_rtc_delta, &time); s3c_rtc_enable(pdev, 0); - return 0; } static int s3c_rtc_resume(struct platform_device *pdev) { - struct rtc_time tm; - struct timespec time; - - time.tv_nsec = 0; - s3c_rtc_enable(pdev, 1); - s3c_rtc_gettime(&pdev->dev, &tm); - rtc_tm_to_time(&tm, &time.tv_sec); - restore_time_delta(&s3c_rtc_delta, &time); - writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); return 0; } diff --git a/trunk/drivers/rtc/rtc-sa1100.c b/trunk/drivers/rtc/rtc-sa1100.c index 677bae820dc3..0918b787c4dd 100644 --- a/trunk/drivers/rtc/rtc-sa1100.c +++ b/trunk/drivers/rtc/rtc-sa1100.c @@ -93,7 +93,7 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) if (rtsr & RTSR_HZ) events |= RTC_UF | RTC_IRQF; - rtc_update_irq(&rtc->class_dev, 1, events); + rtc_update_irq(rtc, 1, events); if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm)) rtc_update_alarm(&rtc_alarm); @@ -119,7 +119,7 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id) */ OSSR = OSSR_M1; /* clear match on timer1 */ - rtc_update_irq(&rtc->class_dev, rtc_timer1_count, RTC_PF | RTC_IRQF); + rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF); if (rtc_timer1_count == 1) rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))); diff --git a/trunk/drivers/rtc/rtc-sh.c b/trunk/drivers/rtc/rtc-sh.c index 198b9f22fbff..6abf4811958c 100644 --- a/trunk/drivers/rtc/rtc-sh.c +++ b/trunk/drivers/rtc/rtc-sh.c @@ -104,7 +104,7 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) writeb(tmp, rtc->regbase + RCR1); - rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events); + rtc_update_irq(&rtc->rtc_dev, 1, events); spin_unlock(&rtc->lock); @@ -139,7 +139,7 @@ static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) rtc->rearm_aie = 1; - rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events); + rtc_update_irq(&rtc->rtc_dev, 1, events); } spin_unlock(&rtc->lock); @@ -153,7 +153,7 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) spin_lock(&rtc->lock); - rtc_update_irq(&rtc->rtc_dev->class_dev, 1, RTC_PF | RTC_IRQF); + rtc_update_irq(&rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); spin_unlock(&rtc->lock); diff --git a/trunk/drivers/rtc/rtc-sysfs.c b/trunk/drivers/rtc/rtc-sysfs.c index 899ab8c514fa..69df94b44841 100644 --- a/trunk/drivers/rtc/rtc-sysfs.c +++ b/trunk/drivers/rtc/rtc-sysfs.c @@ -12,20 +12,26 @@ #include #include +#include "rtc-core.h" + + /* device attributes */ -static ssize_t rtc_sysfs_show_name(struct class_device *dev, char *buf) +static ssize_t +rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr, + char *buf) { return sprintf(buf, "%s\n", to_rtc_device(dev)->name); } -static CLASS_DEVICE_ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL); -static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf) +static ssize_t +rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr, + char *buf) { ssize_t retval; struct rtc_time tm; - retval = rtc_read_time(dev, &tm); + retval = rtc_read_time(to_rtc_device(dev), &tm); if (retval == 0) { retval = sprintf(buf, "%04d-%02d-%02d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); @@ -33,14 +39,15 @@ static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf) return retval; } -static CLASS_DEVICE_ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL); -static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf) +static ssize_t +rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr, + char *buf) { ssize_t retval; struct rtc_time tm; - retval = rtc_read_time(dev, &tm); + retval = rtc_read_time(to_rtc_device(dev), &tm); if (retval == 0) { retval = sprintf(buf, "%02d:%02d:%02d\n", tm.tm_hour, tm.tm_min, tm.tm_sec); @@ -48,14 +55,15 @@ static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf) return retval; } -static CLASS_DEVICE_ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL); -static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf) +static ssize_t +rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr, + char *buf) { ssize_t retval; struct rtc_time tm; - retval = rtc_read_time(dev, &tm); + retval = rtc_read_time(to_rtc_device(dev), &tm); if (retval == 0) { unsigned long time; rtc_tm_to_time(&tm, &time); @@ -64,23 +72,18 @@ static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf) return retval; } -static CLASS_DEVICE_ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL); - -static struct attribute *rtc_attrs[] = { - &class_device_attr_name.attr, - &class_device_attr_date.attr, - &class_device_attr_time.attr, - &class_device_attr_since_epoch.attr, - NULL, -}; -static struct attribute_group rtc_attr_group = { - .attrs = rtc_attrs, +static struct device_attribute rtc_attrs[] = { + __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL), + __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL), + __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL), + __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL), + { }, }; - static ssize_t -rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf) +rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, + char *buf) { ssize_t retval; unsigned long alarm; @@ -94,7 +97,7 @@ rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf) * REVISIT maybe we should require RTC implementations to * disable the RTC alarm after it triggers, for uniformity. */ - retval = rtc_read_alarm(dev, &alm); + retval = rtc_read_alarm(to_rtc_device(dev), &alm); if (retval == 0 && alm.enabled) { rtc_tm_to_time(&alm.time, &alarm); retval = sprintf(buf, "%lu\n", alarm); @@ -104,16 +107,18 @@ rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf) } static ssize_t -rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n) +rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) { ssize_t retval; unsigned long now, alarm; struct rtc_wkalrm alm; + struct rtc_device *rtc = to_rtc_device(dev); /* Only request alarms that trigger in the future. Disable them * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. */ - retval = rtc_read_time(dev, &alm.time); + retval = rtc_read_time(rtc, &alm.time); if (retval < 0) return retval; rtc_tm_to_time(&alm.time, &now); @@ -124,7 +129,7 @@ rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n) * entirely prevent that here, without even the minimal * locking from the /dev/rtcN api. */ - retval = rtc_read_alarm(dev, &alm); + retval = rtc_read_alarm(rtc, &alm); if (retval < 0) return retval; if (alm.enabled) @@ -141,10 +146,10 @@ rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n) } rtc_time_to_tm(alarm, &alm.time); - retval = rtc_set_alarm(dev, &alm); + retval = rtc_set_alarm(rtc, &alm); return (retval < 0) ? retval : n; } -static const CLASS_DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm); @@ -153,71 +158,37 @@ static const CLASS_DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, * suspend-to-disk. So: no attribute unless that side effect is possible. * (Userspace may disable that mechanism later.) */ -static inline int rtc_does_wakealarm(struct class_device *class_dev) +static inline int rtc_does_wakealarm(struct rtc_device *rtc) { - struct rtc_device *rtc; - - if (!device_can_wakeup(class_dev->dev)) + if (!device_can_wakeup(rtc->dev.parent)) return 0; - rtc = to_rtc_device(class_dev); return rtc->ops->set_alarm != NULL; } -static int rtc_sysfs_add_device(struct class_device *class_dev, - struct class_interface *class_intf) +void rtc_sysfs_add_device(struct rtc_device *rtc) { int err; - dev_dbg(class_dev->dev, "rtc intf: sysfs\n"); + /* not all RTCs support both alarms and wakeup */ + if (!rtc_does_wakealarm(rtc)) + return; - err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group); + err = device_create_file(&rtc->dev, &dev_attr_wakealarm); if (err) - dev_err(class_dev->dev, "failed to create %s\n", - "sysfs attributes"); - else if (rtc_does_wakealarm(class_dev)) { - /* not all RTCs support both alarms and wakeup */ - err = class_device_create_file(class_dev, - &class_device_attr_wakealarm); - if (err) { - dev_err(class_dev->dev, "failed to create %s\n", - "alarm attribute"); - sysfs_remove_group(&class_dev->kobj, &rtc_attr_group); - } - } - - return err; + dev_err(rtc->dev.parent, "failed to create " + "alarm attribute, %d", + err); } -static void rtc_sysfs_remove_device(struct class_device *class_dev, - struct class_interface *class_intf) +void rtc_sysfs_del_device(struct rtc_device *rtc) { - if (rtc_does_wakealarm(class_dev)) - class_device_remove_file(class_dev, - &class_device_attr_wakealarm); - sysfs_remove_group(&class_dev->kobj, &rtc_attr_group); + /* REVISIT did we add it successfully? */ + if (rtc_does_wakealarm(rtc)) + device_remove_file(&rtc->dev, &dev_attr_wakealarm); } -/* interface registration */ - -static struct class_interface rtc_sysfs_interface = { - .add = &rtc_sysfs_add_device, - .remove = &rtc_sysfs_remove_device, -}; - -static int __init rtc_sysfs_init(void) +void __init rtc_sysfs_init(struct class *rtc_class) { - return rtc_interface_register(&rtc_sysfs_interface); + rtc_class->dev_attrs = rtc_attrs; } - -static void __exit rtc_sysfs_exit(void) -{ - class_interface_unregister(&rtc_sysfs_interface); -} - -subsys_initcall(rtc_sysfs_init); -module_exit(rtc_sysfs_exit); - -MODULE_AUTHOR("Alessandro Zummo "); -MODULE_DESCRIPTION("RTC class sysfs interface"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/rtc/rtc-test.c b/trunk/drivers/rtc/rtc-test.c index f50a1b8e1607..254c9fce27da 100644 --- a/trunk/drivers/rtc/rtc-test.c +++ b/trunk/drivers/rtc/rtc-test.c @@ -101,11 +101,11 @@ static ssize_t test_irq_store(struct device *dev, retval = count; local_irq_disable(); if (strncmp(buf, "tick", 4) == 0) - rtc_update_irq(&rtc->class_dev, 1, RTC_PF | RTC_IRQF); + rtc_update_irq(rtc, 1, RTC_PF | RTC_IRQF); else if (strncmp(buf, "alarm", 5) == 0) - rtc_update_irq(&rtc->class_dev, 1, RTC_AF | RTC_IRQF); + rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF); else if (strncmp(buf, "update", 6) == 0) - rtc_update_irq(&rtc->class_dev, 1, RTC_UF | RTC_IRQF); + rtc_update_irq(rtc, 1, RTC_UF | RTC_IRQF); else retval = -EINVAL; local_irq_enable(); diff --git a/trunk/drivers/rtc/rtc-vr41xx.c b/trunk/drivers/rtc/rtc-vr41xx.c index e40322b71938..af7596ef29e2 100644 --- a/trunk/drivers/rtc/rtc-vr41xx.c +++ b/trunk/drivers/rtc/rtc-vr41xx.c @@ -97,6 +97,7 @@ static DEFINE_SPINLOCK(rtc_lock); static char rtc_name[] = "RTC"; static unsigned long periodic_frequency; static unsigned long periodic_count; +static unsigned int alarm_enabled; struct resource rtc_resource[2] = { { .name = rtc_name, @@ -188,6 +189,7 @@ static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) low = rtc1_read(ECMPLREG); mid = rtc1_read(ECMPMREG); high = rtc1_read(ECMPHREG); + wkalrm->enabled = alarm_enabled; spin_unlock_irq(&rtc_lock); @@ -206,10 +208,18 @@ static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) spin_lock_irq(&rtc_lock); + if (alarm_enabled) + disable_irq(ELAPSEDTIME_IRQ); + rtc1_write(ECMPLREG, (uint16_t)(alarm_sec << 15)); rtc1_write(ECMPMREG, (uint16_t)(alarm_sec >> 1)); rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17)); + if (wkalrm->enabled) + enable_irq(ELAPSEDTIME_IRQ); + + alarm_enabled = wkalrm->enabled; + spin_unlock_irq(&rtc_lock); return 0; @@ -221,10 +231,24 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long switch (cmd) { case RTC_AIE_ON: - enable_irq(ELAPSEDTIME_IRQ); + spin_lock_irq(&rtc_lock); + + if (!alarm_enabled) { + enable_irq(ELAPSEDTIME_IRQ); + alarm_enabled = 1; + } + + spin_unlock_irq(&rtc_lock); break; case RTC_AIE_OFF: - disable_irq(ELAPSEDTIME_IRQ); + spin_lock_irq(&rtc_lock); + + if (alarm_enabled) { + disable_irq(ELAPSEDTIME_IRQ); + alarm_enabled = 0; + } + + spin_unlock_irq(&rtc_lock); break; case RTC_PIE_ON: enable_irq(RTCLONG1_IRQ); @@ -275,7 +299,7 @@ static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id) rtc2_write(RTCINTREG, ELAPSEDTIME_INT); - rtc_update_irq(&rtc->class_dev, 1, RTC_AF); + rtc_update_irq(rtc, 1, RTC_AF); return IRQ_HANDLED; } @@ -291,7 +315,7 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id) rtc1_write(RTCL1LREG, count); rtc1_write(RTCL1HREG, count >> 16); - rtc_update_irq(&rtc->class_dev, 1, RTC_PF); + rtc_update_irq(rtc, 1, RTC_PF); return IRQ_HANDLED; } diff --git a/trunk/drivers/s390/cio/qdio.c b/trunk/drivers/s390/cio/qdio.c index cba64e4cfcd4..f770018fe1d5 100644 --- a/trunk/drivers/s390/cio/qdio.c +++ b/trunk/drivers/s390/cio/qdio.c @@ -996,18 +996,25 @@ __qdio_outbound_processing(struct qdio_q *q) if (qdio_has_outbound_q_moved(q)) qdio_kick_outbound_handler(q); - if (q->is_iqdio_q) { + if (q->queue_type == QDIO_ZFCP_QFMT) { + if ((!q->hydra_gives_outbound_pcis) && + (!qdio_is_outbound_q_done(q))) + qdio_mark_q(q); + } + else if (((!q->is_iqdio_q) && (!q->is_pci_out)) || + (q->queue_type == QDIO_IQDIO_QFMT_ASYNCH)) { /* - * for asynchronous queues, we better check, if the sent - * buffer is already switched from PRIMED to EMPTY. + * make sure buffer switch from PRIMED to EMPTY is noticed + * and outbound_handler is called */ - if ((q->queue_type == QDIO_IQDIO_QFMT_ASYNCH) && - !qdio_is_outbound_q_done(q)) - qdio_mark_q(q); - - } else if (!q->hydra_gives_outbound_pcis) - if (!qdio_is_outbound_q_done(q)) - qdio_mark_q(q); + if (qdio_is_outbound_q_done(q)) { + del_timer(&q->timer); + } else { + if (!timer_pending(&q->timer)) + mod_timer(&q->timer, jiffies + + QDIO_FORCE_CHECK_TIMEOUT); + } + } qdio_release_q(q); } @@ -1826,6 +1833,7 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->queue_type = QDIO_IQDIO_QFMT_ASYNCH; q->int_parm=int_parm; q->is_input_q=0; + q->is_pci_out = 0; q->schid = irq_ptr->schid; q->cdev = cdev; q->irq_ptr = irq_ptr; @@ -1838,6 +1846,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->tasklet.data=(unsigned long)q; q->tasklet.func=(void(*)(unsigned long)) &qdio_outbound_processing; + q->timer.function=(void(*)(unsigned long)) + &qdio_outbound_processing; + q->timer.data = (long)q; + init_timer(&q->timer); atomic_set(&q->busy_siga_counter,0); q->timing.busy_start=0; @@ -2635,6 +2647,7 @@ qdio_shutdown(struct ccw_device *cdev, int how) for (i=0;ino_output_qs;i++) { tasklet_kill(&irq_ptr->output_qs[i]->tasklet); + del_timer(&irq_ptr->output_qs[i]->timer); wait_event_interruptible_timeout(cdev->private->wait_q, !atomic_read(&irq_ptr-> output_qs[i]-> @@ -3458,6 +3471,10 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags, qdio_perf_stat_inc(&perf_stats.outbound_cnt); return; } + if (callflags & QDIO_FLAG_PCI_OUT) + q->is_pci_out = 1; + else + q->is_pci_out = 0; if (q->is_iqdio_q) { /* one siga for every sbal */ while (count--) diff --git a/trunk/drivers/s390/cio/qdio.h b/trunk/drivers/s390/cio/qdio.h index 2895392eaae4..6d7aad18f6f0 100644 --- a/trunk/drivers/s390/cio/qdio.h +++ b/trunk/drivers/s390/cio/qdio.h @@ -60,6 +60,7 @@ #define QDIO_ACTIVATE_TIMEOUT ((5*HZ)>>10) #define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ) #define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ) +#define QDIO_FORCE_CHECK_TIMEOUT (10*HZ) enum qdio_irq_states { QDIO_IRQ_STATE_INACTIVE, @@ -511,8 +512,8 @@ struct qdio_q { void *irq_ptr; -#ifdef QDIO_USE_TIMERS_FOR_POLLING struct timer_list timer; +#ifdef QDIO_USE_TIMERS_FOR_POLLING atomic_t timer_already_set; spinlock_t timer_lock; #else /* QDIO_USE_TIMERS_FOR_POLLING */ @@ -558,6 +559,7 @@ struct qdio_q { } timing; atomic_t busy_siga_counter; unsigned int queue_type; + unsigned int is_pci_out; /* leave this member at the end. won't be cleared in qdio_fill_qs */ struct slib *slib; /* a page is allocated under this pointer, diff --git a/trunk/drivers/s390/net/netiucv.c b/trunk/drivers/s390/net/netiucv.c index e10e85e85c84..c358764f3264 100644 --- a/trunk/drivers/s390/net/netiucv.c +++ b/trunk/drivers/s390/net/netiucv.c @@ -1862,12 +1862,14 @@ static void netiucv_remove_connection(struct iucv_connection *conn) write_lock_bh(&iucv_connection_rwlock); list_del_init(&conn->list); write_unlock_bh(&iucv_connection_rwlock); + fsm_deltimer(&conn->timer); + netiucv_purge_skb_queue(&conn->collect_queue); if (conn->path) { iucv_path_sever(conn->path, iucvMagic); kfree(conn->path); conn->path = NULL; } - fsm_deltimer(&conn->timer); + netiucv_purge_skb_queue(&conn->commit_queue); kfree_fsm(conn->fsm); kfree_skb(conn->rx_buff); kfree_skb(conn->tx_buff); @@ -2115,7 +2117,6 @@ static void __exit netiucv_exit(void) while (!list_empty(&iucv_connection_list)) { cp = list_entry(iucv_connection_list.next, struct iucv_connection, list); - list_del(&cp->list); ndev = cp->netdev; priv = netdev_priv(ndev); dev = priv->dev; diff --git a/trunk/drivers/s390/net/qeth_eddp.c b/trunk/drivers/s390/net/qeth_eddp.c index dd7034fbfff8..4640f32daae5 100644 --- a/trunk/drivers/s390/net/qeth_eddp.c +++ b/trunk/drivers/s390/net/qeth_eddp.c @@ -620,10 +620,10 @@ qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb, struct qeth_eddp_context * qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb, - struct qeth_hdr *qhdr) + struct qeth_hdr *qhdr, unsigned char sk_protocol) { QETH_DBF_TEXT(trace, 5, "creddpc"); - switch (skb->sk->sk_protocol){ + switch (sk_protocol) { case IPPROTO_TCP: return qeth_eddp_create_context_tcp(card, skb, qhdr); default: diff --git a/trunk/drivers/s390/net/qeth_eddp.h b/trunk/drivers/s390/net/qeth_eddp.h index 103768d3bab2..52910c9252c0 100644 --- a/trunk/drivers/s390/net/qeth_eddp.h +++ b/trunk/drivers/s390/net/qeth_eddp.h @@ -34,7 +34,8 @@ struct qeth_eddp_context_reference { }; extern struct qeth_eddp_context * -qeth_eddp_create_context(struct qeth_card *,struct sk_buff *,struct qeth_hdr *); +qeth_eddp_create_context(struct qeth_card *,struct sk_buff *, + struct qeth_hdr *, unsigned char); extern void qeth_eddp_put_context(struct qeth_eddp_context *); diff --git a/trunk/drivers/s390/net/qeth_main.c b/trunk/drivers/s390/net/qeth_main.c index 6fd8870551d3..29d176036e5c 100644 --- a/trunk/drivers/s390/net/qeth_main.c +++ b/trunk/drivers/s390/net/qeth_main.c @@ -1682,6 +1682,21 @@ qeth_put_reply(struct qeth_reply *reply) kfree(reply); } +static void +qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, struct qeth_card *card) +{ + int rc; + int com; + char * ipa_name; + + com = cmd->hdr.command; + rc = cmd->hdr.return_code; + ipa_name = qeth_get_ipa_cmd_name(com); + + PRINT_ERR("%s(x%X) for %s returned x%X \"%s\"\n", ipa_name, com, + QETH_CARD_IFNAME(card), rc, qeth_get_ipa_msg(rc)); +} + static struct qeth_ipa_cmd * qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) { @@ -1690,8 +1705,11 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) QETH_DBF_TEXT(trace,5,"chkipad"); if (IS_IPA(iob->data)){ cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); - if (IS_IPA_REPLY(cmd)) + if (IS_IPA_REPLY(cmd)) { + if (cmd->hdr.return_code) + qeth_issue_ipa_msg(cmd, card); return cmd; + } else { switch (cmd->hdr.command) { case IPA_CMD_STOPLAN: @@ -2816,6 +2834,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, struct qeth_qdio_out_buffer *buf; int rc; int i; + unsigned int qdio_flags; QETH_DBF_TEXT(trace, 6, "flushbuf"); @@ -2859,13 +2878,13 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, queue->card->perf_stats.outbound_do_qdio_start_time = qeth_get_micros(); } + qdio_flags = QDIO_FLAG_SYNC_OUTPUT; if (under_int) - rc = do_QDIO(CARD_DDEV(queue->card), - QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT, - queue->queue_no, index, count, NULL); - else - rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT, - queue->queue_no, index, count, NULL); + qdio_flags |= QDIO_FLAG_UNDER_INTERRUPT; + if (atomic_read(&queue->set_pci_flags_count)) + qdio_flags |= QDIO_FLAG_PCI_OUT; + rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags, + queue->queue_no, index, count, NULL); if (queue->card->options.performance_stats) queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() - @@ -4490,7 +4509,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) qeth_fill_header(card, hdr, new_skb, ipv, cast_type); } if (large_send == QETH_LARGE_SEND_EDDP) { - ctx = qeth_eddp_create_context(card, new_skb, hdr); + ctx = qeth_eddp_create_context(card, new_skb, hdr, + skb->sk->sk_protocol); if (ctx == NULL) { __qeth_free_new_skb(skb, new_skb); PRINT_WARN("could not create eddp context\n"); @@ -5948,9 +5968,6 @@ qeth_layer2_send_setmac_cb(struct qeth_card *card, cmd = (struct qeth_ipa_cmd *) data; if (cmd->hdr.return_code) { QETH_DBF_TEXT_(trace, 2, "L2er%x", cmd->hdr.return_code); - PRINT_WARN("Error in registering MAC address on " \ - "device %s: x%x\n", CARD_BUS_ID(card), - cmd->hdr.return_code); card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; cmd->hdr.return_code = -EIO; } else { @@ -5985,9 +6002,6 @@ qeth_layer2_send_delmac_cb(struct qeth_card *card, QETH_DBF_TEXT(trace, 2, "L2Dmaccb"); cmd = (struct qeth_ipa_cmd *) data; if (cmd->hdr.return_code) { - PRINT_WARN("Error in deregistering MAC address on " \ - "device %s: x%x\n", CARD_BUS_ID(card), - cmd->hdr.return_code); QETH_DBF_TEXT_(trace, 2, "err%d", cmd->hdr.return_code); cmd->hdr.return_code = -EIO; return 0; @@ -6651,7 +6665,7 @@ qeth_setadpparms_change_macaddr_cb(struct qeth_card *card, QETH_DBF_TEXT(trace,4,"chgmaccb"); cmd = (struct qeth_ipa_cmd *) data; - if (!card->options.layer2 || card->info.guestlan || + if (!card->options.layer2 || !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) { memcpy(card->dev->dev_addr, &cmd->data.setadapterparms.data.change_addr.addr, @@ -8497,6 +8511,7 @@ __qeth_reboot_event_card(struct device *dev, void *data) card = (struct qeth_card *) dev->driver_data; qeth_clear_ip_list(card, 0, 0); qeth_qdio_clear_card(card, 0); + qeth_clear_qdio_buffers(card); return 0; } diff --git a/trunk/drivers/s390/net/qeth_mpc.c b/trunk/drivers/s390/net/qeth_mpc.c index 77c83209d70e..f54fdfdbf06f 100644 --- a/trunk/drivers/s390/net/qeth_mpc.c +++ b/trunk/drivers/s390/net/qeth_mpc.c @@ -157,12 +157,113 @@ unsigned char READ_CCW[]={ }; +struct ipa_rc_msg { + enum qeth_ipa_return_codes rc; + char *msg; +}; +struct ipa_rc_msg qeth_ipa_rc_msg[] = { + {IPA_RC_SUCCESS, "success"}, + {IPA_RC_NOTSUPP, "Command not supported"}, + {IPA_RC_IP_TABLE_FULL, "Add Addr IP Table Full - ipv6"}, + {IPA_RC_UNKNOWN_ERROR, "IPA command failed - reason unknown"}, + {IPA_RC_UNSUPPORTED_COMMAND, "Command not supported"}, + {IPA_RC_DUP_IPV6_REMOTE,"ipv6 address already registered remote"}, + {IPA_RC_DUP_IPV6_HOME, "ipv6 address already registered"}, + {IPA_RC_UNREGISTERED_ADDR, "Address not registered"}, + {IPA_RC_NO_ID_AVAILABLE, "No identifiers available"}, + {IPA_RC_ID_NOT_FOUND, "Identifier not found"}, + {IPA_RC_INVALID_IP_VERSION, "IP version incorrect"}, + {IPA_RC_LAN_FRAME_MISMATCH, "LAN and frame mismatch"}, + {IPA_RC_L2_UNSUPPORTED_CMD, "Unsupported layer 2 command"}, + {IPA_RC_L2_DUP_MAC, "Duplicate MAC address"}, + {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"}, + {IPA_RC_L2_DUP_LAYER3_MAC, "Duplicate with layer 3 MAC"}, + {IPA_RC_L2_GMAC_NOT_FOUND, "GMAC not found"}, + {IPA_RC_L2_MAC_NOT_FOUND, "L2 mac address not found"}, + {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"}, + {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"}, + {IPA_RC_L2_VLAN_ID_NOT_FOUND, "L2 vlan id not found"}, + {IPA_RC_DATA_MISMATCH, "Data field mismatch (v4/v6 mixed)"}, + {IPA_RC_INVALID_MTU_SIZE, "Invalid MTU size"}, + {IPA_RC_INVALID_LANTYPE, "Invalid LAN type"}, + {IPA_RC_INVALID_LANNUM, "Invalid LAN num"}, + {IPA_RC_DUPLICATE_IP_ADDRESS, "Address already registered"}, + {IPA_RC_IP_ADDR_TABLE_FULL, "IP address table full"}, + {IPA_RC_LAN_PORT_STATE_ERROR, "LAN port state error"}, + {IPA_RC_SETIP_NO_STARTLAN, "Setip no startlan received"}, + {IPA_RC_SETIP_ALREADY_RECEIVED, "Setip already received"}, + {IPA_RC_IP_ADDR_ALREADY_USED, "IP address already in use on LAN"}, + {IPA_RC_MULTICAST_FULL, "No task available, multicast full"}, + {IPA_RC_SETIP_INVALID_VERSION, "SETIP invalid IP version"}, + {IPA_RC_UNSUPPORTED_SUBCMD, "Unsupported assist subcommand"}, + {IPA_RC_ARP_ASSIST_NO_ENABLE, "Only partial success, no enable"}, + {IPA_RC_PRIMARY_ALREADY_DEFINED,"Primary already defined"}, + {IPA_RC_SECOND_ALREADY_DEFINED, "Secondary already defined"}, + {IPA_RC_INVALID_SETRTG_INDICATOR,"Invalid SETRTG indicator"}, + {IPA_RC_MC_ADDR_ALREADY_DEFINED,"Multicast address already defined"}, + {IPA_RC_LAN_OFFLINE, "STRTLAN_LAN_DISABLED - LAN offline"}, + {IPA_RC_INVALID_IP_VERSION2, "Invalid IP version"}, + {IPA_RC_FFFF, "Unknown Error"} +}; +char * +qeth_get_ipa_msg(enum qeth_ipa_return_codes rc) +{ + int x = 0; + qeth_ipa_rc_msg[sizeof(qeth_ipa_rc_msg) / + sizeof(struct ipa_rc_msg) - 1].rc = rc; + while(qeth_ipa_rc_msg[x].rc != rc) + x++; + return qeth_ipa_rc_msg[x].msg; +} +struct ipa_cmd_names { + enum qeth_ipa_cmds cmd; + char *name; +}; + +struct ipa_cmd_names qeth_ipa_cmd_names[] = { + {IPA_CMD_STARTLAN, "startlan"}, + {IPA_CMD_STOPLAN, "stoplan"}, + {IPA_CMD_SETVMAC, "setvmac"}, + {IPA_CMD_DELVMAC, "delvmca"}, + {IPA_CMD_SETGMAC, "setgmac"}, + {IPA_CMD_DELGMAC, "delgmac"}, + {IPA_CMD_SETVLAN, "setvlan"}, + {IPA_CMD_DELVLAN, "delvlan"}, + {IPA_CMD_SETCCID, "setccid"}, + {IPA_CMD_DELCCID, "delccid"}, + {IPA_CMD_MODCCID, "setip"}, + {IPA_CMD_SETIP, "setip"}, + {IPA_CMD_QIPASSIST, "qipassist"}, + {IPA_CMD_SETASSPARMS, "setassparms"}, + {IPA_CMD_SETIPM, "setipm"}, + {IPA_CMD_DELIPM, "delipm"}, + {IPA_CMD_SETRTG, "setrtg"}, + {IPA_CMD_DELIP, "delip"}, + {IPA_CMD_SETADAPTERPARMS, "setadapterparms"}, + {IPA_CMD_SET_DIAG_ASS, "set_diag_ass"}, + {IPA_CMD_CREATE_ADDR, "create_addr"}, + {IPA_CMD_DESTROY_ADDR, "destroy_addr"}, + {IPA_CMD_REGISTER_LOCAL_ADDR, "register_local_addr"}, + {IPA_CMD_UNREGISTER_LOCAL_ADDR, "unregister_local_addr"}, + {IPA_CMD_UNKNOWN, "unknown"}, +}; +char * +qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd) +{ + int x = 0; + qeth_ipa_cmd_names[ + sizeof(qeth_ipa_cmd_names)/ + sizeof(struct ipa_cmd_names)-1].cmd = cmd; + while(qeth_ipa_cmd_names[x].cmd != cmd) + x++; + return qeth_ipa_cmd_names[x].name; +} diff --git a/trunk/drivers/s390/net/qeth_mpc.h b/trunk/drivers/s390/net/qeth_mpc.h index d74bc43da72a..1d8083c91765 100644 --- a/trunk/drivers/s390/net/qeth_mpc.h +++ b/trunk/drivers/s390/net/qeth_mpc.h @@ -25,14 +25,14 @@ extern unsigned char IPA_PDU_HEADER[]; #define IPA_CMD_LENGTH (IPA_PDU_HEADER_SIZE + sizeof(struct qeth_ipa_cmd)) -#define QETH_SEQ_NO_LENGTH 4 -#define QETH_MPC_TOKEN_LENGTH 4 +#define QETH_SEQ_NO_LENGTH 4 +#define QETH_MPC_TOKEN_LENGTH 4 #define QETH_MCL_LENGTH 4 #define OSA_ADDR_LEN 6 -#define QETH_TIMEOUT (10 * HZ) -#define QETH_IPA_TIMEOUT (45 * HZ) -#define QETH_IDX_COMMAND_SEQNO 0xffff0000 +#define QETH_TIMEOUT (10 * HZ) +#define QETH_IPA_TIMEOUT (45 * HZ) +#define QETH_IDX_COMMAND_SEQNO 0xffff0000 #define SR_INFO_LEN 16 #define QETH_CLEAR_CHANNEL_PARM -10 @@ -93,79 +93,107 @@ enum qeth_checksum_types { */ #define RESET_ROUTING_FLAG 0x10 /* indicate that routing type shall be set */ enum qeth_routing_types { - NO_ROUTER = 0, /* TODO: set to bit flag used in IPA Command */ - PRIMARY_ROUTER = 1, - SECONDARY_ROUTER = 2, - MULTICAST_ROUTER = 3, - PRIMARY_CONNECTOR = 4, - SECONDARY_CONNECTOR = 5, + NO_ROUTER = 0, /* TODO: set to bit flag used in IPA Command */ + PRIMARY_ROUTER = 1, + SECONDARY_ROUTER = 2, + MULTICAST_ROUTER = 3, + PRIMARY_CONNECTOR = 4, + SECONDARY_CONNECTOR = 5, }; - /* IPA Commands */ enum qeth_ipa_cmds { - IPA_CMD_STARTLAN = 0x01, - IPA_CMD_STOPLAN = 0x02, - IPA_CMD_SETVMAC = 0x21, - IPA_CMD_DELVMAC = 0x22, - IPA_CMD_SETGMAC = 0x23, - IPA_CMD_DELGMAC = 0x24, - IPA_CMD_SETVLAN = 0x25, - IPA_CMD_DELVLAN = 0x26, - IPA_CMD_SETCCID = 0x41, - IPA_CMD_DELCCID = 0x42, - IPA_CMD_MODCCID = 0x43, - IPA_CMD_SETIP = 0xb1, - IPA_CMD_DELIP = 0xb7, - IPA_CMD_QIPASSIST = 0xb2, - IPA_CMD_SETASSPARMS = 0xb3, - IPA_CMD_SETIPM = 0xb4, - IPA_CMD_DELIPM = 0xb5, - IPA_CMD_SETRTG = 0xb6, - IPA_CMD_SETADAPTERPARMS = 0xb8, - IPA_CMD_IPFRAME = 0xb9, - IPA_CMD_ADD_ADDR_ENTRY = 0xc1, - IPA_CMD_DELETE_ADDR_ENTRY = 0xc2, - IPA_CMD_CREATE_ADDR = 0xc3, - IPA_CMD_DESTROY_ADDR = 0xc4, - IPA_CMD_REGISTER_LOCAL_ADDR = 0xd1, - IPA_CMD_UNREGISTER_LOCAL_ADDR = 0xd2, + IPA_CMD_STARTLAN = 0x01, + IPA_CMD_STOPLAN = 0x02, + IPA_CMD_SETVMAC = 0x21, + IPA_CMD_DELVMAC = 0x22, + IPA_CMD_SETGMAC = 0x23, + IPA_CMD_DELGMAC = 0x24, + IPA_CMD_SETVLAN = 0x25, + IPA_CMD_DELVLAN = 0x26, + IPA_CMD_SETCCID = 0x41, + IPA_CMD_DELCCID = 0x42, + IPA_CMD_MODCCID = 0x43, + IPA_CMD_SETIP = 0xb1, + IPA_CMD_QIPASSIST = 0xb2, + IPA_CMD_SETASSPARMS = 0xb3, + IPA_CMD_SETIPM = 0xb4, + IPA_CMD_DELIPM = 0xb5, + IPA_CMD_SETRTG = 0xb6, + IPA_CMD_DELIP = 0xb7, + IPA_CMD_SETADAPTERPARMS = 0xb8, + IPA_CMD_SET_DIAG_ASS = 0xb9, + IPA_CMD_CREATE_ADDR = 0xc3, + IPA_CMD_DESTROY_ADDR = 0xc4, + IPA_CMD_REGISTER_LOCAL_ADDR = 0xd1, + IPA_CMD_UNREGISTER_LOCAL_ADDR = 0xd2, + IPA_CMD_UNKNOWN = 0x00 }; enum qeth_ip_ass_cmds { IPA_CMD_ASS_START = 0x0001, IPA_CMD_ASS_STOP = 0x0002, - IPA_CMD_ASS_CONFIGURE = 0x0003, - IPA_CMD_ASS_ENABLE = 0x0004, + IPA_CMD_ASS_CONFIGURE = 0x0003, + IPA_CMD_ASS_ENABLE = 0x0004, }; enum qeth_arp_process_subcmds { - IPA_CMD_ASS_ARP_SET_NO_ENTRIES = 0x0003, - IPA_CMD_ASS_ARP_QUERY_CACHE = 0x0004, - IPA_CMD_ASS_ARP_ADD_ENTRY = 0x0005, - IPA_CMD_ASS_ARP_REMOVE_ENTRY = 0x0006, - IPA_CMD_ASS_ARP_FLUSH_CACHE = 0x0007, - IPA_CMD_ASS_ARP_QUERY_INFO = 0x0104, - IPA_CMD_ASS_ARP_QUERY_STATS = 0x0204, + IPA_CMD_ASS_ARP_SET_NO_ENTRIES = 0x0003, + IPA_CMD_ASS_ARP_QUERY_CACHE = 0x0004, + IPA_CMD_ASS_ARP_ADD_ENTRY = 0x0005, + IPA_CMD_ASS_ARP_REMOVE_ENTRY = 0x0006, + IPA_CMD_ASS_ARP_FLUSH_CACHE = 0x0007, + IPA_CMD_ASS_ARP_QUERY_INFO = 0x0104, + IPA_CMD_ASS_ARP_QUERY_STATS = 0x0204, }; -/* Return Codes for IPA Commands */ + +/* Return Codes for IPA Commands + * according to OSA card Specs */ + enum qeth_ipa_return_codes { - IPA_RC_SUCCESS = 0x0000, - IPA_RC_NOTSUPP = 0x0001, - IPA_RC_NO_ACCESS = 0x0002, - IPA_RC_FAILED = 0x0003, - IPA_RC_DATA_MISMATCH = 0xe001, - IPA_RC_INVALID_LAN_TYPE = 0xe003, - IPA_RC_INVALID_LAN_NO = 0xe004, - IPA_RC_IPADDR_ALREADY_REG = 0xe005, - IPA_RC_IPADDR_TABLE_FULL = 0xe006, - IPA_RC_IPADDR_ALREADY_USED = 0xe00a, - IPA_RC_ASSNO_NOT_SUPP = 0xe00d, - IPA_RC_ASSCMD_START_FAILED = 0xe00e, - IPA_RC_ASSCMD_PART_SUCCESS = 0xe00f, - IPA_RC_IPADDR_NOT_DEFINED = 0xe010, - IPA_RC_LAN_OFFLINE = 0xe080, + IPA_RC_SUCCESS = 0x0000, + IPA_RC_NOTSUPP = 0x0001, + IPA_RC_IP_TABLE_FULL = 0x0002, + IPA_RC_UNKNOWN_ERROR = 0x0003, + IPA_RC_UNSUPPORTED_COMMAND = 0x0004, + IPA_RC_DUP_IPV6_REMOTE = 0x0008, + IPA_RC_DUP_IPV6_HOME = 0x0010, + IPA_RC_UNREGISTERED_ADDR = 0x0011, + IPA_RC_NO_ID_AVAILABLE = 0x0012, + IPA_RC_ID_NOT_FOUND = 0x0013, + IPA_RC_INVALID_IP_VERSION = 0x0020, + IPA_RC_LAN_FRAME_MISMATCH = 0x0040, + IPA_RC_L2_UNSUPPORTED_CMD = 0x2003, + IPA_RC_L2_DUP_MAC = 0x2005, + IPA_RC_L2_ADDR_TABLE_FULL = 0x2006, + IPA_RC_L2_DUP_LAYER3_MAC = 0x200a, + IPA_RC_L2_GMAC_NOT_FOUND = 0x200b, + IPA_RC_L2_MAC_NOT_FOUND = 0x2010, + IPA_RC_L2_INVALID_VLAN_ID = 0x2015, + IPA_RC_L2_DUP_VLAN_ID = 0x2016, + IPA_RC_L2_VLAN_ID_NOT_FOUND = 0x2017, + IPA_RC_DATA_MISMATCH = 0xe001, + IPA_RC_INVALID_MTU_SIZE = 0xe002, + IPA_RC_INVALID_LANTYPE = 0xe003, + IPA_RC_INVALID_LANNUM = 0xe004, + IPA_RC_DUPLICATE_IP_ADDRESS = 0xe005, + IPA_RC_IP_ADDR_TABLE_FULL = 0xe006, + IPA_RC_LAN_PORT_STATE_ERROR = 0xe007, + IPA_RC_SETIP_NO_STARTLAN = 0xe008, + IPA_RC_SETIP_ALREADY_RECEIVED = 0xe009, + IPA_RC_IP_ADDR_ALREADY_USED = 0xe00a, + IPA_RC_MULTICAST_FULL = 0xe00b, + IPA_RC_SETIP_INVALID_VERSION = 0xe00d, + IPA_RC_UNSUPPORTED_SUBCMD = 0xe00e, + IPA_RC_ARP_ASSIST_NO_ENABLE = 0xe00f, + IPA_RC_PRIMARY_ALREADY_DEFINED = 0xe010, + IPA_RC_SECOND_ALREADY_DEFINED = 0xe011, + IPA_RC_INVALID_SETRTG_INDICATOR = 0xe012, + IPA_RC_MC_ADDR_ALREADY_DEFINED = 0xe013, + IPA_RC_LAN_OFFLINE = 0xe080, + IPA_RC_INVALID_IP_VERSION2 = 0xf001, + IPA_RC_FFFF = 0xffff }; /* IPA function flags; each flag marks availability of respective function */ @@ -183,7 +211,9 @@ enum qeth_ipa_funcs { IPA_SETADAPTERPARMS = 0x00000400L, IPA_VLAN_PRIO = 0x00000800L, IPA_PASSTHRU = 0x00001000L, + IPA_FLUSH_ARP_SUPPORT = 0x00002000L, IPA_FULL_VLAN = 0x00004000L, + IPA_INBOUND_PASSTHRU = 0x00008000L, IPA_SOURCE_MAC = 0x00010000L, IPA_OSA_MC_ROUTER = 0x00020000L, IPA_QUERY_ARP_ASSIST = 0x00040000L, @@ -204,31 +234,30 @@ enum qeth_ipa_setdelip_flags { /* SETADAPTER IPA Command: ****************************************************/ enum qeth_ipa_setadp_cmd { IPA_SETADP_QUERY_COMMANDS_SUPPORTED = 0x01, - IPA_SETADP_ALTER_MAC_ADDRESS = 0x02, - IPA_SETADP_ADD_DELETE_GROUP_ADDRESS = 0x04, - IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR = 0x08, - IPA_SETADP_SET_ADDRESSING_MODE = 0x10, - IPA_SETADP_SET_CONFIG_PARMS = 0x20, - IPA_SETADP_SET_CONFIG_PARMS_EXTENDED = 0x40, - IPA_SETADP_SET_BROADCAST_MODE = 0x80, - IPA_SETADP_SEND_OSA_MESSAGE = 0x0100, - IPA_SETADP_SET_SNMP_CONTROL = 0x0200, - IPA_SETADP_READ_SNMP_PARMS = 0x0400, + IPA_SETADP_ALTER_MAC_ADDRESS = 0x02, + IPA_SETADP_ADD_DELETE_GROUP_ADDRESS = 0x04, + IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR = 0x08, + IPA_SETADP_SET_ADDRESSING_MODE = 0x10, + IPA_SETADP_SET_CONFIG_PARMS = 0x20, + IPA_SETADP_SET_CONFIG_PARMS_EXTENDED = 0x40, + IPA_SETADP_SET_BROADCAST_MODE = 0x80, + IPA_SETADP_SEND_OSA_MESSAGE = 0x0100, + IPA_SETADP_SET_SNMP_CONTROL = 0x0200, + IPA_SETADP_QUERY_CARD_INFO = 0x0400, IPA_SETADP_SET_PROMISC_MODE = 0x0800, - IPA_SETADP_QUERY_CARD_INFO = 0x1000, }; enum qeth_ipa_mac_ops { - CHANGE_ADDR_READ_MAC = 0, - CHANGE_ADDR_REPLACE_MAC = 1, - CHANGE_ADDR_ADD_MAC = 2, - CHANGE_ADDR_DEL_MAC = 4, - CHANGE_ADDR_RESET_MAC = 8, + CHANGE_ADDR_READ_MAC = 0, + CHANGE_ADDR_REPLACE_MAC = 1, + CHANGE_ADDR_ADD_MAC = 2, + CHANGE_ADDR_DEL_MAC = 4, + CHANGE_ADDR_RESET_MAC = 8, }; enum qeth_ipa_addr_ops { - CHANGE_ADDR_READ_ADDR = 0, - CHANGE_ADDR_ADD_ADDR = 1, - CHANGE_ADDR_DEL_ADDR = 2, - CHANGE_ADDR_FLUSH_ADDR_TABLE = 4, + CHANGE_ADDR_READ_ADDR = 0, + CHANGE_ADDR_ADD_ADDR = 1, + CHANGE_ADDR_DEL_ADDR = 2, + CHANGE_ADDR_FLUSH_ADDR_TABLE = 4, }; enum qeth_ipa_promisc_modes { SET_PROMISC_MODE_OFF = 0, @@ -407,15 +436,15 @@ struct qeth_ipacmd_hdr { struct qeth_ipa_cmd { struct qeth_ipacmd_hdr hdr; union { - struct qeth_ipacmd_setdelip4 setdelip4; - struct qeth_ipacmd_setdelip6 setdelip6; + struct qeth_ipacmd_setdelip4 setdelip4; + struct qeth_ipacmd_setdelip6 setdelip6; struct qeth_ipacmd_setdelipm setdelipm; - struct qeth_ipacmd_setassparms setassparms; - struct qeth_ipacmd_layer2setdelmac setdelmac; - struct qeth_ipacmd_layer2setdelvlan setdelvlan; - struct qeth_create_destroy_address create_destroy_addr; - struct qeth_ipacmd_setadpparms setadapterparms; - struct qeth_set_routing setrtg; + struct qeth_ipacmd_setassparms setassparms; + struct qeth_ipacmd_layer2setdelmac setdelmac; + struct qeth_ipacmd_layer2setdelvlan setdelvlan; + struct qeth_create_destroy_address create_destroy_addr; + struct qeth_ipacmd_setadpparms setadapterparms; + struct qeth_set_routing setrtg; } data; } __attribute__ ((packed)); @@ -433,6 +462,12 @@ enum qeth_ipa_arp_return_codes { QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008, }; + +extern char * +qeth_get_ipa_msg(enum qeth_ipa_return_codes rc); +extern char * +qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd); + #define QETH_SETASS_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \ sizeof(struct qeth_ipacmd_setassparms_hdr)) #define QETH_IPA_ARP_DATA_POS(buffer) (buffer + IPA_PDU_HEADER_SIZE + \ @@ -521,7 +556,7 @@ extern unsigned char DM_ACT[]; extern unsigned char IDX_ACTIVATE_READ[]; extern unsigned char IDX_ACTIVATE_WRITE[]; -#define IDX_ACTIVATE_SIZE 0x22 +#define IDX_ACTIVATE_SIZE 0x22 #define QETH_IDX_ACT_ISSUER_RM_TOKEN(buffer) (buffer+0x0c) #define QETH_IDX_NO_PORTNAME_REQUIRED(buffer) ((buffer)[0x0b]&0x80) #define QETH_IDX_ACT_FUNC_LEVEL(buffer) (buffer+0x10) diff --git a/trunk/drivers/s390/net/qeth_sys.c b/trunk/drivers/s390/net/qeth_sys.c index d518419cd0c6..65ffc21afc37 100644 --- a/trunk/drivers/s390/net/qeth_sys.c +++ b/trunk/drivers/s390/net/qeth_sys.c @@ -384,8 +384,6 @@ qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route, route->type = PRIMARY_CONNECTOR; } else if (!strcmp(tmp, "secondary_connector")) { route->type = SECONDARY_CONNECTOR; - } else if (!strcmp(tmp, "multicast_router")) { - route->type = MULTICAST_ROUTER; } else if (!strcmp(tmp, "primary_router")) { route->type = PRIMARY_ROUTER; } else if (!strcmp(tmp, "secondary_router")) { diff --git a/trunk/drivers/sbus/char/bpp.c b/trunk/drivers/sbus/char/bpp.c index a39ee80c9715..74b999d77bbf 100644 --- a/trunk/drivers/sbus/char/bpp.c +++ b/trunk/drivers/sbus/char/bpp.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/sbus/char/rtc.c b/trunk/drivers/sbus/char/rtc.c index 94d185829119..18d18f1a114e 100644 --- a/trunk/drivers/sbus/char/rtc.c +++ b/trunk/drivers/sbus/char/rtc.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/sbus/char/vfc_dev.c b/trunk/drivers/sbus/char/vfc_dev.c index c3135e2fbd5a..6afc7e5df0d4 100644 --- a/trunk/drivers/sbus/char/vfc_dev.c +++ b/trunk/drivers/sbus/char/vfc_dev.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/scsi/Kconfig b/trunk/drivers/scsi/Kconfig index 58c811d20eb2..e62d23f65180 100644 --- a/trunk/drivers/scsi/Kconfig +++ b/trunk/drivers/scsi/Kconfig @@ -170,7 +170,7 @@ config CHR_DEV_SCH If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read and + say M here and read and . The module will be called ch.o. If unsure, say N. @@ -1783,7 +1783,7 @@ config ZFCP This driver is also available as a module. This module will be called zfcp. If you want to compile it as a module, say M here - and read . + and read . config SCSI_SRP tristate "SCSI RDMA Protocol helper library" diff --git a/trunk/drivers/scsi/aic7xxx/aic79xx_osm.h b/trunk/drivers/scsi/aic7xxx/aic79xx_osm.h index 9218f29314fa..ad9761b237dc 100644 --- a/trunk/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/trunk/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/scsi/aic7xxx/aic7xxx_osm.h b/trunk/drivers/scsi/aic7xxx/aic7xxx_osm.h index 85ae5d836fa4..8fee7edc6eb3 100644 --- a/trunk/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/trunk/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -64,7 +64,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/scsi/dpt_i2o.c b/trunk/drivers/scsi/dpt_i2o.c index 6c384ab2884a..8c7d2bbf9b1a 100644 --- a/trunk/drivers/scsi/dpt_i2o.c +++ b/trunk/drivers/scsi/dpt_i2o.c @@ -55,7 +55,6 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver"); #include #include #include -#include #include #include diff --git a/trunk/drivers/scsi/esp_scsi.c b/trunk/drivers/scsi/esp_scsi.c index 99ce03331b64..ec71061aef61 100644 --- a/trunk/drivers/scsi/esp_scsi.c +++ b/trunk/drivers/scsi/esp_scsi.c @@ -2212,7 +2212,7 @@ static void __devinit esp_init_swstate(struct esp *esp) } /* This places the ESP into a known state at boot time. */ -static void __devinit esp_bootup_reset(struct esp *esp) +static void esp_bootup_reset(struct esp *esp) { u8 val; diff --git a/trunk/drivers/scsi/ibmvscsi/ibmvstgt.c b/trunk/drivers/scsi/ibmvscsi/ibmvstgt.c index 6d223dd76440..8ba7dd09d01d 100644 --- a/trunk/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/trunk/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -892,16 +892,16 @@ static int get_system_info(void) if (!rootdn) return -ENOENT; - model = get_property(rootdn, "model", NULL); - id = get_property(rootdn, "system-id", NULL); + model = of_get_property(rootdn, "model", NULL); + id = of_get_property(rootdn, "system-id", NULL); if (model && id) snprintf(system_id, sizeof(system_id), "%s-%s", model, id); - name = get_property(rootdn, "ibm,partition-name", NULL); + name = of_get_property(rootdn, "ibm,partition-name", NULL); if (name) strncpy(partition_name, name, sizeof(partition_name)); - num = get_property(rootdn, "ibm,partition-no", NULL); + num = of_get_property(rootdn, "ibm,partition-no", NULL); if (num) partition_number = *num; diff --git a/trunk/drivers/scsi/ibmvscsi/rpa_vscsi.c b/trunk/drivers/scsi/ibmvscsi/rpa_vscsi.c index 0a533f398f52..d8700aaa6114 100644 --- a/trunk/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/trunk/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -162,11 +162,11 @@ static void gather_partition_info(void) return; } - ppartition_name = get_property(rootdn, "ibm,partition-name", NULL); + ppartition_name = of_get_property(rootdn, "ibm,partition-name", NULL); if (ppartition_name) strncpy(partition_name, ppartition_name, sizeof(partition_name)); - p_number_ptr = get_property(rootdn, "ibm,partition-no", NULL); + p_number_ptr = of_get_property(rootdn, "ibm,partition-no", NULL); if (p_number_ptr) partition_number = *p_number_ptr; of_node_put(rootdn); diff --git a/trunk/drivers/scsi/mac53c94.c b/trunk/drivers/scsi/mac53c94.c index 753d88306cd1..5806ede120a4 100644 --- a/trunk/drivers/scsi/mac53c94.c +++ b/trunk/drivers/scsi/mac53c94.c @@ -471,7 +471,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat goto out_free; } - clkprop = get_property(node, "clock-frequency", &proplen); + clkprop = of_get_property(node, "clock-frequency", &proplen); if (clkprop == NULL || proplen != sizeof(int)) { printk(KERN_ERR "%s: can't get clock frequency, " "assuming 25MHz\n", node->full_name); diff --git a/trunk/drivers/scsi/mesh.c b/trunk/drivers/scsi/mesh.c index 6f50a5b3e4ce..e64d1a19d8d7 100644 --- a/trunk/drivers/scsi/mesh.c +++ b/trunk/drivers/scsi/mesh.c @@ -1947,7 +1947,7 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match) ms->tgts[tgt].current_req = NULL; } - if ((cfp = get_property(mesh, "clock-frequency", NULL))) + if ((cfp = of_get_property(mesh, "clock-frequency", NULL))) ms->clk_freq = *cfp; else { printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n"); diff --git a/trunk/drivers/scsi/scsi_debug.c b/trunk/drivers/scsi/scsi_debug.c index 3e2930b7ee23..06229f225ee9 100644 --- a/trunk/drivers/scsi/scsi_debug.c +++ b/trunk/drivers/scsi/scsi_debug.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/scsi/sg.c b/trunk/drivers/scsi/sg.c index 570977cf9efb..0c691a60a756 100644 --- a/trunk/drivers/scsi/sg.c +++ b/trunk/drivers/scsi/sg.c @@ -41,7 +41,6 @@ static int sg_version_num = 30534; /* 2 digits for each component */ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/scsi/sni_53c710.c b/trunk/drivers/scsi/sni_53c710.c index 6bc505115841..a7dfb65fb842 100644 --- a/trunk/drivers/scsi/sni_53c710.c +++ b/trunk/drivers/scsi/sni_53c710.c @@ -98,7 +98,7 @@ static int __init snirm710_probe(struct platform_device *dev) host->this_id = 7; host->base = base; host->irq = platform_get_irq(dev, 0); - if(request_irq(host->irq, NCR_700_intr, SA_SHIRQ, "snirm710", host)) { + if(request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "snirm710", host)) { printk(KERN_ERR "snirm710: request_irq failed!\n"); goto out_put_host; } diff --git a/trunk/drivers/scsi/sun_esp.c b/trunk/drivers/scsi/sun_esp.c index 8c766bcd1095..bbeb2451d32f 100644 --- a/trunk/drivers/scsi/sun_esp.c +++ b/trunk/drivers/scsi/sun_esp.c @@ -5,6 +5,7 @@ #include #include +#include #include #include diff --git a/trunk/drivers/serial/8250.c b/trunk/drivers/serial/8250.c index 90621c3312bc..48e259a0167d 100644 --- a/trunk/drivers/serial/8250.c +++ b/trunk/drivers/serial/8250.c @@ -251,9 +251,16 @@ static const struct serial8250_config uart_config[] = { .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO | UART_CAP_UUE, }, + [PORT_RM9000] = { + .name = "RM9000", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO, + }, }; -#ifdef CONFIG_SERIAL_8250_AU1X00 +#if defined (CONFIG_SERIAL_8250_AU1X00) /* Au1x00 UART hardware has a weird register layout */ static const u8 au_io_in_map[] = { @@ -289,6 +296,44 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) return au_io_out_map[offset]; } +#elif defined (CONFIG_SERIAL_8250_RM9K) + +static const u8 + regmap_in[8] = { + [UART_RX] = 0x00, + [UART_IER] = 0x0c, + [UART_IIR] = 0x14, + [UART_LCR] = 0x1c, + [UART_MCR] = 0x20, + [UART_LSR] = 0x24, + [UART_MSR] = 0x28, + [UART_SCR] = 0x2c + }, + regmap_out[8] = { + [UART_TX] = 0x04, + [UART_IER] = 0x0c, + [UART_FCR] = 0x18, + [UART_LCR] = 0x1c, + [UART_MCR] = 0x20, + [UART_LSR] = 0x24, + [UART_MSR] = 0x28, + [UART_SCR] = 0x2c + }; + +static inline int map_8250_in_reg(struct uart_8250_port *up, int offset) +{ + if (up->port.iotype != UPIO_RM9000) + return offset; + return regmap_in[offset]; +} + +static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) +{ + if (up->port.iotype != UPIO_RM9000) + return offset; + return regmap_out[offset]; +} + #else /* sane hardware needs no mapping */ @@ -308,8 +353,10 @@ static unsigned int serial_in(struct uart_8250_port *up, int offset) return inb(up->port.iobase + 1); case UPIO_MEM: + case UPIO_DWAPB: return readb(up->port.membase + offset); + case UPIO_RM9000: case UPIO_MEM32: return readl(up->port.membase + offset); @@ -333,6 +380,8 @@ static unsigned int serial_in(struct uart_8250_port *up, int offset) static void serial_out(struct uart_8250_port *up, int offset, int value) { + /* Save the offset before it's remapped */ + int save_offset = offset; offset = map_8250_out_reg(up, offset) << up->port.regshift; switch (up->port.iotype) { @@ -345,6 +394,7 @@ serial_out(struct uart_8250_port *up, int offset, int value) writeb(value, up->port.membase + offset); break; + case UPIO_RM9000: case UPIO_MEM32: writel(value, up->port.membase + offset); break; @@ -359,6 +409,18 @@ serial_out(struct uart_8250_port *up, int offset, int value) writeb(value, up->port.membase + offset); break; + case UPIO_DWAPB: + /* Save the LCR value so it can be re-written when a + * Busy Detect interrupt occurs. */ + if (save_offset == UART_LCR) + up->lcr = value; + writeb(value, up->port.membase + offset); + /* Read the IER to ensure any interrupt is cleared before + * returning from ISR. */ + if (save_offset == UART_TX || save_offset == UART_IER) + value = serial_in(up, UART_IER); + break; + default: outb(value, up->port.iobase + offset); } @@ -373,6 +435,7 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value) #ifdef CONFIG_SERIAL_8250_AU1X00 case UPIO_AU: #endif + case UPIO_DWAPB: serial_out(up, offset, value); serial_in(up, UART_LCR); /* safe, no side-effects */ break; @@ -403,7 +466,7 @@ static inline void _serial_dl_write(struct uart_8250_port *up, int value) serial_outp(up, UART_DLM, value >> 8 & 0xff); } -#ifdef CONFIG_SERIAL_8250_AU1X00 +#if defined (CONFIG_SERIAL_8250_AU1X00) /* Au1x00 haven't got a standard divisor latch */ static int serial_dl_read(struct uart_8250_port *up) { @@ -420,6 +483,24 @@ static void serial_dl_write(struct uart_8250_port *up, int value) else _serial_dl_write(up, value); } +#elif defined (CONFIG_SERIAL_8250_RM9K) +static int serial_dl_read(struct uart_8250_port *up) +{ + return (up->port.iotype == UPIO_RM9000) ? + (((__raw_readl(up->port.membase + 0x10) << 8) | + (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) : + _serial_dl_read(up); +} + +static void serial_dl_write(struct uart_8250_port *up, int value) +{ + if (up->port.iotype == UPIO_RM9000) { + __raw_writel(value, up->port.membase + 0x08); + __raw_writel(value >> 8, up->port.membase + 0x10); + } else { + _serial_dl_write(up, value); + } +} #else #define serial_dl_read(up) _serial_dl_read(up) #define serial_dl_write(up, value) _serial_dl_write(up, value) @@ -621,7 +702,7 @@ static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) * its clones. (We treat the broken original StarTech 16650 V1 as a * 16550, and why not? Startech doesn't seem to even acknowledge its * existence.) - * + * * What evil have men's minds wrought... */ static void autoconfig_has_efr(struct uart_8250_port *up) @@ -674,7 +755,7 @@ static void autoconfig_has_efr(struct uart_8250_port *up) up->bugs |= UART_BUG_QUOT; return; } - + /* * We check for a XR16C850 by setting DLL and DLM to 0, and then * reading back DLL and DLM. The chip type depends on the DLM @@ -817,7 +898,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ serial_outp(up, 0x04, status1); - + serial_dl_write(up, quot); serial_outp(up, UART_LCR, 0); @@ -913,7 +994,6 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) * be frobbing the chips IRQ enable register to see if it exists. */ spin_lock_irqsave(&up->port.lock, flags); -// save_flags(flags); cli(); up->capabilities = 0; up->bugs = 0; @@ -922,7 +1002,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) /* * Do a simple existence test first; if we fail this, * there's no point trying anything else. - * + * * 0x80 is used as a nonsense port to prevent against * false positives due to ISA bus float. The * assumption is that 0x80 is a non-existent port; @@ -961,7 +1041,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) save_mcr = serial_in(up, UART_MCR); save_lcr = serial_in(up, UART_LCR); - /* + /* * Check to see if a UART is really there. Certain broken * internal modems based on the Rockwell chipset fail this * test, because they apparently don't implement the loopback @@ -1068,9 +1148,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) else serial_outp(up, UART_IER, 0); - out: + out: spin_unlock_irqrestore(&up->port.lock, flags); -// restore_flags(flags); DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name); } @@ -1094,7 +1173,7 @@ static void autoconfig_irq(struct uart_8250_port *up) save_mcr = serial_inp(up, UART_MCR); save_ier = serial_inp(up, UART_IER); serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); - + irqs = probe_irq_on(); serial_outp(up, UART_MCR, 0); udelay (10); @@ -1159,8 +1238,11 @@ static void serial8250_start_tx(struct uart_port *port) if (up->bugs & UART_BUG_TXEN) { unsigned char lsr, iir; lsr = serial_in(up, UART_LSR); - iir = serial_in(up, UART_IIR); - if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) + iir = serial_in(up, UART_IIR) & 0x0f; + if ((up->port.type == PORT_RM9000) ? + (lsr & UART_LSR_THRE && + (iir == UART_IIR_NO_INT || iir == UART_IIR_THRI)) : + (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT)) transmit_chars(up); } } @@ -1388,6 +1470,19 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) handled = 1; + end = NULL; + } else if (up->port.iotype == UPIO_DWAPB && + (iir & UART_IIR_BUSY) == UART_IIR_BUSY) { + /* The DesignWare APB UART has an Busy Detect (0x07) + * interrupt meaning an LCR write attempt occured while the + * UART was busy. The interrupt must be cleared by reading + * the UART status register (USR) and the LCR re-written. */ + unsigned int status; + status = *(volatile u32 *)up->port.private_data; + serial_out(up, UART_LCR, up->lcr); + + handled = 1; + end = NULL; } else if (end == NULL) end = l; @@ -1928,7 +2023,7 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios, /* * Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = serial8250_get_divisor(port, baud); /* @@ -2090,6 +2185,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) case UPIO_TSI: case UPIO_MEM32: case UPIO_MEM: + case UPIO_DWAPB: if (!up->port.mapbase) break; @@ -2127,6 +2223,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) case UPIO_TSI: case UPIO_MEM32: case UPIO_MEM: + case UPIO_DWAPB: if (!up->port.mapbase) break; diff --git a/trunk/drivers/serial/Kconfig b/trunk/drivers/serial/Kconfig index ad9f321968e1..e8efe938c4e7 100644 --- a/trunk/drivers/serial/Kconfig +++ b/trunk/drivers/serial/Kconfig @@ -73,17 +73,21 @@ config SERIAL_8250_PCI depends on SERIAL_8250 && PCI default SERIAL_8250 help - This builds standard PCI serial support. You may be able to - disable this feature if you only need legacy serial support. - Saves about 9K. + Say Y here if you have PCI serial ports. + + To compile this driver as a module, choose M here: the module + will be called 8250_pci. config SERIAL_8250_PNP tristate "8250/16550 PNP device support" if EMBEDDED depends on SERIAL_8250 && PNP default SERIAL_8250 help - This builds standard PNP serial support. You may be able to - disable this feature if you only need legacy serial support. + Say Y here if you have serial ports described by PNPBIOS or ACPI. + These are typically ports built into the system board. + + To compile this driver as a module, choose M here: the module + will be called 8250_pnp. config SERIAL_8250_HP300 tristate @@ -254,6 +258,15 @@ config SERIAL_8250_AU1X00 to this option. The driver can handle 1 or 2 serial ports. If unsure, say N. +config SERIAL_8250_RM9K + bool "Support for MIPS RM9xxx integrated serial port" + depends on SERIAL_8250 != n && SERIAL_RM9000 + select SERIAL_8250_SHARE_IRQ + help + Selecting this option will add support for the integrated serial + port hardware found on MIPS RM9122 and similar processors. + If unsure, say N. + comment "Non-8250 serial port support" config SERIAL_AMBA_PL010 @@ -499,6 +512,100 @@ config SERIAL_SA1100_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) +config SERIAL_BFIN + tristate "Blackfin serial port support" + depends on BFIN + select SERIAL_CORE + select SERIAL_BFIN_UART0 if (BF531 || BF532 || BF533 || BF561) + help + Add support for the built-in UARTs on the Blackfin. + + To compile this driver as a module, choose M here: the + module will be called bfin_5xx. + +config SERIAL_BFIN_CONSOLE + bool "Console on Blackfin serial port" + depends on SERIAL_BFIN + select SERIAL_CORE_CONSOLE + +choice + prompt "UART Mode" + depends on SERIAL_BFIN + default SERIAL_BFIN_DMA + help + This driver supports the built-in serial ports of the Blackfin family + of CPUs + +config SERIAL_BFIN_DMA + bool "DMA mode" + depends on DMA_UNCACHED_1M + help + This driver works under DMA mode. If this option is selected, the + blackfin simple dma driver is also enabled. + +config SERIAL_BFIN_PIO + bool "PIO mode" + help + This driver works under PIO mode. + +endchoice + +config SERIAL_BFIN_UART0 + bool "Enable UART0" + depends on SERIAL_BFIN + help + Enable UART0 + +config BFIN_UART0_CTSRTS + bool "Enable UART0 hardware flow control" + depends on SERIAL_BFIN_UART0 + help + Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS + signal. + +config UART0_CTS_PIN + int "UART0 CTS pin" + depends on BFIN_UART0_CTSRTS + default 23 + help + The default pin is GPIO_GP7. + Refer to ./include/asm-blackfin/gpio.h to see the GPIO map. + +config UART0_RTS_PIN + int "UART0 RTS pin" + depends on BFIN_UART0_CTSRTS + default 22 + help + The default pin is GPIO_GP6. + Refer to ./include/asm-blackfin/gpio.h to see the GPIO map. + +config SERIAL_BFIN_UART1 + bool "Enable UART1" + depends on SERIAL_BFIN && (BF534 || BF536 || BF537) + help + Enable UART1 + +config BFIN_UART1_CTSRTS + bool "Enable UART1 hardware flow control" + depends on SERIAL_BFIN_UART1 + help + Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS + signal. + +config UART1_CTS_PIN + int "UART1 CTS pin" + depends on BFIN_UART1_CTSRTS + default -1 + help + Refer to ./include/asm-blackfin/gpio.h to see the GPIO map. + +config UART1_RTS_PIN + int "UART1 RTS pin" + depends on BFIN_UART1_CTSRTS + default -1 + help + Refer to ./include/asm-blackfin/gpio.h to see the GPIO map. + config SERIAL_IMX bool "IMX serial port support" depends on ARM && ARCH_IMX diff --git a/trunk/drivers/serial/Makefile b/trunk/drivers/serial/Makefile index 6b3560c5749a..4959bcb8d1ef 100644 --- a/trunk/drivers/serial/Makefile +++ b/trunk/drivers/serial/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_PXA) += pxa.o obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o +obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o diff --git a/trunk/drivers/serial/amba-pl010.c b/trunk/drivers/serial/amba-pl010.c index f69bd097166e..1a9a24b82636 100644 --- a/trunk/drivers/serial/amba-pl010.c +++ b/trunk/drivers/serial/amba-pl010.c @@ -48,6 +48,7 @@ #include #include #include +#include #include @@ -70,6 +71,7 @@ */ struct uart_amba_port { struct uart_port port; + struct clk *clk; struct amba_device *dev; struct amba_pl010_data *data; unsigned int old_status; @@ -77,73 +79,77 @@ struct uart_amba_port { static void pl010_stop_tx(struct uart_port *port) { + struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int cr; - cr = readb(port->membase + UART010_CR); + cr = readb(uap->port.membase + UART010_CR); cr &= ~UART010_CR_TIE; - writel(cr, port->membase + UART010_CR); + writel(cr, uap->port.membase + UART010_CR); } static void pl010_start_tx(struct uart_port *port) { + struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int cr; - cr = readb(port->membase + UART010_CR); + cr = readb(uap->port.membase + UART010_CR); cr |= UART010_CR_TIE; - writel(cr, port->membase + UART010_CR); + writel(cr, uap->port.membase + UART010_CR); } static void pl010_stop_rx(struct uart_port *port) { + struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int cr; - cr = readb(port->membase + UART010_CR); + cr = readb(uap->port.membase + UART010_CR); cr &= ~(UART010_CR_RIE | UART010_CR_RTIE); - writel(cr, port->membase + UART010_CR); + writel(cr, uap->port.membase + UART010_CR); } static void pl010_enable_ms(struct uart_port *port) { + struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int cr; - cr = readb(port->membase + UART010_CR); + cr = readb(uap->port.membase + UART010_CR); cr |= UART010_CR_MSIE; - writel(cr, port->membase + UART010_CR); + writel(cr, uap->port.membase + UART010_CR); } -static void pl010_rx_chars(struct uart_port *port) +static void pl010_rx_chars(struct uart_amba_port *uap) { - struct tty_struct *tty = port->info->tty; + struct tty_struct *tty = uap->port.info->tty; unsigned int status, ch, flag, rsr, max_count = 256; - status = readb(port->membase + UART01x_FR); + status = readb(uap->port.membase + UART01x_FR); while (UART_RX_DATA(status) && max_count--) { - ch = readb(port->membase + UART01x_DR); + ch = readb(uap->port.membase + UART01x_DR); flag = TTY_NORMAL; - port->icount.rx++; + uap->port.icount.rx++; /* * Note that the error handling code is * out of the main execution path */ - rsr = readb(port->membase + UART01x_RSR) | UART_DUMMY_RSR_RX; + rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX; if (unlikely(rsr & UART01x_RSR_ANY)) { - writel(0, port->membase + UART01x_ECR); + writel(0, uap->port.membase + UART01x_ECR); if (rsr & UART01x_RSR_BE) { rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE); - port->icount.brk++; - if (uart_handle_break(port)) + uap->port.icount.brk++; + if (uart_handle_break(&uap->port)) goto ignore_char; } else if (rsr & UART01x_RSR_PE) - port->icount.parity++; + uap->port.icount.parity++; else if (rsr & UART01x_RSR_FE) - port->icount.frame++; + uap->port.icount.frame++; if (rsr & UART01x_RSR_OE) - port->icount.overrun++; + uap->port.icount.overrun++; - rsr &= port->read_status_mask; + rsr &= uap->port.read_status_mask; if (rsr & UART01x_RSR_BE) flag = TTY_BREAK; @@ -153,53 +159,52 @@ static void pl010_rx_chars(struct uart_port *port) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(port, ch)) + if (uart_handle_sysrq_char(&uap->port, ch)) goto ignore_char; - uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag); + uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag); ignore_char: - status = readb(port->membase + UART01x_FR); + status = readb(uap->port.membase + UART01x_FR); } tty_flip_buffer_push(tty); return; } -static void pl010_tx_chars(struct uart_port *port) +static void pl010_tx_chars(struct uart_amba_port *uap) { - struct circ_buf *xmit = &port->info->xmit; + struct circ_buf *xmit = &uap->port.info->xmit; int count; - if (port->x_char) { - writel(port->x_char, port->membase + UART01x_DR); - port->icount.tx++; - port->x_char = 0; + if (uap->port.x_char) { + writel(uap->port.x_char, uap->port.membase + UART01x_DR); + uap->port.icount.tx++; + uap->port.x_char = 0; return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - pl010_stop_tx(port); + if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { + pl010_stop_tx(&uap->port); return; } - count = port->fifosize >> 1; + count = uap->port.fifosize >> 1; do { - writel(xmit->buf[xmit->tail], port->membase + UART01x_DR); + writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; + uap->port.icount.tx++; if (uart_circ_empty(xmit)) break; } while (--count > 0); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); + uart_write_wakeup(&uap->port); if (uart_circ_empty(xmit)) - pl010_stop_tx(port); + pl010_stop_tx(&uap->port); } -static void pl010_modem_status(struct uart_port *port) +static void pl010_modem_status(struct uart_amba_port *uap) { - struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int status, delta; writel(0, uap->port.membase + UART010_ICR); @@ -226,47 +231,50 @@ static void pl010_modem_status(struct uart_port *port) static irqreturn_t pl010_int(int irq, void *dev_id) { - struct uart_port *port = dev_id; + struct uart_amba_port *uap = dev_id; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; int handled = 0; - spin_lock(&port->lock); + spin_lock(&uap->port.lock); - status = readb(port->membase + UART010_IIR); + status = readb(uap->port.membase + UART010_IIR); if (status) { do { if (status & (UART010_IIR_RTIS | UART010_IIR_RIS)) - pl010_rx_chars(port); + pl010_rx_chars(uap); if (status & UART010_IIR_MIS) - pl010_modem_status(port); + pl010_modem_status(uap); if (status & UART010_IIR_TIS) - pl010_tx_chars(port); + pl010_tx_chars(uap); if (pass_counter-- == 0) break; - status = readb(port->membase + UART010_IIR); + status = readb(uap->port.membase + UART010_IIR); } while (status & (UART010_IIR_RTIS | UART010_IIR_RIS | UART010_IIR_TIS)); handled = 1; } - spin_unlock(&port->lock); + spin_unlock(&uap->port.lock); return IRQ_RETVAL(handled); } static unsigned int pl010_tx_empty(struct uart_port *port) { - return readb(port->membase + UART01x_FR) & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT; + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int status = readb(uap->port.membase + UART01x_FR); + return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT; } static unsigned int pl010_get_mctrl(struct uart_port *port) { + struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int result = 0; unsigned int status; - status = readb(port->membase + UART01x_FR); + status = readb(uap->port.membase + UART01x_FR); if (status & UART01x_FR_DCD) result |= TIOCM_CAR; if (status & UART01x_FR_DSR) @@ -287,17 +295,18 @@ static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl) static void pl010_break_ctl(struct uart_port *port, int break_state) { + struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned long flags; unsigned int lcr_h; - spin_lock_irqsave(&port->lock, flags); - lcr_h = readb(port->membase + UART010_LCRH); + spin_lock_irqsave(&uap->port.lock, flags); + lcr_h = readb(uap->port.membase + UART010_LCRH); if (break_state == -1) lcr_h |= UART01x_LCRH_BRK; else lcr_h &= ~UART01x_LCRH_BRK; - writel(lcr_h, port->membase + UART010_LCRH); - spin_unlock_irqrestore(&port->lock, flags); + writel(lcr_h, uap->port.membase + UART010_LCRH); + spin_unlock_irqrestore(&uap->port.lock, flags); } static int pl010_startup(struct uart_port *port) @@ -305,49 +314,71 @@ static int pl010_startup(struct uart_port *port) struct uart_amba_port *uap = (struct uart_amba_port *)port; int retval; + /* + * Try to enable the clock producer. + */ + retval = clk_enable(uap->clk); + if (retval) + goto out; + + uap->port.uartclk = clk_get_rate(uap->clk); + /* * Allocate the IRQ */ - retval = request_irq(port->irq, pl010_int, 0, "uart-pl010", port); + retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap); if (retval) - return retval; + goto clk_dis; /* * initialise the old status of the modem signals */ - uap->old_status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY; + uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; /* * Finally, enable interrupts */ writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE, - port->membase + UART010_CR); + uap->port.membase + UART010_CR); return 0; + + clk_dis: + clk_disable(uap->clk); + out: + return retval; } static void pl010_shutdown(struct uart_port *port) { + struct uart_amba_port *uap = (struct uart_amba_port *)port; + /* * Free the interrupt */ - free_irq(port->irq, port); + free_irq(uap->port.irq, uap); /* * disable all interrupts, disable the port */ - writel(0, port->membase + UART010_CR); + writel(0, uap->port.membase + UART010_CR); /* disable break condition and fifos */ - writel(readb(port->membase + UART010_LCRH) & + writel(readb(uap->port.membase + UART010_LCRH) & ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN), - port->membase + UART010_LCRH); + uap->port.membase + UART010_LCRH); + + /* + * Shut down the clock producer + */ + clk_disable(uap->clk); } static void pl010_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { + struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int lcr_h, old_cr; unsigned long flags; unsigned int baud, quot; @@ -355,7 +386,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, /* * Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16); quot = uart_get_divisor(port, baud); switch (termios->c_cflag & CSIZE) { @@ -379,66 +410,66 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, if (!(termios->c_cflag & PARODD)) lcr_h |= UART01x_LCRH_EPS; } - if (port->fifosize > 1) + if (uap->port.fifosize > 1) lcr_h |= UART01x_LCRH_FEN; - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&uap->port.lock, flags); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); - port->read_status_mask = UART01x_RSR_OE; + uap->port.read_status_mask = UART01x_RSR_OE; if (termios->c_iflag & INPCK) - port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; + uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= UART01x_RSR_BE; + uap->port.read_status_mask |= UART01x_RSR_BE; /* * Characters to ignore */ - port->ignore_status_mask = 0; + uap->port.ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; + uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= UART01x_RSR_BE; + uap->port.ignore_status_mask |= UART01x_RSR_BE; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART01x_RSR_OE; + uap->port.ignore_status_mask |= UART01x_RSR_OE; } /* * Ignore all characters if CREAD is not set. */ if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_DUMMY_RSR_RX; + uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX; /* first, disable everything */ - old_cr = readb(port->membase + UART010_CR) & ~UART010_CR_MSIE; + old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE; if (UART_ENABLE_MS(port, termios->c_cflag)) old_cr |= UART010_CR_MSIE; - writel(0, port->membase + UART010_CR); + writel(0, uap->port.membase + UART010_CR); /* Set baud rate */ quot -= 1; - writel((quot & 0xf00) >> 8, port->membase + UART010_LCRM); - writel(quot & 0xff, port->membase + UART010_LCRL); + writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM); + writel(quot & 0xff, uap->port.membase + UART010_LCRL); /* * ----------v----------v----------v----------v----- * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L * ----------^----------^----------^----------^----- */ - writel(lcr_h, port->membase + UART010_LCRH); - writel(old_cr, port->membase + UART010_CR); + writel(lcr_h, uap->port.membase + UART010_LCRH); + writel(old_cr, uap->port.membase + UART010_CR); - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&uap->port.lock, flags); } static const char *pl010_type(struct uart_port *port) @@ -514,47 +545,52 @@ static struct uart_amba_port *amba_ports[UART_NR]; static void pl010_console_putchar(struct uart_port *port, int ch) { + struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int status; do { - status = readb(port->membase + UART01x_FR); + status = readb(uap->port.membase + UART01x_FR); barrier(); } while (!UART_TX_READY(status)); - writel(ch, port->membase + UART01x_DR); + writel(ch, uap->port.membase + UART01x_DR); } static void pl010_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_port *port = &amba_ports[co->index]->port; + struct uart_amba_port *uap = amba_ports[co->index]; unsigned int status, old_cr; + clk_enable(uap->clk); + /* * First save the CR then disable the interrupts */ - old_cr = readb(port->membase + UART010_CR); - writel(UART01x_CR_UARTEN, port->membase + UART010_CR); + old_cr = readb(uap->port.membase + UART010_CR); + writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR); - uart_console_write(port, s, count, pl010_console_putchar); + uart_console_write(&uap->port, s, count, pl010_console_putchar); /* * Finally, wait for transmitter to become empty * and restore the TCR */ do { - status = readb(port->membase + UART01x_FR); + status = readb(uap->port.membase + UART01x_FR); barrier(); } while (status & UART01x_FR_BUSY); - writel(old_cr, port->membase + UART010_CR); + writel(old_cr, uap->port.membase + UART010_CR); + + clk_disable(uap->clk); } static void __init -pl010_console_get_options(struct uart_port *port, int *baud, +pl010_console_get_options(struct uart_amba_port *uap, int *baud, int *parity, int *bits) { - if (readb(port->membase + UART010_CR) & UART01x_CR_UARTEN) { + if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) { unsigned int lcr_h, quot; - lcr_h = readb(port->membase + UART010_LCRH); + lcr_h = readb(uap->port.membase + UART010_LCRH); *parity = 'n'; if (lcr_h & UART01x_LCRH_PEN) { @@ -569,14 +605,15 @@ pl010_console_get_options(struct uart_port *port, int *baud, else *bits = 8; - quot = readb(port->membase + UART010_LCRL) | readb(port->membase + UART010_LCRM) << 8; - *baud = port->uartclk / (16 * (quot + 1)); + quot = readb(uap->port.membase + UART010_LCRL) | + readb(uap->port.membase + UART010_LCRM) << 8; + *baud = uap->port.uartclk / (16 * (quot + 1)); } } static int __init pl010_console_setup(struct console *co, char *options) { - struct uart_port *port; + struct uart_amba_port *uap; int baud = 38400; int bits = 8; int parity = 'n'; @@ -589,16 +626,18 @@ static int __init pl010_console_setup(struct console *co, char *options) */ if (co->index >= UART_NR) co->index = 0; - if (!amba_ports[co->index]) + uap = amba_ports[co->index]; + if (!uap) return -ENODEV; - port = &amba_ports[co->index]->port; + + uap->port.uartclk = clk_get_rate(uap->clk); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else - pl010_console_get_options(port, &baud, &parity, &bits); + pl010_console_get_options(uap, &baud, &parity, &bits); - return uart_set_options(port, co, baud, parity, bits, flow); + return uart_set_options(&uap->port, co, baud, parity, bits, flow); } static struct uart_driver amba_reg; @@ -629,7 +668,7 @@ static struct uart_driver amba_reg = { static int pl010_probe(struct amba_device *dev, void *id) { - struct uart_amba_port *port; + struct uart_amba_port *uap; void __iomem *base; int i, ret; @@ -642,8 +681,8 @@ static int pl010_probe(struct amba_device *dev, void *id) goto out; } - port = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); - if (!port) { + uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); + if (!uap) { ret = -ENOMEM; goto out; } @@ -654,51 +693,57 @@ static int pl010_probe(struct amba_device *dev, void *id) goto free; } - port->port.dev = &dev->dev; - port->port.mapbase = dev->res.start; - port->port.membase = base; - port->port.iotype = UPIO_MEM; - port->port.irq = dev->irq[0]; - port->port.uartclk = 14745600; - port->port.fifosize = 16; - port->port.ops = &amba_pl010_pops; - port->port.flags = UPF_BOOT_AUTOCONF; - port->port.line = i; - port->dev = dev; - port->data = dev->dev.platform_data; - - amba_ports[i] = port; - - amba_set_drvdata(dev, port); - ret = uart_add_one_port(&amba_reg, &port->port); + uap->clk = clk_get(&dev->dev, "UARTCLK"); + if (IS_ERR(uap->clk)) { + ret = PTR_ERR(uap->clk); + goto unmap; + } + + uap->port.dev = &dev->dev; + uap->port.mapbase = dev->res.start; + uap->port.membase = base; + uap->port.iotype = UPIO_MEM; + uap->port.irq = dev->irq[0]; + uap->port.fifosize = 16; + uap->port.ops = &amba_pl010_pops; + uap->port.flags = UPF_BOOT_AUTOCONF; + uap->port.line = i; + uap->dev = dev; + uap->data = dev->dev.platform_data; + + amba_ports[i] = uap; + + amba_set_drvdata(dev, uap); + ret = uart_add_one_port(&amba_reg, &uap->port); if (ret) { amba_set_drvdata(dev, NULL); amba_ports[i] = NULL; + clk_put(uap->clk); + unmap: iounmap(base); free: - kfree(port); + kfree(uap); } - out: return ret; } static int pl010_remove(struct amba_device *dev) { - struct uart_amba_port *port = amba_get_drvdata(dev); + struct uart_amba_port *uap = amba_get_drvdata(dev); int i; amba_set_drvdata(dev, NULL); - uart_remove_one_port(&amba_reg, &port->port); + uart_remove_one_port(&amba_reg, &uap->port); for (i = 0; i < ARRAY_SIZE(amba_ports); i++) - if (amba_ports[i] == port) + if (amba_ports[i] == uap) amba_ports[i] = NULL; - iounmap(port->port.membase); - kfree(port); - + iounmap(uap->port.membase); + clk_put(uap->clk); + kfree(uap); return 0; } diff --git a/trunk/drivers/serial/atmel_serial.c b/trunk/drivers/serial/atmel_serial.c index 935f48fa501d..3320bcd92c0a 100644 --- a/trunk/drivers/serial/atmel_serial.c +++ b/trunk/drivers/serial/atmel_serial.c @@ -484,11 +484,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, unsigned long flags; unsigned int mode, imr, quot, baud; + /* Get current mode register */ + mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR); + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); - /* Get current mode register */ - mode = UART_GET_MR(port) & ~(ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR); + if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ + quot /= 8; + mode |= ATMEL_US_USCLKS_MCK_DIV8; + } /* byte size */ switch (termios->c_cflag & CSIZE) { diff --git a/trunk/drivers/serial/atmel_serial.h b/trunk/drivers/serial/atmel_serial.h index 11b44360e108..e0141776517c 100644 --- a/trunk/drivers/serial/atmel_serial.h +++ b/trunk/drivers/serial/atmel_serial.h @@ -46,6 +46,9 @@ #define ATMEL_US_USMODE_ISO7816_T1 6 #define ATMEL_US_USMODE_IRDA 8 #define ATMEL_US_USCLKS (3 << 4) /* Clock Selection */ +#define ATMEL_US_USCLKS_MCK (0 << 4) +#define ATMEL_US_USCLKS_MCK_DIV8 (1 << 4) +#define ATMEL_US_USCLKS_SCK (3 << 4) #define ATMEL_US_CHRL (3 << 6) /* Character Length */ #define ATMEL_US_CHRL_5 (0 << 6) #define ATMEL_US_CHRL_6 (1 << 6) diff --git a/trunk/drivers/serial/bfin_5xx.c b/trunk/drivers/serial/bfin_5xx.c new file mode 100644 index 000000000000..408390f93db9 --- /dev/null +++ b/trunk/drivers/serial/bfin_5xx.c @@ -0,0 +1,1012 @@ +/* + * File: drivers/serial/bfin_5xx.c + * Based on: Based on drivers/serial/sa1100.c + * Author: Aubrey Li + * + * Created: + * Description: Driver for blackfin 5xx serial ports + * + * Rev: $Id: bfin_5xx.c,v 1.19 2006/09/24 02:33:53 aubrey Exp $ + * + * Modified: + * Copyright 2006 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_SERIAL_BFIN_DMA +#include +#include +#include +#include +#endif + +/* UART name and device definitions */ +#define BFIN_SERIAL_NAME "ttyBF" +#define BFIN_SERIAL_MAJOR 204 +#define BFIN_SERIAL_MINOR 64 + +/* + * Setup for console. Argument comes from the menuconfig + */ +#define DMA_RX_XCOUNT 512 +#define DMA_RX_YCOUNT (PAGE_SIZE / DMA_RX_XCOUNT) + +#define DMA_RX_FLUSH_JIFFIES 5 + +#ifdef CONFIG_SERIAL_BFIN_DMA +static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart); +#else +static void bfin_serial_do_work(struct work_struct *work); +static void bfin_serial_tx_chars(struct bfin_serial_port *uart); +static void local_put_char(struct bfin_serial_port *uart, char ch); +#endif + +static void bfin_serial_mctrl_check(struct bfin_serial_port *uart); + +/* + * interrupts are disabled on entry + */ +static void bfin_serial_stop_tx(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + +#ifdef CONFIG_SERIAL_BFIN_DMA + disable_dma(uart->tx_dma_channel); +#else + unsigned short ier; + + ier = UART_GET_IER(uart); + ier &= ~ETBEI; + UART_PUT_IER(uart, ier); +#endif +} + +/* + * port is locked and interrupts are disabled + */ +static void bfin_serial_start_tx(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + +#ifdef CONFIG_SERIAL_BFIN_DMA + bfin_serial_dma_tx_chars(uart); +#else + unsigned short ier; + ier = UART_GET_IER(uart); + ier |= ETBEI; + UART_PUT_IER(uart, ier); + bfin_serial_tx_chars(uart); +#endif +} + +/* + * Interrupts are enabled + */ +static void bfin_serial_stop_rx(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + unsigned short ier; + + ier = UART_GET_IER(uart); + ier &= ~ERBFI; + UART_PUT_IER(uart, ier); +} + +/* + * Set the modem control timer to fire immediately. + */ +static void bfin_serial_enable_ms(struct uart_port *port) +{ +} + +#ifdef CONFIG_SERIAL_BFIN_PIO +static void local_put_char(struct bfin_serial_port *uart, char ch) +{ + unsigned short status; + int flags = 0; + + spin_lock_irqsave(&uart->port.lock, flags); + + do { + status = UART_GET_LSR(uart); + } while (!(status & THRE)); + + UART_PUT_CHAR(uart, ch); + SSYNC(); + + spin_unlock_irqrestore(&uart->port.lock, flags); +} + +static void bfin_serial_rx_chars(struct bfin_serial_port *uart) +{ + struct tty_struct *tty = uart->port.info?uart->port.info->tty:0; + unsigned int status, ch, flg; +#ifdef BF533_FAMILY + static int in_break = 0; +#endif + + status = UART_GET_LSR(uart); + ch = UART_GET_CHAR(uart); + uart->port.icount.rx++; + +#ifdef BF533_FAMILY + /* The BF533 family of processors have a nice misbehavior where + * they continuously generate characters for a "single" break. + * We have to basically ignore this flood until the "next" valid + * character comes across. All other Blackfin families operate + * properly though. + */ + if (in_break) { + if (ch != 0) { + in_break = 0; + ch = UART_GET_CHAR(uart); + } + return; + } +#endif + + if (status & BI) { +#ifdef BF533_FAMILY + in_break = 1; +#endif + uart->port.icount.brk++; + if (uart_handle_break(&uart->port)) + goto ignore_char; + flg = TTY_BREAK; + } else if (status & PE) { + flg = TTY_PARITY; + uart->port.icount.parity++; + } else if (status & OE) { + flg = TTY_OVERRUN; + uart->port.icount.overrun++; + } else if (status & FE) { + flg = TTY_FRAME; + uart->port.icount.frame++; + } else + flg = TTY_NORMAL; + + if (uart_handle_sysrq_char(&uart->port, ch)) + goto ignore_char; + if (tty) + uart_insert_char(&uart->port, status, 2, ch, flg); + +ignore_char: + if (tty) + tty_flip_buffer_push(tty); +} + +static void bfin_serial_tx_chars(struct bfin_serial_port *uart) +{ + struct circ_buf *xmit = &uart->port.info->xmit; + + if (uart->port.x_char) { + UART_PUT_CHAR(uart, uart->port.x_char); + uart->port.icount.tx++; + uart->port.x_char = 0; + return; + } + /* + * Check the modem control lines before + * transmitting anything. + */ + bfin_serial_mctrl_check(uart); + + if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { + bfin_serial_stop_tx(&uart->port); + return; + } + + local_put_char(uart, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + uart->port.icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uart->port); + + if (uart_circ_empty(xmit)) + bfin_serial_stop_tx(&uart->port); +} + +static irqreturn_t bfin_serial_int(int irq, void *dev_id) +{ + struct bfin_serial_port *uart = dev_id; + unsigned short status; + + spin_lock(&uart->port.lock); + status = UART_GET_IIR(uart); + do { + if ((status & IIR_STATUS) == IIR_TX_READY) + bfin_serial_tx_chars(uart); + if ((status & IIR_STATUS) == IIR_RX_READY) + bfin_serial_rx_chars(uart); + status = UART_GET_IIR(uart); + } while (status & (IIR_TX_READY | IIR_RX_READY)); + spin_unlock(&uart->port.lock); + return IRQ_HANDLED; +} + +static void bfin_serial_do_work(struct work_struct *work) +{ + struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue); + + bfin_serial_mctrl_check(uart); +} + +#endif + +#ifdef CONFIG_SERIAL_BFIN_DMA +static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) +{ + struct circ_buf *xmit = &uart->port.info->xmit; + unsigned short ier; + int flags = 0; + + if (!uart->tx_done) + return; + + uart->tx_done = 0; + + if (uart->port.x_char) { + UART_PUT_CHAR(uart, uart->port.x_char); + uart->port.icount.tx++; + uart->port.x_char = 0; + uart->tx_done = 1; + return; + } + /* + * Check the modem control lines before + * transmitting anything. + */ + bfin_serial_mctrl_check(uart); + + if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { + bfin_serial_stop_tx(&uart->port); + uart->tx_done = 1; + return; + } + + spin_lock_irqsave(&uart->port.lock, flags); + uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE); + if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail)) + uart->tx_count = UART_XMIT_SIZE - xmit->tail; + blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail), + (unsigned long)(xmit->buf+xmit->tail+uart->tx_count)); + set_dma_config(uart->tx_dma_channel, + set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, + INTR_ON_BUF, + DIMENSION_LINEAR, + DATA_SIZE_8)); + set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); + set_dma_x_count(uart->tx_dma_channel, uart->tx_count); + set_dma_x_modify(uart->tx_dma_channel, 1); + enable_dma(uart->tx_dma_channel); + ier = UART_GET_IER(uart); + ier |= ETBEI; + UART_PUT_IER(uart, ier); + spin_unlock_irqrestore(&uart->port.lock, flags); +} + +static void bfin_serial_dma_rx_chars(struct bfin_serial_port * uart) +{ + struct tty_struct *tty = uart->port.info->tty; + int i, flg, status; + + status = UART_GET_LSR(uart); + uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);; + + if (status & BI) { + uart->port.icount.brk++; + if (uart_handle_break(&uart->port)) + goto dma_ignore_char; + flg = TTY_BREAK; + } else if (status & PE) { + flg = TTY_PARITY; + uart->port.icount.parity++; + } else if (status & OE) { + flg = TTY_OVERRUN; + uart->port.icount.overrun++; + } else if (status & FE) { + flg = TTY_FRAME; + uart->port.icount.frame++; + } else + flg = TTY_NORMAL; + + for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) { + if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i])) + goto dma_ignore_char; + uart_insert_char(&uart->port, status, 2, uart->rx_dma_buf.buf[i], flg); + } +dma_ignore_char: + tty_flip_buffer_push(tty); +} + +void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) +{ + int x_pos, pos; + int flags = 0; + + bfin_serial_dma_tx_chars(uart); + + spin_lock_irqsave(&uart->port.lock, flags); + x_pos = DMA_RX_XCOUNT - get_dma_curr_xcount(uart->rx_dma_channel); + if (x_pos == DMA_RX_XCOUNT) + x_pos = 0; + + pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; + + if (pos>uart->rx_dma_buf.tail) { + uart->rx_dma_buf.tail = pos; + bfin_serial_dma_rx_chars(uart); + uart->rx_dma_buf.head = uart->rx_dma_buf.tail; + } + spin_unlock_irqrestore(&uart->port.lock, flags); + uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; + add_timer(&(uart->rx_dma_timer)); +} + +static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) +{ + struct bfin_serial_port *uart = dev_id; + struct circ_buf *xmit = &uart->port.info->xmit; + unsigned short ier; + + spin_lock(&uart->port.lock); + if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { + clear_dma_irqstat(uart->tx_dma_channel); + disable_dma(uart->tx_dma_channel); + ier = UART_GET_IER(uart); + ier &= ~ETBEI; + UART_PUT_IER(uart, ier); + xmit->tail = (xmit->tail+uart->tx_count) &(UART_XMIT_SIZE -1); + uart->port.icount.tx+=uart->tx_count; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uart->port); + + if (uart_circ_empty(xmit)) + bfin_serial_stop_tx(&uart->port); + uart->tx_done = 1; + } + + spin_unlock(&uart->port.lock); + return IRQ_HANDLED; +} + +static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) +{ + struct bfin_serial_port *uart = dev_id; + unsigned short irqstat; + + uart->rx_dma_nrows++; + if (uart->rx_dma_nrows == DMA_RX_YCOUNT) { + uart->rx_dma_nrows = 0; + uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT; + bfin_serial_dma_rx_chars(uart); + uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0; + } + spin_lock(&uart->port.lock); + irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); + clear_dma_irqstat(uart->rx_dma_channel); + + spin_unlock(&uart->port.lock); + return IRQ_HANDLED; +} +#endif + +/* + * Return TIOCSER_TEMT when transmitter is not busy. + */ +static unsigned int bfin_serial_tx_empty(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + unsigned short lsr; + + lsr = UART_GET_LSR(uart); + if (lsr & TEMT) + return TIOCSER_TEMT; + else + return 0; +} + +static unsigned int bfin_serial_get_mctrl(struct uart_port *port) +{ +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + if (uart->cts_pin < 0) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + + if (gpio_get_value(uart->cts_pin)) + return TIOCM_DSR | TIOCM_CAR; + else +#endif + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + if (uart->rts_pin < 0) + return; + + if (mctrl & TIOCM_RTS) + gpio_set_value(uart->rts_pin, 0); + else + gpio_set_value(uart->rts_pin, 1); +#endif +} + +/* + * Handle any change of modem status signal since we were last called. + */ +static void bfin_serial_mctrl_check(struct bfin_serial_port *uart) +{ +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + unsigned int status; +# ifdef CONFIG_SERIAL_BFIN_DMA + struct uart_info *info = uart->port.info; + struct tty_struct *tty = info->tty; + + status = bfin_serial_get_mctrl(&uart->port); + if (!(status & TIOCM_CTS)) { + tty->hw_stopped = 1; + } else { + tty->hw_stopped = 0; + } +# else + status = bfin_serial_get_mctrl(&uart->port); + uart_handle_cts_change(&uart->port, status & TIOCM_CTS); + if (!(status & TIOCM_CTS)) + schedule_work(&uart->cts_workqueue); +# endif +#endif +} + +/* + * Interrupts are always disabled. + */ +static void bfin_serial_break_ctl(struct uart_port *port, int break_state) +{ +} + +static int bfin_serial_startup(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + +#ifdef CONFIG_SERIAL_BFIN_DMA + dma_addr_t dma_handle; + + if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) { + printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n"); + return -EBUSY; + } + + if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) { + printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n"); + free_dma(uart->rx_dma_channel); + return -EBUSY; + } + + set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart); + set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart); + + uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA); + uart->rx_dma_buf.head = 0; + uart->rx_dma_buf.tail = 0; + uart->rx_dma_nrows = 0; + + set_dma_config(uart->rx_dma_channel, + set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, + INTR_ON_ROW, DIMENSION_2D, + DATA_SIZE_8)); + set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT); + set_dma_x_modify(uart->rx_dma_channel, 1); + set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT); + set_dma_y_modify(uart->rx_dma_channel, 1); + set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf); + enable_dma(uart->rx_dma_channel); + + uart->rx_dma_timer.data = (unsigned long)(uart); + uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout; + uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; + add_timer(&(uart->rx_dma_timer)); +#else + if (request_irq + (uart->port.irq, bfin_serial_int, IRQF_DISABLED, + "BFIN_UART_RX", uart)) { + printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); + return -EBUSY; + } + + if (request_irq + (uart->port.irq+1, bfin_serial_int, IRQF_DISABLED, + "BFIN_UART_TX", uart)) { + printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n"); + free_irq(uart->port.irq, uart); + return -EBUSY; + } +#endif + UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI); + return 0; +} + +static void bfin_serial_shutdown(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + +#ifdef CONFIG_SERIAL_BFIN_DMA + disable_dma(uart->tx_dma_channel); + free_dma(uart->tx_dma_channel); + disable_dma(uart->rx_dma_channel); + free_dma(uart->rx_dma_channel); + del_timer(&(uart->rx_dma_timer)); +#else + free_irq(uart->port.irq, uart); + free_irq(uart->port.irq+1, uart); +#endif +} + +static void +bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + unsigned long flags; + unsigned int baud, quot; + unsigned short val, ier, lsr, lcr = 0; + + switch (termios->c_cflag & CSIZE) { + case CS8: + lcr = WLS(8); + break; + case CS7: + lcr = WLS(7); + break; + case CS6: + lcr = WLS(6); + break; + case CS5: + lcr = WLS(5); + break; + default: + printk(KERN_ERR "%s: word lengh not supported\n", + __FUNCTION__); + } + + if (termios->c_cflag & CSTOPB) + lcr |= STB; + if (termios->c_cflag & PARENB) { + lcr |= PEN; + if (!(termios->c_cflag & PARODD)) + lcr |= EPS; + } + + /* These controls are not implemented for this port */ + termios->c_iflag |= INPCK | BRKINT | PARMRK; + termios->c_iflag &= ~(IGNPAR | IGNBRK); + + /* These controls are not implemented for this port */ + termios->c_iflag |= INPCK | BRKINT | PARMRK; + termios->c_iflag &= ~(IGNPAR | IGNBRK); + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + spin_lock_irqsave(&uart->port.lock, flags); + + do { + lsr = UART_GET_LSR(uart); + } while (!(lsr & TEMT)); + + /* Disable UART */ + ier = UART_GET_IER(uart); + UART_PUT_IER(uart, 0); + + /* Set DLAB in LCR to Access DLL and DLH */ + val = UART_GET_LCR(uart); + val |= DLAB; + UART_PUT_LCR(uart, val); + SSYNC(); + + UART_PUT_DLL(uart, quot & 0xFF); + SSYNC(); + UART_PUT_DLH(uart, (quot >> 8) & 0xFF); + SSYNC(); + + /* Clear DLAB in LCR to Access THR RBR IER */ + val = UART_GET_LCR(uart); + val &= ~DLAB; + UART_PUT_LCR(uart, val); + SSYNC(); + + UART_PUT_LCR(uart, lcr); + + /* Enable UART */ + UART_PUT_IER(uart, ier); + + val = UART_GET_GCTL(uart); + val |= UCEN; + UART_PUT_GCTL(uart, val); + + spin_unlock_irqrestore(&uart->port.lock, flags); +} + +static const char *bfin_serial_type(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + + return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL; +} + +/* + * Release the memory region(s) being used by 'port'. + */ +static void bfin_serial_release_port(struct uart_port *port) +{ +} + +/* + * Request the memory region(s) being used by 'port'. + */ +static int bfin_serial_request_port(struct uart_port *port) +{ + return 0; +} + +/* + * Configure/autoconfigure the port. + */ +static void bfin_serial_config_port(struct uart_port *port, int flags) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + + if (flags & UART_CONFIG_TYPE && + bfin_serial_request_port(&uart->port) == 0) + uart->port.type = PORT_BFIN; +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + * The only change we allow are to the flags and type, and + * even then only between PORT_BFIN and PORT_UNKNOWN + */ +static int +bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return 0; +} + +static struct uart_ops bfin_serial_pops = { + .tx_empty = bfin_serial_tx_empty, + .set_mctrl = bfin_serial_set_mctrl, + .get_mctrl = bfin_serial_get_mctrl, + .stop_tx = bfin_serial_stop_tx, + .start_tx = bfin_serial_start_tx, + .stop_rx = bfin_serial_stop_rx, + .enable_ms = bfin_serial_enable_ms, + .break_ctl = bfin_serial_break_ctl, + .startup = bfin_serial_startup, + .shutdown = bfin_serial_shutdown, + .set_termios = bfin_serial_set_termios, + .type = bfin_serial_type, + .release_port = bfin_serial_release_port, + .request_port = bfin_serial_request_port, + .config_port = bfin_serial_config_port, + .verify_port = bfin_serial_verify_port, +}; + +static void __init bfin_serial_init_ports(void) +{ + static int first = 1; + int i; + + if (!first) + return; + first = 0; + + for (i = 0; i < nr_ports; i++) { + bfin_serial_ports[i].port.uartclk = get_sclk(); + bfin_serial_ports[i].port.ops = &bfin_serial_pops; + bfin_serial_ports[i].port.line = i; + bfin_serial_ports[i].port.iotype = UPIO_MEM; + bfin_serial_ports[i].port.membase = + (void __iomem *)bfin_serial_resource[i].uart_base_addr; + bfin_serial_ports[i].port.mapbase = + bfin_serial_resource[i].uart_base_addr; + bfin_serial_ports[i].port.irq = + bfin_serial_resource[i].uart_irq; + bfin_serial_ports[i].port.flags = UPF_BOOT_AUTOCONF; +#ifdef CONFIG_SERIAL_BFIN_DMA + bfin_serial_ports[i].tx_done = 1; + bfin_serial_ports[i].tx_count = 0; + bfin_serial_ports[i].tx_dma_channel = + bfin_serial_resource[i].uart_tx_dma_channel; + bfin_serial_ports[i].rx_dma_channel = + bfin_serial_resource[i].uart_rx_dma_channel; + init_timer(&(bfin_serial_ports[i].rx_dma_timer)); +#else + INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work); +#endif +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + bfin_serial_ports[i].cts_pin = + bfin_serial_resource[i].uart_cts_pin; + bfin_serial_ports[i].rts_pin = + bfin_serial_resource[i].uart_rts_pin; +#endif + bfin_serial_hw_init(&bfin_serial_ports[i]); + + } +} + +#ifdef CONFIG_SERIAL_BFIN_CONSOLE +static void bfin_serial_console_putchar(struct uart_port *port, int ch) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + while (!(UART_GET_LSR(uart))) + barrier(); + UART_PUT_CHAR(uart, ch); + SSYNC(); +} + +/* + * Interrupts are disabled on entering + */ +static void +bfin_serial_console_write(struct console *co, const char *s, unsigned int count) +{ + struct bfin_serial_port *uart = &bfin_serial_ports[co->index]; + int flags = 0; + + spin_lock_irqsave(&uart->port.lock, flags); + uart_console_write(&uart->port, s, count, bfin_serial_console_putchar); + spin_unlock_irqrestore(&uart->port.lock, flags); + +} + +/* + * If the port was already initialised (eg, by a boot loader), + * try to determine the current setup. + */ +static void __init +bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, + int *parity, int *bits) +{ + unsigned short status; + + status = UART_GET_IER(uart) & (ERBFI | ETBEI); + if (status == (ERBFI | ETBEI)) { + /* ok, the port was enabled */ + unsigned short lcr, val; + unsigned short dlh, dll; + + lcr = UART_GET_LCR(uart); + + *parity = 'n'; + if (lcr & PEN) { + if (lcr & EPS) + *parity = 'e'; + else + *parity = 'o'; + } + switch (lcr & 0x03) { + case 0: *bits = 5; break; + case 1: *bits = 6; break; + case 2: *bits = 7; break; + case 3: *bits = 8; break; + } + /* Set DLAB in LCR to Access DLL and DLH */ + val = UART_GET_LCR(uart); + val |= DLAB; + UART_PUT_LCR(uart, val); + + dll = UART_GET_DLL(uart); + dlh = UART_GET_DLH(uart); + + /* Clear DLAB in LCR to Access THR RBR IER */ + val = UART_GET_LCR(uart); + val &= ~DLAB; + UART_PUT_LCR(uart, val); + + *baud = get_sclk() / (16*(dll | dlh << 8)); + } + pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits); +} + +static int __init +bfin_serial_console_setup(struct console *co, char *options) +{ + struct bfin_serial_port *uart; + int baud = 57600; + int bits = 8; + int parity = 'n'; +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + int flow = 'r'; +#else + int flow = 'n'; +#endif + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= nr_ports) + co->index = 0; + uart = &bfin_serial_ports[co->index]; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + bfin_serial_console_get_options(uart, &baud, &parity, &bits); + + return uart_set_options(&uart->port, co, baud, parity, bits, flow); +} + +static struct uart_driver bfin_serial_reg; +static struct console bfin_serial_console = { + .name = BFIN_SERIAL_NAME, + .write = bfin_serial_console_write, + .device = uart_console_device, + .setup = bfin_serial_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &bfin_serial_reg, +}; + +static int __init bfin_serial_rs_console_init(void) +{ + bfin_serial_init_ports(); + register_console(&bfin_serial_console); + return 0; +} +console_initcall(bfin_serial_rs_console_init); + +#define BFIN_SERIAL_CONSOLE &bfin_serial_console +#else +#define BFIN_SERIAL_CONSOLE NULL +#endif + +static struct uart_driver bfin_serial_reg = { + .owner = THIS_MODULE, + .driver_name = "bfin-uart", + .dev_name = BFIN_SERIAL_NAME, + .major = BFIN_SERIAL_MAJOR, + .minor = BFIN_SERIAL_MINOR, + .nr = NR_PORTS, + .cons = BFIN_SERIAL_CONSOLE, +}; + +static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state) +{ + struct bfin_serial_port *uart = platform_get_drvdata(dev); + + if (uart) + uart_suspend_port(&bfin_serial_reg, &uart->port); + + return 0; +} + +static int bfin_serial_resume(struct platform_device *dev) +{ + struct bfin_serial_port *uart = platform_get_drvdata(dev); + + if (uart) + uart_resume_port(&bfin_serial_reg, &uart->port); + + return 0; +} + +static int bfin_serial_probe(struct platform_device *dev) +{ + struct resource *res = dev->resource; + int i; + + for (i = 0; i < dev->num_resources; i++, res++) + if (res->flags & IORESOURCE_MEM) + break; + + if (i < dev->num_resources) { + for (i = 0; i < nr_ports; i++, res++) { + if (bfin_serial_ports[i].port.mapbase != res->start) + continue; + bfin_serial_ports[i].port.dev = &dev->dev; + uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + platform_set_drvdata(dev, &bfin_serial_ports[i]); + } + } + + return 0; +} + +static int bfin_serial_remove(struct platform_device *pdev) +{ + struct bfin_serial_port *uart = platform_get_drvdata(pdev); + + +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + gpio_free(uart->cts_pin); + gpio_free(uart->rts_pin); +#endif + + platform_set_drvdata(pdev, NULL); + + if (uart) + uart_remove_one_port(&bfin_serial_reg, &uart->port); + + return 0; +} + +static struct platform_driver bfin_serial_driver = { + .probe = bfin_serial_probe, + .remove = bfin_serial_remove, + .suspend = bfin_serial_suspend, + .resume = bfin_serial_resume, + .driver = { + .name = "bfin-uart", + }, +}; + +static int __init bfin_serial_init(void) +{ + int ret; + + pr_info("Serial: Blackfin serial driver\n"); + + bfin_serial_init_ports(); + + ret = uart_register_driver(&bfin_serial_reg); + if (ret == 0) { + ret = platform_driver_register(&bfin_serial_driver); + if (ret) { + pr_debug("uart register failed\n"); + uart_unregister_driver(&bfin_serial_reg); + } + } + return ret; +} + +static void __exit bfin_serial_exit(void) +{ + platform_driver_unregister(&bfin_serial_driver); + uart_unregister_driver(&bfin_serial_reg); +} + +module_init(bfin_serial_init); +module_exit(bfin_serial_exit); + +MODULE_AUTHOR("Aubrey.Li "); +MODULE_DESCRIPTION("Blackfin generic serial port driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR); diff --git a/trunk/drivers/serial/cpm_uart/cpm_uart_core.c b/trunk/drivers/serial/cpm_uart/cpm_uart_core.c index 7a3b97fdf8d1..f23972bc00c0 100644 --- a/trunk/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/trunk/drivers/serial/cpm_uart/cpm_uart_core.c @@ -934,7 +934,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { .irq = SMC1_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SMC1].port.lock), }, .flags = FLAG_SMC, .tx_nrfifos = TX_NUM_FIFO, @@ -948,7 +948,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { .irq = SMC2_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SMC2].port.lock), }, .flags = FLAG_SMC, .tx_nrfifos = TX_NUM_FIFO, @@ -965,7 +965,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { .irq = SCC1_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC1].port.lock), }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, @@ -979,7 +979,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { .irq = SCC2_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC2].port.lock), }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, @@ -993,7 +993,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { .irq = SCC3_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC3].port.lock), }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, @@ -1007,7 +1007,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { .irq = SCC4_IRQ, .ops = &cpm_uart_pops, .iotype = UPIO_MEM, - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC4].port.lock), }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, diff --git a/trunk/drivers/serial/crisv10.h b/trunk/drivers/serial/crisv10.h deleted file mode 100644 index 4a23340663aa..000000000000 --- a/trunk/drivers/serial/crisv10.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * serial.h: Arch-dep definitions for the Etrax100 serial driver. - * - * Copyright (C) 1998, 1999, 2000 Axis Communications AB - */ - -#ifndef _ETRAX_SERIAL_H -#define _ETRAX_SERIAL_H - -#include -#include - -/* Software state per channel */ - -#ifdef __KERNEL__ -/* - * This is our internal structure for each serial port's state. - * - * Many fields are paralleled by the structure used by the serial_struct - * structure. - * - * For definitions of the flags field, see tty.h - */ - -#define SERIAL_RECV_DESCRIPTORS 8 - -struct etrax_recv_buffer { - struct etrax_recv_buffer *next; - unsigned short length; - unsigned char error; - unsigned char pad; - - unsigned char buffer[0]; -}; - -struct e100_serial { - int baud; - volatile u8 *port; /* R_SERIALx_CTRL */ - u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ - - /* Output registers */ - volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */ - volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST */ - volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD */ - const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS */ - - /* Input registers */ - volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */ - volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST */ - volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */ - volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */ - - int flags; /* defined in tty.h */ - - u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ - u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ - u8 iseteop; /* bit number for R_SET_EOP for the input dma */ - int enabled; /* Set to 1 if the port is enabled in HW config */ - - u8 dma_out_enabled:1; /* Set to 1 if DMA should be used */ - u8 dma_in_enabled:1; /* Set to 1 if DMA should be used */ - - /* end of fields defined in rs_table[] in .c-file */ - u8 uses_dma_in; /* Set to 1 if DMA is used */ - u8 uses_dma_out; /* Set to 1 if DMA is used */ - u8 forced_eop; /* a fifo eop has been forced */ - int baud_base; /* For special baudrates */ - int custom_divisor; /* For special baudrates */ - struct etrax_dma_descr tr_descr; - struct etrax_dma_descr rec_descr[SERIAL_RECV_DESCRIPTORS]; - int cur_rec_descr; - - volatile int tr_running; /* 1 if output is running */ - - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - unsigned long last_active; - int line; - int type; /* PORT_ETRAX */ - int count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ - struct circ_buf xmit; - struct etrax_recv_buffer *first_recv_buffer; - struct etrax_recv_buffer *last_recv_buffer; - unsigned int recv_cnt; - unsigned int max_recv_cnt; - - struct work_struct work; - struct async_icount icount; /* error-statistics etc.*/ - struct ktermios normal_termios; - struct ktermios callout_termios; -#ifdef DECLARE_WAITQUEUE - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; -#else - struct wait_queue *open_wait; - struct wait_queue *close_wait; -#endif - - unsigned long char_time_usec; /* The time for 1 char, in usecs */ - unsigned long flush_time_usec; /* How often we should flush */ - unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */ - unsigned long last_tx_active; /* Last tx time in jiffies */ - unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */ - unsigned long last_rx_active; /* Last rx time in jiffies */ - - int break_detected_cnt; - int errorcode; - -#ifdef CONFIG_ETRAX_RS485 - struct rs485_control rs485; /* RS-485 support */ -#endif -}; - -/* this PORT is not in the standard serial.h. it's not actually used for - * anything since we only have one type of async serial-port anyway in this - * system. - */ - -#define PORT_ETRAX 1 - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - -#endif /* __KERNEL__ */ - -#endif /* !_ETRAX_SERIAL_H */ diff --git a/trunk/drivers/serial/icom.c b/trunk/drivers/serial/icom.c index 246c5572667b..6202995e8211 100644 --- a/trunk/drivers/serial/icom.c +++ b/trunk/drivers/serial/icom.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/serial/imx.c b/trunk/drivers/serial/imx.c index 04cc88cc528c..e42faa4e4282 100644 --- a/trunk/drivers/serial/imx.c +++ b/trunk/drivers/serial/imx.c @@ -46,6 +46,122 @@ #include #include +/* Register definitions */ +#define URXD0 0x0 /* Receiver Register */ +#define URTX0 0x40 /* Transmitter Register */ +#define UCR1 0x80 /* Control Register 1 */ +#define UCR2 0x84 /* Control Register 2 */ +#define UCR3 0x88 /* Control Register 3 */ +#define UCR4 0x8c /* Control Register 4 */ +#define UFCR 0x90 /* FIFO Control Register */ +#define USR1 0x94 /* Status Register 1 */ +#define USR2 0x98 /* Status Register 2 */ +#define UESC 0x9c /* Escape Character Register */ +#define UTIM 0xa0 /* Escape Timer Register */ +#define UBIR 0xa4 /* BRM Incremental Register */ +#define UBMR 0xa8 /* BRM Modulator Register */ +#define UBRC 0xac /* Baud Rate Count Register */ +#define BIPR1 0xb0 /* Incremental Preset Register 1 */ +#define BIPR2 0xb4 /* Incremental Preset Register 2 */ +#define BIPR3 0xb8 /* Incremental Preset Register 3 */ +#define BIPR4 0xbc /* Incremental Preset Register 4 */ +#define BMPR1 0xc0 /* BRM Modulator Register 1 */ +#define BMPR2 0xc4 /* BRM Modulator Register 2 */ +#define BMPR3 0xc8 /* BRM Modulator Register 3 */ +#define BMPR4 0xcc /* BRM Modulator Register 4 */ +#define UTS 0xd0 /* UART Test Register */ + +/* UART Control Register Bit Fields.*/ +#define URXD_CHARRDY (1<<15) +#define URXD_ERR (1<<14) +#define URXD_OVRRUN (1<<13) +#define URXD_FRMERR (1<<12) +#define URXD_BRK (1<<11) +#define URXD_PRERR (1<<10) +#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */ +#define UCR1_ADBR (1<<14) /* Auto detect baud rate */ +#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ +#define UCR1_IDEN (1<<12) /* Idle condition interrupt */ +#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ +#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ +#define UCR1_IREN (1<<7) /* Infrared interface enable */ +#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ +#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ +#define UCR1_SNDBRK (1<<4) /* Send break */ +#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ +#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ +#define UCR1_DOZE (1<<1) /* Doze */ +#define UCR1_UARTEN (1<<0) /* UART enabled */ +#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ +#define UCR2_IRTS (1<<14) /* Ignore RTS pin */ +#define UCR2_CTSC (1<<13) /* CTS pin control */ +#define UCR2_CTS (1<<12) /* Clear to send */ +#define UCR2_ESCEN (1<<11) /* Escape enable */ +#define UCR2_PREN (1<<8) /* Parity enable */ +#define UCR2_PROE (1<<7) /* Parity odd/even */ +#define UCR2_STPB (1<<6) /* Stop */ +#define UCR2_WS (1<<5) /* Word size */ +#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ +#define UCR2_TXEN (1<<2) /* Transmitter enabled */ +#define UCR2_RXEN (1<<1) /* Receiver enabled */ +#define UCR2_SRST (1<<0) /* SW reset */ +#define UCR3_DTREN (1<<13) /* DTR interrupt enable */ +#define UCR3_PARERREN (1<<12) /* Parity enable */ +#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */ +#define UCR3_DSR (1<<10) /* Data set ready */ +#define UCR3_DCD (1<<9) /* Data carrier detect */ +#define UCR3_RI (1<<8) /* Ring indicator */ +#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */ +#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ +#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ +#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ +#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz */ +#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz */ +#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ +#define UCR3_BPEN (1<<0) /* Preset registers enable */ +#define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */ +#define UCR4_INVR (1<<9) /* Inverted infrared reception */ +#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ +#define UCR4_WKEN (1<<7) /* Wake interrupt enable */ +#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ +#define UCR4_IRSC (1<<5) /* IR special case */ +#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ +#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ +#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ +#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ +#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ +#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ +#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ +#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ +#define USR1_RTSS (1<<14) /* RTS pin status */ +#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */ +#define USR1_RTSD (1<<12) /* RTS delta */ +#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ +#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ +#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ +#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ +#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ +#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ +#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */ +#define USR2_ADET (1<<15) /* Auto baud rate detect complete */ +#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */ +#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */ +#define USR2_IDLE (1<<12) /* Idle condition */ +#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */ +#define USR2_WAKE (1<<7) /* Wake */ +#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */ +#define USR2_TXDC (1<<3) /* Transmitter complete */ +#define USR2_BRCD (1<<2) /* Break condition */ +#define USR2_ORE (1<<1) /* Overrun error */ +#define USR2_RDR (1<<0) /* Recv data ready */ +#define UTS_FRCPERR (1<<13) /* Force parity error */ +#define UTS_LOOP (1<<12) /* Loop tx and rx */ +#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ +#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ +#define UTS_TXFULL (1<<4) /* TxFIFO full */ +#define UTS_RXFULL (1<<3) /* RxFIFO full */ +#define UTS_SOFTRST (1<<0) /* Software reset */ + /* We've been assigned a range on the "Low-density serial ports" major */ #define SERIAL_IMX_MAJOR 204 #define MINOR_START 41 @@ -128,7 +244,10 @@ static void imx_timeout(unsigned long data) static void imx_stop_tx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - UCR1((u32)sport->port.membase) &= ~UCR1_TXMPTYEN; + unsigned long temp; + + temp = readl(sport->port.membase + UCR1); + writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); } /* @@ -137,7 +256,10 @@ static void imx_stop_tx(struct uart_port *port) static void imx_stop_rx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - UCR2((u32)sport->port.membase) &= ~UCR2_RXEN; + unsigned long temp; + + temp = readl(sport->port.membase + UCR2); + writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2); } /* @@ -154,10 +276,10 @@ static inline void imx_transmit_buffer(struct imx_port *sport) { struct circ_buf *xmit = &sport->port.info->xmit; - while (!(UTS((u32)sport->port.membase) & UTS_TXFULL)) { + while (!(readl(sport->port.membase + UTS) & UTS_TXFULL)) { /* send xmit->buf[xmit->tail] * out the port here */ - URTX0((u32)sport->port.membase) = xmit->buf[xmit->tail]; + writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); sport->port.icount.tx++; @@ -175,21 +297,24 @@ static inline void imx_transmit_buffer(struct imx_port *sport) static void imx_start_tx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; + unsigned long temp; - UCR1((u32)sport->port.membase) |= UCR1_TXMPTYEN; + temp = readl(sport->port.membase + UCR1); + writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); - imx_transmit_buffer(sport); + if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) + imx_transmit_buffer(sport); } static irqreturn_t imx_rtsint(int irq, void *dev_id) { struct imx_port *sport = (struct imx_port *)dev_id; - unsigned int val = USR1((u32)sport->port.membase)&USR1_RTSS; + unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS; unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); - USR1((u32)sport->port.membase) = USR1_RTSD; + writel(USR1_RTSD, sport->port.membase + USR1); uart_handle_cts_change(&sport->port, !!val); wake_up_interruptible(&sport->port.info->delta_msr_wait); @@ -207,7 +332,7 @@ static irqreturn_t imx_txint(int irq, void *dev_id) if (sport->port.x_char) { /* Send next char */ - URTX0((u32)sport->port.membase) = sport->port.x_char; + writel(sport->port.x_char, sport->port.membase + URTX0); goto out; } @@ -231,17 +356,18 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) struct imx_port *sport = dev_id; unsigned int rx,flg,ignored = 0; struct tty_struct *tty = sport->port.info->tty; - unsigned long flags; + unsigned long flags, temp; - rx = URXD0((u32)sport->port.membase); + rx = readl(sport->port.membase + URXD0); spin_lock_irqsave(&sport->port.lock,flags); do { flg = TTY_NORMAL; sport->port.icount.rx++; - if( USR2((u32)sport->port.membase) & USR2_BRCD ) { - USR2((u32)sport->port.membase) |= USR2_BRCD; + temp = readl(sport->port.membase + USR2); + if( temp & USR2_BRCD ) { + writel(temp | USR2_BRCD, sport->port.membase + USR2); if(uart_handle_break(&sport->port)) goto ignore_char; } @@ -257,7 +383,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) tty_insert_flip_char(tty, rx, flg); ignore_char: - rx = URXD0((u32)sport->port.membase); + rx = readl(sport->port.membase + URXD0); } while(rx & URXD_CHARRDY); out: @@ -301,7 +427,7 @@ static unsigned int imx_tx_empty(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - return USR2((u32)sport->port.membase) & USR2_TXDC ? TIOCSER_TEMT : 0; + return (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; } /* @@ -312,10 +438,10 @@ static unsigned int imx_get_mctrl(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned int tmp = TIOCM_DSR | TIOCM_CAR; - if (USR1((u32)sport->port.membase) & USR1_RTSS) + if (readl(sport->port.membase + USR1) & USR1_RTSS) tmp |= TIOCM_CTS; - if (UCR2((u32)sport->port.membase) & UCR2_CTS) + if (readl(sport->port.membase + UCR2) & UCR2_CTS) tmp |= TIOCM_RTS; return tmp; @@ -324,11 +450,14 @@ static unsigned int imx_get_mctrl(struct uart_port *port) static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct imx_port *sport = (struct imx_port *)port; + unsigned long temp; + + temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; if (mctrl & TIOCM_RTS) - UCR2((u32)sport->port.membase) |= UCR2_CTS; - else - UCR2((u32)sport->port.membase) &= ~UCR2_CTS; + temp |= UCR2_CTS; + + writel(temp, sport->port.membase + UCR2); } /* @@ -337,14 +466,16 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) static void imx_break_ctl(struct uart_port *port, int break_state) { struct imx_port *sport = (struct imx_port *)port; - unsigned long flags; + unsigned long flags, temp; spin_lock_irqsave(&sport->port.lock, flags); + temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK; + if ( break_state != 0 ) - UCR1((u32)sport->port.membase) |= UCR1_SNDBRK; - else - UCR1((u32)sport->port.membase) &= ~UCR1_SNDBRK; + temp |= UCR1_SNDBRK; + + writel(temp, sport->port.membase + UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); } @@ -360,7 +491,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) /* set receiver / transmitter trigger level. * RFDIV is set such way to satisfy requested uartclk value */ - val = TXTL<<10 | RXTL; + val = TXTL << 10 | RXTL; ufcr_rfdiv = (imx_get_perclk1() + sport->port.uartclk / 2) / sport->port.uartclk; if(!ufcr_rfdiv) @@ -373,7 +504,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) val |= UFCR_RFDIV & (ufcr_rfdiv << 7); - UFCR((u32)sport->port.membase) = val; + writel(val, sport->port.membase + UFCR); return 0; } @@ -382,14 +513,15 @@ static int imx_startup(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; int retval; - unsigned long flags; + unsigned long flags, temp; imx_setup_ufcr(sport, 0); /* disable the DREN bit (Data Ready interrupt enable) before * requesting IRQs */ - UCR4((u32)sport->port.membase) &= ~UCR4_DREN; + temp = readl(sport->port.membase + UCR4); + writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); /* * Allocate the IRQ @@ -411,12 +543,16 @@ static int imx_startup(struct uart_port *port) /* * Finally, clear and enable interrupts */ + writel(USR1_RTSD, sport->port.membase + USR1); + + temp = readl(sport->port.membase + UCR1); + temp |= (UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + writel(temp, sport->port.membase + UCR1); - USR1((u32)sport->port.membase) = USR1_RTSD; - UCR1((u32)sport->port.membase) |= - (UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + temp = readl(sport->port.membase + UCR2); + temp |= (UCR2_RXEN | UCR2_TXEN); + writel(temp, sport->port.membase + UCR2); - UCR2((u32)sport->port.membase) |= (UCR2_RXEN | UCR2_TXEN); /* * Enable modem status interrupts */ @@ -437,6 +573,7 @@ static int imx_startup(struct uart_port *port) static void imx_shutdown(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; + unsigned long temp; /* * Stop our timer. @@ -454,8 +591,9 @@ static void imx_shutdown(struct uart_port *port) * Disable all interrupts, port and break condition. */ - UCR1((u32)sport->port.membase) &= - ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + writel(temp, sport->port.membase + UCR1); } static void @@ -548,18 +686,18 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, /* * disable interrupts and drain transmitter */ - old_ucr1 = UCR1((u32)sport->port.membase); - UCR1((u32)sport->port.membase) &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN); + old_ucr1 = readl(sport->port.membase + UCR1); + writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), + sport->port.membase + UCR1); - while ( !(USR2((u32)sport->port.membase) & USR2_TXDC)) + while ( !(readl(sport->port.membase + USR2) & USR2_TXDC)) barrier(); /* then, disable everything */ - old_txrxen = UCR2((u32)sport->port.membase) & ( UCR2_TXEN | UCR2_RXEN ); - UCR2((u32)sport->port.membase) &= ~( UCR2_TXEN | UCR2_RXEN); - - /* set the parity, stop bits and data size */ - UCR2((u32)sport->port.membase) = ucr2; + old_txrxen = readl(sport->port.membase + UCR2); + writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN), + sport->port.membase + UCR2); + old_txrxen &= (UCR2_TXEN | UCR2_RXEN); /* set the baud rate. We assume uartclk = 16 MHz * @@ -567,11 +705,13 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, * --------- = -------- * uartclk UBMR - 1 */ - UBIR((u32)sport->port.membase) = (baud / 100) - 1; - UBMR((u32)sport->port.membase) = 10000 - 1; + writel((baud / 100) - 1, sport->port.membase + UBIR); + writel(10000 - 1, sport->port.membase + UBMR); + + writel(old_ucr1, sport->port.membase + UCR1); - UCR1((u32)sport->port.membase) = old_ucr1; - UCR2((u32)sport->port.membase) |= old_txrxen; + /* set the parity, stop bits and data size */ + writel(ucr2 | old_txrxen, sport->port.membase + UCR2); if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) imx_enable_ms(&sport->port); @@ -730,9 +870,11 @@ static void __init imx_init_ports(void) static void imx_console_putchar(struct uart_port *port, int ch) { struct imx_port *sport = (struct imx_port *)port; - while ((UTS((u32)sport->port.membase) & UTS_TXFULL)) + + while (readl(sport->port.membase + UTS) & UTS_TXFULL) barrier(); - URTX0((u32)sport->port.membase) = ch; + + writel(ch, sport->port.membase + URTX0); } /* @@ -747,13 +889,14 @@ imx_console_write(struct console *co, const char *s, unsigned int count) /* * First, save UCR1/2 and then disable interrupts */ - old_ucr1 = UCR1((u32)sport->port.membase); - old_ucr2 = UCR2((u32)sport->port.membase); + old_ucr1 = readl(sport->port.membase + UCR1); + old_ucr2 = readl(sport->port.membase + UCR2); - UCR1((u32)sport->port.membase) = - (old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN) - & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN); - UCR2((u32)sport->port.membase) = old_ucr2 | UCR2_TXEN; + writel((old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN) & + ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), + sport->port.membase + UCR1); + + writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2); uart_console_write(&sport->port, s, count, imx_console_putchar); @@ -761,10 +904,10 @@ imx_console_write(struct console *co, const char *s, unsigned int count) * Finally, wait for transmitter to become empty * and restore UCR1/2 */ - while (!(USR2((u32)sport->port.membase) & USR2_TXDC)); + while (!(readl(sport->port.membase + USR2) & USR2_TXDC)); - UCR1((u32)sport->port.membase) = old_ucr1; - UCR2((u32)sport->port.membase) = old_ucr2; + writel(old_ucr1, sport->port.membase + UCR1); + writel(old_ucr2, sport->port.membase + UCR2); } /* @@ -776,13 +919,13 @@ imx_console_get_options(struct imx_port *sport, int *baud, int *parity, int *bits) { - if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) { + if ( readl(sport->port.membase + UCR1) | UCR1_UARTEN ) { /* ok, the port was enabled */ unsigned int ucr2, ubir,ubmr, uartclk; unsigned int baud_raw; unsigned int ucfr_rfdiv; - ucr2 = UCR2((u32)sport->port.membase); + ucr2 = readl(sport->port.membase + UCR2); *parity = 'n'; if (ucr2 & UCR2_PREN) { @@ -797,11 +940,10 @@ imx_console_get_options(struct imx_port *sport, int *baud, else *bits = 7; - ubir = UBIR((u32)sport->port.membase) & 0xffff; - ubmr = UBMR((u32)sport->port.membase) & 0xffff; - + ubir = readl(sport->port.membase + UBIR) & 0xffff; + ubmr = readl(sport->port.membase + UBMR) & 0xffff; - ucfr_rfdiv = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) >> 7; + ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7; if (ucfr_rfdiv == 6) ucfr_rfdiv = 7; else diff --git a/trunk/drivers/serial/jsm/jsm_neo.c b/trunk/drivers/serial/jsm/jsm_neo.c index 8be8da37f629..b2d6f5b1a7c2 100644 --- a/trunk/drivers/serial/jsm/jsm_neo.c +++ b/trunk/drivers/serial/jsm/jsm_neo.c @@ -581,8 +581,13 @@ static void neo_parse_modem(struct jsm_channel *ch, u8 signals) return; /* Scrub off lower bits. They signify delta's, which I don't care about */ - msignals &= 0xf0; + /* Keep DDCD and DDSR though */ + msignals &= 0xf8; + if (msignals & UART_MSR_DDCD) + uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD); + if (msignals & UART_MSR_DDSR) + uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS); if (msignals & UART_MSR_DCD) ch->ch_mistat |= UART_MSR_DCD; else diff --git a/trunk/drivers/serial/jsm/jsm_tty.c b/trunk/drivers/serial/jsm/jsm_tty.c index be22bbdbc8e5..281f23a371b2 100644 --- a/trunk/drivers/serial/jsm/jsm_tty.c +++ b/trunk/drivers/serial/jsm/jsm_tty.c @@ -448,6 +448,7 @@ int jsm_uart_port_init(struct jsm_board *brd) continue; brd->channels[i]->uart_port.irq = brd->irq; + brd->channels[i]->uart_port.uartclk = 14745600; brd->channels[i]->uart_port.type = PORT_JSM; brd->channels[i]->uart_port.iotype = UPIO_MEM; brd->channels[i]->uart_port.membase = brd->re_map_membase; diff --git a/trunk/drivers/serial/mpc52xx_uart.c b/trunk/drivers/serial/mpc52xx_uart.c index 8d24cd521056..35f8b86cc78f 100644 --- a/trunk/drivers/serial/mpc52xx_uart.c +++ b/trunk/drivers/serial/mpc52xx_uart.c @@ -257,9 +257,10 @@ mpc52xx_uart_shutdown(struct uart_port *port) { struct mpc52xx_psc __iomem *psc = PSC(port); - /* Shut down the port, interrupt and all */ + /* Shut down the port. Leave TX active if on a console port */ out_8(&psc->command,MPC52xx_PSC_RST_RX); - out_8(&psc->command,MPC52xx_PSC_RST_TX); + if (!uart_console(port)) + out_8(&psc->command,MPC52xx_PSC_RST_TX); port->read_status_mask = 0; out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask); @@ -1069,7 +1070,7 @@ mpc52xx_uart_of_enumerate(void) continue; /* Is a particular device number requested? */ - devno = get_property(np, "port-number", NULL); + devno = of_get_property(np, "port-number", NULL); mpc52xx_uart_of_assign(of_node_get(np), devno ? *devno : -1); } diff --git a/trunk/drivers/serial/mpsc.c b/trunk/drivers/serial/mpsc.c index 3d2fcc57b1ce..d09f2097d5b0 100644 --- a/trunk/drivers/serial/mpsc.c +++ b/trunk/drivers/serial/mpsc.c @@ -183,6 +183,7 @@ struct mpsc_port_info { u8 *txb_p; /* Phys addr of txb */ int txr_head; /* Where new data goes */ int txr_tail; /* Where sent data comes off */ + spinlock_t tx_lock; /* transmit lock */ /* Mirrored values of regs we can't read (if 'mirror_regs' set) */ u32 MPSC_MPCR_m; @@ -1212,6 +1213,9 @@ mpsc_tx_intr(struct mpsc_port_info *pi) { struct mpsc_tx_desc *txre; int rc = 0; + unsigned long iflags; + + spin_lock_irqsave(&pi->tx_lock, iflags); if (!mpsc_sdma_tx_active(pi)) { txre = (struct mpsc_tx_desc *)(pi->txr + @@ -1248,6 +1252,7 @@ mpsc_tx_intr(struct mpsc_port_info *pi) mpsc_sdma_start_tx(pi); /* start next desc if ready */ } + spin_unlock_irqrestore(&pi->tx_lock, iflags); return rc; } @@ -1338,11 +1343,16 @@ static void mpsc_start_tx(struct uart_port *port) { struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + unsigned long iflags; + + spin_lock_irqsave(&pi->tx_lock, iflags); mpsc_unfreeze(pi); mpsc_copy_tx_data(pi); mpsc_sdma_start_tx(pi); + spin_unlock_irqrestore(&pi->tx_lock, iflags); + pr_debug("mpsc_start_tx[%d]\n", port->line); return; } @@ -1625,6 +1635,16 @@ mpsc_console_write(struct console *co, const char *s, uint count) struct mpsc_port_info *pi = &mpsc_ports[co->index]; u8 *bp, *dp, add_cr = 0; int i; + unsigned long iflags; + + spin_lock_irqsave(&pi->tx_lock, iflags); + + while (pi->txr_head != pi->txr_tail) { + while (mpsc_sdma_tx_active(pi)) + udelay(100); + mpsc_sdma_intr_ack(pi); + mpsc_tx_intr(pi); + } while (mpsc_sdma_tx_active(pi)) udelay(100); @@ -1668,6 +1688,7 @@ mpsc_console_write(struct console *co, const char *s, uint count) pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1); } + spin_unlock_irqrestore(&pi->tx_lock, iflags); return; } @@ -2005,7 +2026,8 @@ mpsc_drv_probe(struct platform_device *dev) if (!(rc = mpsc_drv_map_regs(pi, dev))) { mpsc_drv_get_platform_data(pi, dev, dev->id); - if (!(rc = mpsc_make_ready(pi))) + if (!(rc = mpsc_make_ready(pi))) { + spin_lock_init(&pi->tx_lock); if (!(rc = uart_add_one_port(&mpsc_reg, &pi->port))) rc = 0; @@ -2014,6 +2036,7 @@ mpsc_drv_probe(struct platform_device *dev) (struct uart_port *)pi); mpsc_drv_unmap_regs(pi); } + } else mpsc_drv_unmap_regs(pi); } diff --git a/trunk/drivers/serial/of_serial.c b/trunk/drivers/serial/of_serial.c index 09b0b736a751..7ffdaeaf0545 100644 --- a/trunk/drivers/serial/of_serial.c +++ b/trunk/drivers/serial/of_serial.c @@ -29,8 +29,8 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev, int ret; memset(port, 0, sizeof *port); - spd = get_property(np, "current-speed", NULL); - clk = get_property(np, "clock-frequency", NULL); + spd = of_get_property(np, "current-speed", NULL); + clk = of_get_property(np, "clock-frequency", NULL); if (!clk) { dev_warn(&ofdev->dev, "no clock-frequency property set\n"); return -ENODEV; @@ -48,7 +48,8 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev, port->iotype = UPIO_MEM; port->type = type; port->uartclk = *clk; - port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP; + port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP + | UPF_FIXED_PORT; port->dev = &ofdev->dev; port->custom_divisor = *clk / (16 * (*spd)); diff --git a/trunk/drivers/serial/pmac_zilog.c b/trunk/drivers/serial/pmac_zilog.c index be8d75721a85..0fa9f6761763 100644 --- a/trunk/drivers/serial/pmac_zilog.c +++ b/trunk/drivers/serial/pmac_zilog.c @@ -1450,14 +1450,14 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) /* * Detect port type */ - if (device_is_compatible(np, "cobalt")) + if (of_device_is_compatible(np, "cobalt")) uap->flags |= PMACZILOG_FLAG_IS_INTMODEM; - conn = get_property(np, "AAPL,connector", &len); + conn = of_get_property(np, "AAPL,connector", &len); if (conn && (strcmp(conn, "infrared") == 0)) uap->flags |= PMACZILOG_FLAG_IS_IRDA; uap->port_type = PMAC_SCC_ASYNC; /* 1999 Powerbook G3 has slot-names property instead */ - slots = get_property(np, "slot-names", &len); + slots = of_get_property(np, "slot-names", &len); if (slots && slots->count > 0) { if (strcmp(slots->name, "IrDA") == 0) uap->flags |= PMACZILOG_FLAG_IS_IRDA; @@ -1471,7 +1471,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) of_find_node_by_name(NULL, "i2c-modem"); if (i2c_modem) { const char* mid = - get_property(i2c_modem, "modem-id", NULL); + of_get_property(i2c_modem, "modem-id", NULL); if (mid) switch(*mid) { case 0x04 : case 0x05 : diff --git a/trunk/drivers/serial/pxa.c b/trunk/drivers/serial/pxa.c index d403aaa55092..e9c6cb391a23 100644 --- a/trunk/drivers/serial/pxa.c +++ b/trunk/drivers/serial/pxa.c @@ -717,7 +717,7 @@ struct uart_ops serial_pxa_pops = { static struct uart_pxa_port serial_pxa_ports[] = { { /* FFUART */ .name = "FFUART", - .cken = CKEN6_FFUART, + .cken = CKEN_FFUART, .port = { .type = PORT_PXA, .iotype = UPIO_MEM, @@ -731,7 +731,7 @@ static struct uart_pxa_port serial_pxa_ports[] = { }, }, { /* BTUART */ .name = "BTUART", - .cken = CKEN7_BTUART, + .cken = CKEN_BTUART, .port = { .type = PORT_PXA, .iotype = UPIO_MEM, @@ -745,7 +745,7 @@ static struct uart_pxa_port serial_pxa_ports[] = { }, }, { /* STUART */ .name = "STUART", - .cken = CKEN5_STUART, + .cken = CKEN_STUART, .port = { .type = PORT_PXA, .iotype = UPIO_MEM, @@ -759,7 +759,7 @@ static struct uart_pxa_port serial_pxa_ports[] = { }, }, { /* HWUART */ .name = "HWUART", - .cken = CKEN4_HWUART, + .cken = CKEN_HWUART, .port = { .type = PORT_PXA, .iotype = UPIO_MEM, diff --git a/trunk/drivers/serial/s3c2410.c b/trunk/drivers/serial/s3c2410.c index 3ba9208ebd0c..10bc0209cd66 100644 --- a/trunk/drivers/serial/s3c2410.c +++ b/trunk/drivers/serial/s3c2410.c @@ -957,7 +957,7 @@ static struct uart_driver s3c24xx_uart_drv = { static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = { [0] = { .port = { - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock), .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX0, .uartclk = 0, @@ -969,7 +969,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = { }, [1] = { .port = { - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock), .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX1, .uartclk = 0, @@ -983,7 +983,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = { [2] = { .port = { - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock), .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX2, .uartclk = 0, diff --git a/trunk/drivers/serial/serial_core.c b/trunk/drivers/serial/serial_core.c index 0422c0f1f852..326020f86f75 100644 --- a/trunk/drivers/serial/serial_core.c +++ b/trunk/drivers/serial/serial_core.c @@ -37,13 +37,6 @@ #include #include -#undef DEBUG -#ifdef DEBUG -#define DPRINTK(x...) printk(x) -#else -#define DPRINTK(x...) do { } while (0) -#endif - /* * This is used to lock changes in serial line configuration. */ @@ -552,7 +545,7 @@ static void uart_flush_buffer(struct tty_struct *tty) return; } - DPRINTK("uart_flush_buffer(%d) called\n", tty->index); + pr_debug("uart_flush_buffer(%d) called\n", tty->index); spin_lock_irqsave(&port->lock, flags); uart_circ_clear(&state->info->xmit); @@ -672,19 +665,21 @@ static int uart_set_info(struct uart_state *state, */ mutex_lock(&state->mutex); - change_irq = new_serial.irq != port->irq; + change_irq = !(port->flags & UPF_FIXED_PORT) + && new_serial.irq != port->irq; /* * Since changing the 'type' of the port changes its resource * allocations, we should treat type changes the same as * IO port changes. */ - change_port = new_port != port->iobase || - (unsigned long)new_serial.iomem_base != port->mapbase || - new_serial.hub6 != port->hub6 || - new_serial.io_type != port->iotype || - new_serial.iomem_reg_shift != port->regshift || - new_serial.type != port->type; + change_port = !(port->flags & UPF_FIXED_PORT) + && (new_port != port->iobase || + (unsigned long)new_serial.iomem_base != port->mapbase || + new_serial.hub6 != port->hub6 || + new_serial.io_type != port->iotype || + new_serial.iomem_reg_shift != port->regshift || + new_serial.type != port->type); old_flags = port->flags; new_flags = new_serial.flags; @@ -796,8 +791,10 @@ static int uart_set_info(struct uart_state *state, } } - port->irq = new_serial.irq; - port->uartclk = new_serial.baud_base * 16; + if (change_irq) + port->irq = new_serial.irq; + if (!(port->flags & UPF_FIXED_PORT)) + port->uartclk = new_serial.baud_base * 16; port->flags = (port->flags & ~UPF_CHANGE_MASK) | (new_flags & UPF_CHANGE_MASK); port->custom_divisor = new_serial.custom_divisor; @@ -1220,7 +1217,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) port = state->port; - DPRINTK("uart_close(%d) called\n", port->line); + pr_debug("uart_close(%d) called\n", port->line); mutex_lock(&state->mutex); @@ -1339,7 +1336,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) expire = jiffies + timeout; - DPRINTK("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", + pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", port->line, jiffies, expire); /* @@ -1368,7 +1365,7 @@ static void uart_hangup(struct tty_struct *tty) struct uart_state *state = tty->driver_data; BUG_ON(!kernel_locked()); - DPRINTK("uart_hangup(%d)\n", state->port->line); + pr_debug("uart_hangup(%d)\n", state->port->line); mutex_lock(&state->mutex); if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) { @@ -1566,7 +1563,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) int retval, line = tty->index; BUG_ON(!kernel_locked()); - DPRINTK("uart_open(%d) called\n", line); + pr_debug("uart_open(%d) called\n", line); /* * tty->driver->num won't change, so we won't fail here with @@ -2064,6 +2061,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) case UPIO_MEM32: case UPIO_AU: case UPIO_TSI: + case UPIO_DWAPB: snprintf(address, sizeof(address), "MMIO 0x%lx", port->mapbase); break; @@ -2409,6 +2407,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) case UPIO_MEM32: case UPIO_AU: case UPIO_TSI: + case UPIO_DWAPB: return (port1->mapbase == port2->mapbase); } return 0; diff --git a/trunk/drivers/serial/serial_txx9.c b/trunk/drivers/serial/serial_txx9.c index 509ace7e6881..1deb5764326d 100644 --- a/trunk/drivers/serial/serial_txx9.c +++ b/trunk/drivers/serial/serial_txx9.c @@ -15,31 +15,6 @@ * published by the Free Software Foundation. * * Serial driver for TX3927/TX4927/TX4925/TX4938 internal SIO controller - * - * Revision History: - * 0.30 Initial revision. (Renamed from serial_txx927.c) - * 0.31 Use save_flags instead of local_irq_save. - * 0.32 Support SCLK. - * 0.33 Switch TXX9_TTY_NAME by CONFIG_SERIAL_TXX9_STDSERIAL. - * Support TIOCSERGETLSR. - * 0.34 Support slow baudrate. - * 0.40 Merge codes from mainstream kernel (2.4.22). - * 0.41 Fix console checking in rs_shutdown_port(). - * Disable flow-control in serial_console_write(). - * 0.42 Fix minor compiler warning. - * 1.00 Kernel 2.6. Converted to new serial core (based on 8250.c). - * 1.01 Set fifosize to make tx_empry called properly. - * Use standard uart_get_divisor. - * 1.02 Cleanup. (import 8250.c changes) - * 1.03 Fix low-latency mode. (import 8250.c changes) - * 1.04 Remove usage of deprecated functions, cleanup. - * 1.05 More strict check in verify_port. Cleanup. - * 1.06 Do not insert a char caused previous overrun. - * Fix some spin_locks. - * Do not call uart_add_one_port for absent ports. - * 1.07 Use CONFIG_SERIAL_TXX9_NR_UARTS. Cleanup. - * 1.08 Use platform_device. - * Fix and cleanup suspend/resume/initialization codes. */ #if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -62,7 +37,7 @@ #include -static char *serial_version = "1.08"; +static char *serial_version = "1.09"; static char *serial_name = "TX39/49 Serial driver"; #define PASS_LIMIT 256 @@ -70,13 +45,14 @@ static char *serial_name = "TX39/49 Serial driver"; #if !defined(CONFIG_SERIAL_TXX9_STDSERIAL) /* "ttyS" is used for standard serial driver */ #define TXX9_TTY_NAME "ttyTX" -#define TXX9_TTY_MINOR_START (64 + 64) /* ttyTX0(128), ttyTX1(129) */ +#define TXX9_TTY_MINOR_START 196 +#define TXX9_TTY_MAJOR 204 #else /* acts like standard serial driver */ #define TXX9_TTY_NAME "ttyS" #define TXX9_TTY_MINOR_START 64 -#endif #define TXX9_TTY_MAJOR TTY_MAJOR +#endif /* flag aliases */ #define UPF_TXX9_HAVE_CTS_LINE UPF_BUGGY_UART diff --git a/trunk/drivers/serial/sh-sci.c b/trunk/drivers/serial/sh-sci.c index 46c40bbc4bc6..1f89496d530e 100644 --- a/trunk/drivers/serial/sh-sci.c +++ b/trunk/drivers/serial/sh-sci.c @@ -46,6 +46,7 @@ #endif #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) +#include #include #include #include @@ -61,7 +62,7 @@ struct sci_port { unsigned int type; /* Port IRQs: ERI, RXI, TXI, BRI (optional) */ - unsigned int irqs[SCIx_NR_IRQS]; + unsigned int irqs[SCIx_NR_IRQS]; /* Port pin configuration */ void (*init_pins)(struct uart_port *port, @@ -76,6 +77,11 @@ struct sci_port { /* Break timer */ struct timer_list break_timer; int break_flag; + +#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) + /* Port clock */ + struct clk *clk; +#endif }; #ifdef CONFIG_SH_KGDB @@ -163,7 +169,7 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count) usegdb |= sh_bios_in_gdb_mode(); #endif #ifdef CONFIG_SH_KGDB - usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port)); + usegdb |= (kgdb_in_gdb_mode && (sci_port == kgdb_sci_port)); #endif if (usegdb) { @@ -204,7 +210,7 @@ static int kgdb_sci_getchar(void) int c; /* Keep trying to read a character, this could be neater */ - while ((c = get_char(kgdb_sci_port)) < 0) + while ((c = get_char(&kgdb_sci_port->port)) < 0) cpu_relax(); return c; @@ -212,7 +218,7 @@ static int kgdb_sci_getchar(void) static inline void kgdb_sci_putchar(int c) { - put_char(kgdb_sci_port, c); + put_char(&kgdb_sci_port->port, c); } #endif /* CONFIG_SH_KGDB */ @@ -283,12 +289,23 @@ static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag) #endif #if defined(SCIF_ONLY) || defined(SCI_AND_SCIF) -#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710) +#if defined(CONFIG_CPU_SUBTYPE_SH7300) /* SH7300 doesn't use RTS/CTS */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) { sci_out(port, SCFCR, 0); } +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) +static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + + set_sh771x_scif_pfc(port); + if (cflag & CRTSCTS) { + fcr_val |= SCFCR_MCE; + } + sci_out(port, SCFCR, fcr_val); +} #elif defined(CONFIG_CPU_SH3) /* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) @@ -350,7 +367,7 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) } else { #ifdef CONFIG_CPU_SUBTYPE_SH7343 /* Nothing */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) +#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785) ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */ #else ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */ @@ -360,7 +377,9 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) } #endif -#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780) +#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) static inline int scif_txroom(struct uart_port *port) { return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f); @@ -735,12 +754,6 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr) /* Handle BREAKs */ sci_handle_breaks(port); - -#ifdef CONFIG_SH_KGDB - /* Break into the debugger if a break is detected */ - BREAKPOINT(); -#endif - sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); return IRQ_HANDLED; @@ -947,6 +960,10 @@ static int sci_startup(struct uart_port *port) if (s->enable) s->enable(port); +#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) + s->clk = clk_get(NULL, "module_clk"); +#endif + sci_request_irq(s); sci_start_tx(port); sci_start_rx(port, 1); @@ -964,6 +981,11 @@ static void sci_shutdown(struct uart_port *port) if (s->disable) s->disable(port); + +#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) + clk_put(s->clk); + s->clk = NULL; +#endif } static void sci_set_termios(struct uart_port *port, struct ktermios *termios, @@ -971,7 +993,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, { struct sci_port *s = &sci_ports[port->line]; unsigned int status, baud, smr_val; - unsigned long flags; int t; baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); @@ -983,18 +1004,14 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, default: { #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) - struct clk *clk = clk_get(NULL, "module_clk"); - t = SCBRR_VALUE(baud, clk_get_rate(clk)); - clk_put(clk); + t = SCBRR_VALUE(baud, clk_get_rate(s->clk)); #else t = SCBRR_VALUE(baud); #endif - } break; + } } - spin_lock_irqsave(&port->lock, flags); - do { status = sci_in(port, SCxSR); } while (!(status & SCxSR_TEND(port))); @@ -1038,8 +1055,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, if ((termios->c_cflag & CREAD) != 0) sci_start_rx(port,0); - - spin_unlock_irqrestore(&port->lock, flags); } static const char *sci_type(struct uart_port *port) @@ -1220,10 +1235,13 @@ static int __init serial_console_setup(struct console *co, char *options) if (!port->membase || !port->mapbase) return -ENODEV; - spin_lock_init(&port->lock); - port->type = serial_console_port->type; +#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) + if (!serial_console_port->clk) + serial_console_port->clk = clk_get(NULL, "module_clk"); +#endif + if (port->flags & UPF_IOREMAP) sci_config_port(port, 0); @@ -1247,7 +1265,7 @@ static struct console serial_console = { .device = uart_console_device, .write = serial_console_write, .setup = serial_console_setup, - .flags = CON_PRINTBUFFER, + .flags = CON_PRINTBUFFER, .index = -1, .data = &sci_uart_driver, }; @@ -1292,11 +1310,23 @@ int __init kgdb_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; - spin_lock_init(&port->lock); - if (co->index != kgdb_portnum) co->index = kgdb_portnum; + kgdb_sci_port = &sci_ports[co->index]; + port = &kgdb_sci_port->port; + + /* + * Also need to check port->type, we don't actually have any + * UPIO_PORT ports, but uart_report_port() handily misreports + * it anyways if we don't have a port available by the time this is + * called. + */ + if (!port->type) + return -ENODEV; + if (!port->membase || !port->mapbase) + return -ENODEV; + if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else @@ -1311,11 +1341,12 @@ int __init kgdb_console_setup(struct console *co, char *options) #ifdef CONFIG_SH_KGDB_CONSOLE static struct console kgdb_console = { - .name = "ttySC", - .write = kgdb_console_write, - .setup = kgdb_console_setup, - .flags = CON_PRINTBUFFER | CON_ENABLED, - .index = -1, + .name = "ttySC", + .device = uart_console_device, + .write = kgdb_console_write, + .setup = kgdb_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, .data = &sci_uart_driver, }; @@ -1361,9 +1392,19 @@ static int __devinit sci_probe(struct platform_device *dev) struct plat_sci_port *p = dev->dev.platform_data; int i; - for (i = 0; p && p->flags != 0 && i < SCI_NPORTS; p++, i++) { + for (i = 0; p && p->flags != 0; p++, i++) { struct sci_port *sciport = &sci_ports[i]; + /* Sanity check */ + if (unlikely(i == SCI_NPORTS)) { + dev_notice(&dev->dev, "Attempting to register port " + "%d when only %d are available.\n", + i+1, SCI_NPORTS); + dev_notice(&dev->dev, "Consider bumping " + "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); + break; + } + sciport->port.mapbase = p->mapbase; /* @@ -1386,6 +1427,12 @@ static int __devinit sci_probe(struct platform_device *dev) uart_add_one_port(&sci_uart_driver, &sciport->port); } +#if defined(CONFIG_SH_KGDB) && !defined(CONFIG_SH_KGDB_CONSOLE) + kgdb_sci_port = &sci_ports[kgdb_portnum]; + kgdb_getchar = kgdb_sci_getchar; + kgdb_putchar = kgdb_sci_putchar; +#endif + #ifdef CONFIG_CPU_FREQ cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); dev_info(&dev->dev, "sci: CPU frequency notifier registered\n"); diff --git a/trunk/drivers/serial/sh-sci.h b/trunk/drivers/serial/sh-sci.h index 77f7d6351ab1..fb04fb5f9843 100644 --- a/trunk/drivers/serial/sh-sci.h +++ b/trunk/drivers/serial/sh-sci.h @@ -73,9 +73,13 @@ # define SCPDR 0xA4050136 /* 16 bit SCIF */ # define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ # define SCIF_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_SH7710) +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) # define SCSPTR0 0xA4400000 /* 16 bit SCIF */ -# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCI_NPORTS 2 +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define PACR 0xa4050100 +# define PBCR 0xa4050102 +# define SCSCR_INIT(port) 0x3B # define SCIF_ONLY #elif defined(CONFIG_CPU_SUBTYPE_SH73180) # define SCPDR 0xA4050138 /* 16 bit SCIF */ @@ -140,6 +144,16 @@ # define SCIF_ORER 0x0001 /* Overrun error bit */ # define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ # define SCIF_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SH7785) +# define SCSPTR0 0xffea0024 /* 16 bit SCIF */ +# define SCSPTR1 0xffeb0024 /* 16 bit SCIF */ +# define SCSPTR2 0xffec0024 /* 16 bit SCIF */ +# define SCSPTR3 0xffed0024 /* 16 bit SCIF */ +# define SCSPTR4 0xffee0024 /* 16 bit SCIF */ +# define SCSPTR5 0xffef0024 /* 16 bit SCIF */ +# define SCIF_OPER 0x0001 /* Overrun error bit */ +# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCIF_ONLY #elif defined(CONFIG_CPU_SUBTYPE_SH7206) # define SCSPTR0 0xfffe8020 /* 16 bit SCIF */ # define SCSPTR1 0xfffe8820 /* 16 bit SCIF */ @@ -163,7 +177,10 @@ #define SCI_CTRL_FLAGS_RIE 0x40 /* all */ #define SCI_CTRL_FLAGS_TE 0x20 /* all */ #define SCI_CTRL_FLAGS_RE 0x10 /* all */ -#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7780) +#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) #define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */ #else #define SCI_CTRL_FLAGS_REIE 0 @@ -333,9 +350,15 @@ } #ifdef CONFIG_CPU_SH3 -#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \ - defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7710) +#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) +#elif defined(CONFIG_CPU_SUBTYPE_SH7300) || \ + defined(CONFIG_CPU_SUBTYPE_SH7705) #define SCIF_FNS(name, scif_offset, scif_size) \ CPU_SCIF_FNS(name, scif_offset, scif_size) #else @@ -362,8 +385,8 @@ #endif #if defined(CONFIG_CPU_SUBTYPE_SH7300) || \ - defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7710) + defined(CONFIG_CPU_SUBTYPE_SH7705) + SCIF_FNS(SCSMR, 0x00, 16) SCIF_FNS(SCBRR, 0x04, 8) SCIF_FNS(SCSCR, 0x08, 16) @@ -385,7 +408,9 @@ SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8) SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8) SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8) SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) -#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780) +#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) @@ -471,13 +496,24 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */ return 1; } -#elif defined(CONFIG_CPU_SUBTYPE_SH7710) +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) static inline int sci_rxd_in(struct uart_port *port) { - if (port->mapbase == SCSPTR0) - return ctrl_inw(SCSPTR0 + 0x10) & 0x01 ? 1 : 0; - return 1; + return sci_in(port,SCxSR)&0x0010 ? 1 : 0; +} +static inline void set_sh771x_scif_pfc(struct uart_port *port) +{ + if (port->mapbase == 0xA4400000){ + ctrl_outw(ctrl_inw(PACR)&0xffc0,PACR); + ctrl_outw(ctrl_inw(PBCR)&0x0fff,PBCR); + return; + } + if (port->mapbase == 0xA4410000){ + ctrl_outw(ctrl_inw(PBCR)&0xf003,PBCR); + return; + } } + #elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ defined(CONFIG_CPU_SUBTYPE_SH7751) || \ defined(CONFIG_CPU_SUBTYPE_SH4_202) @@ -576,6 +612,23 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ return 1; } +#elif defined(CONFIG_CPU_SUBTYPE_SH7785) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xffea0000) + return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffeb0000) + return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffec0000) + return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffed0000) + return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffee0000) + return ctrl_inw(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffef0000) + return ctrl_inw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */ + return 1; +} #elif defined(CONFIG_CPU_SUBTYPE_SH7206) static inline int sci_rxd_in(struct uart_port *port) { @@ -634,7 +687,9 @@ static inline int sci_rxd_in(struct uart_port *port) * -- Mitch Davis - 15 Jul 2000 */ -#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7780) +#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1) #elif defined(CONFIG_CPU_SUBTYPE_SH7705) #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) diff --git a/trunk/drivers/serial/sunsu.c b/trunk/drivers/serial/sunsu.c index bfd44177a215..2a63cdba3208 100644 --- a/trunk/drivers/serial/sunsu.c +++ b/trunk/drivers/serial/sunsu.c @@ -1312,7 +1312,7 @@ static void sunsu_console_write(struct console *co, const char *s, * - initialize the serial port * Return non-zero if we didn't find a serial port. */ -static int sunsu_console_setup(struct console *co, char *options) +static int __init sunsu_console_setup(struct console *co, char *options) { struct uart_port *port; int baud = 9600; @@ -1343,7 +1343,7 @@ static int sunsu_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -static struct console sunsu_cons = { +static struct console sunsu_console = { .name = "ttyS", .write = sunsu_console_write, .device = uart_console_device, @@ -1373,9 +1373,9 @@ static inline struct console *SUNSU_CONSOLE(int num_uart) if (i == num_uart) return NULL; - sunsu_cons.index = i; + sunsu_console.index = i; - return &sunsu_cons; + return &sunsu_console; } #else #define SUNSU_CONSOLE(num_uart) (NULL) diff --git a/trunk/drivers/spi/Kconfig b/trunk/drivers/spi/Kconfig index 7e54e48efd5c..07c587ec71be 100644 --- a/trunk/drivers/spi/Kconfig +++ b/trunk/drivers/spi/Kconfig @@ -58,6 +58,23 @@ config SPI_ATMEL This selects a driver for the Atmel SPI Controller, present on many AT32 (AVR32) and AT91 (ARM) chips. +config SPI_BFIN + tristate "SPI controller driver for ADI Blackfin5xx" + depends on SPI_MASTER && BFIN + help + This is the SPI controller master driver for Blackfin 5xx processor. + +config SPI_AU1550 + tristate "Au1550/Au12x0 SPI Controller" + depends on SPI_MASTER && (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL + select SPI_BITBANG + help + If you say yes to this option, support will be included for the + Au1550 SPI controller (may also work with Au1200,Au1210,Au1250). + + This driver can also be built as a module. If so, the module + will be called au1550_spi. + config SPI_BITBANG tristate "Bitbanging SPI master" depends on SPI_MASTER && EXPERIMENTAL @@ -153,11 +170,19 @@ config SPI_AT25 This driver can also be built as a module. If so, the module will be called at25. +config SPI_SPIDEV + tristate "User mode SPI device driver support" + depends on SPI_MASTER && EXPERIMENTAL + help + This supports user mode SPI protocol drivers. + + Note that this application programming interface is EXPERIMENTAL + and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes. + # # Add new SPI protocol masters in alphabetical order above this line # - # (slave support would go here) endmenu # "SPI support" diff --git a/trunk/drivers/spi/Makefile b/trunk/drivers/spi/Makefile index 3c280ad89202..624b6363f490 100644 --- a/trunk/drivers/spi/Makefile +++ b/trunk/drivers/spi/Makefile @@ -11,8 +11,10 @@ endif obj-$(CONFIG_SPI_MASTER) += spi.o # SPI master controller drivers (bus) -obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o +obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o +obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o +obj-$(CONFIG_SPI_AU1550) += au1550_spi.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o obj-$(CONFIG_SPI_IMX) += spi_imx.o obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o @@ -24,6 +26,7 @@ obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o # SPI protocol drivers (device/link on bus) obj-$(CONFIG_SPI_AT25) += at25.o +obj-$(CONFIG_SPI_SPIDEV) += spidev.o # ... add above this line ... # SPI slave controller drivers (upstream link) diff --git a/trunk/drivers/spi/au1550_spi.c b/trunk/drivers/spi/au1550_spi.c new file mode 100644 index 000000000000..ae2b1af0dba4 --- /dev/null +++ b/trunk/drivers/spi/au1550_spi.c @@ -0,0 +1,974 @@ +/* + * au1550_spi.c - au1550 psc spi controller driver + * may work also with au1200, au1210, au1250 + * will not work on au1000, au1100 and au1500 (no full spi controller there) + * + * Copyright (c) 2006 ATRON electronic GmbH + * Author: Jan Nikitenko + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static unsigned usedma = 1; +module_param(usedma, uint, 0644); + +/* +#define AU1550_SPI_DEBUG_LOOPBACK +*/ + + +#define AU1550_SPI_DBDMA_DESCRIPTORS 1 +#define AU1550_SPI_DMA_RXTMP_MINSIZE 2048U + +struct au1550_spi { + struct spi_bitbang bitbang; + + volatile psc_spi_t __iomem *regs; + int irq; + unsigned freq_max; + unsigned freq_min; + + unsigned len; + unsigned tx_count; + unsigned rx_count; + const u8 *tx; + u8 *rx; + + void (*rx_word)(struct au1550_spi *hw); + void (*tx_word)(struct au1550_spi *hw); + int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); + irqreturn_t (*irq_callback)(struct au1550_spi *hw); + + struct completion master_done; + + unsigned usedma; + u32 dma_tx_id; + u32 dma_rx_id; + u32 dma_tx_ch; + u32 dma_rx_ch; + + u8 *dma_rx_tmpbuf; + unsigned dma_rx_tmpbuf_size; + u32 dma_rx_tmpbuf_addr; + + struct spi_master *master; + struct device *dev; + struct au1550_spi_info *pdata; +}; + + +/* we use an 8-bit memory device for dma transfers to/from spi fifo */ +static dbdev_tab_t au1550_spi_mem_dbdev = +{ + .dev_id = DBDMA_MEM_CHAN, + .dev_flags = DEV_FLAGS_ANYUSE|DEV_FLAGS_SYNC, + .dev_tsize = 0, + .dev_devwidth = 8, + .dev_physaddr = 0x00000000, + .dev_intlevel = 0, + .dev_intpolarity = 0 +}; + +static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw); + + +/** + * compute BRG and DIV bits to setup spi clock based on main input clock rate + * that was specified in platform data structure + * according to au1550 datasheet: + * psc_tempclk = psc_mainclk / (2 << DIV) + * spiclk = psc_tempclk / (2 * (BRG + 1)) + * BRG valid range is 4..63 + * DIV valid range is 0..3 + */ +static u32 au1550_spi_baudcfg(struct au1550_spi *hw, unsigned speed_hz) +{ + u32 mainclk_hz = hw->pdata->mainclk_hz; + u32 div, brg; + + for (div = 0; div < 4; div++) { + brg = mainclk_hz / speed_hz / (4 << div); + /* now we have BRG+1 in brg, so count with that */ + if (brg < (4 + 1)) { + brg = (4 + 1); /* speed_hz too big */ + break; /* set lowest brg (div is == 0) */ + } + if (brg <= (63 + 1)) + break; /* we have valid brg and div */ + } + if (div == 4) { + div = 3; /* speed_hz too small */ + brg = (63 + 1); /* set highest brg and div */ + } + brg--; + return PSC_SPICFG_SET_BAUD(brg) | PSC_SPICFG_SET_DIV(div); +} + +static inline void au1550_spi_mask_ack_all(struct au1550_spi *hw) +{ + hw->regs->psc_spimsk = + PSC_SPIMSK_MM | PSC_SPIMSK_RR | PSC_SPIMSK_RO + | PSC_SPIMSK_RU | PSC_SPIMSK_TR | PSC_SPIMSK_TO + | PSC_SPIMSK_TU | PSC_SPIMSK_SD | PSC_SPIMSK_MD; + au_sync(); + + hw->regs->psc_spievent = + PSC_SPIEVNT_MM | PSC_SPIEVNT_RR | PSC_SPIEVNT_RO + | PSC_SPIEVNT_RU | PSC_SPIEVNT_TR | PSC_SPIEVNT_TO + | PSC_SPIEVNT_TU | PSC_SPIEVNT_SD | PSC_SPIEVNT_MD; + au_sync(); +} + +static void au1550_spi_reset_fifos(struct au1550_spi *hw) +{ + u32 pcr; + + hw->regs->psc_spipcr = PSC_SPIPCR_RC | PSC_SPIPCR_TC; + au_sync(); + do { + pcr = hw->regs->psc_spipcr; + au_sync(); + } while (pcr != 0); +} + +/* + * dma transfers are used for the most common spi word size of 8-bits + * we cannot easily change already set up dma channels' width, so if we wanted + * dma support for more than 8-bit words (up to 24 bits), we would need to + * setup dma channels from scratch on each spi transfer, based on bits_per_word + * instead we have pre set up 8 bit dma channels supporting spi 4 to 8 bits + * transfers, and 9 to 24 bits spi transfers will be done in pio irq based mode + * callbacks to handle dma or pio are set up in au1550_spi_bits_handlers_set() + */ +static void au1550_spi_chipsel(struct spi_device *spi, int value) +{ + struct au1550_spi *hw = spi_master_get_devdata(spi->master); + unsigned cspol = spi->mode & SPI_CS_HIGH ? 1 : 0; + u32 cfg, stat; + + switch (value) { + case BITBANG_CS_INACTIVE: + if (hw->pdata->deactivate_cs) + hw->pdata->deactivate_cs(hw->pdata, spi->chip_select, + cspol); + break; + + case BITBANG_CS_ACTIVE: + au1550_spi_bits_handlers_set(hw, spi->bits_per_word); + + cfg = hw->regs->psc_spicfg; + au_sync(); + hw->regs->psc_spicfg = cfg & ~PSC_SPICFG_DE_ENABLE; + au_sync(); + + if (spi->mode & SPI_CPOL) + cfg |= PSC_SPICFG_BI; + else + cfg &= ~PSC_SPICFG_BI; + if (spi->mode & SPI_CPHA) + cfg &= ~PSC_SPICFG_CDE; + else + cfg |= PSC_SPICFG_CDE; + + if (spi->mode & SPI_LSB_FIRST) + cfg |= PSC_SPICFG_MLF; + else + cfg &= ~PSC_SPICFG_MLF; + + if (hw->usedma && spi->bits_per_word <= 8) + cfg &= ~PSC_SPICFG_DD_DISABLE; + else + cfg |= PSC_SPICFG_DD_DISABLE; + cfg = PSC_SPICFG_CLR_LEN(cfg); + cfg |= PSC_SPICFG_SET_LEN(spi->bits_per_word); + + cfg = PSC_SPICFG_CLR_BAUD(cfg); + cfg &= ~PSC_SPICFG_SET_DIV(3); + cfg |= au1550_spi_baudcfg(hw, spi->max_speed_hz); + + hw->regs->psc_spicfg = cfg | PSC_SPICFG_DE_ENABLE; + au_sync(); + do { + stat = hw->regs->psc_spistat; + au_sync(); + } while ((stat & PSC_SPISTAT_DR) == 0); + + if (hw->pdata->activate_cs) + hw->pdata->activate_cs(hw->pdata, spi->chip_select, + cspol); + break; + } +} + +static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t) +{ + struct au1550_spi *hw = spi_master_get_devdata(spi->master); + unsigned bpw, hz; + u32 cfg, stat; + + bpw = t ? t->bits_per_word : spi->bits_per_word; + hz = t ? t->speed_hz : spi->max_speed_hz; + + if (bpw < 4 || bpw > 24) { + dev_err(&spi->dev, "setupxfer: invalid bits_per_word=%d\n", + bpw); + return -EINVAL; + } + if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) { + dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n", + hz); + return -EINVAL; + } + + au1550_spi_bits_handlers_set(hw, spi->bits_per_word); + + cfg = hw->regs->psc_spicfg; + au_sync(); + hw->regs->psc_spicfg = cfg & ~PSC_SPICFG_DE_ENABLE; + au_sync(); + + if (hw->usedma && bpw <= 8) + cfg &= ~PSC_SPICFG_DD_DISABLE; + else + cfg |= PSC_SPICFG_DD_DISABLE; + cfg = PSC_SPICFG_CLR_LEN(cfg); + cfg |= PSC_SPICFG_SET_LEN(bpw); + + cfg = PSC_SPICFG_CLR_BAUD(cfg); + cfg &= ~PSC_SPICFG_SET_DIV(3); + cfg |= au1550_spi_baudcfg(hw, hz); + + hw->regs->psc_spicfg = cfg; + au_sync(); + + if (cfg & PSC_SPICFG_DE_ENABLE) { + do { + stat = hw->regs->psc_spistat; + au_sync(); + } while ((stat & PSC_SPISTAT_DR) == 0); + } + + au1550_spi_reset_fifos(hw); + au1550_spi_mask_ack_all(hw); + return 0; +} + +static int au1550_spi_setup(struct spi_device *spi) +{ + struct au1550_spi *hw = spi_master_get_devdata(spi->master); + + if (spi->bits_per_word == 0) + spi->bits_per_word = 8; + if (spi->bits_per_word < 4 || spi->bits_per_word > 24) { + dev_err(&spi->dev, "setup: invalid bits_per_word=%d\n", + spi->bits_per_word); + return -EINVAL; + } + + if (spi->max_speed_hz == 0) + spi->max_speed_hz = hw->freq_max; + if (spi->max_speed_hz > hw->freq_max + || spi->max_speed_hz < hw->freq_min) + return -EINVAL; + /* + * NOTE: cannot change speed and other hw settings immediately, + * otherwise sharing of spi bus is not possible, + * so do not call setupxfer(spi, NULL) here + */ + return 0; +} + +/* + * for dma spi transfers, we have to setup rx channel, otherwise there is + * no reliable way how to recognize that spi transfer is done + * dma complete callbacks are called before real spi transfer is finished + * and if only tx dma channel is set up (and rx fifo overflow event masked) + * spi master done event irq is not generated unless rx fifo is empty (emptied) + * so we need rx tmp buffer to use for rx dma if user does not provide one + */ +static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned size) +{ + hw->dma_rx_tmpbuf = kmalloc(size, GFP_KERNEL); + if (!hw->dma_rx_tmpbuf) + return -ENOMEM; + hw->dma_rx_tmpbuf_size = size; + hw->dma_rx_tmpbuf_addr = dma_map_single(hw->dev, hw->dma_rx_tmpbuf, + size, DMA_FROM_DEVICE); + if (dma_mapping_error(hw->dma_rx_tmpbuf_addr)) { + kfree(hw->dma_rx_tmpbuf); + hw->dma_rx_tmpbuf = 0; + hw->dma_rx_tmpbuf_size = 0; + return -EFAULT; + } + return 0; +} + +static void au1550_spi_dma_rxtmp_free(struct au1550_spi *hw) +{ + dma_unmap_single(hw->dev, hw->dma_rx_tmpbuf_addr, + hw->dma_rx_tmpbuf_size, DMA_FROM_DEVICE); + kfree(hw->dma_rx_tmpbuf); + hw->dma_rx_tmpbuf = 0; + hw->dma_rx_tmpbuf_size = 0; +} + +static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t) +{ + struct au1550_spi *hw = spi_master_get_devdata(spi->master); + dma_addr_t dma_tx_addr; + dma_addr_t dma_rx_addr; + u32 res; + + hw->len = t->len; + hw->tx_count = 0; + hw->rx_count = 0; + + hw->tx = t->tx_buf; + hw->rx = t->rx_buf; + dma_tx_addr = t->tx_dma; + dma_rx_addr = t->rx_dma; + + /* + * check if buffers are already dma mapped, map them otherwise + * use rx buffer in place of tx if tx buffer was not provided + * use temp rx buffer (preallocated or realloc to fit) for rx dma + */ + if (t->rx_buf) { + if (t->rx_dma == 0) { /* if DMA_ADDR_INVALID, map it */ + dma_rx_addr = dma_map_single(hw->dev, + (void *)t->rx_buf, + t->len, DMA_FROM_DEVICE); + if (dma_mapping_error(dma_rx_addr)) + dev_err(hw->dev, "rx dma map error\n"); + } + } else { + if (t->len > hw->dma_rx_tmpbuf_size) { + int ret; + + au1550_spi_dma_rxtmp_free(hw); + ret = au1550_spi_dma_rxtmp_alloc(hw, max(t->len, + AU1550_SPI_DMA_RXTMP_MINSIZE)); + if (ret < 0) + return ret; + } + hw->rx = hw->dma_rx_tmpbuf; + dma_rx_addr = hw->dma_rx_tmpbuf_addr; + dma_sync_single_for_device(hw->dev, dma_rx_addr, + t->len, DMA_FROM_DEVICE); + } + if (t->tx_buf) { + if (t->tx_dma == 0) { /* if DMA_ADDR_INVALID, map it */ + dma_tx_addr = dma_map_single(hw->dev, + (void *)t->tx_buf, + t->len, DMA_TO_DEVICE); + if (dma_mapping_error(dma_tx_addr)) + dev_err(hw->dev, "tx dma map error\n"); + } + } else { + dma_sync_single_for_device(hw->dev, dma_rx_addr, + t->len, DMA_BIDIRECTIONAL); + hw->tx = hw->rx; + } + + /* put buffers on the ring */ + res = au1xxx_dbdma_put_dest(hw->dma_rx_ch, hw->rx, t->len); + if (!res) + dev_err(hw->dev, "rx dma put dest error\n"); + + res = au1xxx_dbdma_put_source(hw->dma_tx_ch, (void *)hw->tx, t->len); + if (!res) + dev_err(hw->dev, "tx dma put source error\n"); + + au1xxx_dbdma_start(hw->dma_rx_ch); + au1xxx_dbdma_start(hw->dma_tx_ch); + + /* by default enable nearly all events interrupt */ + hw->regs->psc_spimsk = PSC_SPIMSK_SD; + au_sync(); + + /* start the transfer */ + hw->regs->psc_spipcr = PSC_SPIPCR_MS; + au_sync(); + + wait_for_completion(&hw->master_done); + + au1xxx_dbdma_stop(hw->dma_tx_ch); + au1xxx_dbdma_stop(hw->dma_rx_ch); + + if (!t->rx_buf) { + /* using the temporal preallocated and premapped buffer */ + dma_sync_single_for_cpu(hw->dev, dma_rx_addr, t->len, + DMA_FROM_DEVICE); + } + /* unmap buffers if mapped above */ + if (t->rx_buf && t->rx_dma == 0 ) + dma_unmap_single(hw->dev, dma_rx_addr, t->len, + DMA_FROM_DEVICE); + if (t->tx_buf && t->tx_dma == 0 ) + dma_unmap_single(hw->dev, dma_tx_addr, t->len, + DMA_TO_DEVICE); + + return hw->rx_count < hw->tx_count ? hw->rx_count : hw->tx_count; +} + +static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw) +{ + u32 stat, evnt; + + stat = hw->regs->psc_spistat; + evnt = hw->regs->psc_spievent; + au_sync(); + if ((stat & PSC_SPISTAT_DI) == 0) { + dev_err(hw->dev, "Unexpected IRQ!\n"); + return IRQ_NONE; + } + + if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO + | PSC_SPIEVNT_RU | PSC_SPIEVNT_TO + | PSC_SPIEVNT_TU | PSC_SPIEVNT_SD)) + != 0) { + /* + * due to an spi error we consider transfer as done, + * so mask all events until before next transfer start + * and stop the possibly running dma immediatelly + */ + au1550_spi_mask_ack_all(hw); + au1xxx_dbdma_stop(hw->dma_rx_ch); + au1xxx_dbdma_stop(hw->dma_tx_ch); + + /* get number of transfered bytes */ + hw->rx_count = hw->len - au1xxx_get_dma_residue(hw->dma_rx_ch); + hw->tx_count = hw->len - au1xxx_get_dma_residue(hw->dma_tx_ch); + + au1xxx_dbdma_reset(hw->dma_rx_ch); + au1xxx_dbdma_reset(hw->dma_tx_ch); + au1550_spi_reset_fifos(hw); + + dev_err(hw->dev, + "Unexpected SPI error: event=0x%x stat=0x%x!\n", + evnt, stat); + + complete(&hw->master_done); + return IRQ_HANDLED; + } + + if ((evnt & PSC_SPIEVNT_MD) != 0) { + /* transfer completed successfully */ + au1550_spi_mask_ack_all(hw); + hw->rx_count = hw->len; + hw->tx_count = hw->len; + complete(&hw->master_done); + } + return IRQ_HANDLED; +} + + +/* routines to handle different word sizes in pio mode */ +#define AU1550_SPI_RX_WORD(size, mask) \ +static void au1550_spi_rx_word_##size(struct au1550_spi *hw) \ +{ \ + u32 fifoword = hw->regs->psc_spitxrx & (u32)(mask); \ + au_sync(); \ + if (hw->rx) { \ + *(u##size *)hw->rx = (u##size)fifoword; \ + hw->rx += (size) / 8; \ + } \ + hw->rx_count += (size) / 8; \ +} + +#define AU1550_SPI_TX_WORD(size, mask) \ +static void au1550_spi_tx_word_##size(struct au1550_spi *hw) \ +{ \ + u32 fifoword = 0; \ + if (hw->tx) { \ + fifoword = *(u##size *)hw->tx & (u32)(mask); \ + hw->tx += (size) / 8; \ + } \ + hw->tx_count += (size) / 8; \ + if (hw->tx_count >= hw->len) \ + fifoword |= PSC_SPITXRX_LC; \ + hw->regs->psc_spitxrx = fifoword; \ + au_sync(); \ +} + +AU1550_SPI_RX_WORD(8,0xff) +AU1550_SPI_RX_WORD(16,0xffff) +AU1550_SPI_RX_WORD(32,0xffffff) +AU1550_SPI_TX_WORD(8,0xff) +AU1550_SPI_TX_WORD(16,0xffff) +AU1550_SPI_TX_WORD(32,0xffffff) + +static int au1550_spi_pio_txrxb(struct spi_device *spi, struct spi_transfer *t) +{ + u32 stat, mask; + struct au1550_spi *hw = spi_master_get_devdata(spi->master); + + hw->tx = t->tx_buf; + hw->rx = t->rx_buf; + hw->len = t->len; + hw->tx_count = 0; + hw->rx_count = 0; + + /* by default enable nearly all events after filling tx fifo */ + mask = PSC_SPIMSK_SD; + + /* fill the transmit FIFO */ + while (hw->tx_count < hw->len) { + + hw->tx_word(hw); + + if (hw->tx_count >= hw->len) { + /* mask tx fifo request interrupt as we are done */ + mask |= PSC_SPIMSK_TR; + } + + stat = hw->regs->psc_spistat; + au_sync(); + if (stat & PSC_SPISTAT_TF) + break; + } + + /* enable event interrupts */ + hw->regs->psc_spimsk = mask; + au_sync(); + + /* start the transfer */ + hw->regs->psc_spipcr = PSC_SPIPCR_MS; + au_sync(); + + wait_for_completion(&hw->master_done); + + return hw->rx_count < hw->tx_count ? hw->rx_count : hw->tx_count; +} + +static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw) +{ + int busy; + u32 stat, evnt; + + stat = hw->regs->psc_spistat; + evnt = hw->regs->psc_spievent; + au_sync(); + if ((stat & PSC_SPISTAT_DI) == 0) { + dev_err(hw->dev, "Unexpected IRQ!\n"); + return IRQ_NONE; + } + + if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO + | PSC_SPIEVNT_RU | PSC_SPIEVNT_TO + | PSC_SPIEVNT_TU | PSC_SPIEVNT_SD)) + != 0) { + dev_err(hw->dev, + "Unexpected SPI error: event=0x%x stat=0x%x!\n", + evnt, stat); + /* + * due to an error we consider transfer as done, + * so mask all events until before next transfer start + */ + au1550_spi_mask_ack_all(hw); + au1550_spi_reset_fifos(hw); + complete(&hw->master_done); + return IRQ_HANDLED; + } + + /* + * while there is something to read from rx fifo + * or there is a space to write to tx fifo: + */ + do { + busy = 0; + stat = hw->regs->psc_spistat; + au_sync(); + + if ((stat & PSC_SPISTAT_RE) == 0 && hw->rx_count < hw->len) { + hw->rx_word(hw); + /* ack the receive request event */ + hw->regs->psc_spievent = PSC_SPIEVNT_RR; + au_sync(); + busy = 1; + } + + if ((stat & PSC_SPISTAT_TF) == 0 && hw->tx_count < hw->len) { + hw->tx_word(hw); + /* ack the transmit request event */ + hw->regs->psc_spievent = PSC_SPIEVNT_TR; + au_sync(); + busy = 1; + } + } while (busy); + + evnt = hw->regs->psc_spievent; + au_sync(); + + if (hw->rx_count >= hw->len || (evnt & PSC_SPIEVNT_MD) != 0) { + /* transfer completed successfully */ + au1550_spi_mask_ack_all(hw); + complete(&hw->master_done); + } + return IRQ_HANDLED; +} + +static int au1550_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) +{ + struct au1550_spi *hw = spi_master_get_devdata(spi->master); + return hw->txrx_bufs(spi, t); +} + +static irqreturn_t au1550_spi_irq(int irq, void *dev, struct pt_regs *regs) +{ + struct au1550_spi *hw = dev; + return hw->irq_callback(hw); +} + +static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw) +{ + if (bpw <= 8) { + if (hw->usedma) { + hw->txrx_bufs = &au1550_spi_dma_txrxb; + hw->irq_callback = &au1550_spi_dma_irq_callback; + } else { + hw->rx_word = &au1550_spi_rx_word_8; + hw->tx_word = &au1550_spi_tx_word_8; + hw->txrx_bufs = &au1550_spi_pio_txrxb; + hw->irq_callback = &au1550_spi_pio_irq_callback; + } + } else if (bpw <= 16) { + hw->rx_word = &au1550_spi_rx_word_16; + hw->tx_word = &au1550_spi_tx_word_16; + hw->txrx_bufs = &au1550_spi_pio_txrxb; + hw->irq_callback = &au1550_spi_pio_irq_callback; + } else { + hw->rx_word = &au1550_spi_rx_word_32; + hw->tx_word = &au1550_spi_tx_word_32; + hw->txrx_bufs = &au1550_spi_pio_txrxb; + hw->irq_callback = &au1550_spi_pio_irq_callback; + } +} + +static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw) +{ + u32 stat, cfg; + + /* set up the PSC for SPI mode */ + hw->regs->psc_ctrl = PSC_CTRL_DISABLE; + au_sync(); + hw->regs->psc_sel = PSC_SEL_PS_SPIMODE; + au_sync(); + + hw->regs->psc_spicfg = 0; + au_sync(); + + hw->regs->psc_ctrl = PSC_CTRL_ENABLE; + au_sync(); + + do { + stat = hw->regs->psc_spistat; + au_sync(); + } while ((stat & PSC_SPISTAT_SR) == 0); + + + cfg = hw->usedma ? 0 : PSC_SPICFG_DD_DISABLE; + cfg |= PSC_SPICFG_SET_LEN(8); + cfg |= PSC_SPICFG_RT_FIFO8 | PSC_SPICFG_TT_FIFO8; + /* use minimal allowed brg and div values as initial setting: */ + cfg |= PSC_SPICFG_SET_BAUD(4) | PSC_SPICFG_SET_DIV(0); + +#ifdef AU1550_SPI_DEBUG_LOOPBACK + cfg |= PSC_SPICFG_LB; +#endif + + hw->regs->psc_spicfg = cfg; + au_sync(); + + au1550_spi_mask_ack_all(hw); + + hw->regs->psc_spicfg |= PSC_SPICFG_DE_ENABLE; + au_sync(); + + do { + stat = hw->regs->psc_spistat; + au_sync(); + } while ((stat & PSC_SPISTAT_DR) == 0); +} + + +static int __init au1550_spi_probe(struct platform_device *pdev) +{ + struct au1550_spi *hw; + struct spi_master *master; + int err = 0; + + master = spi_alloc_master(&pdev->dev, sizeof(struct au1550_spi)); + if (master == NULL) { + dev_err(&pdev->dev, "No memory for spi_master\n"); + err = -ENOMEM; + goto err_nomem; + } + + hw = spi_master_get_devdata(master); + + hw->master = spi_master_get(master); + hw->pdata = pdev->dev.platform_data; + hw->dev = &pdev->dev; + + if (hw->pdata == NULL) { + dev_err(&pdev->dev, "No platform data supplied\n"); + err = -ENOENT; + goto err_no_pdata; + } + + platform_set_drvdata(pdev, hw); + + init_completion(&hw->master_done); + + hw->bitbang.master = hw->master; + hw->bitbang.setup_transfer = au1550_spi_setupxfer; + hw->bitbang.chipselect = au1550_spi_chipsel; + hw->bitbang.master->setup = au1550_spi_setup; + hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs; + + switch (hw->pdata->bus_num) { + case 0: + hw->irq = AU1550_PSC0_INT; + hw->regs = (volatile psc_spi_t *)PSC0_BASE_ADDR; + hw->dma_rx_id = DSCR_CMD0_PSC0_RX; + hw->dma_tx_id = DSCR_CMD0_PSC0_TX; + break; + case 1: + hw->irq = AU1550_PSC1_INT; + hw->regs = (volatile psc_spi_t *)PSC1_BASE_ADDR; + hw->dma_rx_id = DSCR_CMD0_PSC1_RX; + hw->dma_tx_id = DSCR_CMD0_PSC1_TX; + break; + case 2: + hw->irq = AU1550_PSC2_INT; + hw->regs = (volatile psc_spi_t *)PSC2_BASE_ADDR; + hw->dma_rx_id = DSCR_CMD0_PSC2_RX; + hw->dma_tx_id = DSCR_CMD0_PSC2_TX; + break; + case 3: + hw->irq = AU1550_PSC3_INT; + hw->regs = (volatile psc_spi_t *)PSC3_BASE_ADDR; + hw->dma_rx_id = DSCR_CMD0_PSC3_RX; + hw->dma_tx_id = DSCR_CMD0_PSC3_TX; + break; + default: + dev_err(&pdev->dev, "Wrong bus_num of SPI\n"); + err = -ENOENT; + goto err_no_pdata; + } + + if (request_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t), + pdev->name) == NULL) { + dev_err(&pdev->dev, "Cannot reserve iomem region\n"); + err = -ENXIO; + goto err_no_iores; + } + + + if (usedma) { + if (pdev->dev.dma_mask == NULL) + dev_warn(&pdev->dev, "no dma mask\n"); + else + hw->usedma = 1; + } + + if (hw->usedma) { + /* + * create memory device with 8 bits dev_devwidth + * needed for proper byte ordering to spi fifo + */ + int memid = au1xxx_ddma_add_device(&au1550_spi_mem_dbdev); + if (!memid) { + dev_err(&pdev->dev, + "Cannot create dma 8 bit mem device\n"); + err = -ENXIO; + goto err_dma_add_dev; + } + + hw->dma_tx_ch = au1xxx_dbdma_chan_alloc(memid, + hw->dma_tx_id, NULL, (void *)hw); + if (hw->dma_tx_ch == 0) { + dev_err(&pdev->dev, + "Cannot allocate tx dma channel\n"); + err = -ENXIO; + goto err_no_txdma; + } + au1xxx_dbdma_set_devwidth(hw->dma_tx_ch, 8); + if (au1xxx_dbdma_ring_alloc(hw->dma_tx_ch, + AU1550_SPI_DBDMA_DESCRIPTORS) == 0) { + dev_err(&pdev->dev, + "Cannot allocate tx dma descriptors\n"); + err = -ENXIO; + goto err_no_txdma_descr; + } + + + hw->dma_rx_ch = au1xxx_dbdma_chan_alloc(hw->dma_rx_id, + memid, NULL, (void *)hw); + if (hw->dma_rx_ch == 0) { + dev_err(&pdev->dev, + "Cannot allocate rx dma channel\n"); + err = -ENXIO; + goto err_no_rxdma; + } + au1xxx_dbdma_set_devwidth(hw->dma_rx_ch, 8); + if (au1xxx_dbdma_ring_alloc(hw->dma_rx_ch, + AU1550_SPI_DBDMA_DESCRIPTORS) == 0) { + dev_err(&pdev->dev, + "Cannot allocate rx dma descriptors\n"); + err = -ENXIO; + goto err_no_rxdma_descr; + } + + err = au1550_spi_dma_rxtmp_alloc(hw, + AU1550_SPI_DMA_RXTMP_MINSIZE); + if (err < 0) { + dev_err(&pdev->dev, + "Cannot allocate initial rx dma tmp buffer\n"); + goto err_dma_rxtmp_alloc; + } + } + + au1550_spi_bits_handlers_set(hw, 8); + + err = request_irq(hw->irq, au1550_spi_irq, 0, pdev->name, hw); + if (err) { + dev_err(&pdev->dev, "Cannot claim IRQ\n"); + goto err_no_irq; + } + + master->bus_num = hw->pdata->bus_num; + master->num_chipselect = hw->pdata->num_chipselect; + + /* + * precompute valid range for spi freq - from au1550 datasheet: + * psc_tempclk = psc_mainclk / (2 << DIV) + * spiclk = psc_tempclk / (2 * (BRG + 1)) + * BRG valid range is 4..63 + * DIV valid range is 0..3 + * round the min and max frequencies to values that would still + * produce valid brg and div + */ + { + int min_div = (2 << 0) * (2 * (4 + 1)); + int max_div = (2 << 3) * (2 * (63 + 1)); + hw->freq_max = hw->pdata->mainclk_hz / min_div; + hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1; + } + + au1550_spi_setup_psc_as_spi(hw); + + err = spi_bitbang_start(&hw->bitbang); + if (err) { + dev_err(&pdev->dev, "Failed to register SPI master\n"); + goto err_register; + } + + dev_info(&pdev->dev, + "spi master registered: bus_num=%d num_chipselect=%d\n", + master->bus_num, master->num_chipselect); + + return 0; + +err_register: + free_irq(hw->irq, hw); + +err_no_irq: + au1550_spi_dma_rxtmp_free(hw); + +err_dma_rxtmp_alloc: +err_no_rxdma_descr: + if (hw->usedma) + au1xxx_dbdma_chan_free(hw->dma_rx_ch); + +err_no_rxdma: +err_no_txdma_descr: + if (hw->usedma) + au1xxx_dbdma_chan_free(hw->dma_tx_ch); + +err_no_txdma: +err_dma_add_dev: + release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t)); + +err_no_iores: +err_no_pdata: + spi_master_put(hw->master); + +err_nomem: + return err; +} + +static int __exit au1550_spi_remove(struct platform_device *pdev) +{ + struct au1550_spi *hw = platform_get_drvdata(pdev); + + dev_info(&pdev->dev, "spi master remove: bus_num=%d\n", + hw->master->bus_num); + + spi_bitbang_stop(&hw->bitbang); + free_irq(hw->irq, hw); + release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t)); + + if (hw->usedma) { + au1550_spi_dma_rxtmp_free(hw); + au1xxx_dbdma_chan_free(hw->dma_rx_ch); + au1xxx_dbdma_chan_free(hw->dma_tx_ch); + } + + platform_set_drvdata(pdev, NULL); + + spi_master_put(hw->master); + return 0; +} + +static struct platform_driver au1550_spi_drv = { + .remove = __exit_p(au1550_spi_remove), + .driver = { + .name = "au1550-spi", + .owner = THIS_MODULE, + }, +}; + +static int __init au1550_spi_init(void) +{ + return platform_driver_probe(&au1550_spi_drv, au1550_spi_probe); +} +module_init(au1550_spi_init); + +static void __exit au1550_spi_exit(void) +{ + platform_driver_unregister(&au1550_spi_drv); +} +module_exit(au1550_spi_exit); + +MODULE_DESCRIPTION("Au1550 PSC SPI Driver"); +MODULE_AUTHOR("Jan Nikitenko "); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/spi/spi.c b/trunk/drivers/spi/spi.c index 6657331eed93..c3219b29b5ac 100644 --- a/trunk/drivers/spi/spi.c +++ b/trunk/drivers/spi/spi.c @@ -152,6 +152,11 @@ static void spi_drv_shutdown(struct device *dev) sdrv->shutdown(to_spi_device(dev)); } +/** + * spi_register_driver - register a SPI driver + * @sdrv: the driver to register + * Context: can sleep + */ int spi_register_driver(struct spi_driver *sdrv) { sdrv->driver.bus = &spi_bus_type; @@ -183,7 +188,13 @@ static LIST_HEAD(board_list); static DECLARE_MUTEX(board_lock); -/* On typical mainboards, this is purely internal; and it's not needed +/** + * spi_new_device - instantiate one new SPI device + * @master: Controller to which device is connected + * @chip: Describes the SPI device + * Context: can sleep + * + * On typical mainboards, this is purely internal; and it's not needed * after board init creates the hard-wired devices. Some development * platforms may not be able to use spi_register_board_info though, and * this is exported so that for example a USB or parport based adapter @@ -251,7 +262,12 @@ struct spi_device *spi_new_device(struct spi_master *master, } EXPORT_SYMBOL_GPL(spi_new_device); -/* +/** + * spi_register_board_info - register SPI devices for a given board + * @info: array of chip descriptors + * @n: how many descriptors are provided + * Context: can sleep + * * Board-specific early init code calls this (probably during arch_initcall) * with segments of the SPI device table. Any device nodes are created later, * after the relevant parent SPI controller (bus_num) is defined. We keep @@ -337,9 +353,10 @@ static struct class spi_master_class = { /** * spi_alloc_master - allocate SPI master controller * @dev: the controller, possibly using the platform_bus - * @size: how much driver-private data to preallocate; the pointer to this + * @size: how much zeroed driver-private data to allocate; the pointer to this * memory is in the class_data field of the returned class_device, * accessible with spi_master_get_devdata(). + * Context: can sleep * * This call is used only by SPI master controller drivers, which are the * only ones directly touching chip registers. It's how they allocate @@ -375,6 +392,7 @@ EXPORT_SYMBOL_GPL(spi_alloc_master); /** * spi_register_master - register SPI master controller * @master: initialized master, originally from spi_alloc_master() + * Context: can sleep * * SPI master controllers connect to their drivers using some non-SPI bus, * such as the platform bus. The final stage of probe() in that code @@ -437,6 +455,7 @@ static int __unregister(struct device *dev, void *unused) /** * spi_unregister_master - unregister SPI master controller * @master: the master being unregistered + * Context: can sleep * * This call is used only by SPI master controller drivers, which are the * only ones directly touching chip registers. @@ -455,6 +474,7 @@ EXPORT_SYMBOL_GPL(spi_unregister_master); /** * spi_busnum_to_master - look up master associated with bus_num * @bus_num: the master's bus number + * Context: can sleep * * This call may be used with devices that are registered after * arch init time. It returns a refcounted pointer to the relevant @@ -492,6 +512,7 @@ static void spi_complete(void *arg) * spi_sync - blocking/synchronous SPI data transfers * @spi: device with which data will be exchanged * @message: describes the data transfers + * Context: can sleep * * This call may only be used from a context that may sleep. The sleep * is non-interruptible, and has no timeout. Low-overhead controller @@ -508,7 +529,7 @@ static void spi_complete(void *arg) * * The return value is a negative error code if the message could not be * submitted, else zero. When the value is zero, then message->status is - * also defined: it's the completion code for the transfer, either zero + * also defined; it's the completion code for the transfer, either zero * or a negative error code from the controller driver. */ int spi_sync(struct spi_device *spi, struct spi_message *message) @@ -538,6 +559,7 @@ static u8 *buf; * @n_tx: size of txbuf, in bytes * @rxbuf: buffer into which data will be read * @n_rx: size of rxbuf, in bytes (need not be dma-safe) + * Context: can sleep * * This performs a half duplex MicroWire style transaction with the * device, sending txbuf and then reading rxbuf. The return value @@ -545,7 +567,8 @@ static u8 *buf; * This call may only be used from a context that may sleep. * * Parameters to this routine are always copied using a small buffer; - * performance-sensitive or bulk transfer code should instead use + * portable code should never use this for more than 32 bytes. + * Performance-sensitive or bulk transfer code should instead use * spi_{async,sync}() calls with dma-safe buffers. */ int spi_write_then_read(struct spi_device *spi, diff --git a/trunk/drivers/spi/spi_bfin5xx.c b/trunk/drivers/spi/spi_bfin5xx.c new file mode 100644 index 000000000000..ce3c0ce2316e --- /dev/null +++ b/trunk/drivers/spi/spi_bfin5xx.c @@ -0,0 +1,1313 @@ +/* + * File: drivers/spi/bfin5xx_spi.c + * Based on: N/A + * Author: Luke Yang (Analog Devices Inc.) + * + * Created: March. 10th 2006 + * Description: SPI controller driver for Blackfin 5xx + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * Modified: + * March 10, 2006 bfin5xx_spi.c Created. (Luke Yang) + * August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang) + * + * Copyright 2004-2006 Analog Devices 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 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 ; see the file COPYING. + * If not, write to the Free Software Foundation, + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +MODULE_AUTHOR("Luke Yang"); +MODULE_DESCRIPTION("Blackfin 5xx SPI Contoller"); +MODULE_LICENSE("GPL"); + +#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0) + +#define DEFINE_SPI_REG(reg, off) \ +static inline u16 read_##reg(void) \ + { return *(volatile unsigned short*)(SPI0_REGBASE + off); } \ +static inline void write_##reg(u16 v) \ + {*(volatile unsigned short*)(SPI0_REGBASE + off) = v;\ + SSYNC();} + +DEFINE_SPI_REG(CTRL, 0x00) +DEFINE_SPI_REG(FLAG, 0x04) +DEFINE_SPI_REG(STAT, 0x08) +DEFINE_SPI_REG(TDBR, 0x0C) +DEFINE_SPI_REG(RDBR, 0x10) +DEFINE_SPI_REG(BAUD, 0x14) +DEFINE_SPI_REG(SHAW, 0x18) +#define START_STATE ((void*)0) +#define RUNNING_STATE ((void*)1) +#define DONE_STATE ((void*)2) +#define ERROR_STATE ((void*)-1) +#define QUEUE_RUNNING 0 +#define QUEUE_STOPPED 1 +int dma_requested; + +struct driver_data { + /* Driver model hookup */ + struct platform_device *pdev; + + /* SPI framework hookup */ + struct spi_master *master; + + /* BFIN hookup */ + struct bfin5xx_spi_master *master_info; + + /* Driver message queue */ + struct workqueue_struct *workqueue; + struct work_struct pump_messages; + spinlock_t lock; + struct list_head queue; + int busy; + int run; + + /* Message Transfer pump */ + struct tasklet_struct pump_transfers; + + /* Current message transfer state info */ + struct spi_message *cur_msg; + struct spi_transfer *cur_transfer; + struct chip_data *cur_chip; + size_t len_in_bytes; + size_t len; + void *tx; + void *tx_end; + void *rx; + void *rx_end; + int dma_mapped; + dma_addr_t rx_dma; + dma_addr_t tx_dma; + size_t rx_map_len; + size_t tx_map_len; + u8 n_bytes; + void (*write) (struct driver_data *); + void (*read) (struct driver_data *); + void (*duplex) (struct driver_data *); +}; + +struct chip_data { + u16 ctl_reg; + u16 baud; + u16 flag; + + u8 chip_select_num; + u8 n_bytes; + u32 width; /* 0 or 1 */ + u8 enable_dma; + u8 bits_per_word; /* 8 or 16 */ + u8 cs_change_per_word; + u8 cs_chg_udelay; + void (*write) (struct driver_data *); + void (*read) (struct driver_data *); + void (*duplex) (struct driver_data *); +}; + +void bfin_spi_enable(struct driver_data *drv_data) +{ + u16 cr; + + cr = read_CTRL(); + write_CTRL(cr | BIT_CTL_ENABLE); + SSYNC(); +} + +void bfin_spi_disable(struct driver_data *drv_data) +{ + u16 cr; + + cr = read_CTRL(); + write_CTRL(cr & (~BIT_CTL_ENABLE)); + SSYNC(); +} + +/* Caculate the SPI_BAUD register value based on input HZ */ +static u16 hz_to_spi_baud(u32 speed_hz) +{ + u_long sclk = get_sclk(); + u16 spi_baud = (sclk / (2 * speed_hz)); + + if ((sclk % (2 * speed_hz)) > 0) + spi_baud++; + + pr_debug("sclk = %ld, speed_hz = %d, spi_baud = %d\n", sclk, speed_hz, + spi_baud); + + return spi_baud; +} + +static int flush(struct driver_data *drv_data) +{ + unsigned long limit = loops_per_jiffy << 1; + + /* wait for stop and clear stat */ + while (!(read_STAT() & BIT_STAT_SPIF) && limit--) + continue; + + write_STAT(BIT_STAT_CLR); + + return limit; +} + +/* stop controller and re-config current chip*/ +static void restore_state(struct driver_data *drv_data) +{ + struct chip_data *chip = drv_data->cur_chip; + + /* Clear status and disable clock */ + write_STAT(BIT_STAT_CLR); + bfin_spi_disable(drv_data); + pr_debug("restoring spi ctl state\n"); + +#if defined(CONFIG_BF534) || defined(CONFIG_BF536) || defined(CONFIG_BF537) + pr_debug("chip select number is %d\n", chip->chip_select_num); + + switch (chip->chip_select_num) { + case 1: + bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3c00); + SSYNC(); + break; + + case 2: + case 3: + bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJSE_SPI); + SSYNC(); + bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800); + SSYNC(); + break; + + case 4: + bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS4E_SPI); + SSYNC(); + bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3840); + SSYNC(); + break; + + case 5: + bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS5E_SPI); + SSYNC(); + bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3820); + SSYNC(); + break; + + case 6: + bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS6E_SPI); + SSYNC(); + bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3810); + SSYNC(); + break; + + case 7: + bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJCE_SPI); + SSYNC(); + bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800); + SSYNC(); + break; + } +#endif + + /* Load the registers */ + write_CTRL(chip->ctl_reg); + write_BAUD(chip->baud); + write_FLAG(chip->flag); +} + +/* used to kick off transfer in rx mode */ +static unsigned short dummy_read(void) +{ + unsigned short tmp; + tmp = read_RDBR(); + return tmp; +} + +static void null_writer(struct driver_data *drv_data) +{ + u8 n_bytes = drv_data->n_bytes; + + while (drv_data->tx < drv_data->tx_end) { + write_TDBR(0); + while ((read_STAT() & BIT_STAT_TXS)) + continue; + drv_data->tx += n_bytes; + } +} + +static void null_reader(struct driver_data *drv_data) +{ + u8 n_bytes = drv_data->n_bytes; + dummy_read(); + + while (drv_data->rx < drv_data->rx_end) { + while (!(read_STAT() & BIT_STAT_RXS)) + continue; + dummy_read(); + drv_data->rx += n_bytes; + } +} + +static void u8_writer(struct driver_data *drv_data) +{ + pr_debug("cr8-s is 0x%x\n", read_STAT()); + while (drv_data->tx < drv_data->tx_end) { + write_TDBR(*(u8 *) (drv_data->tx)); + while (read_STAT() & BIT_STAT_TXS) + continue; + ++drv_data->tx; + } + + /* poll for SPI completion before returning */ + while (!(read_STAT() & BIT_STAT_SPIF)) + continue; +} + +static void u8_cs_chg_writer(struct driver_data *drv_data) +{ + struct chip_data *chip = drv_data->cur_chip; + + while (drv_data->tx < drv_data->tx_end) { + write_FLAG(chip->flag); + SSYNC(); + + write_TDBR(*(u8 *) (drv_data->tx)); + while (read_STAT() & BIT_STAT_TXS) + continue; + while (!(read_STAT() & BIT_STAT_SPIF)) + continue; + write_FLAG(0xFF00 | chip->flag); + SSYNC(); + if (chip->cs_chg_udelay) + udelay(chip->cs_chg_udelay); + ++drv_data->tx; + } + write_FLAG(0xFF00); + SSYNC(); +} + +static void u8_reader(struct driver_data *drv_data) +{ + pr_debug("cr-8 is 0x%x\n", read_STAT()); + + /* clear TDBR buffer before read(else it will be shifted out) */ + write_TDBR(0xFFFF); + + dummy_read(); + + while (drv_data->rx < drv_data->rx_end - 1) { + while (!(read_STAT() & BIT_STAT_RXS)) + continue; + *(u8 *) (drv_data->rx) = read_RDBR(); + ++drv_data->rx; + } + + while (!(read_STAT() & BIT_STAT_RXS)) + continue; + *(u8 *) (drv_data->rx) = read_SHAW(); + ++drv_data->rx; +} + +static void u8_cs_chg_reader(struct driver_data *drv_data) +{ + struct chip_data *chip = drv_data->cur_chip; + + while (drv_data->rx < drv_data->rx_end) { + write_FLAG(chip->flag); + SSYNC(); + + read_RDBR(); /* kick off */ + while (!(read_STAT() & BIT_STAT_RXS)) + continue; + while (!(read_STAT() & BIT_STAT_SPIF)) + continue; + *(u8 *) (drv_data->rx) = read_SHAW(); + write_FLAG(0xFF00 | chip->flag); + SSYNC(); + if (chip->cs_chg_udelay) + udelay(chip->cs_chg_udelay); + ++drv_data->rx; + } + write_FLAG(0xFF00); + SSYNC(); +} + +static void u8_duplex(struct driver_data *drv_data) +{ + /* in duplex mode, clk is triggered by writing of TDBR */ + while (drv_data->rx < drv_data->rx_end) { + write_TDBR(*(u8 *) (drv_data->tx)); + while (!(read_STAT() & BIT_STAT_SPIF)) + continue; + while (!(read_STAT() & BIT_STAT_RXS)) + continue; + *(u8 *) (drv_data->rx) = read_RDBR(); + ++drv_data->rx; + ++drv_data->tx; + } +} + +static void u8_cs_chg_duplex(struct driver_data *drv_data) +{ + struct chip_data *chip = drv_data->cur_chip; + + while (drv_data->rx < drv_data->rx_end) { + write_FLAG(chip->flag); + SSYNC(); + + write_TDBR(*(u8 *) (drv_data->tx)); + while (!(read_STAT() & BIT_STAT_SPIF)) + continue; + while (!(read_STAT() & BIT_STAT_RXS)) + continue; + *(u8 *) (drv_data->rx) = read_RDBR(); + write_FLAG(0xFF00 | chip->flag); + SSYNC(); + if (chip->cs_chg_udelay) + udelay(chip->cs_chg_udelay); + ++drv_data->rx; + ++drv_data->tx; + } + write_FLAG(0xFF00); + SSYNC(); +} + +static void u16_writer(struct driver_data *drv_data) +{ + pr_debug("cr16 is 0x%x\n", read_STAT()); + while (drv_data->tx < drv_data->tx_end) { + write_TDBR(*(u16 *) (drv_data->tx)); + while ((read_STAT() & BIT_STAT_TXS)) + continue; + drv_data->tx += 2; + } + + /* poll for SPI completion before returning */ + while (!(read_STAT() & BIT_STAT_SPIF)) + continue; +} + +static void u16_cs_chg_writer(struct driver_data *drv_data) +{ + struct chip_data *chip = drv_data->cur_chip; + + while (drv_data->tx < drv_data->tx_end) { + write_FLAG(chip->flag); + SSYNC(); + + write_TDBR(*(u16 *) (drv_data->tx)); + while ((read_STAT() & BIT_STAT_TXS)) + continue; + while (!(read_STAT() & BIT_STAT_SPIF)) + continue; + write_FLAG(0xFF00 | chip->flag); + SSYNC(); + if (chip->cs_chg_udelay) + udelay(chip->cs_chg_udelay); + drv_data->tx += 2; + } + write_FLAG(0xFF00); + SSYNC(); +} + +static void u16_reader(struct driver_data *drv_data) +{ + pr_debug("cr-16 is 0x%x\n", read_STAT()); + dummy_read(); + + while (drv_data->rx < (drv_data->rx_end - 2)) { + while (!(read_STAT() & BIT_STAT_RXS)) + continue; + *(u16 *) (drv_data->rx) = read_RDBR(); + drv_data->rx += 2; + } + + while (!(read_STAT() & BIT_STAT_RXS)) + continue; + *(u16 *) (drv_data->rx) = read_SHAW(); + drv_data->rx += 2; +} + +static void u16_cs_chg_reader(struct driver_data *drv_data) +{ + struct chip_data *chip = drv_data->cur_chip; + + while (drv_data->rx < drv_data->rx_end) { + write_FLAG(chip->flag); + SSYNC(); + + read_RDBR(); /* kick off */ + while (!(read_STAT() & BIT_STAT_RXS)) + continue; + while (!(read_STAT() & BIT_STAT_SPIF)) + continue; + *(u16 *) (drv_data->rx) = read_SHAW(); + write_FLAG(0xFF00 | chip->flag); + SSYNC(); + if (chip->cs_chg_udelay) + udelay(chip->cs_chg_udelay); + drv_data->rx += 2; + } + write_FLAG(0xFF00); + SSYNC(); +} + +static void u16_duplex(struct driver_data *drv_data) +{ + /* in duplex mode, clk is triggered by writing of TDBR */ + while (drv_data->tx < drv_data->tx_end) { + write_TDBR(*(u16 *) (drv_data->tx)); + while (!(read_STAT() & BIT_STAT_SPIF)) + continue; + while (!(read_STAT() & BIT_STAT_RXS)) + continue; + *(u16 *) (drv_data->rx) = read_RDBR(); + drv_data->rx += 2; + drv_data->tx += 2; + } +} + +static void u16_cs_chg_duplex(struct driver_data *drv_data) +{ + struct chip_data *chip = drv_data->cur_chip; + + while (drv_data->tx < drv_data->tx_end) { + write_FLAG(chip->flag); + SSYNC(); + + write_TDBR(*(u16 *) (drv_data->tx)); + while (!(read_STAT() & BIT_STAT_SPIF)) + continue; + while (!(read_STAT() & BIT_STAT_RXS)) + continue; + *(u16 *) (drv_data->rx) = read_RDBR(); + write_FLAG(0xFF00 | chip->flag); + SSYNC(); + if (chip->cs_chg_udelay) + udelay(chip->cs_chg_udelay); + drv_data->rx += 2; + drv_data->tx += 2; + } + write_FLAG(0xFF00); + SSYNC(); +} + +/* test if ther is more transfer to be done */ +static void *next_transfer(struct driver_data *drv_data) +{ + struct spi_message *msg = drv_data->cur_msg; + struct spi_transfer *trans = drv_data->cur_transfer; + + /* Move to next transfer */ + if (trans->transfer_list.next != &msg->transfers) { + drv_data->cur_transfer = + list_entry(trans->transfer_list.next, + struct spi_transfer, transfer_list); + return RUNNING_STATE; + } else + return DONE_STATE; +} + +/* + * caller already set message->status; + * dma and pio irqs are blocked give finished message back + */ +static void giveback(struct driver_data *drv_data) +{ + struct spi_transfer *last_transfer; + unsigned long flags; + struct spi_message *msg; + + spin_lock_irqsave(&drv_data->lock, flags); + msg = drv_data->cur_msg; + drv_data->cur_msg = NULL; + drv_data->cur_transfer = NULL; + drv_data->cur_chip = NULL; + queue_work(drv_data->workqueue, &drv_data->pump_messages); + spin_unlock_irqrestore(&drv_data->lock, flags); + + last_transfer = list_entry(msg->transfers.prev, + struct spi_transfer, transfer_list); + + msg->state = NULL; + + /* disable chip select signal. And not stop spi in autobuffer mode */ + if (drv_data->tx_dma != 0xFFFF) { + write_FLAG(0xFF00); + bfin_spi_disable(drv_data); + } + + if (msg->complete) + msg->complete(msg->context); +} + +static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct driver_data *drv_data = (struct driver_data *)dev_id; + struct spi_message *msg = drv_data->cur_msg; + + pr_debug("in dma_irq_handler\n"); + clear_dma_irqstat(CH_SPI); + + /* + * wait for the last transaction shifted out. yes, these two + * while loops are supposed to be the same (see the HRM). + */ + if (drv_data->tx != NULL) { + while (bfin_read_SPI_STAT() & TXS) + continue; + while (bfin_read_SPI_STAT() & TXS) + continue; + } + + while (!(bfin_read_SPI_STAT() & SPIF)) + continue; + + bfin_spi_disable(drv_data); + + msg->actual_length += drv_data->len_in_bytes; + + /* Move to next transfer */ + msg->state = next_transfer(drv_data); + + /* Schedule transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); + + /* free the irq handler before next transfer */ + pr_debug("disable dma channel irq%d\n", CH_SPI); + dma_disable_irq(CH_SPI); + + return IRQ_HANDLED; +} + +static void pump_transfers(unsigned long data) +{ + struct driver_data *drv_data = (struct driver_data *)data; + struct spi_message *message = NULL; + struct spi_transfer *transfer = NULL; + struct spi_transfer *previous = NULL; + struct chip_data *chip = NULL; + u16 cr, width, dma_width, dma_config; + u32 tranf_success = 1; + + /* Get current state information */ + message = drv_data->cur_msg; + transfer = drv_data->cur_transfer; + chip = drv_data->cur_chip; + + /* + * if msg is error or done, report it back using complete() callback + */ + + /* Handle for abort */ + if (message->state == ERROR_STATE) { + message->status = -EIO; + giveback(drv_data); + return; + } + + /* Handle end of message */ + if (message->state == DONE_STATE) { + message->status = 0; + giveback(drv_data); + return; + } + + /* Delay if requested at end of transfer */ + if (message->state == RUNNING_STATE) { + previous = list_entry(transfer->transfer_list.prev, + struct spi_transfer, transfer_list); + if (previous->delay_usecs) + udelay(previous->delay_usecs); + } + + /* Setup the transfer state based on the type of transfer */ + if (flush(drv_data) == 0) { + dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n"); + message->status = -EIO; + giveback(drv_data); + return; + } + + if (transfer->tx_buf != NULL) { + drv_data->tx = (void *)transfer->tx_buf; + drv_data->tx_end = drv_data->tx + transfer->len; + pr_debug("tx_buf is %p, tx_end is %p\n", transfer->tx_buf, + drv_data->tx_end); + } else { + drv_data->tx = NULL; + } + + if (transfer->rx_buf != NULL) { + drv_data->rx = transfer->rx_buf; + drv_data->rx_end = drv_data->rx + transfer->len; + pr_debug("rx_buf is %p, rx_end is %p\n", transfer->rx_buf, + drv_data->rx_end); + } else { + drv_data->rx = NULL; + } + + drv_data->rx_dma = transfer->rx_dma; + drv_data->tx_dma = transfer->tx_dma; + drv_data->len_in_bytes = transfer->len; + + width = chip->width; + if (width == CFG_SPI_WORDSIZE16) { + drv_data->len = (transfer->len) >> 1; + } else { + drv_data->len = transfer->len; + } + drv_data->write = drv_data->tx ? chip->write : null_writer; + drv_data->read = drv_data->rx ? chip->read : null_reader; + drv_data->duplex = chip->duplex ? chip->duplex : null_writer; + pr_debug + ("transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n", + drv_data->write, chip->write, null_writer); + + /* speed and width has been set on per message */ + message->state = RUNNING_STATE; + dma_config = 0; + + /* restore spi status for each spi transfer */ + if (transfer->speed_hz) { + write_BAUD(hz_to_spi_baud(transfer->speed_hz)); + } else { + write_BAUD(chip->baud); + } + write_FLAG(chip->flag); + + pr_debug("now pumping a transfer: width is %d, len is %d\n", width, + transfer->len); + + /* + * Try to map dma buffer and do a dma transfer if + * successful use different way to r/w according to + * drv_data->cur_chip->enable_dma + */ + if (drv_data->cur_chip->enable_dma && drv_data->len > 6) { + + write_STAT(BIT_STAT_CLR); + disable_dma(CH_SPI); + clear_dma_irqstat(CH_SPI); + bfin_spi_disable(drv_data); + + /* config dma channel */ + pr_debug("doing dma transfer\n"); + if (width == CFG_SPI_WORDSIZE16) { + set_dma_x_count(CH_SPI, drv_data->len); + set_dma_x_modify(CH_SPI, 2); + dma_width = WDSIZE_16; + } else { + set_dma_x_count(CH_SPI, drv_data->len); + set_dma_x_modify(CH_SPI, 1); + dma_width = WDSIZE_8; + } + + /* set transfer width,direction. And enable spi */ + cr = (read_CTRL() & (~BIT_CTL_TIMOD)); + + /* dirty hack for autobuffer DMA mode */ + if (drv_data->tx_dma == 0xFFFF) { + pr_debug("doing autobuffer DMA out.\n"); + + /* no irq in autobuffer mode */ + dma_config = + (DMAFLOW_AUTO | RESTART | dma_width | DI_EN); + set_dma_config(CH_SPI, dma_config); + set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx); + enable_dma(CH_SPI); + write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) | + (CFG_SPI_ENABLE << 14)); + + /* just return here, there can only be one transfer in this mode */ + message->status = 0; + giveback(drv_data); + return; + } + + /* In dma mode, rx or tx must be NULL in one transfer */ + if (drv_data->rx != NULL) { + /* set transfer mode, and enable SPI */ + pr_debug("doing DMA in.\n"); + + /* disable SPI before write to TDBR */ + write_CTRL(cr & ~BIT_CTL_ENABLE); + + /* clear tx reg soformer data is not shifted out */ + write_TDBR(0xFF); + + set_dma_x_count(CH_SPI, drv_data->len); + + /* start dma */ + dma_enable_irq(CH_SPI); + dma_config = (WNR | RESTART | dma_width | DI_EN); + set_dma_config(CH_SPI, dma_config); + set_dma_start_addr(CH_SPI, (unsigned long)drv_data->rx); + enable_dma(CH_SPI); + + cr |= + CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE << + 14); + /* set transfer mode, and enable SPI */ + write_CTRL(cr); + } else if (drv_data->tx != NULL) { + pr_debug("doing DMA out.\n"); + + /* start dma */ + dma_enable_irq(CH_SPI); + dma_config = (RESTART | dma_width | DI_EN); + set_dma_config(CH_SPI, dma_config); + set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx); + enable_dma(CH_SPI); + + write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) | + (CFG_SPI_ENABLE << 14)); + + } + } else { + /* IO mode write then read */ + pr_debug("doing IO transfer\n"); + + write_STAT(BIT_STAT_CLR); + + if (drv_data->tx != NULL && drv_data->rx != NULL) { + /* full duplex mode */ + BUG_ON((drv_data->tx_end - drv_data->tx) != + (drv_data->rx_end - drv_data->rx)); + cr = (read_CTRL() & (~BIT_CTL_TIMOD)); /* clear the TIMOD bits */ + cr |= + CFG_SPI_WRITE | (width << 8) | (CFG_SPI_ENABLE << + 14); + pr_debug("IO duplex: cr is 0x%x\n", cr); + + write_CTRL(cr); + SSYNC(); + + drv_data->duplex(drv_data); + + if (drv_data->tx != drv_data->tx_end) + tranf_success = 0; + } else if (drv_data->tx != NULL) { + /* write only half duplex */ + cr = (read_CTRL() & (~BIT_CTL_TIMOD)); /* clear the TIMOD bits */ + cr |= + CFG_SPI_WRITE | (width << 8) | (CFG_SPI_ENABLE << + 14); + pr_debug("IO write: cr is 0x%x\n", cr); + + write_CTRL(cr); + SSYNC(); + + drv_data->write(drv_data); + + if (drv_data->tx != drv_data->tx_end) + tranf_success = 0; + } else if (drv_data->rx != NULL) { + /* read only half duplex */ + cr = (read_CTRL() & (~BIT_CTL_TIMOD)); /* cleare the TIMOD bits */ + cr |= + CFG_SPI_READ | (width << 8) | (CFG_SPI_ENABLE << + 14); + pr_debug("IO read: cr is 0x%x\n", cr); + + write_CTRL(cr); + SSYNC(); + + drv_data->read(drv_data); + if (drv_data->rx != drv_data->rx_end) + tranf_success = 0; + } + + if (!tranf_success) { + pr_debug("IO write error!\n"); + message->state = ERROR_STATE; + } else { + /* Update total byte transfered */ + message->actual_length += drv_data->len; + + /* Move to next transfer of this msg */ + message->state = next_transfer(drv_data); + } + + /* Schedule next transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); + + } +} + +/* pop a msg from queue and kick off real transfer */ +static void pump_messages(struct work_struct *work) +{ + struct driver_data *drv_data = container_of(work, struct driver_data, pump_messages); + unsigned long flags; + + /* Lock queue and check for queue work */ + spin_lock_irqsave(&drv_data->lock, flags); + if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) { + /* pumper kicked off but no work to do */ + drv_data->busy = 0; + spin_unlock_irqrestore(&drv_data->lock, flags); + return; + } + + /* Make sure we are not already running a message */ + if (drv_data->cur_msg) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return; + } + + /* Extract head of queue */ + drv_data->cur_msg = list_entry(drv_data->queue.next, + struct spi_message, queue); + list_del_init(&drv_data->cur_msg->queue); + + /* Initial message state */ + drv_data->cur_msg->state = START_STATE; + drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, + struct spi_transfer, transfer_list); + + /* Setup the SSP using the per chip configuration */ + drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); + restore_state(drv_data); + pr_debug + ("got a message to pump, state is set to: baud %d, flag 0x%x, ctl 0x%x\n", + drv_data->cur_chip->baud, drv_data->cur_chip->flag, + drv_data->cur_chip->ctl_reg); + pr_debug("the first transfer len is %d\n", drv_data->cur_transfer->len); + + /* Mark as busy and launch transfers */ + tasklet_schedule(&drv_data->pump_transfers); + + drv_data->busy = 1; + spin_unlock_irqrestore(&drv_data->lock, flags); +} + +/* + * got a msg to transfer, queue it in drv_data->queue. + * And kick off message pumper + */ +static int transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct driver_data *drv_data = spi_master_get_devdata(spi->master); + unsigned long flags; + + spin_lock_irqsave(&drv_data->lock, flags); + + if (drv_data->run == QUEUE_STOPPED) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return -ESHUTDOWN; + } + + msg->actual_length = 0; + msg->status = -EINPROGRESS; + msg->state = START_STATE; + + pr_debug("adding an msg in transfer() \n"); + list_add_tail(&msg->queue, &drv_data->queue); + + if (drv_data->run == QUEUE_RUNNING && !drv_data->busy) + queue_work(drv_data->workqueue, &drv_data->pump_messages); + + spin_unlock_irqrestore(&drv_data->lock, flags); + + return 0; +} + +/* first setup for new devices */ +static int setup(struct spi_device *spi) +{ + struct bfin5xx_spi_chip *chip_info = NULL; + struct chip_data *chip; + struct driver_data *drv_data = spi_master_get_devdata(spi->master); + u8 spi_flg; + + /* Abort device setup if requested features are not supported */ + if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) { + dev_err(&spi->dev, "requested mode not fully supported\n"); + return -EINVAL; + } + + /* Zero (the default) here means 8 bits */ + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + if (spi->bits_per_word != 8 && spi->bits_per_word != 16) + return -EINVAL; + + /* Only alloc (or use chip_info) on first setup */ + chip = spi_get_ctldata(spi); + if (chip == NULL) { + chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->enable_dma = 0; + chip_info = spi->controller_data; + } + + /* chip_info isn't always needed */ + if (chip_info) { + chip->enable_dma = chip_info->enable_dma != 0 + && drv_data->master_info->enable_dma; + chip->ctl_reg = chip_info->ctl_reg; + chip->bits_per_word = chip_info->bits_per_word; + chip->cs_change_per_word = chip_info->cs_change_per_word; + chip->cs_chg_udelay = chip_info->cs_chg_udelay; + } + + /* translate common spi framework into our register */ + if (spi->mode & SPI_CPOL) + chip->ctl_reg |= CPOL; + if (spi->mode & SPI_CPHA) + chip->ctl_reg |= CPHA; + if (spi->mode & SPI_LSB_FIRST) + chip->ctl_reg |= LSBF; + /* we dont support running in slave mode (yet?) */ + chip->ctl_reg |= MSTR; + + /* + * if any one SPI chip is registered and wants DMA, request the + * DMA channel for it + */ + if (chip->enable_dma && !dma_requested) { + /* register dma irq handler */ + if (request_dma(CH_SPI, "BF53x_SPI_DMA") < 0) { + pr_debug + ("Unable to request BlackFin SPI DMA channel\n"); + return -ENODEV; + } + if (set_dma_callback(CH_SPI, (void *)dma_irq_handler, drv_data) + < 0) { + pr_debug("Unable to set dma callback\n"); + return -EPERM; + } + dma_disable_irq(CH_SPI); + dma_requested = 1; + } + + /* + * Notice: for blackfin, the speed_hz is the value of register + * SPI_BAUD, not the real baudrate + */ + chip->baud = hz_to_spi_baud(spi->max_speed_hz); + spi_flg = ~(1 << (spi->chip_select)); + chip->flag = ((u16) spi_flg << 8) | (1 << (spi->chip_select)); + chip->chip_select_num = spi->chip_select; + + switch (chip->bits_per_word) { + case 8: + chip->n_bytes = 1; + chip->width = CFG_SPI_WORDSIZE8; + chip->read = chip->cs_change_per_word ? + u8_cs_chg_reader : u8_reader; + chip->write = chip->cs_change_per_word ? + u8_cs_chg_writer : u8_writer; + chip->duplex = chip->cs_change_per_word ? + u8_cs_chg_duplex : u8_duplex; + break; + + case 16: + chip->n_bytes = 2; + chip->width = CFG_SPI_WORDSIZE16; + chip->read = chip->cs_change_per_word ? + u16_cs_chg_reader : u16_reader; + chip->write = chip->cs_change_per_word ? + u16_cs_chg_writer : u16_writer; + chip->duplex = chip->cs_change_per_word ? + u16_cs_chg_duplex : u16_duplex; + break; + + default: + dev_err(&spi->dev, "%d bits_per_word is not supported\n", + chip->bits_per_word); + kfree(chip); + return -ENODEV; + } + + pr_debug("setup spi chip %s, width is %d, dma is %d,", + spi->modalias, chip->width, chip->enable_dma); + pr_debug("ctl_reg is 0x%x, flag_reg is 0x%x\n", + chip->ctl_reg, chip->flag); + + spi_set_ctldata(spi, chip); + + return 0; +} + +/* + * callback for spi framework. + * clean driver specific data + */ +static void cleanup(const struct spi_device *spi) +{ + struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi); + + kfree(chip); +} + +static inline int init_queue(struct driver_data *drv_data) +{ + INIT_LIST_HEAD(&drv_data->queue); + spin_lock_init(&drv_data->lock); + + drv_data->run = QUEUE_STOPPED; + drv_data->busy = 0; + + /* init transfer tasklet */ + tasklet_init(&drv_data->pump_transfers, + pump_transfers, (unsigned long)drv_data); + + /* init messages workqueue */ + INIT_WORK(&drv_data->pump_messages, pump_messages); + drv_data->workqueue = + create_singlethread_workqueue(drv_data->master->cdev.dev->bus_id); + if (drv_data->workqueue == NULL) + return -EBUSY; + + return 0; +} + +static inline int start_queue(struct driver_data *drv_data) +{ + unsigned long flags; + + spin_lock_irqsave(&drv_data->lock, flags); + + if (drv_data->run == QUEUE_RUNNING || drv_data->busy) { + spin_unlock_irqrestore(&drv_data->lock, flags); + return -EBUSY; + } + + drv_data->run = QUEUE_RUNNING; + drv_data->cur_msg = NULL; + drv_data->cur_transfer = NULL; + drv_data->cur_chip = NULL; + spin_unlock_irqrestore(&drv_data->lock, flags); + + queue_work(drv_data->workqueue, &drv_data->pump_messages); + + return 0; +} + +static inline int stop_queue(struct driver_data *drv_data) +{ + unsigned long flags; + unsigned limit = 500; + int status = 0; + + spin_lock_irqsave(&drv_data->lock, flags); + + /* + * This is a bit lame, but is optimized for the common execution path. + * A wait_queue on the drv_data->busy could be used, but then the common + * execution path (pump_messages) would be required to call wake_up or + * friends on every SPI message. Do this instead + */ + drv_data->run = QUEUE_STOPPED; + while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { + spin_unlock_irqrestore(&drv_data->lock, flags); + msleep(10); + spin_lock_irqsave(&drv_data->lock, flags); + } + + if (!list_empty(&drv_data->queue) || drv_data->busy) + status = -EBUSY; + + spin_unlock_irqrestore(&drv_data->lock, flags); + + return status; +} + +static inline int destroy_queue(struct driver_data *drv_data) +{ + int status; + + status = stop_queue(drv_data); + if (status != 0) + return status; + + destroy_workqueue(drv_data->workqueue); + + return 0; +} + +static int __init bfin5xx_spi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct bfin5xx_spi_master *platform_info; + struct spi_master *master; + struct driver_data *drv_data = 0; + int status = 0; + + platform_info = dev->platform_data; + + /* Allocate master with space for drv_data */ + master = spi_alloc_master(dev, sizeof(struct driver_data) + 16); + if (!master) { + dev_err(&pdev->dev, "can not alloc spi_master\n"); + return -ENOMEM; + } + drv_data = spi_master_get_devdata(master); + drv_data->master = master; + drv_data->master_info = platform_info; + drv_data->pdev = pdev; + + master->bus_num = pdev->id; + master->num_chipselect = platform_info->num_chipselect; + master->cleanup = cleanup; + master->setup = setup; + master->transfer = transfer; + + /* Initial and start queue */ + status = init_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "problem initializing queue\n"); + goto out_error_queue_alloc; + } + status = start_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "problem starting queue\n"); + goto out_error_queue_alloc; + } + + /* Register with the SPI framework */ + platform_set_drvdata(pdev, drv_data); + status = spi_register_master(master); + if (status != 0) { + dev_err(&pdev->dev, "problem registering spi master\n"); + goto out_error_queue_alloc; + } + pr_debug("controller probe successfully\n"); + return status; + + out_error_queue_alloc: + destroy_queue(drv_data); + spi_master_put(master); + return status; +} + +/* stop hardware and remove the driver */ +static int __devexit bfin5xx_spi_remove(struct platform_device *pdev) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int status = 0; + + if (!drv_data) + return 0; + + /* Remove the queue */ + status = destroy_queue(drv_data); + if (status != 0) + return status; + + /* Disable the SSP at the peripheral and SOC level */ + bfin_spi_disable(drv_data); + + /* Release DMA */ + if (drv_data->master_info->enable_dma) { + if (dma_channel_active(CH_SPI)) + free_dma(CH_SPI); + } + + /* Disconnect from the SPI framework */ + spi_unregister_master(drv_data->master); + + /* Prevent double remove */ + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int bfin5xx_spi_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int status = 0; + + status = stop_queue(drv_data); + if (status != 0) + return status; + + /* stop hardware */ + bfin_spi_disable(drv_data); + + return 0; +} + +static int bfin5xx_spi_resume(struct platform_device *pdev) +{ + struct driver_data *drv_data = platform_get_drvdata(pdev); + int status = 0; + + /* Enable the SPI interface */ + bfin_spi_enable(drv_data); + + /* Start the queue running */ + status = start_queue(drv_data); + if (status != 0) { + dev_err(&pdev->dev, "problem starting queue (%d)\n", status); + return status; + } + + return 0; +} +#else +#define bfin5xx_spi_suspend NULL +#define bfin5xx_spi_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver bfin5xx_spi_driver = { + .driver = { + .name = "bfin-spi-master", + .bus = &platform_bus_type, + .owner = THIS_MODULE, + }, + .probe = bfin5xx_spi_probe, + .remove = __devexit_p(bfin5xx_spi_remove), + .suspend = bfin5xx_spi_suspend, + .resume = bfin5xx_spi_resume, +}; + +static int __init bfin5xx_spi_init(void) +{ + return platform_driver_register(&bfin5xx_spi_driver); +} + +module_init(bfin5xx_spi_init); + +static void __exit bfin5xx_spi_exit(void) +{ + platform_driver_unregister(&bfin5xx_spi_driver); +} + +module_exit(bfin5xx_spi_exit); diff --git a/trunk/drivers/spi/spi_butterfly.c b/trunk/drivers/spi/spi_butterfly.c index 312987a03210..0ee2b2090252 100644 --- a/trunk/drivers/spi/spi_butterfly.c +++ b/trunk/drivers/spi/spi_butterfly.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -40,8 +40,6 @@ * and use this custom parallel port cable. */ -#undef HAVE_USI /* nyet */ - /* DATA output bits (pins 2..9 == D0..D7) */ #define butterfly_nreset (1 << 1) /* pin 3 */ @@ -49,19 +47,13 @@ #define spi_sck_bit (1 << 0) /* pin 2 */ #define spi_mosi_bit (1 << 7) /* pin 9 */ -#define usi_sck_bit (1 << 3) /* pin 5 */ -#define usi_mosi_bit (1 << 4) /* pin 6 */ - #define vcc_bits ((1 << 6) | (1 << 5)) /* pins 7, 8 */ /* STATUS input bits */ #define spi_miso_bit PARPORT_STATUS_BUSY /* pin 11 */ -#define usi_miso_bit PARPORT_STATUS_PAPEROUT /* pin 12 */ - /* CONTROL output bits */ #define spi_cs_bit PARPORT_CONTROL_SELECT /* pin 17 */ -/* USI uses no chipselect */ @@ -70,15 +62,6 @@ static inline struct butterfly *spidev_to_pp(struct spi_device *spi) return spi->controller_data; } -static inline int is_usidev(struct spi_device *spi) -{ -#ifdef HAVE_USI - return spi->chip_select != 1; -#else - return 0; -#endif -} - struct butterfly { /* REVISIT ... for now, this must be first */ @@ -97,23 +80,13 @@ struct butterfly { /*----------------------------------------------------------------------*/ -/* - * these routines may be slower than necessary because they're hiding - * the fact that there are two different SPI busses on this cable: one - * to the DataFlash chip (or AVR SPI controller), the other to the - * AVR USI controller. - */ - static inline void setsck(struct spi_device *spi, int is_on) { struct butterfly *pp = spidev_to_pp(spi); u8 bit, byte = pp->lastbyte; - if (is_usidev(spi)) - bit = usi_sck_bit; - else - bit = spi_sck_bit; + bit = spi_sck_bit; if (is_on) byte |= bit; @@ -129,10 +102,7 @@ setmosi(struct spi_device *spi, int is_on) struct butterfly *pp = spidev_to_pp(spi); u8 bit, byte = pp->lastbyte; - if (is_usidev(spi)) - bit = usi_mosi_bit; - else - bit = spi_mosi_bit; + bit = spi_mosi_bit; if (is_on) byte |= bit; @@ -148,10 +118,7 @@ static inline int getmiso(struct spi_device *spi) int value; u8 bit; - if (is_usidev(spi)) - bit = usi_miso_bit; - else - bit = spi_miso_bit; + bit = spi_miso_bit; /* only STATUS_BUSY is NOT negated */ value = !(parport_read_status(pp->port) & bit); @@ -166,10 +133,6 @@ static void butterfly_chipselect(struct spi_device *spi, int value) if (value != BITBANG_CS_INACTIVE) setsck(spi, spi->mode & SPI_CPOL); - /* no chipselect on this USI link config */ - if (is_usidev(spi)) - return; - /* here, value == "activate or not"; * most PARPORT_CONTROL_* bits are negated, so we must * morph it to value == "bit value to write in control register" @@ -237,24 +200,16 @@ static void butterfly_attach(struct parport *p) int status; struct butterfly *pp; struct spi_master *master; - struct platform_device *pdev; + struct device *dev = p->physport->dev; - if (butterfly) + if (butterfly || !dev) return; /* REVISIT: this just _assumes_ a butterfly is there ... no probe, * and no way to be selective about what it binds to. */ - /* FIXME where should master->cdev.dev come from? - * e.g. /sys/bus/pnp0/00:0b, some PCI thing, etc - * setting up a platform device like this is an ugly kluge... - */ - pdev = platform_device_register_simple("butterfly", -1, NULL, 0); - if (IS_ERR(pdev)) - return; - - master = spi_alloc_master(&pdev->dev, sizeof *pp); + master = spi_alloc_master(dev, sizeof *pp); if (!master) { status = -ENOMEM; goto done; @@ -300,7 +255,7 @@ static void butterfly_attach(struct parport *p) parport_frob_control(pp->port, spi_cs_bit, 0); /* stabilize power with chip in reset (nRESET), and - * both spi_sck_bit and usi_sck_bit clear (CPOL=0) + * spi_sck_bit clear (CPOL=0) */ pp->lastbyte |= vcc_bits; parport_write_data(pp->port, pp->lastbyte); @@ -334,23 +289,6 @@ static void butterfly_attach(struct parport *p) pr_debug("%s: dataflash at %s\n", p->name, pp->dataflash->dev.bus_id); -#ifdef HAVE_USI - /* Bus 2 is only for talking to the AVR, and it can work no - * matter who masters bus 1; needs appropriate AVR firmware. - */ - pp->info[1].max_speed_hz = 10 /* ?? */ * 1000 * 1000; - strcpy(pp->info[1].modalias, "butterfly"); - // pp->info[1].platform_data = ... TBD ... ; - pp->info[1].chip_select = 2, - pp->info[1].controller_data = pp; - pp->butterfly = spi_new_device(pp->bitbang.master, &pp->info[1]); - if (pp->butterfly) - pr_debug("%s: butterfly at %s\n", p->name, - pp->butterfly->dev.bus_id); - - /* FIXME setup ACK for the IRQ line ... */ -#endif - // dev_info(_what?_, ...) pr_info("%s: AVR Butterfly\n", p->name); butterfly = pp; @@ -366,14 +304,12 @@ static void butterfly_attach(struct parport *p) clean0: (void) spi_master_put(pp->bitbang.master); done: - platform_device_unregister(pdev); pr_debug("%s: butterfly probe, fail %d\n", p->name, status); } static void butterfly_detach(struct parport *p) { struct butterfly *pp; - struct platform_device *pdev; int status; /* FIXME this global is ugly ... but, how to quickly get from @@ -386,7 +322,6 @@ static void butterfly_detach(struct parport *p) butterfly = NULL; /* stop() unregisters child devices too */ - pdev = to_platform_device(pp->bitbang.master->cdev.dev); status = spi_bitbang_stop(&pp->bitbang); /* turn off VCC */ @@ -397,8 +332,6 @@ static void butterfly_detach(struct parport *p) parport_unregister_device(pp->pd); (void) spi_master_put(pp->bitbang.master); - - platform_device_unregister(pdev); } static struct parport_driver butterfly_driver = { diff --git a/trunk/drivers/spi/spi_s3c24xx.c b/trunk/drivers/spi/spi_s3c24xx.c index b10211c420ef..d5a710f6e445 100644 --- a/trunk/drivers/spi/spi_s3c24xx.c +++ b/trunk/drivers/spi/spi_s3c24xx.c @@ -342,8 +342,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) goto err_register; } - dev_dbg(hw->dev, "shutdown=%d\n", hw->bitbang.shutdown); - /* register all the devices associated */ bi = &hw->pdata->board_info[0]; diff --git a/trunk/drivers/spi/spidev.c b/trunk/drivers/spi/spidev.c new file mode 100644 index 000000000000..c0a6dce800a3 --- /dev/null +++ b/trunk/drivers/spi/spidev.c @@ -0,0 +1,584 @@ +/* + * spidev.c -- simple synchronous userspace interface to SPI devices + * + * Copyright (C) 2006 SWAPP + * Andrea Paterniani + * Copyright (C) 2007 David Brownell (simplification, cleanup) + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +/* + * This supports acccess to SPI devices using normal userspace I/O calls. + * Note that while traditional UNIX/POSIX I/O semantics are half duplex, + * and often mask message boundaries, full SPI support requires full duplex + * transfers. There are several kinds of of internal message boundaries to + * handle chipselect management and other protocol options. + * + * SPI has a character major number assigned. We allocate minor numbers + * dynamically using a bitmask. You must use hotplug tools, such as udev + * (or mdev with busybox) to create and destroy the /dev/spidevB.C device + * nodes, since there is no fixed association of minor numbers with any + * particular SPI bus or device. + */ +#define SPIDEV_MAJOR 153 /* assigned */ +#define N_SPI_MINORS 32 /* ... up to 256 */ + +static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG]; + + +/* Bit masks for spi_device.mode management */ +#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL) + + +struct spidev_data { + struct device dev; + struct spi_device *spi; + struct list_head device_entry; + + struct mutex buf_lock; + unsigned users; + u8 *buffer; +}; + +static LIST_HEAD(device_list); +static DEFINE_MUTEX(device_list_lock); + +static unsigned bufsiz = 4096; +module_param(bufsiz, uint, S_IRUGO); +MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message"); + +/*-------------------------------------------------------------------------*/ + +/* Read-only message with current device setup */ +static ssize_t +spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + struct spidev_data *spidev; + struct spi_device *spi; + ssize_t status = 0; + + /* chipselect only toggles at start or end of operation */ + if (count > bufsiz) + return -EMSGSIZE; + + spidev = filp->private_data; + spi = spidev->spi; + + mutex_lock(&spidev->buf_lock); + status = spi_read(spi, spidev->buffer, count); + if (status == 0) { + unsigned long missing; + + missing = copy_to_user(buf, spidev->buffer, count); + if (count && missing == count) + status = -EFAULT; + else + status = count - missing; + } + mutex_unlock(&spidev->buf_lock); + + return status; +} + +/* Write-only message with current device setup */ +static ssize_t +spidev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + struct spidev_data *spidev; + struct spi_device *spi; + ssize_t status = 0; + unsigned long missing; + + /* chipselect only toggles at start or end of operation */ + if (count > bufsiz) + return -EMSGSIZE; + + spidev = filp->private_data; + spi = spidev->spi; + + mutex_lock(&spidev->buf_lock); + missing = copy_from_user(spidev->buffer, buf, count); + if (missing == 0) { + status = spi_write(spi, spidev->buffer, count); + if (status == 0) + status = count; + } else + status = -EFAULT; + mutex_unlock(&spidev->buf_lock); + + return status; +} + +static int spidev_message(struct spidev_data *spidev, + struct spi_ioc_transfer *u_xfers, unsigned n_xfers) +{ + struct spi_message msg; + struct spi_transfer *k_xfers; + struct spi_transfer *k_tmp; + struct spi_ioc_transfer *u_tmp; + struct spi_device *spi = spidev->spi; + unsigned n, total; + u8 *buf; + int status = -EFAULT; + + spi_message_init(&msg); + k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL); + if (k_xfers == NULL) + return -ENOMEM; + + /* Construct spi_message, copying any tx data to bounce buffer. + * We walk the array of user-provided transfers, using each one + * to initialize a kernel version of the same transfer. + */ + mutex_lock(&spidev->buf_lock); + buf = spidev->buffer; + total = 0; + for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers; + n; + n--, k_tmp++, u_tmp++) { + k_tmp->len = u_tmp->len; + + if (u_tmp->rx_buf) { + k_tmp->rx_buf = buf; + if (!access_ok(VERIFY_WRITE, u_tmp->rx_buf, u_tmp->len)) + goto done; + } + if (u_tmp->tx_buf) { + k_tmp->tx_buf = buf; + if (copy_from_user(buf, (const u8 __user *)u_tmp->tx_buf, + u_tmp->len)) + goto done; + } + + total += k_tmp->len; + if (total > bufsiz) { + status = -EMSGSIZE; + goto done; + } + buf += k_tmp->len; + + k_tmp->cs_change = !!u_tmp->cs_change; + k_tmp->bits_per_word = u_tmp->bits_per_word; + k_tmp->delay_usecs = u_tmp->delay_usecs; + k_tmp->speed_hz = u_tmp->speed_hz; +#ifdef VERBOSE + dev_dbg(&spi->dev, + " xfer len %zd %s%s%s%dbits %u usec %uHz\n", + u_tmp->len, + u_tmp->rx_buf ? "rx " : "", + u_tmp->tx_buf ? "tx " : "", + u_tmp->cs_change ? "cs " : "", + u_tmp->bits_per_word ? : spi->bits_per_word, + u_tmp->delay_usecs, + u_tmp->speed_hz ? : spi->max_speed_hz); +#endif + spi_message_add_tail(k_tmp, &msg); + } + + status = spi_sync(spi, &msg); + if (status < 0) + goto done; + + /* copy any rx data out of bounce buffer */ + buf = spidev->buffer; + for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) { + if (u_tmp->rx_buf) { + if (__copy_to_user((u8 __user *)u_tmp->rx_buf, buf, + u_tmp->len)) { + status = -EFAULT; + goto done; + } + } + buf += u_tmp->len; + } + status = total; + +done: + mutex_unlock(&spidev->buf_lock); + kfree(k_xfers); + return status; +} + +static int +spidev_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int err = 0; + int retval = 0; + struct spidev_data *spidev; + struct spi_device *spi; + u32 tmp; + unsigned n_ioc; + struct spi_ioc_transfer *ioc; + + /* Check type and command number */ + if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC) + return -ENOTTY; + + /* Check access direction once here; don't repeat below. + * IOC_DIR is from the user perspective, while access_ok is + * from the kernel perspective; so they look reversed. + */ + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, + (void __user *)arg, _IOC_SIZE(cmd)); + if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, + (void __user *)arg, _IOC_SIZE(cmd)); + if (err) + return -EFAULT; + + spidev = filp->private_data; + spi = spidev->spi; + + switch (cmd) { + /* read requests */ + case SPI_IOC_RD_MODE: + retval = __put_user(spi->mode & SPI_MODE_MASK, + (__u8 __user *)arg); + break; + case SPI_IOC_RD_LSB_FIRST: + retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0, + (__u8 __user *)arg); + break; + case SPI_IOC_RD_BITS_PER_WORD: + retval = __put_user(spi->bits_per_word, (__u8 __user *)arg); + break; + case SPI_IOC_RD_MAX_SPEED_HZ: + retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg); + break; + + /* write requests */ + case SPI_IOC_WR_MODE: + retval = __get_user(tmp, (u8 __user *)arg); + if (retval == 0) { + u8 save = spi->mode; + + if (tmp & ~SPI_MODE_MASK) { + retval = -EINVAL; + break; + } + + tmp |= spi->mode & ~SPI_MODE_MASK; + spi->mode = (u8)tmp; + retval = spi_setup(spi); + if (retval < 0) + spi->mode = save; + else + dev_dbg(&spi->dev, "spi mode %02x\n", tmp); + } + break; + case SPI_IOC_WR_LSB_FIRST: + retval = __get_user(tmp, (__u8 __user *)arg); + if (retval == 0) { + u8 save = spi->mode; + + if (tmp) + spi->mode |= SPI_LSB_FIRST; + else + spi->mode &= ~SPI_LSB_FIRST; + retval = spi_setup(spi); + if (retval < 0) + spi->mode = save; + else + dev_dbg(&spi->dev, "%csb first\n", + tmp ? 'l' : 'm'); + } + break; + case SPI_IOC_WR_BITS_PER_WORD: + retval = __get_user(tmp, (__u8 __user *)arg); + if (retval == 0) { + u8 save = spi->bits_per_word; + + spi->bits_per_word = tmp; + retval = spi_setup(spi); + if (retval < 0) + spi->bits_per_word = save; + else + dev_dbg(&spi->dev, "%d bits per word\n", tmp); + } + break; + case SPI_IOC_WR_MAX_SPEED_HZ: + retval = __get_user(tmp, (__u32 __user *)arg); + if (retval == 0) { + u32 save = spi->max_speed_hz; + + spi->max_speed_hz = tmp; + retval = spi_setup(spi); + if (retval < 0) + spi->max_speed_hz = save; + else + dev_dbg(&spi->dev, "%d Hz (max)\n", tmp); + } + break; + + default: + /* segmented and/or full-duplex I/O request */ + if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0)) + || _IOC_DIR(cmd) != _IOC_WRITE) + return -ENOTTY; + + tmp = _IOC_SIZE(cmd); + if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) { + retval = -EINVAL; + break; + } + n_ioc = tmp / sizeof(struct spi_ioc_transfer); + if (n_ioc == 0) + break; + + /* copy into scratch area */ + ioc = kmalloc(tmp, GFP_KERNEL); + if (!ioc) { + retval = -ENOMEM; + break; + } + if (__copy_from_user(ioc, (void __user *)arg, tmp)) { + retval = -EFAULT; + break; + } + + /* translate to spi_message, execute */ + retval = spidev_message(spidev, ioc, n_ioc); + kfree(ioc); + break; + } + return retval; +} + +static int spidev_open(struct inode *inode, struct file *filp) +{ + struct spidev_data *spidev; + int status = -ENXIO; + + mutex_lock(&device_list_lock); + + list_for_each_entry(spidev, &device_list, device_entry) { + if (spidev->dev.devt == inode->i_rdev) { + status = 0; + break; + } + } + if (status == 0) { + if (!spidev->buffer) { + spidev->buffer = kmalloc(bufsiz, GFP_KERNEL); + if (!spidev->buffer) { + dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); + status = -ENOMEM; + } + } + if (status == 0) { + spidev->users++; + filp->private_data = spidev; + nonseekable_open(inode, filp); + } + } else + pr_debug("spidev: nothing for minor %d\n", iminor(inode)); + + mutex_unlock(&device_list_lock); + return status; +} + +static int spidev_release(struct inode *inode, struct file *filp) +{ + struct spidev_data *spidev; + int status = 0; + + mutex_lock(&device_list_lock); + spidev = filp->private_data; + filp->private_data = NULL; + spidev->users--; + if (!spidev->users) { + kfree(spidev->buffer); + spidev->buffer = NULL; + } + mutex_unlock(&device_list_lock); + + return status; +} + +static struct file_operations spidev_fops = { + .owner = THIS_MODULE, + /* REVISIT switch to aio primitives, so that userspace + * gets more complete API coverage. It'll simplify things + * too, except for the locking. + */ + .write = spidev_write, + .read = spidev_read, + .ioctl = spidev_ioctl, + .open = spidev_open, + .release = spidev_release, +}; + +/*-------------------------------------------------------------------------*/ + +/* The main reason to have this class is to make mdev/udev create the + * /dev/spidevB.C character device nodes exposing our userspace API. + * It also simplifies memory management. + */ + +static void spidev_classdev_release(struct device *dev) +{ + struct spidev_data *spidev; + + spidev = container_of(dev, struct spidev_data, dev); + kfree(spidev); +} + +static struct class spidev_class = { + .name = "spidev", + .owner = THIS_MODULE, + .dev_release = spidev_classdev_release, +}; + +/*-------------------------------------------------------------------------*/ + +static int spidev_probe(struct spi_device *spi) +{ + struct spidev_data *spidev; + int status; + unsigned long minor; + + /* Allocate driver data */ + spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); + if (!spidev) + return -ENOMEM; + + /* Initialize the driver data */ + spidev->spi = spi; + mutex_init(&spidev->buf_lock); + + INIT_LIST_HEAD(&spidev->device_entry); + + /* If we can allocate a minor number, hook up this device. + * Reusing minors is fine so long as udev or mdev is working. + */ + mutex_lock(&device_list_lock); + minor = find_first_zero_bit(minors, ARRAY_SIZE(minors)); + if (minor < N_SPI_MINORS) { + spidev->dev.parent = &spi->dev; + spidev->dev.class = &spidev_class; + spidev->dev.devt = MKDEV(SPIDEV_MAJOR, minor); + snprintf(spidev->dev.bus_id, sizeof spidev->dev.bus_id, + "spidev%d.%d", + spi->master->bus_num, spi->chip_select); + status = device_register(&spidev->dev); + } else { + dev_dbg(&spi->dev, "no minor number available!\n"); + status = -ENODEV; + } + if (status == 0) { + set_bit(minor, minors); + dev_set_drvdata(&spi->dev, spidev); + list_add(&spidev->device_entry, &device_list); + } + mutex_unlock(&device_list_lock); + + if (status != 0) + kfree(spidev); + + return status; +} + +static int spidev_remove(struct spi_device *spi) +{ + struct spidev_data *spidev = dev_get_drvdata(&spi->dev); + + mutex_lock(&device_list_lock); + + list_del(&spidev->device_entry); + dev_set_drvdata(&spi->dev, NULL); + clear_bit(MINOR(spidev->dev.devt), minors); + device_unregister(&spidev->dev); + + mutex_unlock(&device_list_lock); + + return 0; +} + +static struct spi_driver spidev_spi = { + .driver = { + .name = "spidev", + .owner = THIS_MODULE, + }, + .probe = spidev_probe, + .remove = __devexit_p(spidev_remove), + + /* NOTE: suspend/resume methods are not necessary here. + * We don't do anything except pass the requests to/from + * the underlying controller. The refrigerator handles + * most issues; the controller driver handles the rest. + */ +}; + +/*-------------------------------------------------------------------------*/ + +static int __init spidev_init(void) +{ + int status; + + /* Claim our 256 reserved device numbers. Then register a class + * that will key udev/mdev to add/remove /dev nodes. Last, register + * the driver which manages those device numbers. + */ + BUILD_BUG_ON(N_SPI_MINORS > 256); + status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops); + if (status < 0) + return status; + + status = class_register(&spidev_class); + if (status < 0) { + unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); + return status; + } + + status = spi_register_driver(&spidev_spi); + if (status < 0) { + class_unregister(&spidev_class); + unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); + } + return status; +} +module_init(spidev_init); + +static void __exit spidev_exit(void) +{ + spi_unregister_driver(&spidev_spi); + class_unregister(&spidev_class); + unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); +} +module_exit(spidev_exit); + +MODULE_AUTHOR("Andrea Paterniani, "); +MODULE_DESCRIPTION("User mode SPI device interface"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/telephony/ixj.c b/trunk/drivers/telephony/ixj.c index 71cb64e41a1b..c7b0a357b04a 100644 --- a/trunk/drivers/telephony/ixj.c +++ b/trunk/drivers/telephony/ixj.c @@ -7692,7 +7692,7 @@ static int __init ixj_probe_pci(int *cnt) IXJ *j = NULL; for (i = 0; i < IXJMAX - *cnt; i++) { - pci = pci_find_device(PCI_VENDOR_ID_QUICKNET, + pci = pci_get_device(PCI_VENDOR_ID_QUICKNET, PCI_DEVICE_ID_QUICKNET_XJ, pci); if (!pci) break; @@ -7712,6 +7712,7 @@ static int __init ixj_probe_pci(int *cnt) printk(KERN_INFO "ixj: found Internet PhoneJACK PCI at 0x%x\n", j->DSPbase); ++*cnt; } + pci_dev_put(pci); return probe; } diff --git a/trunk/drivers/usb/Kconfig b/trunk/drivers/usb/Kconfig index 9980a4ddfed9..b847bbc8b0e1 100644 --- a/trunk/drivers/usb/Kconfig +++ b/trunk/drivers/usb/Kconfig @@ -85,8 +85,6 @@ source "drivers/usb/class/Kconfig" source "drivers/usb/storage/Kconfig" -source "drivers/usb/input/Kconfig" - source "drivers/usb/image/Kconfig" source "drivers/usb/net/Kconfig" diff --git a/trunk/drivers/usb/Makefile b/trunk/drivers/usb/Makefile index f5de58a63f2b..0ef090b1b37c 100644 --- a/trunk/drivers/usb/Makefile +++ b/trunk/drivers/usb/Makefile @@ -23,15 +23,6 @@ obj-$(CONFIG_USB_PRINTER) += class/ obj-$(CONFIG_USB_STORAGE) += storage/ obj-$(CONFIG_USB) += storage/ -obj-$(CONFIG_USB_ACECAD) += input/ -obj-$(CONFIG_USB_AIPTEK) += input/ -obj-$(CONFIG_USB_ATI_REMOTE) += input/ -obj-$(CONFIG_USB_KBTAB) += input/ -obj-$(CONFIG_USB_MTOUCH) += input/ -obj-$(CONFIG_USB_POWERMATE) += input/ -obj-$(CONFIG_USB_WACOM) += input/ -obj-$(CONFIG_USB_XPAD) += input/ - obj-$(CONFIG_USB_CATC) += net/ obj-$(CONFIG_USB_KAWETH) += net/ obj-$(CONFIG_USB_PEGASUS) += net/ diff --git a/trunk/drivers/usb/atm/usbatm.c b/trunk/drivers/usb/atm/usbatm.c index b3f779f5933a..b082d95bbbaa 100644 --- a/trunk/drivers/usb/atm/usbatm.c +++ b/trunk/drivers/usb/atm/usbatm.c @@ -77,7 +77,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/class/cdc-acm.c b/trunk/drivers/usb/class/cdc-acm.c index 14de3b1b6a20..0081c1d12687 100644 --- a/trunk/drivers/usb/class/cdc-acm.c +++ b/trunk/drivers/usb/class/cdc-acm.c @@ -59,7 +59,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/class/usblp.c b/trunk/drivers/usb/class/usblp.c index 6584cf00f7f3..15e740e3a5c4 100644 --- a/trunk/drivers/usb/class/usblp.c +++ b/trunk/drivers/usb/class/usblp.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/core/hub.c b/trunk/drivers/usb/core/hub.c index bde29ab2b504..f6b74a678de5 100644 --- a/trunk/drivers/usb/core/hub.c +++ b/trunk/drivers/usb/core/hub.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/core/inode.c b/trunk/drivers/usb/core/inode.c index cddfc62c4611..cd4f11157280 100644 --- a/trunk/drivers/usb/core/inode.c +++ b/trunk/drivers/usb/core/inode.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/core/usb.c b/trunk/drivers/usb/core/usb.c index dfd1b5c87ca3..18ddc5e67e39 100644 --- a/trunk/drivers/usb/core/usb.c +++ b/trunk/drivers/usb/core/usb.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/gadget/at91_udc.c b/trunk/drivers/usb/gadget/at91_udc.c index 2a6e3163d944..ba163f35bf21 100644 --- a/trunk/drivers/usb/gadget/at91_udc.c +++ b/trunk/drivers/usb/gadget/at91_udc.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/gadget/dummy_hcd.c b/trunk/drivers/usb/gadget/dummy_hcd.c index 7d7909cf2558..fcb5526cb085 100644 --- a/trunk/drivers/usb/gadget/dummy_hcd.c +++ b/trunk/drivers/usb/gadget/dummy_hcd.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/gadget/ether.c b/trunk/drivers/usb/gadget/ether.c index 1dd8b57f4420..325bf7cfb83f 100644 --- a/trunk/drivers/usb/gadget/ether.c +++ b/trunk/drivers/usb/gadget/ether.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/gadget/goku_udc.c b/trunk/drivers/usb/gadget/goku_udc.c index 65c91d3735de..ae931af05cef 100644 --- a/trunk/drivers/usb/gadget/goku_udc.c +++ b/trunk/drivers/usb/gadget/goku_udc.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/gadget/net2280.c b/trunk/drivers/usb/gadget/net2280.c index 49d737725f70..52779c52b56d 100644 --- a/trunk/drivers/usb/gadget/net2280.c +++ b/trunk/drivers/usb/gadget/net2280.c @@ -54,7 +54,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/gadget/pxa2xx_udc.c b/trunk/drivers/usb/gadget/pxa2xx_udc.c index 2c043a1ea156..84392e835d5f 100644 --- a/trunk/drivers/usb/gadget/pxa2xx_udc.c +++ b/trunk/drivers/usb/gadget/pxa2xx_udc.c @@ -1483,7 +1483,7 @@ static void udc_disable(struct pxa2xx_udc *dev) #ifdef CONFIG_ARCH_PXA /* Disable clock for USB device */ - pxa_set_cken(CKEN11_USB, 0); + pxa_set_cken(CKEN_USB, 0); #endif ep0_idle (dev); @@ -1529,7 +1529,7 @@ static void udc_enable (struct pxa2xx_udc *dev) #ifdef CONFIG_ARCH_PXA /* Enable clock for USB device */ - pxa_set_cken(CKEN11_USB, 1); + pxa_set_cken(CKEN_USB, 1); udelay(5); #endif diff --git a/trunk/drivers/usb/gadget/serial.c b/trunk/drivers/usb/gadget/serial.c index e552668d36b3..f847c3414be3 100644 --- a/trunk/drivers/usb/gadget/serial.c +++ b/trunk/drivers/usb/gadget/serial.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/gadget/zero.c b/trunk/drivers/usb/gadget/zero.c index 8c85e33f74a4..7078374d0b79 100644 --- a/trunk/drivers/usb/gadget/zero.c +++ b/trunk/drivers/usb/gadget/zero.c @@ -67,7 +67,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/host/ehci-hcd.c b/trunk/drivers/usb/host/ehci-hcd.c index c7458f7e56cc..099aff64f536 100644 --- a/trunk/drivers/usb/host/ehci-hcd.c +++ b/trunk/drivers/usb/host/ehci-hcd.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/host/ehci-ps3.c b/trunk/drivers/usb/host/ehci-ps3.c index 4d781a2a9807..37b83ba09969 100644 --- a/trunk/drivers/usb/host/ehci-ps3.c +++ b/trunk/drivers/usb/host/ehci-ps3.c @@ -73,13 +73,6 @@ static const struct hc_driver ps3_ehci_hc_driver = { #endif }; -#if !defined(DEBUG) -#undef dev_dbg -static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( - const struct device *_dev, const char *fmt, ...) {return 0;} -#endif - - static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev) { int result; @@ -104,7 +97,7 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, __LINE__, dev->m_region->lpar_addr); - result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); + result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); if (result) { dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", @@ -162,7 +155,7 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev) fail_ioremap: usb_put_hcd(hcd); fail_create_hcd: - ps3_free_io_irq(virq); + ps3_io_irq_destroy(virq); fail_irq: ps3_free_mmio_region(dev->m_region); fail_mmio: diff --git a/trunk/drivers/usb/host/ohci-hcd.c b/trunk/drivers/usb/host/ohci-hcd.c index e8bbe8bc2598..a66637e725f3 100644 --- a/trunk/drivers/usb/host/ohci-hcd.c +++ b/trunk/drivers/usb/host/ohci-hcd.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/host/ohci-ppc-of.c b/trunk/drivers/usb/host/ohci-ppc-of.c index 08e237c7bc43..c43b66acd4d5 100644 --- a/trunk/drivers/usb/host/ohci-ppc-of.c +++ b/trunk/drivers/usb/host/ohci-ppc-of.c @@ -97,8 +97,8 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) return -ENODEV; is_bigendian = - device_is_compatible(dn, "ohci-bigendian") || - device_is_compatible(dn, "ohci-be"); + of_device_is_compatible(dn, "ohci-bigendian") || + of_device_is_compatible(dn, "ohci-be"); dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n"); diff --git a/trunk/drivers/usb/host/ohci-ps3.c b/trunk/drivers/usb/host/ohci-ps3.c index 62283a3926de..d7cf07288b0b 100644 --- a/trunk/drivers/usb/host/ohci-ps3.c +++ b/trunk/drivers/usb/host/ohci-ps3.c @@ -75,14 +75,6 @@ static const struct hc_driver ps3_ohci_hc_driver = { #endif }; -/* redefine dev_dbg to do a syntax check */ - -#if !defined(DEBUG) -#undef dev_dbg -static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( - const struct device *_dev, const char *fmt, ...) {return 0;} -#endif - static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev) { int result; @@ -107,7 +99,7 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, __LINE__, dev->m_region->lpar_addr); - result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); + result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); if (result) { dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", @@ -165,7 +157,7 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev) fail_ioremap: usb_put_hcd(hcd); fail_create_hcd: - ps3_free_io_irq(virq); + ps3_io_irq_destroy(virq); fail_irq: ps3_free_mmio_region(dev->m_region); fail_mmio: diff --git a/trunk/drivers/usb/host/ohci-pxa27x.c b/trunk/drivers/usb/host/ohci-pxa27x.c index f1563dc319d3..23d2fe5a62f4 100644 --- a/trunk/drivers/usb/host/ohci-pxa27x.c +++ b/trunk/drivers/usb/host/ohci-pxa27x.c @@ -80,7 +80,7 @@ static int pxa27x_start_hc(struct device *dev) inf = dev->platform_data; - pxa_set_cken(CKEN10_USBHOST, 1); + pxa_set_cken(CKEN_USBHOST, 1); UHCHR |= UHCHR_FHR; udelay(11); @@ -123,7 +123,7 @@ static void pxa27x_stop_hc(struct device *dev) UHCCOMS |= 1; udelay(10); - pxa_set_cken(CKEN10_USBHOST, 0); + pxa_set_cken(CKEN_USBHOST, 0); } diff --git a/trunk/drivers/usb/host/sl811-hcd.c b/trunk/drivers/usb/host/sl811-hcd.c index 5fa5647ea095..4cfa3ff2c993 100644 --- a/trunk/drivers/usb/host/sl811-hcd.c +++ b/trunk/drivers/usb/host/sl811-hcd.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/host/u132-hcd.c b/trunk/drivers/usb/host/u132-hcd.c index a7fa0d75567d..ff0dba01f1c7 100644 --- a/trunk/drivers/usb/host/u132-hcd.c +++ b/trunk/drivers/usb/host/u132-hcd.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/image/mdc800.c b/trunk/drivers/usb/image/mdc800.c index d308afd06935..36502a06f73a 100644 --- a/trunk/drivers/usb/image/mdc800.c +++ b/trunk/drivers/usb/image/mdc800.c @@ -94,7 +94,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/usb/image/microtek.c b/trunk/drivers/usb/image/microtek.c index 896cb2b71020..51bd80d2b8cc 100644 --- a/trunk/drivers/usb/image/microtek.c +++ b/trunk/drivers/usb/image/microtek.c @@ -128,7 +128,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/usb/input/Kconfig b/trunk/drivers/usb/input/Kconfig deleted file mode 100644 index a792e42f58af..000000000000 --- a/trunk/drivers/usb/input/Kconfig +++ /dev/null @@ -1,225 +0,0 @@ -# -# USB Input driver configuration -# -comment "USB Input Devices" - depends on USB - -config USB_AIPTEK - tristate "Aiptek 6000U/8000U tablet support" - depends on USB && INPUT - help - Say Y here if you want to use the USB version of the Aiptek 6000U - or Aiptek 8000U tablet. Make sure to say Y to "Mouse support" - (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" - (CONFIG_INPUT_EVDEV) as well. - - To compile this driver as a module, choose M here: the - module will be called aiptek. - -config USB_WACOM - tristate "Wacom Intuos/Graphire tablet support" - depends on USB && INPUT - help - Say Y here if you want to use the USB version of the Wacom Intuos - or Graphire tablet. Make sure to say Y to "Mouse support" - (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" - (CONFIG_INPUT_EVDEV) as well. - - To compile this driver as a module, choose M here: the - module will be called wacom. - -config USB_ACECAD - tristate "Acecad Flair tablet support" - depends on USB && INPUT - help - Say Y here if you want to use the USB version of the Acecad Flair - tablet. Make sure to say Y to "Mouse support" - (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" - (CONFIG_INPUT_EVDEV) as well. - - To compile this driver as a module, choose M here: the - module will be called acecad. - -config USB_KBTAB - tristate "KB Gear JamStudio tablet support" - depends on USB && INPUT - help - Say Y here if you want to use the USB version of the KB Gear - JamStudio tablet. Make sure to say Y to "Mouse support" - (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" - (CONFIG_INPUT_EVDEV) as well. - - To compile this driver as a module, choose M here: the - module will be called kbtab. - -config USB_POWERMATE - tristate "Griffin PowerMate and Contour Jog support" - depends on USB && INPUT - ---help--- - Say Y here if you want to use Griffin PowerMate or Contour Jog devices. - These are aluminum dials which can measure clockwise and anticlockwise - rotation. The dial also acts as a pushbutton. The base contains an LED - which can be instructed to pulse or to switch to a particular intensity. - - You can download userspace tools from - . - - To compile this driver as a module, choose M here: the - module will be called powermate. - -config USB_TOUCHSCREEN - tristate "USB Touchscreen Driver" - depends on USB && INPUT - ---help--- - USB Touchscreen driver for: - - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700) - - PanJit TouchSet USB - - 3M MicroTouch USB (EX II series) - - ITM - - some other eTurboTouch - - Gunze AHL61 - - DMC TSC-10/25 - - Have a look at for - a usage description and the required user-space stuff. - - To compile this driver as a module, choose M here: the - module will be called usbtouchscreen. - -config USB_TOUCHSCREEN_EGALAX - default y - bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED - depends on USB_TOUCHSCREEN - -config USB_TOUCHSCREEN_PANJIT - default y - bool "PanJit device support" if EMBEDDED - depends on USB_TOUCHSCREEN - -config USB_TOUCHSCREEN_3M - default y - bool "3M/Microtouch EX II series device support" if EMBEDDED - depends on USB_TOUCHSCREEN - -config USB_TOUCHSCREEN_ITM - default y - bool "ITM device support" if EMBEDDED - depends on USB_TOUCHSCREEN - -config USB_TOUCHSCREEN_ETURBO - default y - bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED - depends on USB_TOUCHSCREEN - -config USB_TOUCHSCREEN_GUNZE - default y - bool "Gunze AHL61 device support" if EMBEDDED - depends on USB_TOUCHSCREEN - -config USB_TOUCHSCREEN_DMC_TSC10 - default y - bool "DMC TSC-10/25 device support" if EMBEDDED - depends on USB_TOUCHSCREEN - -config USB_YEALINK - tristate "Yealink usb-p1k voip phone" - depends on USB && INPUT && EXPERIMENTAL - ---help--- - Say Y here if you want to enable keyboard and LCD functions of the - Yealink usb-p1k usb phones. The audio part is enabled by the generic - usb sound driver, so you might want to enable that as well. - - For information about how to use these additional functions, see - . - - To compile this driver as a module, choose M here: the module will be - called yealink. - -config USB_XPAD - tristate "X-Box gamepad support" - depends on USB && INPUT - ---help--- - Say Y here if you want to use the X-Box pad with your computer. - Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV) - and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well. - - For information about how to connect the X-Box pad to USB, see - . - - To compile this driver as a module, choose M here: the - module will be called xpad. - -config USB_ATI_REMOTE - tristate "ATI / X10 USB RF remote control" - depends on USB && INPUT - ---help--- - Say Y here if you want to use an ATI or X10 "Lola" USB remote control. - These are RF remotes with USB receivers. - The ATI remote comes with many of ATI's All-In-Wonder video cards. - The X10 "Lola" remote is available at: - - This driver provides mouse pointer, left and right mouse buttons, - and maps all the other remote buttons to keypress events. - - To compile this driver as a module, choose M here: the module will be - called ati_remote. - -config USB_ATI_REMOTE2 - tristate "ATI / Philips USB RF remote control" - depends on USB && INPUT - ---help--- - Say Y here if you want to use an ATI or Philips USB RF remote control. - These are RF remotes with USB receivers. - ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards - and is also available as a separate product. - This driver provides mouse pointer, left and right mouse buttons, - and maps all the other remote buttons to keypress events. - - To compile this driver as a module, choose M here: the module will be - called ati_remote2. - -config USB_KEYSPAN_REMOTE - tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" - depends on USB && INPUT && EXPERIMENTAL - ---help--- - Say Y here if you want to use a Keyspan DMR USB remote control. - Currently only the UIA-11 type of receiver has been tested. The tag - on the receiver that connects to the USB port should have a P/N that - will tell you what type of DMR you have. The UIA-10 type is not - supported at this time. This driver maps all buttons to keypress - events. - - To compile this driver as a module, choose M here: the module will - be called keyspan_remote. - -config USB_APPLETOUCH - tristate "Apple USB Touchpad support" - depends on USB && INPUT - ---help--- - Say Y here if you want to use an Apple USB Touchpad. - - These are the touchpads that can be found on post-February 2005 - Apple Powerbooks (prior models have a Synaptics touchpad connected - to the ADB bus). - - This driver provides a basic mouse driver but can be interfaced - with the synaptics X11 driver to provide acceleration and - scrolling in X11. - - For further information, see - . - - To compile this driver as a module, choose M here: the - module will be called appletouch. - -config USB_GTCO - tristate "GTCO CalComp/InterWrite USB Support" - depends on USB && INPUT - ---help--- - Say Y here if you want to use the USB version of the GTCO - CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support" - (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" - (CONFIG_INPUT_EVDEV) as well. - - To compile this driver as a module, choose M here: the - module will be called gtco. diff --git a/trunk/drivers/usb/input/Makefile b/trunk/drivers/usb/input/Makefile deleted file mode 100644 index 284a0734e0cd..000000000000 --- a/trunk/drivers/usb/input/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# -# Makefile for the USB input drivers -# - -# Multipart objects. -wacom-objs := wacom_wac.o wacom_sys.o - -obj-$(CONFIG_USB_AIPTEK) += aiptek.o -obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o -obj-$(CONFIG_USB_ATI_REMOTE2) += ati_remote2.o -obj-$(CONFIG_USB_KBTAB) += kbtab.o -obj-$(CONFIG_USB_KEYSPAN_REMOTE) += keyspan_remote.o -obj-$(CONFIG_USB_TOUCHSCREEN) += usbtouchscreen.o -obj-$(CONFIG_USB_POWERMATE) += powermate.o -obj-$(CONFIG_USB_WACOM) += wacom.o -obj-$(CONFIG_USB_ACECAD) += acecad.o -obj-$(CONFIG_USB_YEALINK) += yealink.o -obj-$(CONFIG_USB_XPAD) += xpad.o -obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o -obj-$(CONFIG_USB_GTCO) += gtco.o - -ifeq ($(CONFIG_USB_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif diff --git a/trunk/drivers/usb/misc/idmouse.c b/trunk/drivers/usb/misc/idmouse.c index 15c70bd048c4..8d0e360636e6 100644 --- a/trunk/drivers/usb/misc/idmouse.c +++ b/trunk/drivers/usb/misc/idmouse.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/misc/legousbtower.c b/trunk/drivers/usb/misc/legousbtower.c index 5dce797bddb7..1713e19a7899 100644 --- a/trunk/drivers/usb/misc/legousbtower.c +++ b/trunk/drivers/usb/misc/legousbtower.c @@ -80,7 +80,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/misc/rio500.c b/trunk/drivers/usb/misc/rio500.c index fdf68479a166..88f6abe73624 100644 --- a/trunk/drivers/usb/misc/rio500.c +++ b/trunk/drivers/usb/misc/rio500.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include "rio500_usb.h" diff --git a/trunk/drivers/usb/misc/sisusbvga/sisusb_con.c b/trunk/drivers/usb/misc/sisusbvga/sisusb_con.c index 1730d8642a47..5947afb0017e 100644 --- a/trunk/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/trunk/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include #include @@ -322,7 +321,7 @@ sisusbcon_deinit(struct vc_data *c) /* interface routine */ static u8 sisusbcon_build_attr(struct vc_data *c, u8 color, u8 intensity, - u8 blink, u8 underline, u8 reverse) + u8 blink, u8 underline, u8 reverse, u8 unused) { u8 attr = color; diff --git a/trunk/drivers/usb/mon/mon_main.c b/trunk/drivers/usb/mon/mon_main.c index 8a1df2c9c73e..8977ec0d0f99 100644 --- a/trunk/drivers/usb/mon/mon_main.c +++ b/trunk/drivers/usb/mon/mon_main.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/usb/serial/usb-serial.c b/trunk/drivers/usb/serial/usb-serial.c index 7639022cdf84..87f378806db6 100644 --- a/trunk/drivers/usb/serial/usb-serial.c +++ b/trunk/drivers/usb/serial/usb-serial.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/usb/storage/usb.h b/trunk/drivers/usb/storage/usb.h index 21f3ddbc9080..6dac1ffdde86 100644 --- a/trunk/drivers/usb/storage/usb.h +++ b/trunk/drivers/usb/storage/usb.h @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/video/Kconfig b/trunk/drivers/video/Kconfig index d18b51f989c9..1132ba5ff391 100644 --- a/trunk/drivers/video/Kconfig +++ b/trunk/drivers/video/Kconfig @@ -5,6 +5,11 @@ menu "Graphics support" source "drivers/video/backlight/Kconfig" +source "drivers/video/display/Kconfig" + +config VGASTATE + tristate + default n config FB tristate "Support for frame buffer devices" @@ -90,6 +95,43 @@ config FB_CFB_IMAGEBLIT blitting. This is used by drivers that don't provide their own (accelerated) version. +config FB_SYS_FILLRECT + tristate + depends on FB + default n + ---help--- + Include the sys_fillrect function for generic software rectangle + filling. This is used by drivers that don't provide their own + (accelerated) version and the framebuffer is in system RAM. + +config FB_SYS_COPYAREA + tristate + depends on FB + default n + ---help--- + Include the sys_copyarea function for generic software area copying. + This is used by drivers that don't provide their own (accelerated) + version and the framebuffer is in system RAM. + +config FB_SYS_IMAGEBLIT + tristate + depends on FB + default n + ---help--- + Include the sys_imageblit function for generic software image + blitting. This is used by drivers that don't provide their own + (accelerated) version and the framebuffer is in system RAM. + +config FB_SYS_FOPS + tristate + depends on FB + default n + +config FB_DEFERRED_IO + bool + depends on FB + default y + config FB_SVGALIB tristate depends on FB @@ -191,7 +233,7 @@ config FB_ARMCLCD If you want to compile this as a module (=code which can be inserted into and removed from the running kernel), say M - here and read . The module + here and read . The module will be called amba-clcd. choice @@ -375,9 +417,10 @@ config FB_FM2 config FB_ARC tristate "Arc Monochrome LCD board support" depends on FB && X86 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS help This enables support for the Arc Monochrome LCD board. The board is based on the KS-108 lcd controller and is typically a matrix @@ -475,6 +518,8 @@ config FB_VGA16 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VGASTATE + select FONT_8x16 if FRAMEBUFFER_CONSOLE help This is the frame buffer device driver for VGA 16 color graphic cards. Say Y if you have such a card. @@ -519,15 +564,25 @@ config FB_HP300 default y config FB_TGA - tristate "TGA framebuffer support" - depends on FB && ALPHA + tristate "TGA/SFB+ framebuffer support" + depends on FB && (ALPHA || TC) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select BITREVERSE - help - This is the frame buffer device driver for generic TGA graphic - cards. Say Y if you have one of those. + ---help--- + This is the frame buffer device driver for generic TGA and SFB+ + graphic cards. These include DEC ZLXp-E1, -E2 and -E3 PCI cards, + also known as PBXGA-A, -B and -C, and DEC ZLX-E1, -E2 and -E3 + TURBOchannel cards, also known as PMAGD-A, -B and -C. + + Due to hardware limitations ZLX-E2 and E3 cards are not supported + for DECstation 5000/200 systems. Additionally due to firmware + limitations these cards may cause troubles with booting DECstation + 5000/240 and /260 systems, but are fully supported under Linux if + you manage to get it going. ;-) + + Say Y if you have one of those. config FB_VESA bool "VESA VGA graphics support" @@ -551,6 +606,21 @@ config FB_IMAC help This is the frame buffer device driver for the Intel-based Macintosh +config FB_HECUBA + tristate "Hecuba board support" + depends on FB && X86 && MMU + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS + select FB_DEFERRED_IO + help + This enables support for the Hecuba board. This driver was tested + with an E-Ink 800x600 display and x86 SBCs through a 16 bit GPIO + interface (8 bit data, 4 bit control). If you anticpate using + this driver, say Y or M; otherwise say N. You must specify the + GPIO IO address to be used for setting control and data. + config FB_HGA tristate "Hercules mono graphics support" depends on FB && X86 @@ -686,6 +756,7 @@ config FB_NVIDIA select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select BITREVERSE + select VGASTATE help This driver supports graphics boards with the nVidia chips, TNT and newer. For very old chipsets, such as the RIVA128, then use @@ -724,6 +795,7 @@ config FB_RIVA select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select BITREVERSE + select VGASTATE help This driver supports graphics boards with the nVidia Riva/Geforce chips. @@ -770,6 +842,7 @@ config FB_I810 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VGASTATE help This driver supports the on-board graphics built in to the Intel 810 and 815 chipsets. Say Y if you have and plan to use such a board. @@ -809,6 +882,22 @@ config FB_I810_I2C select FB_DDC help +config FB_LE80578 + tristate "Intel LE80578 (Vermilion) support" + depends on FB && PCI && X86 + select FB_MODE_HELPERS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + This driver supports the LE80578 (Vermilion Range) chipset + +config FB_CARILLO_RANCH + tristate "Intel Carillo Ranch support" + depends on FB_LE80578 && FB && PCI && X86 + help + This driver supports the LE80578 (Carillo Ranch) board + config FB_INTEL tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)" depends on FB && EXPERIMENTAL && PCI && X86 @@ -1120,6 +1209,8 @@ config FB_S3 select FB_CFB_IMAGEBLIT select FB_TILEBLITTING select FB_SVGALIB + select VGASTATE + select FONT_8x16 if FRAMEBUFFER_CONSOLE ---help--- Driver for graphics boards with S3 Trio / S3 Virge chip. @@ -1130,6 +1221,7 @@ config FB_SAVAGE select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VGASTATE help This driver supports notebooks and computers with S3 Savage PCI/AGP chips. @@ -1196,6 +1288,7 @@ config FB_NEOMAGIC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VGASTATE help This driver supports notebooks with NeoMagic PCI chips. Say Y if you have such a graphics card. @@ -1383,6 +1476,32 @@ config FB_LEO This is the frame buffer device driver for the SBUS-based Sun ZX (leo) frame buffer cards. +config FB_XVR500 + bool "Sun XVR-500 3DLABS Wildcat support" + depends on FB && PCI && SPARC64 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + This is the framebuffer device for the Sun XVR-500 and similar + graphics cards based upon the 3DLABS Wildcat chipset. The driver + only works on sparc64 systems where the system firwmare has + mostly initialized the card already. It is treated as a + completely dumb framebuffer device. + +config FB_XVR2500 + bool "Sun XVR-2500 3DLABS Wildcat support" + depends on FB && PCI && SPARC64 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + This is the framebuffer device for the Sun XVR-2500 and similar + graphics cards based upon the 3DLABS Wildcat chipset. The driver + only works on sparc64 systems where the system firwmare has + mostly initialized the card already. It is treated as a + completely dumb framebuffer device. + config FB_PCI bool "PCI framebuffers" depends on (FB = y) && PCI && SPARC @@ -1494,7 +1613,7 @@ config FB_PXA This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The module will be called pxafb. If you want to compile it as a module, - say M here and read . + say M here and read . If unsure, say N. @@ -1547,7 +1666,7 @@ config FB_W100 This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The module will be called w100fb. If you want to compile it as a module, - say M here and read . + say M here and read . If unsure, say N. @@ -1564,7 +1683,7 @@ config FB_S3C2410 This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The module will be called s3c2410fb. If you want to compile it as a module, - say M here and read . + say M here and read . If unsure, say N. config FB_S3C2410_DEBUG @@ -1636,12 +1755,24 @@ config FB_PS3_DEFAULT_SIZE_M The default value can be overridden on the kernel command line using the "ps3fb" option (e.g. "ps3fb=9M"); -config FB_VIRTUAL - tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" - depends on FB +config FB_XILINX + tristate "Xilinx frame buffer support" + depends on FB && XILINX_VIRTEX select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + ---help--- + Include support for the Xilinx ML300/ML403 reference design + framebuffer. ML300 carries a 640*480 LCD display on the board, + ML403 uses a standard DB15 VGA connector. + +config FB_VIRTUAL + tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" + depends on FB + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS ---help--- This is a `virtual' frame buffer device. It operates on a chunk of unswappable kernel memory instead of on the memory of a graphics diff --git a/trunk/drivers/video/Makefile b/trunk/drivers/video/Makefile index 869351785ee8..a916c204274f 100644 --- a/trunk/drivers/video/Makefile +++ b/trunk/drivers/video/Makefile @@ -4,6 +4,7 @@ # Each configuration option enables a list of files. +obj-$(CONFIG_VGASTATE) += vgastate.o obj-y += fb_notify.o obj-$(CONFIG_FB) += fb.o fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ @@ -12,14 +13,19 @@ fb-objs := $(fb-y) obj-$(CONFIG_VT) += console/ obj-$(CONFIG_LOGO) += logo/ -obj-y += backlight/ +obj-y += backlight/ display/ obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o +obj-$(CONFIG_FB_SYS_FILLRECT) += sysfillrect.o +obj-$(CONFIG_FB_SYS_COPYAREA) += syscopyarea.o +obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o +obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o obj-$(CONFIG_FB_SVGALIB) += svgalib.o obj-$(CONFIG_FB_MACMODES) += macmodes.o obj-$(CONFIG_FB_DDC) += fb_ddc.o +obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o # Hardware specific drivers go first obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o @@ -30,7 +36,7 @@ obj-$(CONFIG_FB_PM2) += pm2fb.o obj-$(CONFIG_FB_PM3) += pm3fb.o obj-$(CONFIG_FB_MATROX) += matrox/ -obj-$(CONFIG_FB_RIVA) += riva/ vgastate.o +obj-$(CONFIG_FB_RIVA) += riva/ obj-$(CONFIG_FB_NVIDIA) += nvidia/ obj-$(CONFIG_FB_ATY) += aty/ macmodes.o obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o @@ -40,8 +46,7 @@ obj-$(CONFIG_FB_KYRO) += kyro/ obj-$(CONFIG_FB_SAVAGE) += savage/ obj-$(CONFIG_FB_GEODE) += geode/ obj-$(CONFIG_FB_MBX) += mbx/ -obj-$(CONFIG_FB_I810) += vgastate.o -obj-$(CONFIG_FB_NEOMAGIC) += neofb.o vgastate.o +obj-$(CONFIG_FB_NEOMAGIC) += neofb.o obj-$(CONFIG_FB_3DFX) += tdfxfb.o obj-$(CONFIG_FB_CONTROL) += controlfb.o obj-$(CONFIG_FB_PLATINUM) += platinumfb.o @@ -51,7 +56,8 @@ obj-$(CONFIG_FB_IMSTT) += imsttfb.o obj-$(CONFIG_FB_FM2) += fm2fb.o obj-$(CONFIG_FB_CYBLA) += cyblafb.o obj-$(CONFIG_FB_TRIDENT) += tridentfb.o -obj-$(CONFIG_FB_S3) += s3fb.o vgastate.o +obj-$(CONFIG_FB_LE80578) += vermilion/ +obj-$(CONFIG_FB_S3) += s3fb.o obj-$(CONFIG_FB_STI) += stifb.o obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o @@ -66,7 +72,10 @@ obj-$(CONFIG_FB_ACORN) += acornfb.o obj-$(CONFIG_FB_ATARI) += atafb.o c2p.o atafb_mfb.o \ atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o obj-$(CONFIG_FB_MAC) += macfb.o +obj-$(CONFIG_FB_HECUBA) += hecubafb.o obj-$(CONFIG_FB_HGA) += hgafb.o +obj-$(CONFIG_FB_XVR500) += sunxvr500.o +obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o obj-$(CONFIG_FB_IGA) += igafb.o obj-$(CONFIG_FB_APOLLO) += dnfb.o obj-$(CONFIG_FB_Q40) += q40fb.o @@ -100,11 +109,12 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o +obj-$(CONFIG_FB_XILINX) += xilinxfb.o # Platform or fallback drivers go here obj-$(CONFIG_FB_VESA) += vesafb.o obj-$(CONFIG_FB_IMAC) += imacfb.o -obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o +obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o # the test framebuffer is last diff --git a/trunk/drivers/video/arcfb.c b/trunk/drivers/video/arcfb.c index 30a8369757e7..db15baca3f7b 100644 --- a/trunk/drivers/video/arcfb.c +++ b/trunk/drivers/video/arcfb.c @@ -262,7 +262,8 @@ static void arcfb_lcd_update_page(struct arcfb_par *par, unsigned int upper, ks108_set_yaddr(par, chipindex, upper/8); linesize = par->info->var.xres/8; - src = par->info->screen_base + (left/8) + (upper * linesize); + src = (unsigned char __force *) par->info->screen_base + (left/8) + + (upper * linesize); ks108_set_xaddr(par, chipindex, left); bitmask=1; @@ -368,7 +369,7 @@ static void arcfb_fillrect(struct fb_info *info, { struct arcfb_par *par = info->par; - cfb_fillrect(info, rect); + sys_fillrect(info, rect); /* update the physical lcd */ arcfb_lcd_update(par, rect->dx, rect->dy, rect->width, rect->height); @@ -379,7 +380,7 @@ static void arcfb_copyarea(struct fb_info *info, { struct arcfb_par *par = info->par; - cfb_copyarea(info, area); + sys_copyarea(info, area); /* update the physical lcd */ arcfb_lcd_update(par, area->dx, area->dy, area->width, area->height); @@ -389,7 +390,7 @@ static void arcfb_imageblit(struct fb_info *info, const struct fb_image *image) { struct arcfb_par *par = info->par; - cfb_imageblit(info, image); + sys_imageblit(info, image); /* update the physical lcd */ arcfb_lcd_update(par, image->dx, image->dy, image->width, @@ -439,14 +440,11 @@ static int arcfb_ioctl(struct fb_info *info, * the fb. it's inefficient for them to do anything less than 64*8 * writes since we update the lcd in each write() anyway. */ -static ssize_t arcfb_write(struct file *file, const char __user *buf, size_t count, - loff_t *ppos) +static ssize_t arcfb_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) { /* modded from epson 1355 */ - struct inode *inode; - int fbidx; - struct fb_info *info; unsigned long p; int err=-EINVAL; unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount; @@ -454,13 +452,6 @@ static ssize_t arcfb_write(struct file *file, const char __user *buf, size_t cou unsigned int xres; p = *ppos; - inode = file->f_path.dentry->d_inode; - fbidx = iminor(inode); - info = registered_fb[fbidx]; - - if (!info || !info->screen_base) - return -ENODEV; - par = info->par; xres = info->var.xres; fbmemlength = (xres * info->var.yres)/8; @@ -477,7 +468,7 @@ static ssize_t arcfb_write(struct file *file, const char __user *buf, size_t cou if (count) { char *base_addr; - base_addr = info->screen_base; + base_addr = (char __force *)info->screen_base; count -= copy_from_user(base_addr + p, buf, count); *ppos += count; err = -EFAULT; @@ -503,6 +494,7 @@ static ssize_t arcfb_write(struct file *file, const char __user *buf, size_t cou static struct fb_ops arcfb_ops = { .owner = THIS_MODULE, .fb_open = arcfb_open, + .fb_read = fb_sys_read, .fb_write = arcfb_write, .fb_release = arcfb_release, .fb_pan_display = arcfb_pan_display, @@ -603,7 +595,7 @@ static int arcfb_remove(struct platform_device *dev) if (info) { unregister_framebuffer(info); - vfree(info->screen_base); + vfree((void __force *)info->screen_base); framebuffer_release(info); } return 0; diff --git a/trunk/drivers/video/aty/ati_ids.h b/trunk/drivers/video/aty/ati_ids.h index 39ab483fc250..90e7df22f508 100644 --- a/trunk/drivers/video/aty/ati_ids.h +++ b/trunk/drivers/video/aty/ati_ids.h @@ -209,4 +209,4 @@ #define PCI_CHIP_R423_5D57 0x5D57 #define PCI_CHIP_RS350_7834 0x7834 #define PCI_CHIP_RS350_7835 0x7835 - +#define PCI_CHIP_RS480_5955 0x5955 diff --git a/trunk/drivers/video/aty/aty128fb.c b/trunk/drivers/video/aty/aty128fb.c index e86d7e0c9825..7fea4d8ae8e2 100644 --- a/trunk/drivers/video/aty/aty128fb.c +++ b/trunk/drivers/video/aty/aty128fb.c @@ -2165,18 +2165,29 @@ static void __devexit aty128_remove(struct pci_dev *pdev) static int aty128fb_blank(int blank, struct fb_info *fb) { struct aty128fb_par *par = fb->par; - u8 state = 0; + u8 state; if (par->lock_blank || par->asleep) return 0; - if (blank & FB_BLANK_VSYNC_SUSPEND) - state |= 2; - if (blank & FB_BLANK_HSYNC_SUSPEND) - state |= 1; - if (blank & FB_BLANK_POWERDOWN) - state |= 4; - + switch (blank) { + case FB_BLANK_NORMAL: + state = 4; + break; + case FB_BLANK_VSYNC_SUSPEND: + state = 6; + break; + case FB_BLANK_HSYNC_SUSPEND: + state = 5; + break; + case FB_BLANK_POWERDOWN: + state = 7; + break; + case FB_BLANK_UNBLANK: + default: + state = 0; + break; + } aty_st_8(CRTC_EXT_CNTL+1, state); if (par->chip_gen == rage_M3) { @@ -2430,7 +2441,7 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state) wait_for_idle(par); /* Blank display and LCD */ - aty128fb_blank(VESA_POWERDOWN, info); + aty128fb_blank(FB_BLANK_POWERDOWN, info); /* Sleep */ par->asleep = 1; diff --git a/trunk/drivers/video/aty/atyfb_base.c b/trunk/drivers/video/aty/atyfb_base.c index 8514f2a6f060..ea67dd902d4e 100644 --- a/trunk/drivers/video/aty/atyfb_base.c +++ b/trunk/drivers/video/aty/atyfb_base.c @@ -2297,20 +2297,6 @@ static int __devinit aty_init(struct fb_info *info) par->pll_limits.xclk = 53; } #endif - if (pll) - par->pll_limits.pll_max = pll; - if (mclk) - par->pll_limits.mclk = mclk; - if (xclk) - par->pll_limits.xclk = xclk; - - aty_calc_mem_refresh(par, par->pll_limits.xclk); - par->pll_per = 1000000/par->pll_limits.pll_max; - par->mclk_per = 1000000/par->pll_limits.mclk; - par->xclk_per = 1000000/par->pll_limits.xclk; - - par->ref_clk_per = 1000000000000ULL / 14318180; - xtal = "14.31818"; #ifdef CONFIG_FB_ATY_GX if (!M64_HAS(INTEGRATED)) { @@ -2338,6 +2324,7 @@ static int __devinit aty_init(struct fb_info *info) case DAC_IBMRGB514: par->dac_ops = &aty_dac_ibm514; break; +#ifdef CONFIG_ATARI case DAC_ATI68860_B: case DAC_ATI68860_C: par->dac_ops = &aty_dac_ati68860b; @@ -2346,6 +2333,7 @@ static int __devinit aty_init(struct fb_info *info) case DAC_ATT21C498: par->dac_ops = &aty_dac_att21c498; break; +#endif default: PRINTKI("aty_init: DAC type not implemented yet!\n"); par->dac_ops = &aty_dac_unsupported; @@ -2389,8 +2377,29 @@ static int __devinit aty_init(struct fb_info *info) /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */ if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM) par->pll_limits.mclk = 63; + /* Mobility + 32bit memory interface need halved XCLK. */ + if (M64_HAS(MOBIL_BUS) && par->ram_type == SDRAM32) + par->pll_limits.xclk = (par->pll_limits.xclk + 1) >> 1; } +#endif + /* Allow command line to override clocks. */ + if (pll) + par->pll_limits.pll_max = pll; + if (mclk) + par->pll_limits.mclk = mclk; + if (xclk) + par->pll_limits.xclk = xclk; + + aty_calc_mem_refresh(par, par->pll_limits.xclk); + par->pll_per = 1000000/par->pll_limits.pll_max; + par->mclk_per = 1000000/par->pll_limits.mclk; + par->xclk_per = 1000000/par->pll_limits.xclk; + + par->ref_clk_per = 1000000000000ULL / 14318180; + xtal = "14.31818"; + +#ifdef CONFIG_FB_ATY_CT if (M64_HAS(GTB_DSP)) { u8 pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par); diff --git a/trunk/drivers/video/aty/mach64_ct.c b/trunk/drivers/video/aty/mach64_ct.c index 1fdcfdbf669b..cc9e9779b75f 100644 --- a/trunk/drivers/video/aty/mach64_ct.c +++ b/trunk/drivers/video/aty/mach64_ct.c @@ -608,12 +608,10 @@ static void aty_resume_pll_ct(const struct fb_info *info, aty_st_pll_ct(SCLK_FB_DIV, pll->ct.sclk_fb_div, par); aty_st_pll_ct(SPLL_CNTL2, pll->ct.spll_cntl2, par); /* - * The sclk has been started. However, I believe the first clock - * ticks it generates are not very stable. Hope this primitive loop - * helps for Rage Mobilities that sometimes crash when - * we switch to sclk. (Daniel Mantione, 13-05-2003) + * SCLK has been started. Wait for the PLL to lock. 5 ms + * should be enough according to mach64 programmer's guide. */ - udelay(500); + mdelay(5); } aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par); diff --git a/trunk/drivers/video/aty/radeon_base.c b/trunk/drivers/video/aty/radeon_base.c index a4b3fd185de7..2ce050193018 100644 --- a/trunk/drivers/video/aty/radeon_base.c +++ b/trunk/drivers/video/aty/radeon_base.c @@ -100,6 +100,8 @@ { PCI_VENDOR_ID_ATI, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (flags) | (CHIP_FAMILY_##family) } static struct pci_device_id radeonfb_pci_table[] = { + /* Radeon Xpress 200m */ + CHIP_DEF(PCI_CHIP_RS480_5955, RS480, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), /* Mobility M6 */ CHIP_DEF(PCI_CHIP_RADEON_LY, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), CHIP_DEF(PCI_CHIP_RADEON_LZ, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), @@ -422,7 +424,7 @@ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo) if (dp == NULL) return -ENODEV; - val = get_property(dp, "ATY,RefCLK", NULL); + val = of_get_property(dp, "ATY,RefCLK", NULL); if (!val || !*val) { printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n"); return -EINVAL; @@ -430,11 +432,11 @@ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo) rinfo->pll.ref_clk = (*val) / 10; - val = get_property(dp, "ATY,SCLK", NULL); + val = of_get_property(dp, "ATY,SCLK", NULL); if (val && *val) rinfo->pll.sclk = (*val) / 10; - val = get_property(dp, "ATY,MCLK", NULL); + val = of_get_property(dp, "ATY,MCLK", NULL); if (val && *val) rinfo->pll.mclk = (*val) / 10; @@ -1994,7 +1996,8 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo) /* framebuffer size */ if ((rinfo->family == CHIP_FAMILY_RS100) || (rinfo->family == CHIP_FAMILY_RS200) || - (rinfo->family == CHIP_FAMILY_RS300)) { + (rinfo->family == CHIP_FAMILY_RS300) || + (rinfo->family == CHIP_FAMILY_RS480) ) { u32 tom = INREG(NB_TOM); tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024); diff --git a/trunk/drivers/video/aty/radeon_monitor.c b/trunk/drivers/video/aty/radeon_monitor.c index 737b5c09dbdb..2030ed813429 100644 --- a/trunk/drivers/video/aty/radeon_monitor.c +++ b/trunk/drivers/video/aty/radeon_monitor.c @@ -70,7 +70,7 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ int i, mt = MT_NONE; RTRACE("analyzing OF properties...\n"); - pmt = get_property(dp, "display-type", NULL); + pmt = of_get_property(dp, "display-type", NULL); if (!pmt) return MT_NONE; RTRACE("display-type: %s\n", pmt); @@ -89,7 +89,7 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ } for (i = 0; propnames[i] != NULL; ++i) { - pedid = get_property(dp, propnames[i], NULL); + pedid = of_get_property(dp, propnames[i], NULL); if (pedid != NULL) break; } @@ -98,9 +98,10 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ * single-head cards have hdno == -1 and skip this step */ if (pedid == NULL && dp->parent && (hdno != -1)) - pedid = get_property(dp->parent, (hdno == 0) ? "EDID1" : "EDID2", NULL); + pedid = of_get_property(dp->parent, + (hdno == 0) ? "EDID1" : "EDID2", NULL); if (pedid == NULL && dp->parent && (hdno == 0)) - pedid = get_property(dp->parent, "EDID", NULL); + pedid = of_get_property(dp->parent, "EDID", NULL); if (pedid == NULL) return mt; @@ -130,7 +131,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_ do { if (!dp) return MT_NONE; - pname = get_property(dp, "name", NULL); + pname = of_get_property(dp, "name", NULL); if (!pname) return MT_NONE; len = strlen(pname); diff --git a/trunk/drivers/video/aty/radeon_pm.c b/trunk/drivers/video/aty/radeon_pm.c index c411293cefc8..be1d57bf9dc8 100644 --- a/trunk/drivers/video/aty/radeon_pm.c +++ b/trunk/drivers/video/aty/radeon_pm.c @@ -1290,7 +1290,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo) if (rinfo->of_node != NULL) { int size; - mrtable = get_property(rinfo->of_node, "ATY,MRT", &size); + mrtable = of_get_property(rinfo->of_node, "ATY,MRT", &size); if (mrtable) mrtable_size = size >> 2; else @@ -2826,11 +2826,15 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlis rinfo->pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM); /* Enable/Disable dynamic clocks: TODO add sysfs access */ - rinfo->dynclk = dynclk; - if (dynclk == 1) { + if (rinfo->family == CHIP_FAMILY_RS480) + rinfo->dynclk = -1; + else + rinfo->dynclk = dynclk; + + if (rinfo->dynclk == 1) { radeon_pm_enable_dynamic_mode(rinfo); printk("radeonfb: Dynamic Clock Power Management enabled\n"); - } else if (dynclk == 0) { + } else if (rinfo->dynclk == 0) { radeon_pm_disable_dynamic_mode(rinfo); printk("radeonfb: Dynamic Clock Power Management disabled\n"); } diff --git a/trunk/drivers/video/aty/radeonfb.h b/trunk/drivers/video/aty/radeonfb.h index 319000360285..7ebffcdfd1e3 100644 --- a/trunk/drivers/video/aty/radeonfb.h +++ b/trunk/drivers/video/aty/radeonfb.h @@ -48,6 +48,7 @@ enum radeon_family { CHIP_FAMILY_RV350, CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */ CHIP_FAMILY_R420, /* R420/R423/M18 */ + CHIP_FAMILY_RS480, CHIP_FAMILY_LAST, }; @@ -64,7 +65,8 @@ enum radeon_family { ((rinfo)->family == CHIP_FAMILY_RV350) || \ ((rinfo)->family == CHIP_FAMILY_R350) || \ ((rinfo)->family == CHIP_FAMILY_RV380) || \ - ((rinfo)->family == CHIP_FAMILY_R420)) + ((rinfo)->family == CHIP_FAMILY_R420) || \ + ((rinfo)->family == CHIP_FAMILY_RS480) ) /* * Chip flags diff --git a/trunk/drivers/video/backlight/Kconfig b/trunk/drivers/video/backlight/Kconfig index 47d15b5d985a..fbef663fc057 100644 --- a/trunk/drivers/video/backlight/Kconfig +++ b/trunk/drivers/video/backlight/Kconfig @@ -63,3 +63,11 @@ config BACKLIGHT_PROGEAR help If you have a Frontpath ProGear say Y to enable the backlight driver. + +config BACKLIGHT_CARILLO_RANCH + tristate "Intel Carillo Ranch Backlight Driver" + depends on BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 + default n + help + If you have a Intel LE80578 (Carillo Ranch) say Y to enable the + backlight driver. diff --git a/trunk/drivers/video/backlight/Makefile b/trunk/drivers/video/backlight/Makefile index 0c3ce46f5094..c6e2266f63e2 100644 --- a/trunk/drivers/video/backlight/Makefile +++ b/trunk/drivers/video/backlight/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o +obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o diff --git a/trunk/drivers/video/backlight/cr_bllcd.c b/trunk/drivers/video/backlight/cr_bllcd.c new file mode 100644 index 000000000000..e9bbc3455c94 --- /dev/null +++ b/trunk/drivers/video/backlight/cr_bllcd.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) Intel Corp. 2007. + * All Rights Reserved. + * + * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to + * develop this driver. + * + * This file is part of the Carillo Ranch video subsystem driver. + * The Carillo Ranch video subsystem driver is free software; + * you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The Carillo Ranch video subsystem driver 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 driver; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Thomas Hellstrom + * Alan Hourihane + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The LVDS- and panel power controls sits on the + * GPIO port of the ISA bridge. + */ + +#define CRVML_DEVICE_LPC 0x27B8 +#define CRVML_REG_GPIOBAR 0x48 +#define CRVML_REG_GPIOEN 0x4C +#define CRVML_GPIOEN_BIT (1 << 4) +#define CRVML_PANEL_PORT 0x38 +#define CRVML_LVDS_ON 0x00000001 +#define CRVML_PANEL_ON 0x00000002 +#define CRVML_BACKLIGHT_OFF 0x00000004 + +/* The PLL Clock register sits on Host bridge */ +#define CRVML_DEVICE_MCH 0x5001 +#define CRVML_REG_MCHBAR 0x44 +#define CRVML_REG_MCHEN 0x54 +#define CRVML_MCHEN_BIT (1 << 28) +#define CRVML_MCHMAP_SIZE 4096 +#define CRVML_REG_CLOCK 0xc3c +#define CRVML_CLOCK_SHIFT 8 +#define CRVML_CLOCK_MASK 0x00000f00 + +static struct pci_dev *lpc_dev; +static u32 gpio_bar; + +struct cr_panel { + struct backlight_device *cr_backlight_device; + struct lcd_device *cr_lcd_device; +}; + +static int cr_backlight_set_intensity(struct backlight_device *bd) +{ + int intensity = bd->props.brightness; + u32 addr = gpio_bar + CRVML_PANEL_PORT; + u32 cur = inl(addr); + + if (bd->props.power == FB_BLANK_UNBLANK) + intensity = FB_BLANK_UNBLANK; + if (bd->props.fb_blank == FB_BLANK_UNBLANK) + intensity = FB_BLANK_UNBLANK; + if (bd->props.power == FB_BLANK_POWERDOWN) + intensity = FB_BLANK_POWERDOWN; + if (bd->props.fb_blank == FB_BLANK_POWERDOWN) + intensity = FB_BLANK_POWERDOWN; + + if (intensity == FB_BLANK_UNBLANK) { /* FULL ON */ + cur &= ~CRVML_BACKLIGHT_OFF; + outl(cur, addr); + } else if (intensity == FB_BLANK_POWERDOWN) { /* OFF */ + cur |= CRVML_BACKLIGHT_OFF; + outl(cur, addr); + } /* anything else, don't bother */ + + return 0; +} + +static int cr_backlight_get_intensity(struct backlight_device *bd) +{ + u32 addr = gpio_bar + CRVML_PANEL_PORT; + u32 cur = inl(addr); + u8 intensity; + + if (cur & CRVML_BACKLIGHT_OFF) + intensity = FB_BLANK_POWERDOWN; + else + intensity = FB_BLANK_UNBLANK; + + return intensity; +} + +static struct backlight_ops cr_backlight_ops = { + .get_brightness = cr_backlight_get_intensity, + .update_status = cr_backlight_set_intensity, +}; + +static void cr_panel_on(void) +{ + u32 addr = gpio_bar + CRVML_PANEL_PORT; + u32 cur = inl(addr); + + if (!(cur & CRVML_PANEL_ON)) { + /* Make sure LVDS controller is down. */ + if (cur & 0x00000001) { + cur &= ~CRVML_LVDS_ON; + outl(cur, addr); + } + /* Power up Panel */ + schedule_timeout(HZ / 10); + cur |= CRVML_PANEL_ON; + outl(cur, addr); + } + + /* Power up LVDS controller */ + + if (!(cur & CRVML_LVDS_ON)) { + schedule_timeout(HZ / 10); + outl(cur | CRVML_LVDS_ON, addr); + } +} + +static void cr_panel_off(void) +{ + u32 addr = gpio_bar + CRVML_PANEL_PORT; + u32 cur = inl(addr); + + /* Power down LVDS controller first to avoid high currents */ + if (cur & CRVML_LVDS_ON) { + cur &= ~CRVML_LVDS_ON; + outl(cur, addr); + } + if (cur & CRVML_PANEL_ON) { + schedule_timeout(HZ / 10); + outl(cur & ~CRVML_PANEL_ON, addr); + } +} + +static int cr_lcd_set_power(struct lcd_device *ld, int power) +{ + if (power == FB_BLANK_UNBLANK) + cr_panel_on(); + if (power == FB_BLANK_POWERDOWN) + cr_panel_off(); + + return 0; +} + +static struct lcd_ops cr_lcd_ops = { + .set_power = cr_lcd_set_power, +}; + +static int cr_backlight_probe(struct platform_device *pdev) +{ + struct cr_panel *crp; + u8 dev_en; + + crp = kzalloc(sizeof(crp), GFP_KERNEL); + if (crp == NULL) + return -ENOMEM; + + lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL, + CRVML_DEVICE_LPC, NULL); + if (!lpc_dev) { + printk("INTEL CARILLO RANCH LPC not found.\n"); + return -ENODEV; + } + + pci_read_config_byte(lpc_dev, CRVML_REG_GPIOEN, &dev_en); + if (!(dev_en & CRVML_GPIOEN_BIT)) { + printk(KERN_ERR + "Carillo Ranch GPIO device was not enabled.\n"); + pci_dev_put(lpc_dev); + return -ENODEV; + } + + crp->cr_backlight_device = backlight_device_register("cr-backlight", + &pdev->dev, NULL, + &cr_backlight_ops); + if (IS_ERR(crp->cr_backlight_device)) { + pci_dev_put(lpc_dev); + return PTR_ERR(crp->cr_backlight_device); + } + + crp->cr_lcd_device = lcd_device_register("cr-lcd", + &pdev->dev, + &cr_lcd_ops); + + if (IS_ERR(crp->cr_lcd_device)) { + pci_dev_put(lpc_dev); + return PTR_ERR(crp->cr_backlight_device); + } + + pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR, + &gpio_bar); + gpio_bar &= ~0x3F; + + crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK; + crp->cr_backlight_device->props.brightness = 0; + crp->cr_backlight_device->props.max_brightness = 0; + cr_backlight_set_intensity(crp->cr_backlight_device); + + cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_UNBLANK); + + platform_set_drvdata(pdev, crp); + + return 0; +} + +static int cr_backlight_remove(struct platform_device *pdev) +{ + struct cr_panel *crp = platform_get_drvdata(pdev); + crp->cr_backlight_device->props.power = FB_BLANK_POWERDOWN; + crp->cr_backlight_device->props.brightness = 0; + crp->cr_backlight_device->props.max_brightness = 0; + cr_backlight_set_intensity(crp->cr_backlight_device); + cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_POWERDOWN); + backlight_device_unregister(crp->cr_backlight_device); + lcd_device_unregister(crp->cr_lcd_device); + pci_dev_put(lpc_dev); + + return 0; +} + +static struct platform_driver cr_backlight_driver = { + .probe = cr_backlight_probe, + .remove = cr_backlight_remove, + .driver = { + .name = "cr_backlight", + }, +}; + +static struct platform_device *crp; + +static int __init cr_backlight_init(void) +{ + int ret = platform_driver_register(&cr_backlight_driver); + + if (!ret) { + crp = platform_device_alloc("cr_backlight", -1); + if (!crp) + return -ENOMEM; + + ret = platform_device_add(crp); + + if (ret) { + platform_device_put(crp); + platform_driver_unregister(&cr_backlight_driver); + } + } + + printk("Carillo Ranch Backlight Driver Initialized.\n"); + + return ret; +} + +static void __exit cr_backlight_exit(void) +{ + platform_device_unregister(crp); + platform_driver_unregister(&cr_backlight_driver); +} + +module_init(cr_backlight_init); +module_exit(cr_backlight_exit); + +MODULE_AUTHOR("Tungsten Graphics Inc."); +MODULE_DESCRIPTION("Carillo Ranch Backlight Driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/cfbcopyarea.c b/trunk/drivers/video/cfbcopyarea.c index 6faea4034e3d..032210f45be3 100644 --- a/trunk/drivers/video/cfbcopyarea.c +++ b/trunk/drivers/video/cfbcopyarea.c @@ -22,8 +22,6 @@ * help moving some redundant computations and branches out of the loop, too. */ - - #include #include #include @@ -31,6 +29,7 @@ #include #include #include +#include "fb_draw.h" #if BITS_PER_LONG == 32 # define FB_WRITEL fb_writel @@ -40,17 +39,6 @@ # define FB_READL fb_readq #endif - /* - * Compose two values, using a bitmask as decision value - * This is equivalent to (a & mask) | (b & ~mask) - */ - -static inline unsigned long -comp(unsigned long a, unsigned long b, unsigned long mask) -{ - return ((a ^ b) & mask) ^ b; -} - /* * Generic bitwise copy algorithm */ diff --git a/trunk/drivers/video/cfbfillrect.c b/trunk/drivers/video/cfbfillrect.c index f00b50aab606..71623b4f8ca2 100644 --- a/trunk/drivers/video/cfbfillrect.c +++ b/trunk/drivers/video/cfbfillrect.c @@ -21,6 +21,7 @@ #include #include #include +#include "fb_draw.h" #if BITS_PER_LONG == 32 # define FB_WRITEL fb_writel @@ -28,73 +29,6 @@ #else # define FB_WRITEL fb_writeq # define FB_READL fb_readq -#endif - - /* - * Compose two values, using a bitmask as decision value - * This is equivalent to (a & mask) | (b & ~mask) - */ - -static inline unsigned long -comp(unsigned long a, unsigned long b, unsigned long mask) -{ - return ((a ^ b) & mask) ^ b; -} - - /* - * Create a pattern with the given pixel's color - */ - -#if BITS_PER_LONG == 64 -static inline unsigned long -pixel_to_pat( u32 bpp, u32 pixel) -{ - switch (bpp) { - case 1: - return 0xfffffffffffffffful*pixel; - case 2: - return 0x5555555555555555ul*pixel; - case 4: - return 0x1111111111111111ul*pixel; - case 8: - return 0x0101010101010101ul*pixel; - case 12: - return 0x0001001001001001ul*pixel; - case 16: - return 0x0001000100010001ul*pixel; - case 24: - return 0x0000000001000001ul*pixel; - case 32: - return 0x0000000100000001ul*pixel; - default: - panic("pixel_to_pat(): unsupported pixelformat\n"); - } -} -#else -static inline unsigned long -pixel_to_pat( u32 bpp, u32 pixel) -{ - switch (bpp) { - case 1: - return 0xfffffffful*pixel; - case 2: - return 0x55555555ul*pixel; - case 4: - return 0x11111111ul*pixel; - case 8: - return 0x01010101ul*pixel; - case 12: - return 0x00001001ul*pixel; - case 16: - return 0x00010001ul*pixel; - case 24: - return 0x00000001ul*pixel; - case 32: - return 0x00000001ul*pixel; - default: - panic("pixel_to_pat(): unsupported pixelformat\n"); - } -} #endif /* diff --git a/trunk/drivers/video/cirrusfb.c b/trunk/drivers/video/cirrusfb.c index 2c4bc6205738..8269d704ab2a 100644 --- a/trunk/drivers/video/cirrusfb.c +++ b/trunk/drivers/video/cirrusfb.c @@ -98,15 +98,6 @@ #define assert(expr) #endif -#ifdef TRUE -#undef TRUE -#endif -#ifdef FALSE -#undef FALSE -#endif -#define TRUE 1 -#define FALSE 0 - #define MB_ (1024*1024) #define KB_ (1024) @@ -146,9 +137,9 @@ static const struct cirrusfb_board_info_rec { char *name; /* ASCII name of chipset */ long maxclock[5]; /* maximum video clock */ /* for 1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */ - unsigned init_sr07 : 1; /* init SR07 during init_vgachip() */ - unsigned init_sr1f : 1; /* write SR1F during init_vgachip() */ - unsigned scrn_start_bit19 : 1; /* construct bit 19 of screen start address */ + bool init_sr07 : 1; /* init SR07 during init_vgachip() */ + bool init_sr1f : 1; /* write SR1F during init_vgachip() */ + bool scrn_start_bit19 : 1; /* construct bit 19 of screen start address */ /* initial SR07 value, then for each mode */ unsigned char sr07; @@ -166,9 +157,9 @@ static const struct cirrusfb_board_info_rec { /* the SD64/P4 have a higher max. videoclock */ 140000, 140000, 140000, 140000, 140000, }, - .init_sr07 = TRUE, - .init_sr1f = TRUE, - .scrn_start_bit19 = TRUE, + .init_sr07 = true, + .init_sr1f = true, + .scrn_start_bit19 = true, .sr07 = 0xF0, .sr07_1bpp = 0xF0, .sr07_8bpp = 0xF1, @@ -180,9 +171,9 @@ static const struct cirrusfb_board_info_rec { /* guess */ 90000, 90000, 90000, 90000, 90000 }, - .init_sr07 = TRUE, - .init_sr1f = TRUE, - .scrn_start_bit19 = FALSE, + .init_sr07 = true, + .init_sr1f = true, + .scrn_start_bit19 = false, .sr07 = 0x80, .sr07_1bpp = 0x80, .sr07_8bpp = 0x81, @@ -194,9 +185,9 @@ static const struct cirrusfb_board_info_rec { /* guess */ 90000, 90000, 90000, 90000, 90000 }, - .init_sr07 = TRUE, - .init_sr1f = TRUE, - .scrn_start_bit19 = FALSE, + .init_sr07 = true, + .init_sr1f = true, + .scrn_start_bit19 = false, .sr07 = 0x20, .sr07_1bpp = 0x20, .sr07_8bpp = 0x21, @@ -208,9 +199,9 @@ static const struct cirrusfb_board_info_rec { /* guess */ 90000, 90000, 90000, 90000, 90000 }, - .init_sr07 = TRUE, - .init_sr1f = TRUE, - .scrn_start_bit19 = FALSE, + .init_sr07 = true, + .init_sr1f = true, + .scrn_start_bit19 = false, .sr07 = 0x80, .sr07_1bpp = 0x80, .sr07_8bpp = 0x81, @@ -221,9 +212,9 @@ static const struct cirrusfb_board_info_rec { .maxclock = { 135100, 135100, 85500, 85500, 0 }, - .init_sr07 = TRUE, - .init_sr1f = FALSE, - .scrn_start_bit19 = TRUE, + .init_sr07 = true, + .init_sr1f = false, + .scrn_start_bit19 = true, .sr07 = 0x20, .sr07_1bpp = 0x20, .sr07_8bpp = 0x21, @@ -235,9 +226,9 @@ static const struct cirrusfb_board_info_rec { /* for the GD5430. GD5446 can do more... */ 85500, 85500, 50000, 28500, 0 }, - .init_sr07 = TRUE, - .init_sr1f = TRUE, - .scrn_start_bit19 = TRUE, + .init_sr07 = true, + .init_sr1f = true, + .scrn_start_bit19 = true, .sr07 = 0xA0, .sr07_1bpp = 0xA1, .sr07_1bpp_mux = 0xA7, @@ -250,9 +241,9 @@ static const struct cirrusfb_board_info_rec { .maxclock = { 135100, 200000, 200000, 135100, 135100 }, - .init_sr07 = TRUE, - .init_sr1f = TRUE, - .scrn_start_bit19 = TRUE, + .init_sr07 = true, + .init_sr1f = true, + .scrn_start_bit19 = true, .sr07 = 0x10, .sr07_1bpp = 0x11, .sr07_8bpp = 0x11, @@ -264,9 +255,9 @@ static const struct cirrusfb_board_info_rec { /* guess */ 135100, 135100, 135100, 135100, 135100, }, - .init_sr07 = FALSE, - .init_sr1f = FALSE, - .scrn_start_bit19 = TRUE, + .init_sr07 = false, + .init_sr1f = false, + .scrn_start_bit19 = true, } }; @@ -815,7 +806,7 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, default: DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel); - assert (FALSE); + assert(false); /* should never occur */ break; } @@ -886,7 +877,7 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, default: DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel); - assert (FALSE); + assert(false); /* should never occur */ break; } @@ -3203,7 +3194,7 @@ void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_clas break; default: /* should never occur */ - assert (FALSE); + assert(false); break; } diff --git a/trunk/drivers/video/console/fbcon.c b/trunk/drivers/video/console/fbcon.c index 0429fd2cece0..73813c60d03a 100644 --- a/trunk/drivers/video/console/fbcon.c +++ b/trunk/drivers/video/console/fbcon.c @@ -107,7 +107,9 @@ static struct display fb_display[MAX_NR_CONSOLES]; static signed char con2fb_map[MAX_NR_CONSOLES]; static signed char con2fb_map_boot[MAX_NR_CONSOLES]; +#ifndef MODULE static int logo_height; +#endif static int logo_lines; /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO enums. */ @@ -576,6 +578,13 @@ static int fbcon_takeover(int show_logo) return err; } +#ifdef MODULE +static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, + int cols, int rows, int new_cols, int new_rows) +{ + logo_shown = FBCON_LOGO_DONTSHOW; +} +#else static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, int cols, int rows, int new_cols, int new_rows) { @@ -584,6 +593,11 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, int cnt, erase = vc->vc_video_erase_char, step; unsigned short *save = NULL, *r, *q; + if (info->flags & FBINFO_MODULE) { + logo_shown = FBCON_LOGO_DONTSHOW; + return; + } + /* * remove underline attribute from erase character * if black and white framebuffer. @@ -618,8 +632,13 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, r -= cols; } if (!save) { - vc->vc_y += logo_lines; - vc->vc_pos += logo_lines * vc->vc_size_row; + int lines; + if (vc->vc_y + logo_lines >= rows) + lines = rows - vc->vc_y - 1; + else + lines = logo_lines; + vc->vc_y += lines; + vc->vc_pos += lines * vc->vc_size_row; } } scr_memsetw((unsigned short *) vc->vc_origin, @@ -650,6 +669,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, vc->vc_top = logo_lines; } } +#endif /* MODULE */ #ifdef CONFIG_FB_TILEBLITTING static void set_blitting_type(struct vc_data *vc, struct fb_info *info) @@ -665,6 +685,17 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info) fbcon_set_bitops(ops); } } + +static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) +{ + int err = 0; + + if (info->flags & FBINFO_MISC_TILEBLITTING && + info->tileops->fb_get_tilemax(info) < charcount) + err = 1; + + return err; +} #else static void set_blitting_type(struct vc_data *vc, struct fb_info *info) { @@ -675,6 +706,12 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info) fbcon_set_rotation(info); fbcon_set_bitops(ops); } + +static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) +{ + return 0; +} + #endif /* CONFIG_MISC_TILEBLITTING */ @@ -968,7 +1005,9 @@ static const char *fbcon_startup(void) if (!p->fontdata) { if (!fontname[0] || !(font = find_font(fontname))) font = get_default_font(info->var.xres, - info->var.yres); + info->var.yres, + info->pixmap.blit_x, + info->pixmap.blit_y); vc->vc_font.width = font->width; vc->vc_font.height = font->height; vc->vc_font.data = (void *)(p->fontdata = font->data); @@ -1088,7 +1127,9 @@ static void fbcon_init(struct vc_data *vc, int init) if (!fontname[0] || !(font = find_font(fontname))) font = get_default_font(info->var.xres, - info->var.yres); + info->var.yres, + info->pixmap.blit_x, + info->pixmap.blit_y); vc->vc_font.width = font->width; vc->vc_font.height = font->height; vc->vc_font.data = (void *)(p->fontdata = font->data); @@ -1305,7 +1346,7 @@ static void fbcon_cursor(struct vc_data *vc, int mode) int y; int c = scr_readw((u16 *) vc->vc_pos); - if (fbcon_is_inactive(vc, info)) + if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) return; ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; @@ -2475,6 +2516,7 @@ static int fbcon_copy_font(struct vc_data *vc, int con) static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags) { + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; unsigned charcount = font->charcount; int w = font->width; int h = font->height; @@ -2488,6 +2530,15 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne if (charcount != 256 && charcount != 512) return -EINVAL; + /* Make sure drawing engine can handle the font */ + if (!(info->pixmap.blit_x & (1 << (font->width - 1))) || + !(info->pixmap.blit_y & (1 << (font->height - 1)))) + return -EINVAL; + + /* Make sure driver can handle the font length */ + if (fbcon_invalid_charcount(info, charcount)) + return -EINVAL; + size = h * pitch * charcount; new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER); @@ -2532,7 +2583,8 @@ static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, cha const struct font_desc *f; if (!name) - f = get_default_font(info->var.xres, info->var.yres); + f = get_default_font(info->var.xres, info->var.yres, + info->pixmap.blit_x, info->pixmap.blit_y); else if (!(f = find_font(name))) return -ENOENT; @@ -2829,7 +2881,7 @@ static void fbcon_set_all_vcs(struct fb_info *info) struct fbcon_ops *ops = info->fbcon_par; struct vc_data *vc; struct display *p; - int i, rows, cols; + int i, rows, cols, fg = -1; if (!ops || ops->currcon < 0) return; @@ -2840,34 +2892,23 @@ static void fbcon_set_all_vcs(struct fb_info *info) registered_fb[con2fb_map[i]] != info) continue; + if (CON_IS_VISIBLE(vc)) { + fg = i; + continue; + } + p = &fb_display[vc->vc_num]; set_blitting_type(vc, info); var_to_display(p, &info->var, info); - cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); - rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); + cols = FBCON_SWAP(p->rotate, info->var.xres, info->var.yres); + rows = FBCON_SWAP(p->rotate, info->var.yres, info->var.xres); cols /= vc->vc_font.width; rows /= vc->vc_font.height; vc_resize(vc, cols, rows); - - if (CON_IS_VISIBLE(vc)) { - updatescrollmode(p, info, vc); - scrollback_max = 0; - scrollback_current = 0; - - if (!fbcon_is_inactive(vc, info)) { - ops->var.xoffset = ops->var.yoffset = - p->yscroll = 0; - ops->update_start(info); - } - - fbcon_set_palette(vc, color_table); - update_screen(vc); - if (softback_buf) - fbcon_update_softback(vc); - } } - ops->p = &fb_display[ops->currcon]; + if (fg != -1) + fbcon_modechanged(info); } static int fbcon_mode_deleted(struct fb_info *info, @@ -3002,6 +3043,42 @@ static void fbcon_new_modelist(struct fb_info *info) } } +static void fbcon_get_requirement(struct fb_info *info, + struct fb_blit_caps *caps) +{ + struct vc_data *vc; + struct display *p; + + if (caps->flags) { + int i, charcnt; + + for (i = first_fb_vc; i <= last_fb_vc; i++) { + vc = vc_cons[i].d; + if (vc && vc->vc_mode == KD_TEXT && + info->node == con2fb_map[i]) { + p = &fb_display[i]; + caps->x |= 1 << (vc->vc_font.width - 1); + caps->y |= 1 << (vc->vc_font.height - 1); + charcnt = (p->userfont) ? + FNTCHARCNT(p->fontdata) : 256; + if (caps->len < charcnt) + caps->len = charcnt; + } + } + } else { + vc = vc_cons[fg_console].d; + + if (vc && vc->vc_mode == KD_TEXT && + info->node == con2fb_map[fg_console]) { + p = &fb_display[fg_console]; + caps->x = 1 << (vc->vc_font.width - 1); + caps->y = 1 << (vc->vc_font.height - 1); + caps->len = (p->userfont) ? + FNTCHARCNT(p->fontdata) : 256; + } + } +} + static int fbcon_event_notify(struct notifier_block *self, unsigned long action, void *data) { @@ -3009,6 +3086,7 @@ static int fbcon_event_notify(struct notifier_block *self, struct fb_info *info = event->info; struct fb_videomode *mode; struct fb_con2fbmap *con2fb; + struct fb_blit_caps *caps; int ret = 0; /* @@ -3057,6 +3135,10 @@ static int fbcon_event_notify(struct notifier_block *self, case FB_EVENT_NEW_MODELIST: fbcon_new_modelist(info); break; + case FB_EVENT_GET_REQ: + caps = event->data; + fbcon_get_requirement(info, caps); + break; } done: diff --git a/trunk/drivers/video/console/fonts.c b/trunk/drivers/video/console/fonts.c index c960728b7e82..a6828d0a4c56 100644 --- a/trunk/drivers/video/console/fonts.c +++ b/trunk/drivers/video/console/fonts.c @@ -98,6 +98,8 @@ const struct font_desc *find_font(const char *name) * get_default_font - get default font * @xres: screen size of X * @yres: screen size of Y + * @font_w: bit array of supported widths (1 - 32) + * @font_h: bit array of supported heights (1 - 32) * * Get the default font for a specified screen size. * Dimensions are in pixels. @@ -107,7 +109,8 @@ const struct font_desc *find_font(const char *name) * */ -const struct font_desc *get_default_font(int xres, int yres) +const struct font_desc *get_default_font(int xres, int yres, u32 font_w, + u32 font_h) { int i, c, cc; const struct font_desc *f, *g; @@ -129,6 +132,11 @@ const struct font_desc *get_default_font(int xres, int yres) #endif if ((yres < 400) == (f->height <= 8)) c += 1000; + + if (!(font_w & (1 << (f->width - 1))) || + !(font_w & (1 << (f->height - 1)))) + c += 1000; + if (c > cc) { cc = c; g = f; diff --git a/trunk/drivers/video/console/mdacon.c b/trunk/drivers/video/console/mdacon.c index 124ecbe6f88c..bd8d995fe25d 100644 --- a/trunk/drivers/video/console/mdacon.c +++ b/trunk/drivers/video/console/mdacon.c @@ -384,7 +384,7 @@ static inline u16 mda_convert_attr(u16 ch) } static u8 mdacon_build_attr(struct vc_data *c, u8 color, u8 intensity, - u8 blink, u8 underline, u8 reverse) + u8 blink, u8 underline, u8 reverse, u8 italic) { /* The attribute is just a bit vector: * @@ -397,6 +397,7 @@ static u8 mdacon_build_attr(struct vc_data *c, u8 color, u8 intensity, return (intensity & 3) | ((underline & 1) << 2) | ((reverse & 1) << 3) | + (!!italic << 4) | ((blink & 1) << 7); } diff --git a/trunk/drivers/video/console/promcon.c b/trunk/drivers/video/console/promcon.c index b78eac63459f..ae02e4eb18e7 100644 --- a/trunk/drivers/video/console/promcon.c +++ b/trunk/drivers/video/console/promcon.c @@ -548,7 +548,8 @@ promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) } #if !(PROMCON_COLOR) -static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) +static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, + u8 _blink, u8 _underline, u8 _reverse, u8 _italic) { return (_reverse) ? 0xf : 0x7; } diff --git a/trunk/drivers/video/console/sticon.c b/trunk/drivers/video/console/sticon.c index 57b21e533036..67a682d6cc7b 100644 --- a/trunk/drivers/video/console/sticon.c +++ b/trunk/drivers/video/console/sticon.c @@ -314,7 +314,7 @@ static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos, } static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, - u8 blink, u8 underline, u8 reverse) + u8 blink, u8 underline, u8 reverse, u8 italic) { u8 attr = ((color & 0x70) >> 1) | ((color & 7)); diff --git a/trunk/drivers/video/console/sticore.c b/trunk/drivers/video/console/sticore.c index 88e7038eab88..717b360d0415 100644 --- a/trunk/drivers/video/console/sticore.c +++ b/trunk/drivers/video/console/sticore.c @@ -495,7 +495,7 @@ sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) return NULL; fbfont = find_font(fbfont_name); if (!fbfont) - fbfont = get_default_font(1024,768); + fbfont = get_default_font(1024,768, ~(u32)0, ~(u32)0); if (!fbfont) return NULL; diff --git a/trunk/drivers/video/console/vgacon.c b/trunk/drivers/video/console/vgacon.c index 3e67c34df9a5..2460b82a1d93 100644 --- a/trunk/drivers/video/console/vgacon.c +++ b/trunk/drivers/video/console/vgacon.c @@ -86,8 +86,6 @@ static int vgacon_set_origin(struct vc_data *c); static void vgacon_save_screen(struct vc_data *c); static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines); -static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, - u8 blink, u8 underline, u8 reverse); static void vgacon_invert_region(struct vc_data *c, u16 * p, int count); static unsigned long vgacon_uni_pagedir[2]; @@ -578,12 +576,14 @@ static void vgacon_deinit(struct vc_data *c) } static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, - u8 blink, u8 underline, u8 reverse) + u8 blink, u8 underline, u8 reverse, u8 italic) { u8 attr = color; if (vga_can_do_color) { - if (underline) + if (italic) + attr = (attr & 0xF0) | c->vc_itcolor; + else if (underline) attr = (attr & 0xf0) | c->vc_ulcolor; else if (intensity == 0) attr = (attr & 0xf0) | c->vc_halfcolor; @@ -597,7 +597,9 @@ static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, if (intensity == 2) attr ^= 0x08; if (!vga_can_do_color) { - if (underline) + if (italic) + attr = (attr & 0xF8) | 0x02; + else if (underline) attr = (attr & 0xf8) | 0x01; else if (intensity == 0) attr = (attr & 0xf0) | 0x08; @@ -658,6 +660,9 @@ static void vgacon_set_cursor_size(int xpos, int from, int to) static void vgacon_cursor(struct vc_data *c, int mode) { + if (c->vc_mode != KD_TEXT) + return; + vgacon_restore_screen(c); switch (mode) { @@ -1316,7 +1321,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, unsigned long oldo; unsigned int delta; - if (t || b != c->vc_rows || vga_is_gfx) + if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT) return 0; if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2) diff --git a/trunk/drivers/video/display/Kconfig b/trunk/drivers/video/display/Kconfig new file mode 100644 index 000000000000..f99af931d4f8 --- /dev/null +++ b/trunk/drivers/video/display/Kconfig @@ -0,0 +1,24 @@ +# +# Display drivers configuration +# + +menu "Display device support" + +config DISPLAY_SUPPORT + tristate "Display panel/monitor support" + ---help--- + This framework adds support for low-level control of a display. + This includes support for power. + + Enable this to be able to choose the drivers for controlling the + physical display panel/monitor on some platforms. This not only + covers LCD displays for PDAs but also other types of displays + such as CRT, TVout etc. + + To have support for your specific display panel you will have to + select the proper drivers which depend on this option. + +comment "Display hardware drivers" + depends on DISPLAY_SUPPORT + +endmenu diff --git a/trunk/drivers/video/display/Makefile b/trunk/drivers/video/display/Makefile new file mode 100644 index 000000000000..c0ea832bf171 --- /dev/null +++ b/trunk/drivers/video/display/Makefile @@ -0,0 +1,6 @@ +# Display drivers + +display-objs := display-sysfs.o + +obj-$(CONFIG_DISPLAY_SUPPORT) += display.o + diff --git a/trunk/drivers/video/display/display-sysfs.c b/trunk/drivers/video/display/display-sysfs.c new file mode 100644 index 000000000000..35477177bef4 --- /dev/null +++ b/trunk/drivers/video/display/display-sysfs.c @@ -0,0 +1,217 @@ +/* + * display-sysfs.c - Display output driver sysfs interface + * + * Copyright (C) 2007 James Simmons + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 +#include +#include +#include +#include + +static ssize_t display_show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct display_device *dsp = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name); +} + +static ssize_t display_show_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct display_device *dsp = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type); +} + +static ssize_t display_show_contrast(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct display_device *dsp = dev_get_drvdata(dev); + ssize_t rc = -ENXIO; + + mutex_lock(&dsp->lock); + if (likely(dsp->driver) && dsp->driver->get_contrast) + rc = sprintf(buf, "%d\n", dsp->driver->get_contrast(dsp)); + mutex_unlock(&dsp->lock); + return rc; +} + +static ssize_t display_store_contrast(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct display_device *dsp = dev_get_drvdata(dev); + ssize_t ret = -EINVAL, size; + int contrast; + char *endp; + + contrast = simple_strtoul(buf, &endp, 0); + size = endp - buf; + + if (*endp && isspace(*endp)) + size++; + + if (size != count) + return ret; + + mutex_lock(&dsp->lock); + if (likely(dsp->driver && dsp->driver->set_contrast)) { + pr_debug("display: set contrast to %d\n", contrast); + dsp->driver->set_contrast(dsp, contrast); + ret = count; + } + mutex_unlock(&dsp->lock); + return ret; +} + +static ssize_t display_show_max_contrast(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct display_device *dsp = dev_get_drvdata(dev); + ssize_t rc = -ENXIO; + + mutex_lock(&dsp->lock); + if (likely(dsp->driver)) + rc = sprintf(buf, "%d\n", dsp->driver->max_contrast); + mutex_unlock(&dsp->lock); + return rc; +} + +static struct device_attribute display_attrs[] = { + __ATTR(name, S_IRUGO, display_show_name, NULL), + __ATTR(type, S_IRUGO, display_show_type, NULL), + __ATTR(contrast, S_IRUGO | S_IWUSR, display_show_contrast, display_store_contrast), + __ATTR(max_contrast, S_IRUGO, display_show_max_contrast, NULL), +}; + +static int display_suspend(struct device *dev, pm_message_t state) +{ + struct display_device *dsp = dev_get_drvdata(dev); + + mutex_lock(&dsp->lock); + if (likely(dsp->driver->suspend)) + dsp->driver->suspend(dsp, state); + mutex_unlock(&dsp->lock); + return 0; +}; + +static int display_resume(struct device *dev) +{ + struct display_device *dsp = dev_get_drvdata(dev); + + mutex_lock(&dsp->lock); + if (likely(dsp->driver->resume)) + dsp->driver->resume(dsp); + mutex_unlock(&dsp->lock); + return 0; +}; + +static struct mutex allocated_dsp_lock; +static DEFINE_IDR(allocated_dsp); +static struct class *display_class; + +struct display_device *display_device_register(struct display_driver *driver, + struct device *parent, void *devdata) +{ + struct display_device *new_dev = NULL; + int ret = -EINVAL; + + if (unlikely(!driver)) + return ERR_PTR(ret); + + mutex_lock(&allocated_dsp_lock); + ret = idr_pre_get(&allocated_dsp, GFP_KERNEL); + mutex_unlock(&allocated_dsp_lock); + if (!ret) + return ERR_PTR(ret); + + new_dev = kzalloc(sizeof(struct display_device), GFP_KERNEL); + if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) { + // Reserve the index for this display + mutex_lock(&allocated_dsp_lock); + ret = idr_get_new(&allocated_dsp, new_dev, &new_dev->idx); + mutex_unlock(&allocated_dsp_lock); + + if (!ret) { + new_dev->dev = device_create(display_class, parent, 0, + "display%d", new_dev->idx); + if (!IS_ERR(new_dev->dev)) { + dev_set_drvdata(new_dev->dev, new_dev); + new_dev->parent = parent; + new_dev->driver = driver; + mutex_init(&new_dev->lock); + return new_dev; + } + mutex_lock(&allocated_dsp_lock); + idr_remove(&allocated_dsp, new_dev->idx); + mutex_unlock(&allocated_dsp_lock); + ret = -EINVAL; + } + } + kfree(new_dev); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(display_device_register); + +void display_device_unregister(struct display_device *ddev) +{ + if (!ddev) + return; + // Free device + mutex_lock(&ddev->lock); + device_unregister(ddev->dev); + mutex_unlock(&ddev->lock); + // Mark device index as avaliable + mutex_lock(&allocated_dsp_lock); + idr_remove(&allocated_dsp, ddev->idx); + mutex_unlock(&allocated_dsp_lock); + kfree(ddev); +} +EXPORT_SYMBOL(display_device_unregister); + +static int __init display_class_init(void) +{ + display_class = class_create(THIS_MODULE, "display"); + if (IS_ERR(display_class)) { + printk(KERN_ERR "Failed to create display class\n"); + display_class = NULL; + return -EINVAL; + } + display_class->dev_attrs = display_attrs; + display_class->suspend = display_suspend; + display_class->resume = display_resume; + mutex_init(&allocated_dsp_lock); + return 0; +} + +static void __exit display_class_exit(void) +{ + class_destroy(display_class); +} + +module_init(display_class_init); +module_exit(display_class_exit); + +MODULE_DESCRIPTION("Display Hardware handling"); +MODULE_AUTHOR("James Simmons "); +MODULE_LICENSE("GPL"); + diff --git a/trunk/drivers/video/epson1355fb.c b/trunk/drivers/video/epson1355fb.c index 29e07c109887..ca2c54ce508e 100644 --- a/trunk/drivers/video/epson1355fb.c +++ b/trunk/drivers/video/epson1355fb.c @@ -403,17 +403,10 @@ static inline unsigned long copy_to_user16(void *to, const void *from, static ssize_t -epson1355fb_read(struct file *file, char *buf, size_t count, loff_t * ppos) +epson1355fb_read(struct fb_info *info, char *buf, size_t count, loff_t * ppos) { - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; unsigned long p = *ppos; - /* from fbmem.c except for our own copy_*_user */ - if (!info || !info->screen_base) - return -ENODEV; - if (p >= info->fix.smem_len) return 0; if (count >= info->fix.smem_len) @@ -434,19 +427,12 @@ epson1355fb_read(struct file *file, char *buf, size_t count, loff_t * ppos) } static ssize_t -epson1355fb_write(struct file *file, const char *buf, +epson1355fb_write(struct fb_info *info, const char *buf, size_t count, loff_t * ppos) { - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; unsigned long p = *ppos; int err; - /* from fbmem.c except for our own copy_*_user */ - if (!info || !info->screen_base) - return -ENODEV; - /* from fbmem.c except for our own copy_*_user */ if (p > info->fix.smem_len) return -ENOSPC; @@ -650,9 +636,10 @@ int __init epson1355fb_probe(struct platform_device *dev) } info = framebuffer_alloc(sizeof(struct epson1355_par) + sizeof(u32) * 256, &dev->dev); - if (!info) + if (!info) { rc = -ENOMEM; goto bail; + } default_par = info->par; default_par->reg_addr = (unsigned long) ioremap(EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN); diff --git a/trunk/drivers/video/fb_defio.c b/trunk/drivers/video/fb_defio.c new file mode 100644 index 000000000000..1a8643f053d8 --- /dev/null +++ b/trunk/drivers/video/fb_defio.c @@ -0,0 +1,151 @@ +/* + * linux/drivers/video/fb_defio.c + * + * Copyright (C) 2006 Jaya Kumar + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* to support deferred IO */ +#include +#include + +/* this is to find and return the vmalloc-ed fb pages */ +static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma, + unsigned long vaddr, int *type) +{ + unsigned long offset; + struct page *page; + struct fb_info *info = vma->vm_private_data; + /* info->screen_base is in System RAM */ + void *screen_base = (void __force *) info->screen_base; + + offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); + if (offset >= info->fix.smem_len) + return NOPAGE_SIGBUS; + + page = vmalloc_to_page(screen_base + offset); + if (!page) + return NOPAGE_OOM; + + get_page(page); + if (type) + *type = VM_FAULT_MINOR; + return page; +} + +int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + struct fb_info *info = file->private_data; + + /* Kill off the delayed work */ + cancel_rearming_delayed_work(&info->deferred_work); + + /* Run it immediately */ + return schedule_delayed_work(&info->deferred_work, 0); +} +EXPORT_SYMBOL_GPL(fb_deferred_io_fsync); + +/* vm_ops->page_mkwrite handler */ +static int fb_deferred_io_mkwrite(struct vm_area_struct *vma, + struct page *page) +{ + struct fb_info *info = vma->vm_private_data; + struct fb_deferred_io *fbdefio = info->fbdefio; + + /* this is a callback we get when userspace first tries to + write to the page. we schedule a workqueue. that workqueue + will eventually mkclean the touched pages and execute the + deferred framebuffer IO. then if userspace touches a page + again, we repeat the same scheme */ + + /* protect against the workqueue changing the page list */ + mutex_lock(&fbdefio->lock); + list_add(&page->lru, &fbdefio->pagelist); + mutex_unlock(&fbdefio->lock); + + /* come back after delay to process the deferred IO */ + schedule_delayed_work(&info->deferred_work, fbdefio->delay); + return 0; +} + +static struct vm_operations_struct fb_deferred_io_vm_ops = { + .nopage = fb_deferred_io_nopage, + .page_mkwrite = fb_deferred_io_mkwrite, +}; + +static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + vma->vm_ops = &fb_deferred_io_vm_ops; + vma->vm_flags |= ( VM_IO | VM_RESERVED | VM_DONTEXPAND ); + vma->vm_private_data = info; + return 0; +} + +/* workqueue callback */ +static void fb_deferred_io_work(struct work_struct *work) +{ + struct fb_info *info = container_of(work, struct fb_info, + deferred_work.work); + struct list_head *node, *next; + struct page *cur; + struct fb_deferred_io *fbdefio = info->fbdefio; + + /* here we mkclean the pages, then do all deferred IO */ + mutex_lock(&fbdefio->lock); + list_for_each_entry(cur, &fbdefio->pagelist, lru) { + lock_page(cur); + page_mkclean(cur); + unlock_page(cur); + } + + /* driver's callback with pagelist */ + fbdefio->deferred_io(info, &fbdefio->pagelist); + + /* clear the list */ + list_for_each_safe(node, next, &fbdefio->pagelist) { + list_del(node); + } + mutex_unlock(&fbdefio->lock); +} + +void fb_deferred_io_init(struct fb_info *info) +{ + struct fb_deferred_io *fbdefio = info->fbdefio; + + BUG_ON(!fbdefio); + mutex_init(&fbdefio->lock); + info->fbops->fb_mmap = fb_deferred_io_mmap; + INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work); + INIT_LIST_HEAD(&fbdefio->pagelist); + if (fbdefio->delay == 0) /* set a default of 1 s */ + fbdefio->delay = HZ; +} +EXPORT_SYMBOL_GPL(fb_deferred_io_init); + +void fb_deferred_io_cleanup(struct fb_info *info) +{ + struct fb_deferred_io *fbdefio = info->fbdefio; + + BUG_ON(!fbdefio); + cancel_delayed_work(&info->deferred_work); + flush_scheduled_work(); +} +EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup); + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/fb_draw.h b/trunk/drivers/video/fb_draw.h new file mode 100644 index 000000000000..c5c45203833b --- /dev/null +++ b/trunk/drivers/video/fb_draw.h @@ -0,0 +1,72 @@ +#ifndef _FB_DRAW_H +#define _FB_DRAW_H + +#include + + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ + +static inline unsigned long +comp(unsigned long a, unsigned long b, unsigned long mask) +{ + return ((a ^ b) & mask) ^ b; +} + + /* + * Create a pattern with the given pixel's color + */ + +#if BITS_PER_LONG == 64 +static inline unsigned long +pixel_to_pat( u32 bpp, u32 pixel) +{ + switch (bpp) { + case 1: + return 0xfffffffffffffffful*pixel; + case 2: + return 0x5555555555555555ul*pixel; + case 4: + return 0x1111111111111111ul*pixel; + case 8: + return 0x0101010101010101ul*pixel; + case 12: + return 0x0001001001001001ul*pixel; + case 16: + return 0x0001000100010001ul*pixel; + case 24: + return 0x0000000001000001ul*pixel; + case 32: + return 0x0000000100000001ul*pixel; + default: + panic("pixel_to_pat(): unsupported pixelformat\n"); + } +} +#else +static inline unsigned long +pixel_to_pat( u32 bpp, u32 pixel) +{ + switch (bpp) { + case 1: + return 0xfffffffful*pixel; + case 2: + return 0x55555555ul*pixel; + case 4: + return 0x11111111ul*pixel; + case 8: + return 0x01010101ul*pixel; + case 12: + return 0x00001001ul*pixel; + case 16: + return 0x00010001ul*pixel; + case 24: + return 0x00000001ul*pixel; + case 32: + return 0x00000001ul*pixel; + default: + panic("pixel_to_pat(): unsupported pixelformat\n"); + } +} +#endif +#endif /* FB_DRAW_H */ diff --git a/trunk/drivers/video/fb_sys_fops.c b/trunk/drivers/video/fb_sys_fops.c new file mode 100644 index 000000000000..cf2538d669cd --- /dev/null +++ b/trunk/drivers/video/fb_sys_fops.c @@ -0,0 +1,104 @@ +/* + * linux/drivers/video/fb_sys_read.c - Generic file operations where + * framebuffer is in system RAM + * + * Copyright (C) 2007 Antonino Daplas + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ +#include +#include +#include + +ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count, + loff_t *ppos) +{ + unsigned long p = *ppos; + void *src; + int err = 0; + unsigned long total_size; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p >= total_size) + return 0; + + if (count >= total_size) + count = total_size; + + if (count + p > total_size) + count = total_size - p; + + src = (void __force *)(info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + if (copy_to_user(buf, src, count)) + err = -EFAULT; + + if (!err) + *ppos += count; + + return (err) ? err : count; +} +EXPORT_SYMBOL_GPL(fb_sys_read); + +ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + void *dst; + int err = 0; + unsigned long total_size; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; + } + + if (count + p > total_size) { + if (!err) + err = -ENOSPC; + + count = total_size - p; + } + + dst = (void __force *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + if (copy_from_user(dst, buf, count)) + err = -EFAULT; + + if (!err) + *ppos += count; + + return (err) ? err : count; +} +EXPORT_SYMBOL_GPL(fb_sys_write); + +MODULE_AUTHOR("Antonino Daplas "); +MODULE_DESCRIPTION("Generic file read (fb in system RAM)"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/fbmem.c b/trunk/drivers/video/fbmem.c index 28225265159a..08d4e11d9121 100644 --- a/trunk/drivers/video/fbmem.c +++ b/trunk/drivers/video/fbmem.c @@ -354,59 +354,59 @@ static void fb_rotate_logo(struct fb_info *info, u8 *dst, if (rotate == FB_ROTATE_UD) { fb_rotate_logo_ud(image->data, dst, image->width, image->height); - image->dx = info->var.xres - image->width; - image->dy = info->var.yres - image->height; + image->dx = info->var.xres - image->width - image->dx; + image->dy = info->var.yres - image->height - image->dy; } else if (rotate == FB_ROTATE_CW) { fb_rotate_logo_cw(image->data, dst, image->width, image->height); tmp = image->width; image->width = image->height; image->height = tmp; - image->dx = info->var.xres - image->width; + tmp = image->dy; + image->dy = image->dx; + image->dx = info->var.xres - image->width - tmp; } else if (rotate == FB_ROTATE_CCW) { fb_rotate_logo_ccw(image->data, dst, image->width, image->height); tmp = image->width; image->width = image->height; image->height = tmp; - image->dy = info->var.yres - image->height; + tmp = image->dx; + image->dx = image->dy; + image->dy = info->var.yres - image->height - tmp; } image->data = dst; } static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, - int rotate) + int rotate, unsigned int num) { - int x; + unsigned int x; if (rotate == FB_ROTATE_UR) { - for (x = 0; x < num_online_cpus() && - x * (fb_logo.logo->width + 8) <= - info->var.xres - fb_logo.logo->width; x++) { + for (x = 0; + x < num && image->dx + image->width <= info->var.xres; + x++) { info->fbops->fb_imageblit(info, image); - image->dx += fb_logo.logo->width + 8; + image->dx += image->width + 8; } } else if (rotate == FB_ROTATE_UD) { - for (x = 0; x < num_online_cpus() && - x * (fb_logo.logo->width + 8) <= - info->var.xres - fb_logo.logo->width; x++) { + for (x = 0; x < num && image->dx >= 0; x++) { info->fbops->fb_imageblit(info, image); - image->dx -= fb_logo.logo->width + 8; + image->dx -= image->width + 8; } } else if (rotate == FB_ROTATE_CW) { - for (x = 0; x < num_online_cpus() && - x * (fb_logo.logo->width + 8) <= - info->var.yres - fb_logo.logo->width; x++) { + for (x = 0; + x < num && image->dy + image->height <= info->var.yres; + x++) { info->fbops->fb_imageblit(info, image); - image->dy += fb_logo.logo->width + 8; + image->dy += image->height + 8; } } else if (rotate == FB_ROTATE_CCW) { - for (x = 0; x < num_online_cpus() && - x * (fb_logo.logo->width + 8) <= - info->var.yres - fb_logo.logo->width; x++) { + for (x = 0; x < num && image->dy >= 0; x++) { info->fbops->fb_imageblit(info, image); - image->dy -= fb_logo.logo->width + 8; + image->dy -= image->height + 8; } } } @@ -418,7 +418,8 @@ int fb_prepare_logo(struct fb_info *info, int rotate) memset(&fb_logo, 0, sizeof(struct logo_data)); - if (info->flags & FBINFO_MISC_TILEBLITTING) + if (info->flags & FBINFO_MISC_TILEBLITTING || + info->flags & FBINFO_MODULE) return 0; if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { @@ -483,7 +484,8 @@ int fb_show_logo(struct fb_info *info, int rotate) struct fb_image image; /* Return if the frame buffer is not mapped or suspended */ - if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING) + if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING || + info->flags & FBINFO_MODULE) return 0; image.depth = 8; @@ -532,7 +534,7 @@ int fb_show_logo(struct fb_info *info, int rotate) fb_rotate_logo(info, logo_rotate, &image, rotate); } - fb_do_show_logo(info, &image, rotate); + fb_do_show_logo(info, &image, rotate, num_online_cpus()); kfree(palette); if (saved_pseudo_palette != NULL) @@ -586,7 +588,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) return -EPERM; if (info->fbops->fb_read) - return info->fbops->fb_read(file, buf, count, ppos); + return info->fbops->fb_read(info, buf, count, ppos); total_size = info->screen_size; @@ -661,7 +663,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) return -EPERM; if (info->fbops->fb_write) - return info->fbops->fb_write(file, buf, count, ppos); + return info->fbops->fb_write(info, buf, count, ppos); total_size = info->screen_size; @@ -771,14 +773,37 @@ fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) return 0; } +static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, + u32 activate) +{ + struct fb_event event; + struct fb_blit_caps caps, fbcaps; + int err = 0; + + memset(&caps, 0, sizeof(caps)); + memset(&fbcaps, 0, sizeof(fbcaps)); + caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0; + event.info = info; + event.data = ∩︀ + fb_notifier_call_chain(FB_EVENT_GET_REQ, &event); + info->fbops->fb_get_caps(info, &fbcaps, var); + + if (((fbcaps.x ^ caps.x) & caps.x) || + ((fbcaps.y ^ caps.y) & caps.y) || + (fbcaps.len < caps.len)) + err = -EINVAL; + + return err; +} + int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) { - int err, flags = info->flags; + int flags = info->flags; + int ret = 0; if (var->activate & FB_ACTIVATE_INV_MODE) { struct fb_videomode mode1, mode2; - int ret = 0; fb_var_to_videomode(&mode1, var); fb_var_to_videomode(&mode2, &info->var); @@ -796,40 +821,51 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) if (!ret) fb_delete_videomode(&mode1, &info->modelist); - return ret; + + ret = (ret) ? -EINVAL : 0; + goto done; } if ((var->activate & FB_ACTIVATE_FORCE) || memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { + u32 activate = var->activate; + if (!info->fbops->fb_check_var) { *var = info->var; - return 0; + goto done; } - if ((err = info->fbops->fb_check_var(var, info))) - return err; + ret = info->fbops->fb_check_var(var, info); + + if (ret) + goto done; if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { struct fb_videomode mode; - int err = 0; + + if (info->fbops->fb_get_caps) { + ret = fb_check_caps(info, var, activate); + + if (ret) + goto done; + } info->var = *var; + if (info->fbops->fb_set_par) info->fbops->fb_set_par(info); fb_pan_display(info, &info->var); - fb_set_cmap(&info->cmap, info); - fb_var_to_videomode(&mode, &info->var); if (info->modelist.prev && info->modelist.next && !list_empty(&info->modelist)) - err = fb_add_videomode(&mode, &info->modelist); + ret = fb_add_videomode(&mode, &info->modelist); - if (!err && (flags & FBINFO_MISC_USEREVENT)) { + if (!ret && (flags & FBINFO_MISC_USEREVENT)) { struct fb_event event; - int evnt = (var->activate & FB_ACTIVATE_ALL) ? + int evnt = (activate & FB_ACTIVATE_ALL) ? FB_EVENT_MODE_CHANGE_ALL : FB_EVENT_MODE_CHANGE; @@ -839,7 +875,9 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) } } } - return 0; + + done: + return ret; } int @@ -1266,6 +1304,9 @@ static const struct file_operations fb_fops = { #ifdef HAVE_ARCH_FB_UNMAPPED_AREA .get_unmapped_area = get_fb_unmapped_area, #endif +#ifdef CONFIG_FB_DEFERRED_IO + .fsync = fb_deferred_io_fsync, +#endif }; struct class *fb_class; @@ -1316,6 +1357,12 @@ register_framebuffer(struct fb_info *fb_info) } fb_info->pixmap.offset = 0; + if (!fb_info->pixmap.blit_x) + fb_info->pixmap.blit_x = ~(u32)0; + + if (!fb_info->pixmap.blit_y) + fb_info->pixmap.blit_y = ~(u32)0; + if (!fb_info->modelist.prev || !fb_info->modelist.next) INIT_LIST_HEAD(&fb_info->modelist); diff --git a/trunk/drivers/video/fbmon.c b/trunk/drivers/video/fbmon.c index 6b385c39b8b5..438b9411905c 100644 --- a/trunk/drivers/video/fbmon.c +++ b/trunk/drivers/video/fbmon.c @@ -48,8 +48,9 @@ #define DPRINTK(fmt, args...) #endif -#define FBMON_FIX_HEADER 1 -#define FBMON_FIX_INPUT 2 +#define FBMON_FIX_HEADER 1 +#define FBMON_FIX_INPUT 2 +#define FBMON_FIX_TIMINGS 3 #ifdef CONFIG_FB_MODE_HELPERS struct broken_edid { @@ -71,6 +72,12 @@ static const struct broken_edid brokendb[] = { .model = 0x5a44, .fix = FBMON_FIX_INPUT, }, + /* Sharp UXGA? */ + { + .manufacturer = "SHP", + .model = 0x138e, + .fix = FBMON_FIX_TIMINGS, + }, }; static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, @@ -87,6 +94,55 @@ static void copy_string(unsigned char *c, unsigned char *s) while (i-- && (*--s == 0x20)) *s = 0; } +static int edid_is_serial_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xff) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static int edid_is_ascii_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xfe) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static int edid_is_limits_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xfd) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static int edid_is_monitor_block(unsigned char *block) +{ + if ((block[0] == 0x00) && (block[1] == 0x00) && + (block[2] == 0x00) && (block[3] == 0xfc) && + (block[4] == 0x00)) + return 1; + else + return 0; +} + +static int edid_is_timing_block(unsigned char *block) +{ + if ((block[0] != 0x00) || (block[1] != 0x00) || + (block[2] != 0x00) || (block[4] != 0x00)) + return 1; + else + return 0; +} + static int check_edid(unsigned char *edid) { unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4]; @@ -104,9 +160,6 @@ static int check_edid(unsigned char *edid) for (i = 0; i < ARRAY_SIZE(brokendb); i++) { if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) && brokendb[i].model == model) { - printk("fbmon: The EDID Block of " - "Manufacturer: %s Model: 0x%x is known to " - "be broken,\n", manufacturer, model); fix = brokendb[i].fix; break; } @@ -115,8 +168,10 @@ static int check_edid(unsigned char *edid) switch (fix) { case FBMON_FIX_HEADER: for (i = 0; i < 8; i++) { - if (edid[i] != edid_v1_header[i]) + if (edid[i] != edid_v1_header[i]) { ret = fix; + break; + } } break; case FBMON_FIX_INPUT: @@ -126,14 +181,34 @@ static int check_edid(unsigned char *edid) if (b[4] & 0x01 && b[0] & 0x80) ret = fix; break; + case FBMON_FIX_TIMINGS: + b = edid + DETAILED_TIMING_DESCRIPTIONS_START; + ret = fix; + + for (i = 0; i < 4; i++) { + if (edid_is_limits_block(b)) { + ret = 0; + break; + } + + b += DETAILED_TIMING_DESCRIPTION_SIZE; + } + + break; } + if (ret) + printk("fbmon: The EDID Block of " + "Manufacturer: %s Model: 0x%x is known to " + "be broken,\n", manufacturer, model); + return ret; } static void fix_edid(unsigned char *edid, int fix) { - unsigned char *b; + int i; + unsigned char *b, csum = 0; switch (fix) { case FBMON_FIX_HEADER: @@ -145,6 +220,37 @@ static void fix_edid(unsigned char *edid, int fix) b = edid + EDID_STRUCT_DISPLAY; b[0] &= ~0x80; edid[127] += 0x80; + break; + case FBMON_FIX_TIMINGS: + printk("fbmon: trying to fix monitor timings\n"); + b = edid + DETAILED_TIMING_DESCRIPTIONS_START; + for (i = 0; i < 4; i++) { + if (!(edid_is_serial_block(b) || + edid_is_ascii_block(b) || + edid_is_monitor_block(b) || + edid_is_timing_block(b))) { + b[0] = 0x00; + b[1] = 0x00; + b[2] = 0x00; + b[3] = 0xfd; + b[4] = 0x00; + b[5] = 60; /* vfmin */ + b[6] = 60; /* vfmax */ + b[7] = 30; /* hfmin */ + b[8] = 75; /* hfmax */ + b[9] = 17; /* pixclock - 170 MHz*/ + b[10] = 0; /* GTF */ + break; + } + + b += DETAILED_TIMING_DESCRIPTION_SIZE; + } + + for (i = 0; i < EDID_LENGTH - 1; i++) + csum += edid[i]; + + edid[127] = 256 - csum; + break; } } @@ -273,46 +379,6 @@ static void get_chroma(unsigned char *block, struct fb_monspecs *specs) DPRINTK("WhiteY: 0.%03d\n", specs->chroma.whitey); } -static int edid_is_serial_block(unsigned char *block) -{ - if ((block[0] == 0x00) && (block[1] == 0x00) && - (block[2] == 0x00) && (block[3] == 0xff) && - (block[4] == 0x00)) - return 1; - else - return 0; -} - -static int edid_is_ascii_block(unsigned char *block) -{ - if ((block[0] == 0x00) && (block[1] == 0x00) && - (block[2] == 0x00) && (block[3] == 0xfe) && - (block[4] == 0x00)) - return 1; - else - return 0; -} - -static int edid_is_limits_block(unsigned char *block) -{ - if ((block[0] == 0x00) && (block[1] == 0x00) && - (block[2] == 0x00) && (block[3] == 0xfd) && - (block[4] == 0x00)) - return 1; - else - return 0; -} - -static int edid_is_monitor_block(unsigned char *block) -{ - if ((block[0] == 0x00) && (block[1] == 0x00) && - (block[2] == 0x00) && (block[3] == 0xfc) && - (block[4] == 0x00)) - return 1; - else - return 0; -} - static void calc_mode_timings(int xres, int yres, int refresh, struct fb_videomode *mode) { @@ -795,15 +861,6 @@ static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs) } } -static int edid_is_timing_block(unsigned char *block) -{ - if ((block[0] != 0x00) || (block[1] != 0x00) || - (block[2] != 0x00) || (block[4] != 0x00)) - return 1; - else - return 0; -} - int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) { int i; diff --git a/trunk/drivers/video/fbsysfs.c b/trunk/drivers/video/fbsysfs.c index 40c80c8190e2..d4a2c11d9809 100644 --- a/trunk/drivers/video/fbsysfs.c +++ b/trunk/drivers/video/fbsysfs.c @@ -376,7 +376,7 @@ static ssize_t show_pan(struct device *device, { struct fb_info *fb_info = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset, - fb_info->var.xoffset); + fb_info->var.yoffset); } static ssize_t show_name(struct device *device, diff --git a/trunk/drivers/video/hecubafb.c b/trunk/drivers/video/hecubafb.c new file mode 100644 index 000000000000..abfcb50364c8 --- /dev/null +++ b/trunk/drivers/video/hecubafb.c @@ -0,0 +1,471 @@ +/* + * linux/drivers/video/hecubafb.c -- FB driver for Hecuba controller + * + * Copyright (C) 2006, Jaya Kumar + * This work was sponsored by CIS(M) Sdn Bhd + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. + * This work was possible because of apollo display code from E-Ink's website + * http://support.eink.com/community + * All information used to write this code is from public material made + * available by E-Ink on its support site. Some commands such as 0xA4 + * were found by looping through cmd=0x00 thru 0xFF and supplying random + * values. There are other commands that the display is capable of, + * beyond the 5 used here but they are more complex. + * + * This driver is written to be used with the Hecuba display controller + * board, and tested with the EInk 800x600 display in 1 bit mode. + * The interface between Hecuba and the host is TTL based GPIO. The + * GPIO requirements are 8 writable data lines and 6 lines for control. + * Only 4 of the controls are actually used here but 6 for future use. + * The driver requires the IO addresses for data and control GPIO at + * load time. It is also possible to use this display with a standard + * PC parallel port. + * + * General notes: + * - User must set hecubafb_enable=1 to enable it + * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Apollo controller specific defines */ +#define APOLLO_START_NEW_IMG 0xA0 +#define APOLLO_STOP_IMG_DATA 0xA1 +#define APOLLO_DISPLAY_IMG 0xA2 +#define APOLLO_ERASE_DISPLAY 0xA3 +#define APOLLO_INIT_DISPLAY 0xA4 + +/* Hecuba interface specific defines */ +/* WUP is inverted, CD is inverted, DS is inverted */ +#define HCB_NWUP_BIT 0x01 +#define HCB_NDS_BIT 0x02 +#define HCB_RW_BIT 0x04 +#define HCB_NCD_BIT 0x08 +#define HCB_ACK_BIT 0x80 + +/* Display specific information */ +#define DPY_W 600 +#define DPY_H 800 + +struct hecubafb_par { + unsigned long dio_addr; + unsigned long cio_addr; + unsigned long c2io_addr; + unsigned char ctl; + struct fb_info *info; + unsigned int irq; +}; + +static struct fb_fix_screeninfo hecubafb_fix __devinitdata = { + .id = "hecubafb", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_MONO01, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_var_screeninfo hecubafb_var __devinitdata = { + .xres = DPY_W, + .yres = DPY_H, + .xres_virtual = DPY_W, + .yres_virtual = DPY_H, + .bits_per_pixel = 1, + .nonstd = 1, +}; + +static unsigned long dio_addr; +static unsigned long cio_addr; +static unsigned long c2io_addr; +static unsigned long splashval; +static unsigned int nosplash; +static unsigned int hecubafb_enable; +static unsigned int irq; + +static DECLARE_WAIT_QUEUE_HEAD(hecubafb_waitq); + +static void hcb_set_ctl(struct hecubafb_par *par) +{ + outb(par->ctl, par->cio_addr); +} + +static unsigned char hcb_get_ctl(struct hecubafb_par *par) +{ + return inb(par->c2io_addr); +} + +static void hcb_set_data(struct hecubafb_par *par, unsigned char value) +{ + outb(value, par->dio_addr); +} + +static int __devinit apollo_init_control(struct hecubafb_par *par) +{ + unsigned char ctl; + /* for init, we want the following setup to be set: + WUP = lo + ACK = hi + DS = hi + RW = hi + CD = lo + */ + + /* write WUP to lo, DS to hi, RW to hi, CD to lo */ + par->ctl = HCB_NWUP_BIT | HCB_RW_BIT | HCB_NCD_BIT ; + par->ctl &= ~HCB_NDS_BIT; + hcb_set_ctl(par); + + /* check ACK is not lo */ + ctl = hcb_get_ctl(par); + if ((ctl & HCB_ACK_BIT)) { + printk(KERN_ERR "Fail because ACK is already low\n"); + return -ENXIO; + } + + return 0; +} + +static void hcb_wait_for_ack(struct hecubafb_par *par) +{ + + int timeout; + unsigned char ctl; + + timeout=500; + do { + ctl = hcb_get_ctl(par); + if ((ctl & HCB_ACK_BIT)) + return; + udelay(1); + } while (timeout--); + printk(KERN_ERR "timed out waiting for ack\n"); +} + +static void hcb_wait_for_ack_clear(struct hecubafb_par *par) +{ + + int timeout; + unsigned char ctl; + + timeout=500; + do { + ctl = hcb_get_ctl(par); + if (!(ctl & HCB_ACK_BIT)) + return; + udelay(1); + } while (timeout--); + printk(KERN_ERR "timed out waiting for clear\n"); +} + +static void apollo_send_data(struct hecubafb_par *par, unsigned char data) +{ + /* set data */ + hcb_set_data(par, data); + + /* set DS low */ + par->ctl |= HCB_NDS_BIT; + hcb_set_ctl(par); + + hcb_wait_for_ack(par); + + /* set DS hi */ + par->ctl &= ~(HCB_NDS_BIT); + hcb_set_ctl(par); + + hcb_wait_for_ack_clear(par); +} + +static void apollo_send_command(struct hecubafb_par *par, unsigned char data) +{ + /* command so set CD to high */ + par->ctl &= ~(HCB_NCD_BIT); + hcb_set_ctl(par); + + /* actually strobe with command */ + apollo_send_data(par, data); + + /* clear CD back to low */ + par->ctl |= (HCB_NCD_BIT); + hcb_set_ctl(par); +} + +/* main hecubafb functions */ + +static void hecubafb_dpy_update(struct hecubafb_par *par) +{ + int i; + unsigned char *buf = (unsigned char __force *)par->info->screen_base; + + apollo_send_command(par, 0xA0); + + for (i=0; i < (DPY_W*DPY_H/8); i++) { + apollo_send_data(par, *(buf++)); + } + + apollo_send_command(par, 0xA1); + apollo_send_command(par, 0xA2); +} + +/* this is called back from the deferred io workqueue */ +static void hecubafb_dpy_deferred_io(struct fb_info *info, + struct list_head *pagelist) +{ + hecubafb_dpy_update(info->par); +} + +static void hecubafb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + struct hecubafb_par *par = info->par; + + sys_fillrect(info, rect); + + hecubafb_dpy_update(par); +} + +static void hecubafb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + struct hecubafb_par *par = info->par; + + sys_copyarea(info, area); + + hecubafb_dpy_update(par); +} + +static void hecubafb_imageblit(struct fb_info *info, + const struct fb_image *image) +{ + struct hecubafb_par *par = info->par; + + sys_imageblit(info, image); + + hecubafb_dpy_update(par); +} + +/* + * this is the slow path from userspace. they can seek and write to + * the fb. it's inefficient to do anything less than a full screen draw + */ +static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long p; + int err=-EINVAL; + struct hecubafb_par *par; + unsigned int xres; + unsigned int fbmemlength; + + p = *ppos; + par = info->par; + xres = info->var.xres; + fbmemlength = (xres * info->var.yres)/8; + + if (p > fbmemlength) + return -ENOSPC; + + err = 0; + if ((count + p) > fbmemlength) { + count = fbmemlength - p; + err = -ENOSPC; + } + + if (count) { + char *base_addr; + + base_addr = (char __force *)info->screen_base; + count -= copy_from_user(base_addr + p, buf, count); + *ppos += count; + err = -EFAULT; + } + + hecubafb_dpy_update(par); + + if (count) + return count; + + return err; +} + +static struct fb_ops hecubafb_ops = { + .owner = THIS_MODULE, + .fb_read = fb_sys_read, + .fb_write = hecubafb_write, + .fb_fillrect = hecubafb_fillrect, + .fb_copyarea = hecubafb_copyarea, + .fb_imageblit = hecubafb_imageblit, +}; + +static struct fb_deferred_io hecubafb_defio = { + .delay = HZ, + .deferred_io = hecubafb_dpy_deferred_io, +}; + +static int __devinit hecubafb_probe(struct platform_device *dev) +{ + struct fb_info *info; + int retval = -ENOMEM; + int videomemorysize; + unsigned char *videomemory; + struct hecubafb_par *par; + + videomemorysize = (DPY_W*DPY_H)/8; + + if (!(videomemory = vmalloc(videomemorysize))) + return retval; + + memset(videomemory, 0, videomemorysize); + + info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev); + if (!info) + goto err; + + info->screen_base = (char __iomem *) videomemory; + info->fbops = &hecubafb_ops; + + info->var = hecubafb_var; + info->fix = hecubafb_fix; + info->fix.smem_len = videomemorysize; + par = info->par; + par->info = info; + + if (!dio_addr || !cio_addr || !c2io_addr) { + printk(KERN_WARNING "no IO addresses supplied\n"); + goto err1; + } + par->dio_addr = dio_addr; + par->cio_addr = cio_addr; + par->c2io_addr = c2io_addr; + info->flags = FBINFO_FLAG_DEFAULT; + + info->fbdefio = &hecubafb_defio; + fb_deferred_io_init(info); + + retval = register_framebuffer(info); + if (retval < 0) + goto err1; + platform_set_drvdata(dev, info); + + printk(KERN_INFO + "fb%d: Hecuba frame buffer device, using %dK of video memory\n", + info->node, videomemorysize >> 10); + + /* this inits the dpy */ + apollo_init_control(par); + + apollo_send_command(par, APOLLO_INIT_DISPLAY); + apollo_send_data(par, 0x81); + + /* have to wait while display resets */ + udelay(1000); + + /* if we were told to splash the screen, we just clear it */ + if (!nosplash) { + apollo_send_command(par, APOLLO_ERASE_DISPLAY); + apollo_send_data(par, splashval); + } + + return 0; +err1: + framebuffer_release(info); +err: + vfree(videomemory); + return retval; +} + +static int __devexit hecubafb_remove(struct platform_device *dev) +{ + struct fb_info *info = platform_get_drvdata(dev); + + if (info) { + fb_deferred_io_cleanup(info); + unregister_framebuffer(info); + vfree((void __force *)info->screen_base); + framebuffer_release(info); + } + return 0; +} + +static struct platform_driver hecubafb_driver = { + .probe = hecubafb_probe, + .remove = hecubafb_remove, + .driver = { + .name = "hecubafb", + }, +}; + +static struct platform_device *hecubafb_device; + +static int __init hecubafb_init(void) +{ + int ret; + + if (!hecubafb_enable) { + printk(KERN_ERR "Use hecubafb_enable to enable the device\n"); + return -ENXIO; + } + + ret = platform_driver_register(&hecubafb_driver); + if (!ret) { + hecubafb_device = platform_device_alloc("hecubafb", 0); + if (hecubafb_device) + ret = platform_device_add(hecubafb_device); + else + ret = -ENOMEM; + + if (ret) { + platform_device_put(hecubafb_device); + platform_driver_unregister(&hecubafb_driver); + } + } + return ret; + +} + +static void __exit hecubafb_exit(void) +{ + platform_device_unregister(hecubafb_device); + platform_driver_unregister(&hecubafb_driver); +} + +module_param(nosplash, uint, 0); +MODULE_PARM_DESC(nosplash, "Disable doing the splash screen"); +module_param(hecubafb_enable, uint, 0); +MODULE_PARM_DESC(hecubafb_enable, "Enable communication with Hecuba board"); +module_param(dio_addr, ulong, 0); +MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480"); +module_param(cio_addr, ulong, 0); +MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400"); +module_param(c2io_addr, ulong, 0); +MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408"); +module_param(splashval, ulong, 0); +MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white"); +module_param(irq, uint, 0); +MODULE_PARM_DESC(irq, "IRQ for the Hecuba board"); + +module_init(hecubafb_init); +module_exit(hecubafb_exit); + +MODULE_DESCRIPTION("fbdev driver for Hecuba board"); +MODULE_AUTHOR("Jaya Kumar"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/i810/i810.h b/trunk/drivers/video/i810/i810.h index aa65ffce915b..889e4ea5edc1 100644 --- a/trunk/drivers/video/i810/i810.h +++ b/trunk/drivers/video/i810/i810.h @@ -133,7 +133,7 @@ /* Masks (AND ops) and OR's */ #define FB_START_MASK (0x3f << (32 - 6)) #define MMIO_ADDR_MASK (0x1FFF << (32 - 13)) -#define FREQ_MASK 0x1EF +#define FREQ_MASK (1 << 4) #define SCR_OFF 0x20 #define DRAM_ON 0x08 #define DRAM_OFF 0xE7 diff --git a/trunk/drivers/video/intelfb/intelfbhw.c b/trunk/drivers/video/intelfb/intelfbhw.c index c1eb18bf0883..16bc8d75e36e 100644 --- a/trunk/drivers/video/intelfb/intelfbhw.c +++ b/trunk/drivers/video/intelfb/intelfbhw.c @@ -1428,6 +1428,24 @@ static void refresh_ring(struct intelfb_info *dinfo); static void reset_state(struct intelfb_info *dinfo); static void do_flush(struct intelfb_info *dinfo); +static u32 get_ring_space(struct intelfb_info *dinfo) +{ + u32 ring_space; + + if (dinfo->ring_tail >= dinfo->ring_head) + ring_space = dinfo->ring.size - + (dinfo->ring_tail - dinfo->ring_head); + else + ring_space = dinfo->ring_head - dinfo->ring_tail; + + if (ring_space > RING_MIN_FREE) + ring_space -= RING_MIN_FREE; + else + ring_space = 0; + + return ring_space; +} + static int wait_ring(struct intelfb_info *dinfo, int n) { @@ -1442,13 +1460,8 @@ wait_ring(struct intelfb_info *dinfo, int n) end = jiffies + (HZ * 3); while (dinfo->ring_space < n) { dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK; - if (dinfo->ring_tail + RING_MIN_FREE < dinfo->ring_head) - dinfo->ring_space = dinfo->ring_head - - (dinfo->ring_tail + RING_MIN_FREE); - else - dinfo->ring_space = (dinfo->ring.size + - dinfo->ring_head) - - (dinfo->ring_tail + RING_MIN_FREE); + dinfo->ring_space = get_ring_space(dinfo); + if (dinfo->ring_head != last_head) { end = jiffies + (HZ * 3); last_head = dinfo->ring_head; @@ -1513,12 +1526,7 @@ refresh_ring(struct intelfb_info *dinfo) dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK; dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK; - if (dinfo->ring_tail + RING_MIN_FREE < dinfo->ring_head) - dinfo->ring_space = dinfo->ring_head - - (dinfo->ring_tail + RING_MIN_FREE); - else - dinfo->ring_space = (dinfo->ring.size + dinfo->ring_head) - - (dinfo->ring_tail + RING_MIN_FREE); + dinfo->ring_space = get_ring_space(dinfo); } static void diff --git a/trunk/drivers/video/logo/Kconfig b/trunk/drivers/video/logo/Kconfig index f0e6512c87ff..9397bcef3018 100644 --- a/trunk/drivers/video/logo/Kconfig +++ b/trunk/drivers/video/logo/Kconfig @@ -2,73 +2,69 @@ # Logo configuration # -menu "Logo configuration" - -config LOGO +menuconfig LOGO bool "Bootup logo" depends on FB || SGI_NEWPORT_CONSOLE help Enable and select frame buffer bootup logos. +if LOGO + config LOGO_LINUX_MONO bool "Standard black and white Linux logo" - depends on LOGO default y config LOGO_LINUX_VGA16 bool "Standard 16-color Linux logo" - depends on LOGO default y config LOGO_LINUX_CLUT224 bool "Standard 224-color Linux logo" - depends on LOGO default y config LOGO_DEC_CLUT224 bool "224-color Digital Equipment Corporation Linux logo" - depends on LOGO && (MACH_DECSTATION || ALPHA) + depends on MACH_DECSTATION || ALPHA default y config LOGO_MAC_CLUT224 bool "224-color Macintosh Linux logo" - depends on LOGO && MAC + depends on MAC default y config LOGO_PARISC_CLUT224 bool "224-color PA-RISC Linux logo" - depends on LOGO && PARISC + depends on PARISC default y config LOGO_SGI_CLUT224 bool "224-color SGI Linux logo" - depends on LOGO && (SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS) + depends on SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS default y config LOGO_SUN_CLUT224 bool "224-color Sun Linux logo" - depends on LOGO && SPARC + depends on SPARC default y config LOGO_SUPERH_MONO bool "Black and white SuperH Linux logo" - depends on LOGO && SUPERH + depends on SUPERH default y config LOGO_SUPERH_VGA16 bool "16-color SuperH Linux logo" - depends on LOGO && SUPERH + depends on SUPERH default y config LOGO_SUPERH_CLUT224 bool "224-color SuperH Linux logo" - depends on LOGO && SUPERH + depends on SUPERH default y config LOGO_M32R_CLUT224 bool "224-color M32R Linux logo" - depends on LOGO && M32R + depends on M32R default y -endmenu - +endif # LOGO diff --git a/trunk/drivers/video/modedb.c b/trunk/drivers/video/modedb.c index 3e517940c5a5..3741ad729401 100644 --- a/trunk/drivers/video/modedb.c +++ b/trunk/drivers/video/modedb.c @@ -395,7 +395,7 @@ static int my_atoi(const char *name) for (;; name++) { switch (*name) { - case '0'...'9': + case '0' ... '9': val = 10*val+(*name-'0'); break; default: @@ -548,7 +548,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, } else goto done; break; - case '0'...'9': + case '0' ... '9': break; case 'M': if (!yres_specified) diff --git a/trunk/drivers/video/neofb.c b/trunk/drivers/video/neofb.c index 395ccedde9a6..bd30aba242d0 100644 --- a/trunk/drivers/video/neofb.c +++ b/trunk/drivers/video/neofb.c @@ -665,6 +665,7 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->red.msb_right = 0; var->green.msb_right = 0; var->blue.msb_right = 0; + var->transp.msb_right = 0; switch (var->bits_per_pixel) { case 8: /* PSEUDOCOLOUR, 256 */ diff --git a/trunk/drivers/video/nvidia/nv_accel.c b/trunk/drivers/video/nvidia/nv_accel.c index 9efb8a3854e2..fa4821c5572b 100644 --- a/trunk/drivers/video/nvidia/nv_accel.c +++ b/trunk/drivers/video/nvidia/nv_accel.c @@ -69,27 +69,38 @@ static const int NVCopyROP_PM[16] = { 0x5A, /* invert */ }; -static inline void NVFlush(struct nvidia_par *par) +static inline void nvidiafb_safe_mode(struct fb_info *info) { + struct nvidia_par *par = info->par; + + touch_softlockup_watchdog(); + info->pixmap.scan_align = 1; + par->lockup = 1; +} + +static inline void NVFlush(struct fb_info *info) +{ + struct nvidia_par *par = info->par; int count = 1000000000; while (--count && READ_GET(par) != par->dmaPut) ; if (!count) { printk("nvidiafb: DMA Flush lockup\n"); - par->lockup = 1; + nvidiafb_safe_mode(info); } } -static inline void NVSync(struct nvidia_par *par) +static inline void NVSync(struct fb_info *info) { + struct nvidia_par *par = info->par; int count = 1000000000; while (--count && NV_RD32(par->PGRAPH, 0x0700)) ; if (!count) { printk("nvidiafb: DMA Sync lockup\n"); - par->lockup = 1; + nvidiafb_safe_mode(info); } } @@ -101,8 +112,9 @@ static void NVDmaKickoff(struct nvidia_par *par) } } -static void NVDmaWait(struct nvidia_par *par, int size) +static void NVDmaWait(struct fb_info *info, int size) { + struct nvidia_par *par = info->par; int dmaGet; int count = 1000000000, cnt; size++; @@ -135,34 +147,38 @@ static void NVDmaWait(struct nvidia_par *par, int size) } if (!count) { - printk("DMA Wait Lockup\n"); - par->lockup = 1; + printk("nvidiafb: DMA Wait Lockup\n"); + nvidiafb_safe_mode(info); } } -static void NVSetPattern(struct nvidia_par *par, u32 clr0, u32 clr1, +static void NVSetPattern(struct fb_info *info, u32 clr0, u32 clr1, u32 pat0, u32 pat1) { - NVDmaStart(par, PATTERN_COLOR_0, 4); + struct nvidia_par *par = info->par; + + NVDmaStart(info, par, PATTERN_COLOR_0, 4); NVDmaNext(par, clr0); NVDmaNext(par, clr1); NVDmaNext(par, pat0); NVDmaNext(par, pat1); } -static void NVSetRopSolid(struct nvidia_par *par, u32 rop, u32 planemask) +static void NVSetRopSolid(struct fb_info *info, u32 rop, u32 planemask) { + struct nvidia_par *par = info->par; + if (planemask != ~0) { - NVSetPattern(par, 0, planemask, ~0, ~0); + NVSetPattern(info, 0, planemask, ~0, ~0); if (par->currentRop != (rop + 32)) { - NVDmaStart(par, ROP_SET, 1); + NVDmaStart(info, par, ROP_SET, 1); NVDmaNext(par, NVCopyROP_PM[rop]); par->currentRop = rop + 32; } } else if (par->currentRop != rop) { if (par->currentRop >= 16) - NVSetPattern(par, ~0, ~0, ~0, ~0); - NVDmaStart(par, ROP_SET, 1); + NVSetPattern(info, ~0, ~0, ~0, ~0); + NVDmaStart(info, par, ROP_SET, 1); NVDmaNext(par, NVCopyROP[rop]); par->currentRop = rop; } @@ -175,7 +191,7 @@ static void NVSetClippingRectangle(struct fb_info *info, int x1, int y1, int h = y2 - y1 + 1; int w = x2 - x1 + 1; - NVDmaStart(par, CLIP_POINT, 2); + NVDmaStart(info, par, CLIP_POINT, 2); NVDmaNext(par, (y1 << 16) | x1); NVDmaNext(par, (h << 16) | w); } @@ -237,23 +253,23 @@ void NVResetGraphics(struct fb_info *info) break; } - NVDmaStart(par, SURFACE_FORMAT, 4); + NVDmaStart(info, par, SURFACE_FORMAT, 4); NVDmaNext(par, surfaceFormat); NVDmaNext(par, pitch | (pitch << 16)); NVDmaNext(par, 0); NVDmaNext(par, 0); - NVDmaStart(par, PATTERN_FORMAT, 1); + NVDmaStart(info, par, PATTERN_FORMAT, 1); NVDmaNext(par, patternFormat); - NVDmaStart(par, RECT_FORMAT, 1); + NVDmaStart(info, par, RECT_FORMAT, 1); NVDmaNext(par, rectFormat); - NVDmaStart(par, LINE_FORMAT, 1); + NVDmaStart(info, par, LINE_FORMAT, 1); NVDmaNext(par, lineFormat); par->currentRop = ~0; /* set to something invalid */ - NVSetRopSolid(par, ROP_COPY, ~0); + NVSetRopSolid(info, ROP_COPY, ~0); NVSetClippingRectangle(info, 0, 0, info->var.xres_virtual, info->var.yres_virtual); @@ -269,10 +285,10 @@ int nvidiafb_sync(struct fb_info *info) return 0; if (!par->lockup) - NVFlush(par); + NVFlush(info); if (!par->lockup) - NVSync(par); + NVSync(info); return 0; } @@ -287,7 +303,7 @@ void nvidiafb_copyarea(struct fb_info *info, const struct fb_copyarea *region) if (par->lockup) return cfb_copyarea(info, region); - NVDmaStart(par, BLIT_POINT_SRC, 3); + NVDmaStart(info, par, BLIT_POINT_SRC, 3); NVDmaNext(par, (region->sy << 16) | region->sx); NVDmaNext(par, (region->dy << 16) | region->dx); NVDmaNext(par, (region->height << 16) | region->width); @@ -312,19 +328,19 @@ void nvidiafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) color = ((u32 *) info->pseudo_palette)[rect->color]; if (rect->rop != ROP_COPY) - NVSetRopSolid(par, rect->rop, ~0); + NVSetRopSolid(info, rect->rop, ~0); - NVDmaStart(par, RECT_SOLID_COLOR, 1); + NVDmaStart(info, par, RECT_SOLID_COLOR, 1); NVDmaNext(par, color); - NVDmaStart(par, RECT_SOLID_RECTS(0), 2); + NVDmaStart(info, par, RECT_SOLID_RECTS(0), 2); NVDmaNext(par, (rect->dx << 16) | rect->dy); NVDmaNext(par, (rect->width << 16) | rect->height); NVDmaKickoff(par); if (rect->rop != ROP_COPY) - NVSetRopSolid(par, ROP_COPY, ~0); + NVSetRopSolid(info, ROP_COPY, ~0); } static void nvidiafb_mono_color_expand(struct fb_info *info, @@ -346,7 +362,7 @@ static void nvidiafb_mono_color_expand(struct fb_info *info, bg = ((u32 *) info->pseudo_palette)[image->bg_color] | mask; } - NVDmaStart(par, RECT_EXPAND_TWO_COLOR_CLIP, 7); + NVDmaStart(info, par, RECT_EXPAND_TWO_COLOR_CLIP, 7); NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff)); NVDmaNext(par, ((image->dy + image->height) << 16) | ((image->dx + image->width) & 0xffff)); @@ -357,7 +373,7 @@ static void nvidiafb_mono_color_expand(struct fb_info *info, NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff)); while (dsize >= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS) { - NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0), + NVDmaStart(info, par, RECT_EXPAND_TWO_COLOR_DATA(0), RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS); for (j = RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS; j--;) { @@ -370,7 +386,7 @@ static void nvidiafb_mono_color_expand(struct fb_info *info, } if (dsize) { - NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0), dsize); + NVDmaStart(info, par, RECT_EXPAND_TWO_COLOR_DATA(0), dsize); for (j = dsize; j--;) { tmp = data[k++]; diff --git a/trunk/drivers/video/nvidia/nv_hw.c b/trunk/drivers/video/nvidia/nv_hw.c index ea426115c6f9..f297c7b14a41 100644 --- a/trunk/drivers/video/nvidia/nv_hw.c +++ b/trunk/drivers/video/nvidia/nv_hw.c @@ -686,7 +686,7 @@ static void nForceUpdateArbitrationSettings(unsigned VClk, if ((par->Chipset & 0x0FF0) == 0x01A0) { unsigned int uMClkPostDiv; - dev = pci_find_slot(0, 3); + dev = pci_get_bus_and_slot(0, 3); pci_read_config_dword(dev, 0x6C, &uMClkPostDiv); uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf; @@ -694,11 +694,11 @@ static void nForceUpdateArbitrationSettings(unsigned VClk, uMClkPostDiv = 4; MClk = 400000 / uMClkPostDiv; } else { - dev = pci_find_slot(0, 5); + dev = pci_get_bus_and_slot(0, 5); pci_read_config_dword(dev, 0x4c, &MClk); MClk /= 1000; } - + pci_dev_put(dev); pll = NV_RD32(par->PRAMDAC0, 0x0500); M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; @@ -707,19 +707,21 @@ static void nForceUpdateArbitrationSettings(unsigned VClk, sim_data.pix_bpp = (char)pixelDepth; sim_data.enable_video = 0; sim_data.enable_mp = 0; - pci_find_slot(0, 1); + dev = pci_get_bus_and_slot(0, 1); pci_read_config_dword(dev, 0x7C, &sim_data.memory_type); + pci_dev_put(dev); sim_data.memory_type = (sim_data.memory_type >> 12) & 1; sim_data.memory_width = 64; - dev = pci_find_slot(0, 3); + dev = pci_get_bus_and_slot(0, 3); pci_read_config_dword(dev, 0, &memctrl); + pci_dev_put(dev); memctrl >>= 16; if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) { int dimm[3]; - pci_find_slot(0, 2); + dev = pci_get_bus_and_slot(0, 2); pci_read_config_dword(dev, 0x40, &dimm[0]); dimm[0] = (dimm[0] >> 8) & 0x4f; pci_read_config_dword(dev, 0x44, &dimm[1]); @@ -731,6 +733,7 @@ static void nForceUpdateArbitrationSettings(unsigned VClk, printk("nvidiafb: your nForce DIMMs are not arranged " "in optimal banks!\n"); } + pci_dev_put(dev); } sim_data.mem_latency = 3; diff --git a/trunk/drivers/video/nvidia/nv_i2c.c b/trunk/drivers/video/nvidia/nv_i2c.c index b8588973e400..afe4567e1ff4 100644 --- a/trunk/drivers/video/nvidia/nv_i2c.c +++ b/trunk/drivers/video/nvidia/nv_i2c.c @@ -30,16 +30,14 @@ static void nvidia_gpio_setscl(void *data, int state) struct nvidia_par *par = chan->par; u32 val; - VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1); - val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0; + val = NVReadCrtc(par, chan->ddc_base + 1) & 0xf0; if (state) val |= 0x20; else val &= ~0x20; - VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1); - VGA_WR08(par->PCIO, 0x3d5, val | 0x1); + NVWriteCrtc(par, chan->ddc_base + 1, val | 0x01); } static void nvidia_gpio_setsda(void *data, int state) @@ -48,16 +46,14 @@ static void nvidia_gpio_setsda(void *data, int state) struct nvidia_par *par = chan->par; u32 val; - VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1); - val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0; + val = NVReadCrtc(par, chan->ddc_base + 1) & 0xf0; if (state) val |= 0x10; else val &= ~0x10; - VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1); - VGA_WR08(par->PCIO, 0x3d5, val | 0x1); + NVWriteCrtc(par, chan->ddc_base + 1, val | 0x01); } static int nvidia_gpio_getscl(void *data) @@ -66,12 +62,9 @@ static int nvidia_gpio_getscl(void *data) struct nvidia_par *par = chan->par; u32 val = 0; - VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base); - if (VGA_RD08(par->PCIO, 0x3d5) & 0x04) + if (NVReadCrtc(par, chan->ddc_base) & 0x04) val = 1; - val = VGA_RD08(par->PCIO, 0x3d5); - return val; } @@ -81,20 +74,21 @@ static int nvidia_gpio_getsda(void *data) struct nvidia_par *par = chan->par; u32 val = 0; - VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base); - if (VGA_RD08(par->PCIO, 0x3d5) & 0x08) + if (NVReadCrtc(par, chan->ddc_base) & 0x08) val = 1; return val; } -static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name) +static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name, + unsigned int i2c_class) { int rc; strcpy(chan->adapter.name, name); chan->adapter.owner = THIS_MODULE; chan->adapter.id = I2C_HW_B_NVIDIA; + chan->adapter.class = i2c_class; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = &chan->par->pci_dev->dev; chan->algo.setsda = nvidia_gpio_setsda; @@ -127,83 +121,39 @@ static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name) void nvidia_create_i2c_busses(struct nvidia_par *par) { - par->bus = 3; - par->chan[0].par = par; par->chan[1].par = par; par->chan[2].par = par; - par->chan[0].ddc_base = 0x3e; - nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0"); + par->chan[0].ddc_base = 0x36; + nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0", I2C_CLASS_HWMON); - par->chan[1].ddc_base = 0x36; - nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1"); + par->chan[1].ddc_base = 0x3e; + nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1", 0); par->chan[2].ddc_base = 0x50; - nvidia_setup_i2c_bus(&par->chan[2], "nvidia #2"); + nvidia_setup_i2c_bus(&par->chan[2], "nvidia #2", 0); } void nvidia_delete_i2c_busses(struct nvidia_par *par) { - if (par->chan[0].par) - i2c_del_adapter(&par->chan[0].adapter); - par->chan[0].par = NULL; - - if (par->chan[1].par) - i2c_del_adapter(&par->chan[1].adapter); - par->chan[1].par = NULL; - - if (par->chan[2].par) - i2c_del_adapter(&par->chan[2].adapter); - par->chan[2].par = NULL; - -} + int i; -static u8 *nvidia_do_probe_i2c_edid(struct nvidia_i2c_chan *chan) -{ - u8 start = 0x0; - struct i2c_msg msgs[] = { - { - .addr = 0x50, - .len = 1, - .buf = &start, - }, { - .addr = 0x50, - .flags = I2C_M_RD, - .len = EDID_LENGTH, - }, - }; - u8 *buf; - - if (!chan->par) - return NULL; - - buf = kmalloc(EDID_LENGTH, GFP_KERNEL); - if (!buf) { - dev_warn(&chan->par->pci_dev->dev, "Out of memory!\n"); - return NULL; + for (i = 0; i < 3; i++) { + if (!par->chan[i].par) + continue; + i2c_del_adapter(&par->chan[i].adapter); + par->chan[i].par = NULL; } - msgs[1].buf = buf; - - if (i2c_transfer(&chan->adapter, msgs, 2) == 2) - return buf; - dev_dbg(&chan->par->pci_dev->dev, "Unable to read EDID block.\n"); - kfree(buf); - return NULL; } int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid) { struct nvidia_par *par = info->par; u8 *edid = NULL; - int i; - for (i = 0; i < 3; i++) { - /* Do the real work */ - edid = nvidia_do_probe_i2c_edid(&par->chan[conn - 1]); - if (edid) - break; - } + if (par->chan[conn - 1].par) + edid = fb_ddc_read(&par->chan[conn - 1].adapter); if (!edid && conn == 1) { /* try to get from firmware */ diff --git a/trunk/drivers/video/nvidia/nv_local.h b/trunk/drivers/video/nvidia/nv_local.h index e009d242ea10..68e508daa417 100644 --- a/trunk/drivers/video/nvidia/nv_local.h +++ b/trunk/drivers/video/nvidia/nv_local.h @@ -73,9 +73,9 @@ #define NVDmaNext(par, data) \ NV_WR32(&(par)->dmaBase[(par)->dmaCurrent++], 0, (data)) -#define NVDmaStart(par, tag, size) { \ +#define NVDmaStart(info, par, tag, size) { \ if((par)->dmaFree <= (size)) \ - NVDmaWait(par, size); \ + NVDmaWait(info, size); \ NVDmaNext(par, ((size) << 18) | (tag)); \ (par)->dmaFree -= ((size) + 1); \ } diff --git a/trunk/drivers/video/nvidia/nv_of.c b/trunk/drivers/video/nvidia/nv_of.c index 163a774a1b30..73afd7eb9977 100644 --- a/trunk/drivers/video/nvidia/nv_of.c +++ b/trunk/drivers/video/nvidia/nv_of.c @@ -46,15 +46,15 @@ int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid) for (dp = NULL; (dp = of_get_next_child(parent, dp)) != NULL;) { - pname = get_property(dp, "name", NULL); + pname = of_get_property(dp, "name", NULL); if (!pname) continue; len = strlen(pname); if ((pname[len-1] == 'A' && conn == 1) || (pname[len-1] == 'B' && conn == 2)) { for (i = 0; propnames[i] != NULL; ++i) { - pedid = get_property(dp, propnames[i], - NULL); + pedid = of_get_property(dp, + propnames[i], NULL); if (pedid != NULL) break; } @@ -65,7 +65,7 @@ int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid) } if (pedid == NULL) { for (i = 0; propnames[i] != NULL; ++i) { - pedid = get_property(parent, propnames[i], NULL); + pedid = of_get_property(parent, propnames[i], NULL); if (pedid != NULL) break; } diff --git a/trunk/drivers/video/nvidia/nv_setup.c b/trunk/drivers/video/nvidia/nv_setup.c index eab3e282a4de..707e2c8a13ed 100644 --- a/trunk/drivers/video/nvidia/nv_setup.c +++ b/trunk/drivers/video/nvidia/nv_setup.c @@ -261,7 +261,7 @@ static void nv10GetConfig(struct nvidia_par *par) } #endif - dev = pci_find_slot(0, 1); + dev = pci_get_bus_and_slot(0, 1); if ((par->Chipset & 0xffff) == 0x01a0) { int amt = 0; @@ -276,6 +276,7 @@ static void nv10GetConfig(struct nvidia_par *par) par->RamAmountKBytes = (NV_RD32(par->PFB, 0x020C) & 0xFFF00000) >> 10; } + pci_dev_put(dev); par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 6)) ? 14318 : 13500; @@ -656,7 +657,7 @@ int NVCommonSetup(struct fb_info *info) par->LVDS = 0; if (par->FlatPanel && par->twoHeads) { NV_WR32(par->PRAMDAC0, 0x08B0, 0x00010004); - if (par->PRAMDAC0[0x08b4] & 1) + if (NV_RD32(par->PRAMDAC0, 0x08b4) & 1) par->LVDS = 1; printk("nvidiafb: Panel is %s\n", par->LVDS ? "LVDS" : "TMDS"); } diff --git a/trunk/drivers/video/nvidia/nv_type.h b/trunk/drivers/video/nvidia/nv_type.h index 86e65dea60d3..38f7cc0a2331 100644 --- a/trunk/drivers/video/nvidia/nv_type.h +++ b/trunk/drivers/video/nvidia/nv_type.h @@ -4,8 +4,9 @@ #include #include #include -#include #include +#include +#include

"; @@ -326,12 +328,21 @@ while ($ARGV[0] =~ m/^-(.*)/) { } } +# get kernel version from env +sub get_kernel_version() { + my $version; + + if (defined($ENV{'KERNELVERSION'})) { + $version = $ENV{'KERNELVERSION'}; + } + return $version; +} # generate a sequence of code that will splice in highlighting information # using the s// operator. my $dohighlight = ""; foreach my $pattern (keys %highlights) { -# print "scanning pattern $pattern ($highlights{$pattern})\n"; +# print STDERR "scanning pattern:$pattern, highlight:($highlights{$pattern})\n"; $dohighlight .= "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n"; } @@ -378,13 +389,19 @@ sub output_highlight { # confess "output_highlight got called with no args?\n"; # } +# print STDERR "contents b4:$contents\n"; eval $dohighlight; die $@ if $@; + if ($output_mode eq "html") { + $contents =~ s/\\\\//; + } +# print STDERR "contents af:$contents\n"; + foreach $line (split "\n", $contents) { - if ($line eq ""){ + if ($line eq ""){ print $lineprefix, $blankline; } else { - $line =~ s/\\\\\\/\&/g; + $line =~ s/\\\\\\/\&/g; print $lineprefix, $line; } print "\n"; @@ -414,7 +431,7 @@ sub output_enum_html(%) { print "enum ".$args{'enum'}." {
\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { - print " ".$parameter.""; + print " ".$parameter.""; if ($count != $#{$args{'parameterlist'}}) { $count++; print ",\n"; @@ -462,15 +479,16 @@ sub output_struct_html(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function - print " $1$parameter) ($2);
\n"; + print "    $1$parameter) ($2);
\n"; } elsif ($type =~ m/^(.*?)\s*(:.*)/) { - print " $1 $parameter$2;
\n"; + # bitfield + print "    $1 $parameter$2;
\n"; } else { - print " $type $parameter;
\n"; + print "    $type $parameter;
\n"; } } print "};
\n"; @@ -483,7 +501,7 @@ sub output_struct_html(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print "

".$parameter."\n"; print "
"; output_highlight($args{'parameterdescs'}{$parameter_name}); @@ -525,7 +543,7 @@ sub output_function_html(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print "
".$parameter."\n"; print "
"; output_highlight($args{'parameterdescs'}{$parameter_name}); @@ -592,6 +610,7 @@ sub output_function_xml(%) { print "\n"; print " ".$args{'function'}."\n"; print " 9\n"; + print " " . get_kernel_version() . "\n"; print "\n"; print "\n"; print " ".$args{'function'}."\n"; @@ -668,6 +687,7 @@ sub output_struct_xml(%) { print "\n"; print " ".$args{'type'}." ".$args{'struct'}."\n"; print " 9\n"; + print " " . get_kernel_version() . "\n"; print "\n"; print "\n"; print " ".$args{'type'}." ".$args{'struct'}."\n"; @@ -691,7 +711,7 @@ sub output_struct_xml(%) { $parameter_name =~ s/\[.*//; defined($args{'parameterdescs'}{$parameter_name}) || next; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function @@ -752,6 +772,7 @@ sub output_enum_xml(%) { print "\n"; print " enum ".$args{'enum'}."\n"; print " 9\n"; + print " " . get_kernel_version() . "\n"; print "\n"; print "\n"; print " enum ".$args{'enum'}."\n"; @@ -767,11 +788,11 @@ sub output_enum_xml(%) { print "enum ".$args{'enum'}." {\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { - print " $parameter"; - if ($count != $#{$args{'parameterlist'}}) { + print " $parameter"; + if ($count != $#{$args{'parameterlist'}}) { $count++; print ","; - } + } print "\n"; } print "};"; @@ -1007,7 +1028,7 @@ sub output_enum_man(%) { print "enum ".$args{'enum'}." {\n"; $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { - print ".br\n.BI \" $parameter\"\n"; + print ".br\n.BI \" $parameter\"\n"; if ($count == $#{$args{'parameterlist'}}) { print "\n};\n"; last; @@ -1054,7 +1075,7 @@ sub output_struct_man(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function @@ -1077,7 +1098,7 @@ sub output_struct_man(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print ".IP \"".$parameter."\" 12\n"; output_highlight($args{'parameterdescs'}{$parameter_name}); } @@ -1187,7 +1208,7 @@ sub output_enum_text(%) { print "enum ".$args{'enum'}." {\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { - print "\t$parameter"; + print "\t$parameter"; if ($count != $#{$args{'parameterlist'}}) { $count++; print ","; @@ -1232,7 +1253,7 @@ sub output_struct_text(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function @@ -1252,7 +1273,7 @@ sub output_struct_text(%) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print "$parameter\n\t"; print $args{'parameterdescs'}{$parameter_name}."\n"; } @@ -1284,7 +1305,7 @@ sub output_declaration { ( $function_only == 1 && defined($function_table{$name})) || ( $function_only == 2 && !defined($function_table{$name}))) { - &$func(@_); + &$func(@_); $section_counter++; } } @@ -1317,8 +1338,8 @@ sub dump_struct($$) { my $file = shift; if ($x =~/(struct|union)\s+(\w+)\s*{(.*)}/) { - $declaration_name = $2; - my $members = $3; + $declaration_name = $2; + my $members = $3; # ignore embedded structs or unions $members =~ s/{.*?}//g; @@ -1345,7 +1366,7 @@ sub dump_struct($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse struct or union!\n"; + print STDERR "Error(${file}:$.): Cannot parse struct or union!\n"; ++$errors; } } @@ -1356,15 +1377,15 @@ sub dump_enum($$) { $x =~ s@/\*.*?\*/@@gos; # strip comments. if ($x =~ /enum\s+(\w+)\s*{(.*)}/) { - $declaration_name = $1; - my $members = $2; + $declaration_name = $1; + my $members = $2; foreach my $arg (split ',', $members) { $arg =~ s/^\s*(\w+).*/$1/; push @parameterlist, $arg; if (!$parameterdescs{$arg}) { - $parameterdescs{$arg} = $undescribed; - print STDERR "Warning(${file}:$.): Enum value '$arg' ". + $parameterdescs{$arg} = $undescribed; + print STDERR "Warning(${file}:$.): Enum value '$arg' ". "not described in enum '$declaration_name'\n"; } @@ -1382,7 +1403,7 @@ sub dump_enum($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse enum!\n"; + print STDERR "Error(${file}:$.): Cannot parse enum!\n"; ++$errors; } } @@ -1393,12 +1414,12 @@ sub dump_typedef($$) { $x =~ s@/\*.*?\*/@@gos; # strip comments. while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) { - $x =~ s/\(*.\)\s*;$/;/; + $x =~ s/\(*.\)\s*;$/;/; $x =~ s/\[*.\]\s*;$/;/; } if ($x =~ /typedef.*\s+(\w+)\s*;/) { - $declaration_name = $1; + $declaration_name = $1; output_declaration($declaration_name, 'typedef', @@ -1410,7 +1431,7 @@ sub dump_typedef($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse typedef!\n"; + print STDERR "Error(${file}:$.): Cannot parse typedef!\n"; ++$errors; } } @@ -1424,14 +1445,14 @@ sub create_parameterlist($$$) { # temporarily replace commas inside function pointer definition while ($args =~ /(\([^\),]+),/) { - $args =~ s/(\([^\),]+),/$1#/g; + $args =~ s/(\([^\),]+),/$1#/g; } foreach my $arg (split($splitter, $args)) { # strip comments $arg =~ s/\/\*.*\*\///; - # strip leading/trailing spaces - $arg =~ s/^\s*//; + # strip leading/trailing spaces + $arg =~ s/^\s*//; $arg =~ s/\s*$//; $arg =~ s/\s+/ /; @@ -1456,7 +1477,16 @@ sub create_parameterlist($$$) { if ($args[0] =~ m/\*/) { $args[0] =~ s/(\*+)\s*/ $1/; } - my @first_arg = split('\s+', shift @args); + + my @first_arg; + if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) { + shift @args; + push(@first_arg, split('\s+', $1)); + push(@first_arg, $2); + } else { + @first_arg = split('\s+', shift @args); + } + unshift(@args, pop @first_arg); $type = join " ", @first_arg; @@ -1514,15 +1544,15 @@ sub push_parameter($$$) { $parameterdescs{$param_name} = $undescribed; if (($type eq 'function') || ($type eq 'enum')) { - print STDERR "Warning(${file}:$.): Function parameter ". + print STDERR "Warning(${file}:$.): Function parameter ". "or member '$param' not " . "described in '$declaration_name'\n"; } print STDERR "Warning(${file}:$.):". - " No description found for parameter '$param'\n"; + " No description found for parameter '$param'\n"; ++$warnings; - } - } + } + } push @parameterlist, $param; $parametertypes{$param} = $type; @@ -1664,10 +1694,10 @@ sub process_state3_function($$) { # do nothing } elsif ($x =~ /([^\{]*)/) { - $prototype .= $1; + $prototype .= $1; } if (($x =~ /\{/) || ($x =~ /\#define/) || ($x =~ /;/)) { - $prototype =~ s@/\*.*?\*/@@gos; # strip comments. + $prototype =~ s@/\*.*?\*/@@gos; # strip comments. $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. $prototype =~ s@^\s+@@gos; # strip leading spaces dump_function($prototype,$file); @@ -1688,17 +1718,17 @@ sub process_state3_type($$) { } while (1) { - if ( $x =~ /([^{};]*)([{};])(.*)/ ) { + if ( $x =~ /([^{};]*)([{};])(.*)/ ) { $prototype .= $1 . $2; ($2 eq '{') && $brcount++; ($2 eq '}') && $brcount--; if (($2 eq ';') && ($brcount == 0)) { - dump_declaration($prototype,$file); + dump_declaration($prototype,$file); reset_state(); - last; + last; } $x = $3; - } else { + } else { $prototype .= $x; last; } @@ -1756,7 +1786,7 @@ sub process_file($) { } else { $section = $1; } - } + } elsif (/$doc_decl/o) { $identifier = $1; if (/\s*([\w\s]+?)\s*-/) { @@ -1849,13 +1879,13 @@ sub process_file($) { } } elsif ($state == 3) { # scanning for function '{' (end of prototype) if ($decl_type eq 'function') { - process_state3_function($_, $file); + process_state3_function($_, $file); } else { - process_state3_type($_, $file); + process_state3_type($_, $file); } } elsif ($state == 4) { # Documentation block - if (/$doc_block/) { + if (/$doc_block/) { dump_section($section, $contents); output_intro({'sectionlist' => \@sectionlist, 'sections' => \%sections }); @@ -1873,7 +1903,7 @@ sub process_file($) { } else { $section = $1; } - } + } elsif (/$doc_end/) { dump_section($section, $contents); @@ -1900,8 +1930,8 @@ sub process_file($) { { $contents .= $1 . "\n"; } - } - } + } + } } if ($initial_section_counter == $section_counter) { print STDERR "Warning(${file}): no structured comments found\n"; diff --git a/trunk/scripts/mkcompile_h b/trunk/scripts/mkcompile_h index 82d0af46f0ef..a8740df07b09 100755 --- a/trunk/scripts/mkcompile_h +++ b/trunk/scripts/mkcompile_h @@ -18,19 +18,32 @@ fi # Do not expand names set -f -if [ -r .version ]; then - VERSION=`cat .version` +# Fix the language to get consistent output +LC_ALL=C +export LC_ALL + +if [ -z "$KBUILD_BUILD_VERSION" ]; then + if [ -r .version ]; then + VERSION=`cat .version` + else + VERSION=0 + echo 0 > .version + fi else - VERSION=0 - echo 0 > .version + VERSION=$KBUILD_BUILD_VERSION fi +if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then + TIMESTAMP=`date` +else + TIMESTAMP=$KBUILD_BUILD_TIMESTAMP +fi UTS_VERSION="#$VERSION" CONFIG_FLAGS="" if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi -UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS `LC_ALL=C LANG=C date`" +UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP" # Truncate to maximum length @@ -46,7 +59,7 @@ UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/" echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\" - echo \#define LINUX_COMPILE_TIME \"`LC_ALL=C LANG=C date +%T`\" + echo \#define LINUX_COMPILE_TIME \"`date +%T`\" echo \#define LINUX_COMPILE_BY \"`whoami`\" echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\" @@ -58,7 +71,7 @@ UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/" echo \#define LINUX_COMPILE_DOMAIN fi - echo \#define LINUX_COMPILER \"`LC_ALL=C LANG=C $CC -v 2>&1 | tail -n 1`\" + echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\" ) > .tmpcompile # Only replace the real compile.h if the new one is different, diff --git a/trunk/scripts/mkuboot.sh b/trunk/scripts/mkuboot.sh index 4b06c5eea728..2e3d3cd916b8 100755 --- a/trunk/scripts/mkuboot.sh +++ b/trunk/scripts/mkuboot.sh @@ -4,7 +4,7 @@ # Build U-Boot image when `mkimage' tool is available. # -MKIMAGE=$(type -path ${CROSS_COMPILE}mkimage) +MKIMAGE=$(type -path "${CROSS_COMPILE}mkimage") if [ -z "${MKIMAGE}" ]; then MKIMAGE=$(type -path mkimage) diff --git a/trunk/scripts/mod/file2alias.c b/trunk/scripts/mod/file2alias.c index b2f73ffb40bd..ed1244dd58d0 100644 --- a/trunk/scripts/mod/file2alias.c +++ b/trunk/scripts/mod/file2alias.c @@ -37,7 +37,6 @@ typedef unsigned char __u8; * even potentially has different endianness and word sizes, since * we handle those differences explicitly below */ #include "../../include/linux/mod_devicetable.h" -#include "../../include/linux/input.h" #define ADD(str, sep, cond, field) \ do { \ @@ -416,31 +415,33 @@ static int do_input_entry(const char *filename, struct input_device_id *id, sprintf(alias + strlen(alias), "-e*"); if (id->flags & INPUT_DEVICE_ID_MATCH_EVBIT) - do_input(alias, id->evbit, 0, EV_MAX); + do_input(alias, id->evbit, 0, INPUT_DEVICE_ID_EV_MAX); sprintf(alias + strlen(alias), "k*"); if (id->flags & INPUT_DEVICE_ID_MATCH_KEYBIT) - do_input(alias, id->keybit, KEY_MIN_INTERESTING, KEY_MAX); + do_input(alias, id->keybit, + INPUT_DEVICE_ID_KEY_MIN_INTERESTING, + INPUT_DEVICE_ID_KEY_MAX); sprintf(alias + strlen(alias), "r*"); if (id->flags & INPUT_DEVICE_ID_MATCH_RELBIT) - do_input(alias, id->relbit, 0, REL_MAX); + do_input(alias, id->relbit, 0, INPUT_DEVICE_ID_REL_MAX); sprintf(alias + strlen(alias), "a*"); if (id->flags & INPUT_DEVICE_ID_MATCH_ABSBIT) - do_input(alias, id->absbit, 0, ABS_MAX); + do_input(alias, id->absbit, 0, INPUT_DEVICE_ID_ABS_MAX); sprintf(alias + strlen(alias), "m*"); if (id->flags & INPUT_DEVICE_ID_MATCH_MSCIT) - do_input(alias, id->mscbit, 0, MSC_MAX); + do_input(alias, id->mscbit, 0, INPUT_DEVICE_ID_MSC_MAX); sprintf(alias + strlen(alias), "l*"); if (id->flags & INPUT_DEVICE_ID_MATCH_LEDBIT) - do_input(alias, id->ledbit, 0, LED_MAX); + do_input(alias, id->ledbit, 0, INPUT_DEVICE_ID_LED_MAX); sprintf(alias + strlen(alias), "s*"); if (id->flags & INPUT_DEVICE_ID_MATCH_SNDBIT) - do_input(alias, id->sndbit, 0, SND_MAX); + do_input(alias, id->sndbit, 0, INPUT_DEVICE_ID_SND_MAX); sprintf(alias + strlen(alias), "f*"); if (id->flags & INPUT_DEVICE_ID_MATCH_FFBIT) - do_input(alias, id->ffbit, 0, FF_MAX); + do_input(alias, id->ffbit, 0, INPUT_DEVICE_ID_FF_MAX); sprintf(alias + strlen(alias), "w*"); if (id->flags & INPUT_DEVICE_ID_MATCH_SWBIT) - do_input(alias, id->swbit, 0, SW_MAX); + do_input(alias, id->swbit, 0, INPUT_DEVICE_ID_SW_MAX); return 1; } diff --git a/trunk/scripts/mod/mk_elfconfig.c b/trunk/scripts/mod/mk_elfconfig.c index 725d61c0fb43..db3881f14c2d 100644 --- a/trunk/scripts/mod/mk_elfconfig.c +++ b/trunk/scripts/mod/mk_elfconfig.c @@ -55,7 +55,8 @@ main(int argc, char **argv) else exit(1); - if ((strcmp(argv[1], "v850") == 0) || (strcmp(argv[1], "h8300") == 0)) + if ((strcmp(argv[1], "v850") == 0) || (strcmp(argv[1], "h8300") == 0) + || (strcmp(argv[1], "blackfin") == 0)) printf("#define MODULE_SYMBOL_PREFIX \"_\"\n"); else printf("#define MODULE_SYMBOL_PREFIX \"\"\n"); diff --git a/trunk/scripts/mod/modpost.c b/trunk/scripts/mod/modpost.c index 78d659cbb36a..480e18b00aa6 100644 --- a/trunk/scripts/mod/modpost.c +++ b/trunk/scripts/mod/modpost.c @@ -55,6 +55,17 @@ void warn(const char *fmt, ...) va_end(arglist); } +void merror(const char *fmt, ...) +{ + va_list arglist; + + fprintf(stderr, "ERROR: "); + + va_start(arglist, fmt); + vfprintf(stderr, fmt, arglist); + va_end(arglist); +} + static int is_vmlinux(const char *modname) { const char *myname; @@ -333,10 +344,10 @@ void release_file(void *file, unsigned long size) munmap(file, size); } -static void parse_elf(struct elf_info *info, const char *filename) +static int parse_elf(struct elf_info *info, const char *filename) { unsigned int i; - Elf_Ehdr *hdr = info->hdr; + Elf_Ehdr *hdr; Elf_Shdr *sechdrs; Elf_Sym *sym; @@ -346,9 +357,18 @@ static void parse_elf(struct elf_info *info, const char *filename) exit(1); } info->hdr = hdr; - if (info->size < sizeof(*hdr)) - goto truncated; - + if (info->size < sizeof(*hdr)) { + /* file too small, assume this is an empty .o file */ + return 0; + } + /* Is this a valid ELF file? */ + if ((hdr->e_ident[EI_MAG0] != ELFMAG0) || + (hdr->e_ident[EI_MAG1] != ELFMAG1) || + (hdr->e_ident[EI_MAG2] != ELFMAG2) || + (hdr->e_ident[EI_MAG3] != ELFMAG3)) { + /* Not an ELF file - silently ignore it */ + return 0; + } /* Fix endianness in ELF header */ hdr->e_shoff = TO_NATIVE(hdr->e_shoff); hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); @@ -371,8 +391,10 @@ static void parse_elf(struct elf_info *info, const char *filename) = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; const char *secname; - if (sechdrs[i].sh_offset > info->size) - goto truncated; + if (sechdrs[i].sh_offset > info->size) { + fatal("%s is truncated. sechdrs[i].sh_offset=%u > sizeof(*hrd)=%ul\n", filename, (unsigned int)sechdrs[i].sh_offset, sizeof(*hdr)); + return 0; + } secname = secstrings + sechdrs[i].sh_name; if (strcmp(secname, ".modinfo") == 0) { info->modinfo = (void *)hdr + sechdrs[i].sh_offset; @@ -407,10 +429,7 @@ static void parse_elf(struct elf_info *info, const char *filename) sym->st_value = TO_NATIVE(sym->st_value); sym->st_size = TO_NATIVE(sym->st_size); } - return; - - truncated: - fatal("%s is truncated.\n", filename); + return 1; } static void parse_elf_finish(struct elf_info *info) @@ -581,9 +600,17 @@ static int strrcmp(const char *s, const char *sub) * the pattern is identified by: * tosec = .init.text | .exit.text | .init.data * fromsec = .data - * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one + * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console * * Pattern 3: + * Whitelist all references from .pci_fixup* section to .init.text + * This is part of the PCI init when built-in + * + * Pattern 4: + * Whitelist all refereces from .text.head to .init.data + * Whitelist all refereces from .text.head to .init.text + * + * Pattern 5: * Some symbols belong to init section but still it is ok to reference * these from non-init sections as these symbols don't have any memory * allocated for them and symbol address and value are same. So even @@ -591,6 +618,40 @@ static int strrcmp(const char *s, const char *sub) * For ex. symbols marking the init section boundaries. * This pattern is identified by * refsymname = __init_begin, _sinittext, _einittext + * + * Pattern 6: + * During the early init phase we have references from .init.text to + * .text we have an intended section mismatch - do not warn about it. + * See kernel_init() in init/main.c + * tosec = .init.text + * fromsec = .text + * atsym = kernel_init + * + * Pattern 7: + * Logos used in drivers/video/logo reside in __initdata but the + * funtion that references them are EXPORT_SYMBOL() so cannot be + * marker __init. So we whitelist them here. + * The pattern is: + * tosec = .init.data + * fromsec = .text* + * refsymname = logo_ + * + * Pattern 8: + * Symbols contained in .paravirtprobe may safely reference .init.text. + * The pattern is: + * tosec = .init.text + * fromsec = .paravirtprobe + * + * Pattern 9: + * Some of functions are common code between boot time and hotplug + * time. The bootmem allocater is called only boot time in its + * functions. So it's ok to reference. + * tosec = .init.text + * + * Pattern 10: + * ia64 has machvec table for each platform. It is mixture of function + * pointer of .init.text and .text. + * fromsec = .machvec **/ static int secref_whitelist(const char *modname, const char *tosec, const char *fromsec, const char *atsym, @@ -617,6 +678,12 @@ static int secref_whitelist(const char *modname, const char *tosec, NULL }; + const char *pat4sym[] = { + "sparse_index_alloc", + "zone_wait_table_init", + NULL + }; + /* Check for pattern 1 */ if (strcmp(tosec, ".init.data") != 0) f1 = 0; @@ -642,25 +709,50 @@ static int secref_whitelist(const char *modname, const char *tosec, if (f1 && f2) return 1; - /* Whitelist all references from .pci_fixup section if vmlinux - * Whitelist all refereces from .text.head to .init.data if vmlinux - * Whitelist all refereces from .text.head to .init.text if vmlinux - */ - if (is_vmlinux(modname)) { - if ((strcmp(fromsec, ".pci_fixup") == 0) && - (strcmp(tosec, ".init.text") == 0)) + /* Check for pattern 3 */ + if ((strncmp(fromsec, ".pci_fixup", strlen(".pci_fixup")) == 0) && + (strcmp(tosec, ".init.text") == 0)) + return 1; + + /* Check for pattern 4 */ + if ((strcmp(fromsec, ".text.head") == 0) && + ((strcmp(tosec, ".init.data") == 0) || + (strcmp(tosec, ".init.text") == 0))) + return 1; + + /* Check for pattern 5 */ + for (s = pat3refsym; *s; s++) + if (strcmp(refsymname, *s) == 0) + return 1; + + /* Check for pattern 6 */ + if ((strcmp(tosec, ".init.text") == 0) && + (strcmp(fromsec, ".text") == 0) && + (strcmp(refsymname, "kernel_init") == 0)) return 1; - if ((strcmp(fromsec, ".text.head") == 0) && - ((strcmp(tosec, ".init.data") == 0) || - (strcmp(tosec, ".init.text") == 0))) + /* Check for pattern 7 */ + if ((strcmp(tosec, ".init.data") == 0) && + (strncmp(fromsec, ".text", strlen(".text")) == 0) && + (strncmp(refsymname, "logo_", strlen("logo_")) == 0)) return 1; - /* Check for pattern 3 */ - for (s = pat3refsym; *s; s++) - if (strcmp(refsymname, *s) == 0) + /* Check for pattern 8 */ + if ((strcmp(tosec, ".init.text") == 0) && + (strcmp(fromsec, ".paravirtprobe") == 0)) + return 1; + + /* Check for pattern 9 */ + if ((strcmp(tosec, ".init.text") == 0) && + (strcmp(fromsec, ".text") == 0)) + for (s = pat4sym; *s; s++) + if (strcmp(atsym, *s) == 0) return 1; - } + + /* Check for pattern 10 */ + if (strcmp(fromsec, ".machvec") == 0) + return 1; + return 0; } @@ -1090,7 +1182,8 @@ static void read_symbols(char *modname) struct elf_info info = { }; Elf_Sym *sym; - parse_elf(&info, modname); + if (!parse_elf(&info, modname)) + return; mod = new_module(modname); @@ -1265,9 +1358,14 @@ static int add_versions(struct buffer *b, struct module *mod) exp = find_symbol(s->name); if (!exp || exp->module == mod) { if (have_vmlinux && !s->weak) { - warn("\"%s\" [%s.ko] undefined!\n", - s->name, mod->name); - err = warn_unresolved ? 0 : 1; + if (warn_unresolved) { + warn("\"%s\" [%s.ko] undefined!\n", + s->name, mod->name); + } else { + merror("\"%s\" [%s.ko] undefined!\n", + s->name, mod->name); + err = 1; + } } continue; } @@ -1318,6 +1416,7 @@ static void add_depends(struct buffer *b, struct module *mod, buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); buf_printf(b, "\"depends="); for (s = mod->unres; s; s = s->next) { + const char *p; if (!s->module) continue; @@ -1325,8 +1424,11 @@ static void add_depends(struct buffer *b, struct module *mod, continue; s->module->seen = 1; - buf_printf(b, "%s%s", first ? "" : ",", - strrchr(s->module->name, '/') + 1); + if ((p = strrchr(s->module->name, '/')) != NULL) + p++; + else + p = s->module->name; + buf_printf(b, "%s%s", first ? "" : ",", p); first = 0; } buf_printf(b, "\";\n"); diff --git a/trunk/scripts/mod/modpost.h b/trunk/scripts/mod/modpost.h index d398c61e55ef..0858caa9c03f 100644 --- a/trunk/scripts/mod/modpost.h +++ b/trunk/scripts/mod/modpost.h @@ -145,3 +145,4 @@ void release_file(void *file, unsigned long size); void fatal(const char *fmt, ...); void warn(const char *fmt, ...); +void merror(const char *fmt, ...); diff --git a/trunk/scripts/mod/sumversion.c b/trunk/scripts/mod/sumversion.c index 8a2875689e4d..6873d5af80d5 100644 --- a/trunk/scripts/mod/sumversion.c +++ b/trunk/scripts/mod/sumversion.c @@ -397,10 +397,9 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen) (int) strlen(basename) - 2, basename); file = grab_file(filelist, &len); - if (!file) { - warn("could not find versions for %s\n", filelist); + if (!file) + /* not a module or .mod file missing - ignore */ return; - } sources = strchr(file, '\n'); if (!sources) { diff --git a/trunk/security/capability.c b/trunk/security/capability.c index b868e7eda5f0..38296a005465 100644 --- a/trunk/security/capability.c +++ b/trunk/security/capability.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/security/commoncap.c b/trunk/security/commoncap.c index 5a5ef5ca7ea9..384379ede4fd 100644 --- a/trunk/security/commoncap.c +++ b/trunk/security/commoncap.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/security/selinux/hooks.c b/trunk/security/selinux/hooks.c index 885a9a958b8d..ad8dd4e8657e 100644 --- a/trunk/security/selinux/hooks.c +++ b/trunk/security/selinux/hooks.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -1758,12 +1757,11 @@ static inline void flush_unauthorized_files(struct files_struct * files) } } file_list_unlock(); - - /* Reset controlling tty. */ - if (drop_tty) - proc_set_tty(current, NULL); } mutex_unlock(&tty_mutex); + /* Reset controlling tty. */ + if (drop_tty) + no_tty(); /* Revalidate access to inherited open files. */ diff --git a/trunk/sound/aoa/codecs/snd-aoa-codec-onyx.c b/trunk/sound/aoa/codecs/snd-aoa-codec-onyx.c index 7f980be5d060..e91f9f66f395 100644 --- a/trunk/sound/aoa/codecs/snd-aoa-codec-onyx.c +++ b/trunk/sound/aoa/codecs/snd-aoa-codec-onyx.c @@ -1061,7 +1061,7 @@ static int onyx_i2c_attach(struct i2c_adapter *adapter) busnode = pmac_i2c_get_bus_node(bus); while ((dev = of_get_next_child(busnode, dev)) != NULL) { - if (device_is_compatible(dev, "pcm3052")) { + if (of_device_is_compatible(dev, "pcm3052")) { const u32 *addr; printk(KERN_DEBUG PFX "found pcm3052\n"); addr = of_get_property(dev, "reg", NULL); @@ -1074,7 +1074,7 @@ static int onyx_i2c_attach(struct i2c_adapter *adapter) /* if that didn't work, try desperate mode for older * machines that have stuff missing from the device tree */ - if (!device_is_compatible(busnode, "k2-i2c")) + if (!of_device_is_compatible(busnode, "k2-i2c")) return -ENODEV; printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n"); diff --git a/trunk/sound/aoa/codecs/snd-aoa-codec-tas.c b/trunk/sound/aoa/codecs/snd-aoa-codec-tas.c index ceca38486eae..041fe52cbf29 100644 --- a/trunk/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/trunk/sound/aoa/codecs/snd-aoa-codec-tas.c @@ -938,7 +938,7 @@ static int tas_i2c_attach(struct i2c_adapter *adapter) busnode = pmac_i2c_get_bus_node(bus); while ((dev = of_get_next_child(busnode, dev)) != NULL) { - if (device_is_compatible(dev, "tas3004")) { + if (of_device_is_compatible(dev, "tas3004")) { const u32 *addr; printk(KERN_DEBUG PFX "found tas3004\n"); addr = of_get_property(dev, "reg", NULL); diff --git a/trunk/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/trunk/sound/aoa/soundbus/i2sbus/i2sbus-core.c index 79fc4bc09e5e..0fccdbf51663 100644 --- a/trunk/sound/aoa/soundbus/i2sbus/i2sbus-core.c +++ b/trunk/sound/aoa/soundbus/i2sbus/i2sbus-core.c @@ -336,8 +336,8 @@ static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match) } while ((np = of_get_next_child(dev->ofdev.node, np))) { - if (device_is_compatible(np, "i2sbus") || - device_is_compatible(np, "i2s-modem")) { + if (of_device_is_compatible(np, "i2sbus") || + of_device_is_compatible(np, "i2s-modem")) { got += i2sbus_add_dev(dev, control, np); } } diff --git a/trunk/sound/arm/pxa2xx-ac97.c b/trunk/sound/arm/pxa2xx-ac97.c index 28db4be7a16f..19c65a8d86a7 100644 --- a/trunk/sound/arm/pxa2xx-ac97.c +++ b/trunk/sound/arm/pxa2xx-ac97.c @@ -260,7 +260,7 @@ static int pxa2xx_ac97_do_suspend(struct snd_card *card, pm_message_t state) if (platform_ops && platform_ops->suspend) platform_ops->suspend(platform_ops->priv); GCR |= GCR_ACLINK_OFF; - pxa_set_cken(CKEN2_AC97, 0); + pxa_set_cken(CKEN_AC97, 0); return 0; } @@ -269,7 +269,7 @@ static int pxa2xx_ac97_do_resume(struct snd_card *card) { pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data; - pxa_set_cken(CKEN2_AC97, 1); + pxa_set_cken(CKEN_AC97, 1); if (platform_ops && platform_ops->resume) platform_ops->resume(platform_ops->priv); snd_ac97_resume(pxa2xx_ac97_ac97); @@ -337,7 +337,7 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) /* Use GPIO 113 as AC97 Reset on Bulverde */ pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); #endif - pxa_set_cken(CKEN2_AC97, 1); + pxa_set_cken(CKEN_AC97, 1); ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus); if (ret) @@ -361,10 +361,10 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) err: if (card) snd_card_free(card); - if (CKEN & CKEN2_AC97) { + if (CKEN & CKEN_AC97) { GCR |= GCR_ACLINK_OFF; free_irq(IRQ_AC97, NULL); - pxa_set_cken(CKEN2_AC97, 0); + pxa_set_cken(CKEN_AC97, 0); } return ret; } @@ -378,7 +378,7 @@ static int __devexit pxa2xx_ac97_remove(struct platform_device *dev) platform_set_drvdata(dev, NULL); GCR |= GCR_ACLINK_OFF; free_irq(IRQ_AC97, NULL); - pxa_set_cken(CKEN2_AC97, 0); + pxa_set_cken(CKEN_AC97, 0); } return 0; diff --git a/trunk/sound/core/control.c b/trunk/sound/core/control.c index 86de7258b76d..1f1ab9c1b668 100644 --- a/trunk/sound/core/control.c +++ b/trunk/sound/core/control.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/sound/core/hwdep.c b/trunk/sound/core/hwdep.c index 96ffdf18c3fe..51ad95b7c894 100644 --- a/trunk/sound/core/hwdep.c +++ b/trunk/sound/core/hwdep.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/sound/core/oss/mixer_oss.c b/trunk/sound/core/oss/mixer_oss.c index 74a2923eb401..fccad8f0a6bb 100644 --- a/trunk/sound/core/oss/mixer_oss.c +++ b/trunk/sound/core/oss/mixer_oss.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/trunk/sound/core/oss/pcm_oss.c b/trunk/sound/core/oss/pcm_oss.c index c4744bb07f41..fc11572c48cf 100644 --- a/trunk/sound/core/oss/pcm_oss.c +++ b/trunk/sound/core/oss/pcm_oss.c @@ -28,7 +28,6 @@ #include #include -#include #include #include #include diff --git a/trunk/sound/core/pcm_native.c b/trunk/sound/core/pcm_native.c index 3e276fcf3336..905234817c89 100644 --- a/trunk/sound/core/pcm_native.c +++ b/trunk/sound/core/pcm_native.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/trunk/sound/core/rawmidi.c b/trunk/sound/core/rawmidi.c index d14dcbb6dbca..e470c3c7d611 100644 --- a/trunk/sound/core/rawmidi.c +++ b/trunk/sound/core/rawmidi.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/sound/core/seq/oss/seq_oss.c b/trunk/sound/core/seq/oss/seq_oss.c index 2eb987308b53..bc0992398461 100644 --- a/trunk/sound/core/seq/oss/seq_oss.c +++ b/trunk/sound/core/seq/oss/seq_oss.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/trunk/sound/core/seq/seq_clientmgr.c b/trunk/sound/core/seq/seq_clientmgr.c index 694efe832b67..b31b5282a2c8 100644 --- a/trunk/sound/core/seq/seq_clientmgr.c +++ b/trunk/sound/core/seq/seq_clientmgr.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/trunk/sound/core/timer.c b/trunk/sound/core/timer.c index 160e40ede723..67520b3c0042 100644 --- a/trunk/sound/core/timer.c +++ b/trunk/sound/core/timer.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/sound/oss/Kconfig b/trunk/sound/oss/Kconfig index 4c419300305d..4b30ae6d8ba5 100644 --- a/trunk/sound/oss/Kconfig +++ b/trunk/sound/oss/Kconfig @@ -5,23 +5,22 @@ # # Prompt user for primary drivers. -config OBSOLETE_OSS +config OSS_OBSOLETE bool "Obsolete OSS drivers" depends on SOUND_PRIME help This option enables support for obsolete OSS drivers that - are scheduled for removal in the near future since there - are ALSA drivers for the same hardware. + are scheduled for removal in the near future. Please contact Adrian Bunk if you had to - say Y here because your soundcard is not properly supported + say Y here because your hardware is not properly supported by ALSA. If unsure, say N. config SOUND_BT878 tristate "BT878 audio dma" - depends on SOUND_PRIME && PCI + depends on SOUND_PRIME && PCI && OSS_OBSOLETE ---help--- Audio DMA support for bt878 based grabber boards. As you might have already noticed, bt878 is listed with two functions in /proc/pci. @@ -45,22 +44,9 @@ config SOUND_BCM_CS4297A note that CONFIG_KGDB should not be enabled at the same time, since it also attempts to use this UART port. -config SOUND_ES1371 - tristate "Creative Ensoniq AudioPCI 97 (ES1371)" - depends on SOUND_PRIME && PCI && OBSOLETE_OSS - help - Say Y or M if you have a PCI sound card utilizing the Ensoniq - ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if - your sound card uses an ES1371 without removing your computer's - cover, use lspci -n and look for the PCI ID 1274:1371. Since - Ensoniq was bought by Creative Labs, Sound Blaster 64/PCI - models are either ES1370 or ES1371 based. This driver differs - slightly from OSS/Free, so PLEASE READ - . - config SOUND_ICH tristate "Intel ICH (i8xx) audio support" - depends on SOUND_PRIME && PCI + depends on SOUND_PRIME && PCI && OSS_OBSOLETE help Support for integral audio in Intel's I/O Controller Hub (ICH) chipset, as used on the 810/820/840 motherboards. @@ -362,7 +348,7 @@ config MSND_FIFOSIZE config SOUND_VIA82CXXX tristate "VIA 82C686 Audio Codec" - depends on SOUND_PRIME && PCI + depends on SOUND_PRIME && PCI && OSS_OBSOLETE help Say Y here to include support for the audio codec found on VIA 82Cxxx-based chips. Typically these are built into a motherboard. @@ -416,7 +402,7 @@ config SOUND_DMAP config SOUND_CS4232 tristate "Crystal CS4232 based (PnP) cards" - depends on SOUND_OSS + depends on SOUND_OSS && OSS_OBSOLETE help Say Y here if you have a card based on the Crystal CS4232 chip set, which uses its own Plug and Play protocol. @@ -735,7 +721,7 @@ config SOUND_WAVEARTIST config SOUND_TVMIXER tristate "TV card (bt848) mixer support" - depends on SOUND_PRIME && I2C && VIDEO_V4L1 + depends on SOUND_PRIME && I2C && VIDEO_V4L1 && OSS_OBSOLETE help Support for audio mixer facilities on the BT848 TV frame-grabber card. diff --git a/trunk/sound/oss/btaudio.c b/trunk/sound/oss/btaudio.c index f813ae9c2134..4d5cf05b8922 100644 --- a/trunk/sound/oss/btaudio.c +++ b/trunk/sound/oss/btaudio.c @@ -344,7 +344,7 @@ static int btaudio_mixer_ioctl(struct inode *inode, struct file *file, if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; memset(&info,0,sizeof(info)); - strlcpy(info.id,"bt878",sizeof(info.id)-1); + strlcpy(info.id, "bt878", sizeof(info.id)); strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)); if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; diff --git a/trunk/sound/oss/dmasound/Kconfig b/trunk/sound/oss/dmasound/Kconfig index 18e149f52a88..71b313479f83 100644 --- a/trunk/sound/oss/dmasound/Kconfig +++ b/trunk/sound/oss/dmasound/Kconfig @@ -12,20 +12,6 @@ config DMASOUND_ATARI want). If you want to compile it as a module, say M here and read . -config DMASOUND_PMAC - tristate "PowerMac DMA sound support" - depends on PPC32 && PPC_PMAC && SOUND && I2C && OBSOLETE_OSS - select DMASOUND - help - If you want to use the internal audio of your PowerMac in Linux, - answer Y to this question. This will provide a Sun-like /dev/audio, - compatible with the Linux/i386 sound system. Otherwise, say N. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you - want). If you want to compile it as a module, say M here and read - . - config DMASOUND_PAULA tristate "Amiga DMA sound support" depends on (AMIGA || APUS) && SOUND diff --git a/trunk/sound/oss/dmasound/dmasound_awacs.c b/trunk/sound/oss/dmasound/dmasound_awacs.c index 730fa1d001a5..8f6388004f44 100644 --- a/trunk/sound/oss/dmasound/dmasound_awacs.c +++ b/trunk/sound/oss/dmasound/dmasound_awacs.c @@ -362,7 +362,7 @@ setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* of_get_property(np,"audio-gpio",NULL); if (property != 0 && strcmp(property,name) == 0) break; - } else if (compatible && device_is_compatible(np, compatible)) + } else if (compatible && of_device_is_compatible(np, compatible)) break; np = of_get_next_child(gpiop, np); } @@ -2620,17 +2620,17 @@ get_codec_type(struct device_node *info) if (info) { /* must do awacs first to allow screamer to overide it */ - if (device_is_compatible(info, "awacs")) + if (of_device_is_compatible(info, "awacs")) codec = AWACS_AWACS ; - if (device_is_compatible(info, "screamer")) + if (of_device_is_compatible(info, "screamer")) codec = AWACS_SCREAMER; - if (device_is_compatible(info, "burgundy")) + if (of_device_is_compatible(info, "burgundy")) codec = AWACS_BURGUNDY ; - if (device_is_compatible(info, "daca")) + if (of_device_is_compatible(info, "daca")) codec = AWACS_DACA; - if (device_is_compatible(info, "tumbler")) + if (of_device_is_compatible(info, "tumbler")) codec = AWACS_TUMBLER; - if (device_is_compatible(info, "snapper")) + if (of_device_is_compatible(info, "snapper")) codec = AWACS_SNAPPER; } return codec ; @@ -2772,7 +2772,7 @@ set_hw_byteswap(struct device_node *io) for (mio = io->parent; mio ; mio = mio->parent) { if (strcmp(mio->name, "mac-io") == 0) { - if (device_is_compatible(mio, "Keylargo")) + if (of_device_is_compatible(mio, "Keylargo")) kl = 1; break; } diff --git a/trunk/sound/oss/sh_dac_audio.c b/trunk/sound/oss/sh_dac_audio.c index 7ea9accc2ba4..b493660deb36 100644 --- a/trunk/sound/oss/sh_dac_audio.c +++ b/trunk/sound/oss/sh_dac_audio.c @@ -104,7 +104,7 @@ static void dac_audio_set_rate(void) unsigned long interval; struct clk *clk; - clk = clk_get("module_clk"); + clk = clk_get(NULL, "module_clk"); interval = (clk_get_rate(clk) / 4) / rate; clk_put(clk); ctrl_outl(interval, TMU1_TCOR); diff --git a/trunk/sound/oss/swarm_cs4297a.c b/trunk/sound/oss/swarm_cs4297a.c index 016b918329ad..a8057f259553 100644 --- a/trunk/sound/oss/swarm_cs4297a.c +++ b/trunk/sound/oss/swarm_cs4297a.c @@ -75,7 +75,6 @@ #include #include #include -#include #include #include diff --git a/trunk/sound/oss/trident.c b/trunk/sound/oss/trident.c index 72a8a0ed36a2..d98d311542ed 100644 --- a/trunk/sound/oss/trident.c +++ b/trunk/sound/oss/trident.c @@ -207,7 +207,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/sound/oss/via82cxxx_audio.c b/trunk/sound/oss/via82cxxx_audio.c index 7ab3a732e184..5d3c0372df32 100644 --- a/trunk/sound/oss/via82cxxx_audio.c +++ b/trunk/sound/oss/via82cxxx_audio.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/sound/ppc/pmac.c b/trunk/sound/ppc/pmac.c index 2bae9c1a2b54..5a2bef44a2f5 100644 --- a/trunk/sound/ppc/pmac.c +++ b/trunk/sound/ppc/pmac.c @@ -843,7 +843,7 @@ static void __init detect_byte_swap(struct snd_pmac *chip) /* if seems that Keylargo can't byte-swap */ for (mio = chip->node->parent; mio; mio = mio->parent) { if (strcmp(mio->name, "mac-io") == 0) { - if (device_is_compatible(mio, "Keylargo")) + if (of_device_is_compatible(mio, "Keylargo")) chip->can_byte_swap = 0; break; } @@ -910,7 +910,7 @@ static int __init snd_pmac_detect(struct snd_pmac *chip) chip->node = of_find_node_by_name(NULL, "i2s-a"); if (chip->node && chip->node->parent && chip->node->parent->parent) { - if (device_is_compatible(chip->node->parent->parent, + if (of_device_is_compatible(chip->node->parent->parent, "K2-Keylargo")) chip->is_k2 = 1; } @@ -941,22 +941,22 @@ static int __init snd_pmac_detect(struct snd_pmac *chip) return -ENODEV; } /* This should be verified on older screamers */ - if (device_is_compatible(sound, "screamer")) { + if (of_device_is_compatible(sound, "screamer")) { chip->model = PMAC_SCREAMER; // chip->can_byte_swap = 0; /* FIXME: check this */ } - if (device_is_compatible(sound, "burgundy")) { + if (of_device_is_compatible(sound, "burgundy")) { chip->model = PMAC_BURGUNDY; chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ } - if (device_is_compatible(sound, "daca")) { + if (of_device_is_compatible(sound, "daca")) { chip->model = PMAC_DACA; chip->can_capture = 0; /* no capture */ chip->can_duplex = 0; // chip->can_byte_swap = 0; /* FIXME: check this */ chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ } - if (device_is_compatible(sound, "tumbler")) { + if (of_device_is_compatible(sound, "tumbler")) { chip->model = PMAC_TUMBLER; chip->can_capture = 0; /* no capture */ chip->can_duplex = 0; @@ -965,7 +965,7 @@ static int __init snd_pmac_detect(struct snd_pmac *chip) chip->freq_table = tumbler_freqs; chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ } - if (device_is_compatible(sound, "snapper")) { + if (of_device_is_compatible(sound, "snapper")) { chip->model = PMAC_SNAPPER; // chip->can_byte_swap = 0; /* FIXME: check this */ chip->num_freqs = ARRAY_SIZE(tumbler_freqs); diff --git a/trunk/sound/ppc/tumbler.c b/trunk/sound/ppc/tumbler.c index 54e333fbb1d0..5821cdd0bec9 100644 --- a/trunk/sound/ppc/tumbler.c +++ b/trunk/sound/ppc/tumbler.c @@ -1060,7 +1060,7 @@ static struct device_node *find_compatible_audio_device(const char *name) for (np = of_get_next_child(gpiop, NULL); np; np = of_get_next_child(gpiop, np)) { - if (device_is_compatible(np, name)) + if (of_device_is_compatible(np, name)) break; } of_node_put(gpiop); diff --git a/trunk/sound/soc/pxa/pxa2xx-ac97.c b/trunk/sound/soc/pxa/pxa2xx-ac97.c index 1bbbeff84ef0..b222755763e7 100644 --- a/trunk/sound/soc/pxa/pxa2xx-ac97.c +++ b/trunk/sound/soc/pxa/pxa2xx-ac97.c @@ -256,7 +256,7 @@ static int pxa2xx_ac97_suspend(struct platform_device *pdev, struct snd_soc_cpu_dai *dai) { GCR |= GCR_ACLINK_OFF; - pxa_set_cken(CKEN2_AC97, 0); + pxa_set_cken(CKEN_AC97, 0); return 0; } @@ -271,7 +271,7 @@ static int pxa2xx_ac97_resume(struct platform_device *pdev, /* Use GPIO 113 as AC97 Reset on Bulverde */ pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); #endif - pxa_set_cken(CKEN2_AC97, 1); + pxa_set_cken(CKEN_AC97, 1); return 0; } @@ -296,14 +296,14 @@ static int pxa2xx_ac97_probe(struct platform_device *pdev) /* Use GPIO 113 as AC97 Reset on Bulverde */ pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); #endif - pxa_set_cken(CKEN2_AC97, 1); + pxa_set_cken(CKEN_AC97, 1); return 0; err: - if (CKEN & CKEN2_AC97) { + if (CKEN & CKEN_AC97) { GCR |= GCR_ACLINK_OFF; free_irq(IRQ_AC97, NULL); - pxa_set_cken(CKEN2_AC97, 0); + pxa_set_cken(CKEN_AC97, 0); } return ret; } @@ -312,7 +312,7 @@ static void pxa2xx_ac97_remove(struct platform_device *pdev) { GCR |= GCR_ACLINK_OFF; free_irq(IRQ_AC97, NULL); - pxa_set_cken(CKEN2_AC97, 0); + pxa_set_cken(CKEN_AC97, 0); } static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, diff --git a/trunk/sound/soc/pxa/pxa2xx-i2s.c b/trunk/sound/soc/pxa/pxa2xx-i2s.c index 575a6137c040..50c5c83f67db 100644 --- a/trunk/sound/soc/pxa/pxa2xx-i2s.c +++ b/trunk/sound/soc/pxa/pxa2xx-i2s.c @@ -149,7 +149,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm); pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk); - pxa_set_cken(CKEN8_I2S, 1); + pxa_set_cken(CKEN_I2S, 1); pxa_i2s_wait(); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -234,7 +234,7 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) if (SACR1 & (SACR1_DREC | SACR1_DRPL)) { SACR0 &= ~SACR0_ENB; pxa_i2s_wait(); - pxa_set_cken(CKEN8_I2S, 0); + pxa_set_cken(CKEN_I2S, 0); } } diff --git a/trunk/usr/Kconfig b/trunk/usr/Kconfig index 07727f3c7cea..86cecb59dd07 100644 --- a/trunk/usr/Kconfig +++ b/trunk/usr/Kconfig @@ -17,7 +17,7 @@ config INITRAMFS_SOURCE When multiple directories and files are specified then the initramfs image will be the aggregate of all of them. - See for more details. If you are not sure, leave it blank.