diff options
1149 files changed, 21281 insertions, 10955 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-rbd b/Documentation/ABI/testing/sysfs-bus-rbd new file mode 100644 index 000000000000..90a87e2a572b --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-rbd @@ -0,0 +1,83 @@ +What: /sys/bus/rbd/ +Date: November 2010 +Contact: Yehuda Sadeh <yehuda@hq.newdream.net>, + Sage Weil <sage@newdream.net> +Description: + +Being used for adding and removing rbd block devices. + +Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name] + + $ echo "192.168.0.1 name=admin rbd foo" > /sys/bus/rbd/add + +The snapshot name can be "-" or omitted to map the image read/write. A <dev-id> +will be assigned for any registered block device. If snapshot is used, it will +be mapped read-only. + +Removal of a device: + + $ echo <dev-id> > /sys/bus/rbd/remove + +Entries under /sys/bus/rbd/devices/<dev-id>/ +-------------------------------------------- + +client_id + + The ceph unique client id that was assigned for this specific session. + +major + + The block device major number. + +name + + The name of the rbd image. + +pool + + The pool where this rbd image resides. The pool-name pair is unique + per rados system. + +size + + The size (in bytes) of the mapped block device. + +refresh + + Writing to this file will reread the image header data and set + all relevant datastructures accordingly. + +current_snap + + The current snapshot for which the device is mapped. + +create_snap + + Create a snapshot: + + $ echo <snap-name> > /sys/bus/rbd/devices/<dev-id>/snap_create + +rollback_snap + + Rolls back data to the specified snapshot. This goes over the entire + list of rados blocks and sends a rollback command to each. + + $ echo <snap-name> > /sys/bus/rbd/devices/<dev-id>/snap_rollback + +snap_* + + A directory per each snapshot + + +Entries under /sys/bus/rbd/devices/<dev-id>/snap_<snap-name> +------------------------------------------------------------- + +id + + The rados internal snapshot id assigned for this snapshot + +size + + The size of the image when this snapshot was taken. + + diff --git a/Documentation/ABI/testing/sysfs-platform-asus-laptop b/Documentation/ABI/testing/sysfs-platform-asus-laptop index 1d775390e856..41ff8ae4dee0 100644 --- a/Documentation/ABI/testing/sysfs-platform-asus-laptop +++ b/Documentation/ABI/testing/sysfs-platform-asus-laptop @@ -47,6 +47,20 @@ Date: January 2007 KernelVersion: 2.6.20 Contact: "Corentin Chary" <corentincj@iksaif.net> Description: - Control the bluetooth device. 1 means on, 0 means off. + Control the wlan device. 1 means on, 0 means off. This may control the led, the device or both. Users: Lapsus + +What: /sys/devices/platform/asus_laptop/wimax +Date: October 2010 +KernelVersion: 2.6.37 +Contact: "Corentin Chary" <corentincj@iksaif.net> +Description: + Control the wimax device. 1 means on, 0 means off. + +What: /sys/devices/platform/asus_laptop/wwan +Date: October 2010 +KernelVersion: 2.6.37 +Contact: "Corentin Chary" <corentincj@iksaif.net> +Description: + Control the wwan (3G) device. 1 means on, 0 means off. diff --git a/Documentation/ABI/testing/sysfs-platform-eeepc-wmi b/Documentation/ABI/testing/sysfs-platform-eeepc-wmi new file mode 100644 index 000000000000..e4b5fef5fadd --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-eeepc-wmi @@ -0,0 +1,10 @@ +What: /sys/devices/platform/eeepc-wmi/cpufv +Date: Oct 2010 +KernelVersion: 2.6.37 +Contact: "Corentin Chary" <corentincj@iksaif.net> +Description: + Change CPU clock configuration (write-only). + There are three available clock configuration: + * 0 -> Super Performance Mode + * 1 -> High Performance Mode + * 2 -> Power Saving Mode diff --git a/Documentation/DocBook/sh.tmpl b/Documentation/DocBook/sh.tmpl index d858d92cf6d9..4a38f604fa66 100644 --- a/Documentation/DocBook/sh.tmpl +++ b/Documentation/DocBook/sh.tmpl @@ -79,10 +79,6 @@ </sect2> </sect1> </chapter> - <chapter id="clk"> - <title>Clock Framework Extensions</title> -!Iinclude/linux/sh_clk.h - </chapter> <chapter id="mach"> <title>Machine Specific Interfaces</title> <sect1 id="dreamcast"> diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl index 4d4ce0e61e42..b4665b9c40b0 100644 --- a/Documentation/DocBook/uio-howto.tmpl +++ b/Documentation/DocBook/uio-howto.tmpl @@ -16,7 +16,7 @@ </orgname> <address> - <email>hjk@linutronix.de</email> + <email>hjk@hansjkoch.de</email> </address> </affiliation> </author> @@ -114,7 +114,7 @@ GPL version 2. <para>If you know of any translations for this document, or you are interested in translating it, please email me -<email>hjk@linutronix.de</email>. +<email>hjk@hansjkoch.de</email>. </para> </sect1> @@ -171,7 +171,7 @@ interested in translating it, please email me <title>Feedback</title> <para>Find something wrong with this document? (Or perhaps something right?) I would love to hear from you. Please email me at - <email>hjk@linutronix.de</email>.</para> + <email>hjk@hansjkoch.de</email>.</para> </sect1> </chapter> diff --git a/Documentation/development-process/2.Process b/Documentation/development-process/2.Process index 97726eba6102..911a45186340 100644 --- a/Documentation/development-process/2.Process +++ b/Documentation/development-process/2.Process @@ -154,7 +154,7 @@ The stages that a patch goes through are, generally: inclusion, it should be accepted by a relevant subsystem maintainer - though this acceptance is not a guarantee that the patch will make it all the way to the mainline. The patch will show up in the maintainer's - subsystem tree and into the staging trees (described below). When the + subsystem tree and into the -next trees (described below). When the process works, this step leads to more extensive review of the patch and the discovery of any problems resulting from the integration of this patch with work being done by others. @@ -236,7 +236,7 @@ finding the right maintainer. Sending patches directly to Linus is not normally the right way to go. -2.4: STAGING TREES +2.4: NEXT TREES The chain of subsystem trees guides the flow of patches into the kernel, but it also raises an interesting question: what if somebody wants to look @@ -250,7 +250,7 @@ changes land in the mainline kernel. One could pull changes from all of the interesting subsystem trees, but that would be a big and error-prone job. -The answer comes in the form of staging trees, where subsystem trees are +The answer comes in the form of -next trees, where subsystem trees are collected for testing and review. The older of these trees, maintained by Andrew Morton, is called "-mm" (for memory management, which is how it got started). The -mm tree integrates patches from a long list of subsystem @@ -275,7 +275,7 @@ directory at: Use of the MMOTM tree is likely to be a frustrating experience, though; there is a definite chance that it will not even compile. -The other staging tree, started more recently, is linux-next, maintained by +The other -next tree, started more recently, is linux-next, maintained by Stephen Rothwell. The linux-next tree is, by design, a snapshot of what the mainline is expected to look like after the next merge window closes. Linux-next trees are announced on the linux-kernel and linux-next mailing @@ -303,12 +303,25 @@ volatility of linux-next tends to make it a difficult development target. See http://lwn.net/Articles/289013/ for more information on this topic, and stay tuned; much is still in flux where linux-next is involved. -Besides the mmotm and linux-next trees, the kernel source tree now contains -the drivers/staging/ directory and many sub-directories for drivers or -filesystems that are on their way to being added to the kernel tree -proper, but they remain in drivers/staging/ while they still need more -work. - +2.4.1: STAGING TREES + +The kernel source tree now contains the drivers/staging/ directory, where +many sub-directories for drivers or filesystems that are on their way to +being added to the kernel tree live. They remain in drivers/staging while +they still need more work; once complete, they can be moved into the +kernel proper. This is a way to keep track of drivers that aren't +up to Linux kernel coding or quality standards, but people may want to use +them and track development. + +Greg Kroah-Hartman currently (as of 2.6.36) maintains the staging tree. +Drivers that still need work are sent to him, with each driver having +its own subdirectory in drivers/staging/. Along with the driver source +files, a TODO file should be present in the directory as well. The TODO +file lists the pending work that the driver needs for acceptance into +the kernel proper, as well as a list of people that should be Cc'd for any +patches to the driver. Staging drivers that don't currently build should +have their config entries depend upon CONFIG_BROKEN. Once they can +be successfully built without outside patches, CONFIG_BROKEN can be removed. 2.5: TOOLS diff --git a/Documentation/driver-model/interface.txt b/Documentation/driver-model/interface.txt deleted file mode 100644 index c66912bfe866..000000000000 --- a/Documentation/driver-model/interface.txt +++ /dev/null @@ -1,129 +0,0 @@ - -Device Interfaces - -Introduction -~~~~~~~~~~~~ - -Device interfaces are the logical interfaces of device classes that correlate -directly to userspace interfaces, like device nodes. - -Each device class may have multiple interfaces through which you can -access the same device. An input device may support the mouse interface, -the 'evdev' interface, and the touchscreen interface. A SCSI disk would -support the disk interface, the SCSI generic interface, and possibly a raw -device interface. - -Device interfaces are registered with the class they belong to. As devices -are added to the class, they are added to each interface registered with -the class. The interface is responsible for determining whether the device -supports the interface or not. - - -Programming Interface -~~~~~~~~~~~~~~~~~~~~~ - -struct device_interface { - char * name; - rwlock_t lock; - u32 devnum; - struct device_class * devclass; - - struct list_head node; - struct driver_dir_entry dir; - - int (*add_device)(struct device *); - int (*add_device)(struct intf_data *); -}; - -int interface_register(struct device_interface *); -void interface_unregister(struct device_interface *); - - -An interface must specify the device class it belongs to. It is added -to that class's list of interfaces on registration. - - -Interfaces can be added to a device class at any time. Whenever it is -added, each device in the class is passed to the interface's -add_device callback. When an interface is removed, each device is -removed from the interface. - - -Devices -~~~~~~~ -Once a device is added to a device class, it is added to each -interface that is registered with the device class. The class -is expected to place a class-specific data structure in -struct device::class_data. The interface can use that (along with -other fields of struct device) to determine whether or not the driver -and/or device support that particular interface. - - -Data -~~~~ - -struct intf_data { - struct list_head node; - struct device_interface * intf; - struct device * dev; - u32 intf_num; -}; - -int interface_add_data(struct interface_data *); - -The interface is responsible for allocating and initializing a struct -intf_data and calling interface_add_data() to add it to the device's list -of interfaces it belongs to. This list will be iterated over when the device -is removed from the class (instead of all possible interfaces for a class). -This structure should probably be embedded in whatever per-device data -structure the interface is allocating anyway. - -Devices are enumerated within the interface. This happens in interface_add_data() -and the enumerated value is stored in the struct intf_data for that device. - -sysfs -~~~~~ -Each interface is given a directory in the directory of the device -class it belongs to: - -Interfaces get a directory in the class's directory as well: - - class/ - `-- input - |-- devices - |-- drivers - |-- mouse - `-- evdev - -When a device is added to the interface, a symlink is created that points -to the device's directory in the physical hierarchy: - - class/ - `-- input - |-- devices - | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ - |-- drivers - | `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/ - |-- mouse - | `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ - `-- evdev - `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ - - -Future Plans -~~~~~~~~~~~~ -A device interface is correlated directly with a userspace interface -for a device, specifically a device node. For instance, a SCSI disk -exposes at least two interfaces to userspace: the standard SCSI disk -interface and the SCSI generic interface. It might also export a raw -device interface. - -Many interfaces have a major number associated with them and each -device gets a minor number. Or, multiple interfaces might share one -major number, and each will receive a range of minor numbers (like in -the case of input devices). - -These major and minor numbers could be stored in the interface -structure. Major and minor allocations could happen when the interface -is registered with the class, or via a helper function. - diff --git a/Documentation/edac.txt b/Documentation/edac.txt index 0b875e8da969..9ee774de57cd 100644 --- a/Documentation/edac.txt +++ b/Documentation/edac.txt @@ -196,7 +196,7 @@ csrow3. The representation of the above is reflected in the directory tree in EDAC's sysfs interface. Starting in directory /sys/devices/system/edac/mc each memory controller will be represented -by its own 'mcX' directory, where 'X" is the index of the MC. +by its own 'mcX' directory, where 'X' is the index of the MC. ..../edac/mc/ @@ -207,7 +207,7 @@ by its own 'mcX' directory, where 'X" is the index of the MC. .... Under each 'mcX' directory each 'csrowX' is again represented by a -'csrowX', where 'X" is the csrow index: +'csrowX', where 'X' is the csrow index: .../mc/mc0/ @@ -232,7 +232,7 @@ EDAC control and attribute files. In 'mcX' directories are EDAC control and attribute files for -this 'X" instance of the memory controllers: +this 'X' instance of the memory controllers: Counter reset control file: @@ -343,7 +343,7 @@ Sdram memory scrubbing rate: 'csrowX' DIRECTORIES In the 'csrowX' directories are EDAC control and attribute files for -this 'X" instance of csrow: +this 'X' instance of csrow: Total Uncorrectable Errors count attribute file: diff --git a/Documentation/fb/00-INDEX b/Documentation/fb/00-INDEX index a618fd99c9f0..30a70542e823 100644 --- a/Documentation/fb/00-INDEX +++ b/Documentation/fb/00-INDEX @@ -4,33 +4,41 @@ please mail me. Geert Uytterhoeven <geert@linux-m68k.org> 00-INDEX - - this file + - this file. arkfb.txt - info on the fbdev driver for ARK Logic chips. aty128fb.txt - info on the ATI Rage128 frame buffer driver. cirrusfb.txt - info on the driver for Cirrus Logic chipsets. +cmap_xfbdev.txt + - an introduction to fbdev's cmap structures. deferred_io.txt - an introduction to deferred IO. +efifb.txt + - info on the EFI platform driver for Intel based Apple computers. +ep93xx-fb.txt + - info on the driver for EP93xx LCD controller. fbcon.txt - intro to and usage guide for the framebuffer console (fbcon). framebuffer.txt - introduction to frame buffer devices. -imacfb.txt - - info on the generic EFI platform driver for Intel based Macs. +gxfb.txt + - info on the framebuffer driver for AMD Geode GX2 based processors. intel810.txt - documentation for the Intel 810/815 framebuffer driver. intelfb.txt - docs for Intel 830M/845G/852GM/855GM/865G/915G/945G fb driver. internals.txt - quick overview of frame buffer device internals. +lxfb.txt + - info on the framebuffer driver for AMD Geode LX based processors. matroxfb.txt - info on the Matrox framebuffer driver for Alpha, Intel and PPC. +metronomefb.txt + - info on the driver for the Metronome display controller. modedb.txt - info on the video mode database. -matroxfb.txt - - info on the Matrox frame buffer driver. pvr2fb.txt - info on the PowerVR 2 frame buffer driver. pxafb.txt @@ -39,13 +47,23 @@ s3fb.txt - info on the fbdev driver for S3 Trio/Virge chips. sa1100fb.txt - information about the driver for the SA-1100 LCD controller. +sh7760fb.txt + - info on the SH7760/SH7763 integrated LCDC Framebuffer driver. sisfb.txt - info on the framebuffer device driver for various SiS chips. sstfb.txt - info on the frame buffer driver for 3dfx' Voodoo Graphics boards. tgafb.txt - - info on the TGA (DECChip 21030) frame buffer driver + - info on the TGA (DECChip 21030) frame buffer driver. +tridentfb.txt + info on the framebuffer driver for some Trident chip based cards. +uvesafb.txt + - info on the userspace VESA (VBE2+ compliant) frame buffer device. vesafb.txt - - info on the VESA frame buffer device + - info on the VESA frame buffer device. +viafb.modes + - list of modes for VIA Integration Graphic Chip. +viafb.txt + - info on the VIA Integration Graphic Chip console framebuffer driver. vt8623fb.txt - info on the fb driver for the graphics core in VIA VT8623 chipsets. diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index a91f30890011..b6426f15b4ae 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -173,12 +173,13 @@ prototypes: sector_t (*bmap)(struct address_space *, sector_t); int (*invalidatepage) (struct page *, unsigned long); int (*releasepage) (struct page *, int); + void (*freepage)(struct page *); int (*direct_IO)(int, struct kiocb *, const struct iovec *iov, loff_t offset, unsigned long nr_segs); int (*launder_page) (struct page *); locking rules: - All except set_page_dirty may block + All except set_page_dirty and freepage may block BKL PageLocked(page) i_mutex writepage: no yes, unlocks (see below) @@ -193,6 +194,7 @@ perform_write: no n/a yes bmap: no invalidatepage: no yes releasepage: no yes +freepage: no yes direct_IO: no launder_page: no yes @@ -288,6 +290,9 @@ buffers from the page in preparation for freeing it. It returns zero to indicate that the buffers are (or may be) freeable. If ->releasepage is zero, the kernel assumes that the fs has no private interest in the buffers. + ->freepage() is called when the kernel is done dropping the page +from the page cache. + ->launder_page() may be called prior to releasing a page if it is still found to be dirty. It returns zero if the page was successfully cleaned, or an error value if not. Note that in order to prevent the page diff --git a/Documentation/filesystems/configfs/configfs_example_explicit.c b/Documentation/filesystems/configfs/configfs_example_explicit.c index d428cc9f07f3..fd53869f5633 100644 --- a/Documentation/filesystems/configfs/configfs_example_explicit.c +++ b/Documentation/filesystems/configfs/configfs_example_explicit.c @@ -89,7 +89,7 @@ static ssize_t childless_storeme_write(struct childless *childless, char *p = (char *) page; tmp = simple_strtoul(p, &p, 10); - if (!p || (*p && (*p != '\n'))) + if ((*p != '\0') && (*p != '\n')) return -EINVAL; if (tmp > INT_MAX) diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index ed7e5efc06d8..20899e095e7e 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -534,6 +534,7 @@ struct address_space_operations { sector_t (*bmap)(struct address_space *, sector_t); int (*invalidatepage) (struct page *, unsigned long); int (*releasepage) (struct page *, int); + void (*freepage)(struct page *); ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov, loff_t offset, unsigned long nr_segs); struct page* (*get_xip_page)(struct address_space *, sector_t, @@ -660,11 +661,10 @@ struct address_space_operations { releasepage: releasepage is called on PagePrivate pages to indicate that the page should be freed if possible. ->releasepage should remove any private data from the page and clear the - PagePrivate flag. It may also remove the page from the - address_space. If this fails for some reason, it may indicate - failure with a 0 return value. - This is used in two distinct though related cases. The first - is when the VM finds a clean page with no active users and + PagePrivate flag. If releasepage() fails for some reason, it must + indicate failure with a 0 return value. + releasepage() is used in two distinct though related cases. The + first is when the VM finds a clean page with no active users and wants to make it a free page. If ->releasepage succeeds, the page will be removed from the address_space and become free. @@ -679,6 +679,12 @@ struct address_space_operations { need to ensure this. Possibly it can clear the PageUptodate bit if it cannot free private data yet. + freepage: freepage is called once the page is no longer visible in + the page cache in order to allow the cleanup of any private + data. Since it may be called by the memory reclaimer, it + should not assume that the original address_space mapping still + exists, and it should not block. + direct_IO: called by the generic read/write routines to perform direct_IO - that is IO requests which bypass the page cache and transfer data directly between the storage and the diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index 9633da01ff46..792faa3c06cf 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -617,6 +617,16 @@ and have the following read/write attributes: is configured as an output, this value may be written; any nonzero value is treated as high. + If the pin can be configured as interrupt-generating interrupt + and if it has been configured to generate interrupts (see the + description of "edge"), you can poll(2) on that file and + poll(2) will return whenever the interrupt was triggered. If + you use poll(2), set the events POLLPRI and POLLERR. If you + use select(2), set the file descriptor in exceptfds. After + poll(2) returns, either lseek(2) to the beginning of the sysfs + file and read the new value or close the file and re-open it + to read the value. + "edge" ... reads as either "none", "rising", "falling", or "both". Write these strings to select the signal edge(s) that will make poll(2) on the "value" file return. diff --git a/Documentation/hwmon/lm93 b/Documentation/hwmon/lm93 index ac711f357faf..7a10616d0b44 100644 --- a/Documentation/hwmon/lm93 +++ b/Documentation/hwmon/lm93 @@ -11,7 +11,7 @@ Authors: Mark M. Hoffman <mhoffman@lightlink.com> Ported to 2.6 by Eric J. Bowersox <ericb@aspsys.com> Adapted to 2.6.20 by Carsten Emde <ce@osadl.org> - Modified for mainline integration by Hans J. Koch <hjk@linutronix.de> + Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de> Module Parameters ----------------- diff --git a/Documentation/hwmon/max6650 b/Documentation/hwmon/max6650 index 8be7beb9e3e8..c565650fcfc6 100644 --- a/Documentation/hwmon/max6650 +++ b/Documentation/hwmon/max6650 @@ -8,7 +8,7 @@ Supported chips: Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf Authors: - Hans J. Koch <hjk@linutronix.de> + Hans J. Koch <hjk@hansjkoch.de> John Morris <john.morris@spirentcom.com> Claus Gindhart <claus.gindhart@kontron.com> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 92e83e53148f..8b61c9360999 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2175,11 +2175,6 @@ and is between 256 and 4096 characters. It is defined in the file reset_devices [KNL] Force drivers to reset the underlying device during initialization. - resource_alloc_from_bottom - Allocate new resources from the beginning of available - space, not the end. If you need to use this, please - report a bug. - resume= [SWSUSP] Specify the partition device for software suspend @@ -2385,6 +2380,11 @@ and is between 256 and 4096 characters. It is defined in the file improve throughput, but will also increase the amount of memory reserved for use by the client. + swapaccount[=0|1] + [KNL] Enable accounting of swap in memory resource + controller if no parameter or 1 is given or disable + it if 0 is given (See Documentation/cgroups/memory.txt) + swiotlb= [IA-64] Number of I/O TLB slabs switches= [HW,M68k] diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index fe95105992c5..3c5e465296e1 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -144,6 +144,7 @@ tcp_adv_win_scale - INTEGER Count buffering overhead as bytes/2^tcp_adv_win_scale (if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale), if it is <= 0. + Possible values are [-31, 31], inclusive. Default: 2 tcp_allowed_congestion_control - STRING diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index 489e9bacd165..41cc7b30d7dd 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -379,8 +379,8 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: zero) bool pm_runtime_suspended(struct device *dev); - - return true if the device's runtime PM status is 'suspended', or false - otherwise + - return true if the device's runtime PM status is 'suspended' and its + 'power.disable_depth' field is equal to zero, or false otherwise void pm_runtime_allow(struct device *dev); - set the power.runtime_auto flag for the device and decrease its usage diff --git a/Documentation/sh/clk.txt b/Documentation/sh/clk.txt deleted file mode 100644 index 114b595cfa97..000000000000 --- a/Documentation/sh/clk.txt +++ /dev/null @@ -1,32 +0,0 @@ -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-dependent. 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/MAINTAINERS b/MAINTAINERS index 8e6548dbd5db..6a588873cf8d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -559,14 +559,14 @@ W: http://maxim.org.za/at91_26.html S: Maintained ARM/BCMRING ARM ARCHITECTURE -M: Leo Chen <leochen@broadcom.com> +M: Jiandong Zheng <jdzheng@broadcom.com> M: Scott Branden <sbranden@broadcom.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-bcmring ARM/BCMRING MTD NAND DRIVER -M: Leo Chen <leochen@broadcom.com> +M: Jiandong Zheng <jdzheng@broadcom.com> M: Scott Branden <sbranden@broadcom.com> L: linux-mtd@lists.infradead.org S: Maintained @@ -815,7 +815,7 @@ F: drivers/mmc/host/msm_sdcc.c F: drivers/mmc/host/msm_sdcc.h F: drivers/serial/msm_serial.h F: drivers/serial/msm_serial.c -T: git git://codeaurora.org/quic/kernel/dwalker/linux-msm.git +T: git git://codeaurora.org/quic/kernel/davidb/linux-msm.git S: Maintained ARM/TOSA MACHINE SUPPORT @@ -1359,7 +1359,7 @@ F: include/net/bluetooth/ BONDING DRIVER M: Jay Vosburgh <fubar@us.ibm.com> -L: bonding-devel@lists.sourceforge.net +L: netdev@vger.kernel.org W: http://sourceforge.net/projects/bonding/ S: Supported F: drivers/net/bonding/ @@ -1829,6 +1829,13 @@ W: http://www.chelsio.com S: Supported F: drivers/net/cxgb4vf/ +STMMAC ETHERNET DRIVER +M: Giuseppe Cavallaro <peppe.cavallaro@st.com> +L: netdev@vger.kernel.org +W: http://www.stlinux.com +S: Supported +F: drivers/net/stmmac/ + CYBERPRO FB DRIVER M: Russell King <linux@arm.linux.org.uk> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -2008,6 +2015,7 @@ F: drivers/hwmon/dme1737.c DOCBOOK FOR DOCUMENTATION M: Randy Dunlap <rdunlap@xenotime.net> S: Maintained +F: scripts/kernel-doc DOCKING STATION DRIVER M: Shaohua Li <shaohua.li@intel.com> @@ -2018,6 +2026,7 @@ F: drivers/acpi/dock.c DOCUMENTATION M: Randy Dunlap <rdunlap@xenotime.net> L: linux-doc@vger.kernel.org +T: quilt oss.oracle.com/~rdunlap/kernel-doc-patches/current/ S: Maintained F: Documentation/ @@ -2051,7 +2060,7 @@ F: Documentation/blockdev/drbd/ DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS M: Greg Kroah-Hartman <gregkh@suse.de> -T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6.git S: Supported F: Documentation/kobject.txt F: drivers/base/ @@ -2071,7 +2080,7 @@ F: include/drm/ INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets) M: Chris Wilson <chris@chris-wilson.co.uk> -L: intel-gfx@lists.freedesktop.org +L: intel-gfx@lists.freedesktop.org (subscribers-only) L: dri-devel@lists.freedesktop.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git S: Supported @@ -2435,10 +2444,12 @@ F: drivers/net/wan/sdla.c FRAMEBUFFER LAYER L: linux-fbdev@vger.kernel.org W: http://linux-fbdev.sourceforge.net/ +Q: http://patchwork.kernel.org/project/linux-fbdev/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6.git S: Orphan F: Documentation/fb/ -F: drivers/video/fb* +F: drivers/video/ +F: include/video/ F: include/linux/fb.h FREESCALE DMA DRIVER @@ -4053,9 +4064,8 @@ F: drivers/scsi/NCR_D700.* NETEFFECT IWARP RNIC DRIVER (IW_NES) M: Faisal Latif <faisal.latif@intel.com> -M: Chien Tung <chien.tin.tung@intel.com> L: linux-rdma@vger.kernel.org -W: http://www.neteffect.com +W: http://www.intel.com/Products/Server/Adapters/Server-Cluster/Server-Cluster-overview.htm S: Supported F: drivers/infiniband/hw/nes/ @@ -5828,6 +5838,8 @@ M: Chris Metcalf <cmetcalf@tilera.com> W: http://www.tilera.com/scm/ S: Supported F: arch/tile/ +F: drivers/char/hvc_tile.c +F: drivers/net/tile/ TLAN NETWORK DRIVER M: Samuel Chessman <chessman@tux.org> @@ -5920,7 +5932,6 @@ F: include/linux/tty.h TULIP NETWORK DRIVERS M: Grant Grundler <grundler@parisc-linux.org> -M: Kyle McMartin <kyle@mcmartin.ca> L: netdev@vger.kernel.org S: Maintained F: drivers/net/tulip/ @@ -6572,6 +6583,15 @@ F: include/linux/mfd/wm8400* F: include/sound/wm????.h F: sound/soc/codecs/wm* +WORKQUEUE +M: Tejun Heo <tj@kernel.org> +L: linux-kernel@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git +S: Maintained +F: include/linux/workqueue.h +F: kernel/workqueue.c +F: Documentation/workqueue.txt + X.25 NETWORK LAYER M: Andrew Hendry <andrew.hendry@gmail.com> L: linux-x25@vger.kernel.org @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 37 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc7 NAME = Flesh-Eating Bats with Fangs # *DOCUMENTATION* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index db524e75c4a2..d56d21c0573b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -9,7 +9,7 @@ config ARM select GENERIC_ATOMIC64 if (!CPU_32v6K || !AEABI) select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB - select HAVE_KPROBES if (!XIP_KERNEL) + select HAVE_KPROBES if (!XIP_KERNEL && !THUMB2_KERNEL) select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) @@ -1311,7 +1311,7 @@ config HZ config THUMB2_KERNEL bool "Compile the kernel in Thumb-2 mode" - depends on CPU_V7 && EXPERIMENTAL + depends on CPU_V7 && !CPU_V6 && EXPERIMENTAL select AEABI select ARM_ASM_UNIFIED help @@ -1759,7 +1759,7 @@ comment "At least one emulation must be selected" config FPE_NWFPE bool "NWFPE math emulation" - depends on !AEABI || OABI_COMPAT + depends on (!AEABI || OABI_COMPAT) && !THUMB2_KERNEL ---help--- Say Y to include the NWFPE floating point emulator in the kernel. This is necessary to run most binaries. Linux does not currently diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 4a590f4113e2..4d26f2c52a75 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -70,12 +70,7 @@ else $(obj)/uImage: LOADADDR=$(ZRELADDR) endif -ifeq ($(CONFIG_THUMB2_KERNEL),y) -# Set bit 0 to 1 so that "mov pc, rx" switches to Thumb-2 mode -$(obj)/uImage: STARTADDR=$(shell echo $(LOADADDR) | sed -e "s/.$$/1/") -else $(obj)/uImage: STARTADDR=$(LOADADDR) -endif $(obj)/uImage: $(obj)/zImage FORCE $(call if_changed,uimage) diff --git a/arch/arm/boot/bootp/init.S b/arch/arm/boot/bootp/init.S index 8b0de41c3dcb..78b508075161 100644 --- a/arch/arm/boot/bootp/init.S +++ b/arch/arm/boot/bootp/init.S @@ -73,6 +73,8 @@ move: ldmia r4!, {r7 - r10} @ move 32-bytes at a time .size _start, . - _start + .align + .type data,#object data: .word initrd_start @ source initrd address .word initrd_phys @ destination initrd address diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 6825c34646d4..7193884ed8b0 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -125,9 +125,13 @@ wait: mrc p14, 0, pc, c0, c1, 0 * sort out different calling conventions */ .align + .arm @ Always enter in ARM state start: .type start,#function - .rept 8 + THUMB( adr r12, BSYM(1f) ) + THUMB( bx r12 ) + THUMB( .rept 6 ) + ARM( .rept 8 ) mov r0, r0 .endr @@ -135,6 +139,7 @@ start: .word 0x016f2818 @ Magic numbers to help the loader .word start @ absolute load/run zImage address .word _edata @ zImage end address + THUMB( .thumb ) 1: mov r7, r1 @ save architecture ID mov r8, r2 @ save atags pointer @@ -174,7 +179,8 @@ not_angel: ldr sp, [r0, #28] #ifdef CONFIG_AUTO_ZRELADDR @ determine final kernel image address - and r4, pc, #0xf8000000 + mov r4, pc + and r4, r4, #0xf8000000 add r4, r4, #TEXT_OFFSET #else ldr r4, =zreladdr @@ -445,7 +451,8 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size */ mov r1, #0x1e orr r1, r1, #3 << 10 - mov r2, pc, lsr #20 + mov r2, pc + mov r2, r2, lsr #20 orr r1, r1, r2, lsl #20 add r0, r3, r2, lsl #2 str r1, [r0], #4 @@ -1084,6 +1091,6 @@ memdump: mov r12, r0 reloc_end: .align - .section ".stack", "w" + .section ".stack", "aw", %nobits user_stack: .space 4096 user_stack_end: diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in index d08168941bd6..366a924019ac 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.in +++ b/arch/arm/boot/compressed/vmlinux.lds.in @@ -57,7 +57,7 @@ SECTIONS .bss : { *(.bss) } _end = .; - .stack (NOLOAD) : { *(.stack) } + .stack : { *(.stack) } .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 772f95f1aecd..e6388dcd8cfa 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -146,9 +146,15 @@ static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val) unsigned int shift = (irq % 4) * 8; unsigned int cpu = cpumask_first(mask_val); u32 val; + struct irq_desc *desc; spin_lock(&irq_controller_lock); - irq_desc[irq].node = cpu; + desc = irq_to_desc(irq); + if (desc == NULL) { + spin_unlock(&irq_controller_lock); + return -EINVAL; + } + desc->node = cpu; val = readl(reg) & ~(0xff << shift); val |= 1 << (cpu + shift); writel(val, reg); @@ -210,7 +216,7 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) void __init gic_dist_init(unsigned int gic_nr, void __iomem *base, unsigned int irq_start) { - unsigned int max_irq, i; + unsigned int gic_irqs, irq_limit, i; u32 cpumask = 1 << smp_processor_id(); if (gic_nr >= MAX_GIC_NR) @@ -226,47 +232,49 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base, /* * Find out how many interrupts are supported. - */ - max_irq = readl(base + GIC_DIST_CTR) & 0x1f; - max_irq = (max_irq + 1) * 32; - - /* * The GIC only supports up to 1020 interrupt sources. - * Limit this to either the architected maximum, or the - * platform maximum. */ - if (max_irq > max(1020, NR_IRQS)) - max_irq = max(1020, NR_IRQS); + gic_irqs = readl(base + GIC_DIST_CTR) & 0x1f; + gic_irqs = (gic_irqs + 1) * 32; + if (gic_irqs > 1020) + gic_irqs = 1020; /* * Set all global interrupts to be level triggered, active low. */ - for (i = 32; i < max_irq; i += 16) + for (i = 32; i < gic_irqs; i += 16) writel(0, base + GIC_DIST_CONFIG + i * 4 / 16); /* * Set all global interrupts to this CPU only. */ - for (i = 32; i < max_irq; i += 4) + for (i = 32; i < gic_irqs; i += 4) writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); /* * Set priority on all global interrupts. */ - for (i = 32; i < max_irq; i += 4) + for (i = 32; i < gic_irqs; i += 4) writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); /* * Disable all interrupts. Leave the PPI and SGIs alone * as these enables are banked registers. */ - for (i = 32; i < max_irq; i += 32) + for (i = 32; i < gic_irqs; i += 32) writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); /* + * Limit number of interrupts registered to the platform maximum + */ + irq_limit = gic_data[gic_nr].irq_offset + gic_irqs; + if (WARN_ON(irq_limit > NR_IRQS)) + irq_limit = NR_IRQS; + + /* * Setup the Linux IRQ subsystem. */ - for (i = irq_start; i < gic_data[gic_nr].irq_offset + max_irq; i++) { + for (i = irq_start; i < irq_limit; i++) { set_irq_chip(i, &gic_chip); set_irq_chip_data(i, &gic_data[gic_nr]); set_irq_handler(i, handle_level_irq); diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig new file mode 100644 index 000000000000..38cb7c985426 --- /dev/null +++ b/arch/arm/configs/at91rm9200_defconfig @@ -0,0 +1,341 @@ +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_AT91=y +CONFIG_MACH_ONEARM=y +CONFIG_ARCH_AT91RM9200DK=y +CONFIG_MACH_AT91RM9200EK=y +CONFIG_MACH_CSB337=y +CONFIG_MACH_CSB637=y +CONFIG_MACH_CARMEVA=y +CONFIG_MACH_ATEB9200=y +CONFIG_MACH_KB9200=y +CONFIG_MACH_PICOTUX2XX=y +CONFIG_MACH_KAFA=y +CONFIG_MACH_ECBAT91=y +CONFIG_MACH_YL9200=y +CONFIG_MACH_CPUAT91=y +CONFIG_MACH_ECO920=y +CONFIG_MTD_AT91_DATAFLASH_CARD=y +CONFIG_AT91_PROGRAMMABLE_CLOCKS=y +CONFIG_AT91_TIMER_HZ=100 +# CONFIG_ARM_THUMB is not set +CONFIG_PCCARD=y +CONFIG_AT91_CF=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_LEDS=y +CONFIG_LEDS_CPU=y +CONFIG_ZBOOT_ROM_TEXT=0x10000000 +CONFIG_ZBOOT_ROM_BSS=0x20040000 +CONFIG_KEXEC=y +CONFIG_FPE_NWFPE=y +CONFIG_BINFMT_MISC=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=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=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_TUNNEL=m +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +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 +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_MTD=y +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_AFS_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PLATRAM=y +CONFIG_MTD_DATAFLASH=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_ATMEL=y +CONFIG_MTD_NAND_PLATFORM=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_ATMEL_TCLIB=y +CONFIG_EEPROM_LEGACY=m +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_NETDEVICES=y +CONFIG_TUN=m +CONFIG_PHYLIB=y +CONFIG_DAVICOM_PHY=y +CONFIG_SMSC_PHY=y +CONFIG_MICREL_PHY=y +CONFIG_NET_ETHERNET=y +CONFIG_ARM_AT91_ETHER=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_EPSON2888=y +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=640 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480 +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +CONFIG_LEGACY_PTY_COUNT=32 +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_GPIO=y +CONFIG_SPI=y +CONFIG_SPI_ATMEL=y +CONFIG_SPI_BITBANG=y +CONFIG_GPIO_SYSFS=y +CONFIG_HWMON=m +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_DS1621=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM73=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_PCF8591=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y +CONFIG_AT91RM9200_WATCHDOG=y +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y +CONFIG_FB_S1D13XXX=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_DISPLAY_SUPPORT=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FONTS=y +CONFIG_FONT_MINI_4x6=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_USB=y +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_MON=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_CONSOLE=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_FTDI_SIO=y +CONFIG_USB_SERIAL_KEYSPAN=y +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_MCT_U232=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_GADGET=y +CONFIG_USB_ETH=m +CONFIG_USB_MASS_STORAGE=m +CONFIG_MMC=y +CONFIG_MMC_AT91=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_HCTOSYS is not set +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_PCF8563=y +CONFIG_RTC_DRV_AT91RM9200=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_XATTR is not set +CONFIG_REISERFS_FS=y +CONFIG_AUTOFS4_FS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_NTFS_FS=m +CONFIG_TMPFS=y +CONFIG_CONFIGFS_FS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RUBIN=y +CONFIG_CRAMFS=y +CONFIG_MINIX_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NFSD=y +CONFIG_SMB_FS=m +CONFIG_CIFS=m +CONFIG_PARTITION_ADVANCED=y +CONFIG_MAC_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +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=y +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=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_FTRACE is not set +CONFIG_CRYPTO_PCBC=y +CONFIG_CRYPTO_SHA1=y diff --git a/arch/arm/configs/at91rm9200dk_defconfig b/arch/arm/configs/at91rm9200dk_defconfig deleted file mode 100644 index 4438e64f3bfb..000000000000 --- a/arch/arm/configs/at91rm9200dk_defconfig +++ /dev/null @@ -1,72 +0,0 @@ -CONFIG_EXPERIMENTAL=y -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_AT91=y -CONFIG_ARCH_AT91RM9200DK=y -CONFIG_MACH_ECO920=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y -# CONFIG_ARM_THUMB is not set -CONFIG_PCCARD=y -CONFIG_AT91_CF=y -CONFIG_LEDS=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw" -CONFIG_FPE_NWFPE=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IPV6 is not set -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_GPIO=y -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -CONFIG_AT91RM9200_WATCHDOG=y -# CONFIG_VGA_CONSOLE is not set -# CONFIG_USB_HID is not set -CONFIG_USB=y -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y -CONFIG_USB_MON=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_GADGET=y -CONFIG_MMC=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_AT91RM9200=y -CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y diff --git a/arch/arm/configs/at91rm9200ek_defconfig b/arch/arm/configs/at91rm9200ek_defconfig deleted file mode 100644 index ccd517c64bc7..000000000000 --- a/arch/arm/configs/at91rm9200ek_defconfig +++ /dev/null @@ -1,73 +0,0 @@ -CONFIG_EXPERIMENTAL=y -# CONFIG_LOCALVERSION_AUTO is not set -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_AT91=y -CONFIG_MACH_AT91RM9200EK=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y -# CONFIG_ARM_THUMB is not set -CONFIG_LEDS=y -CONFIG_LEDS_CPU=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw" -CONFIG_FPE_NWFPE=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IPV6 is not set -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_GPIO=y -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -CONFIG_AT91RM9200_WATCHDOG=y -CONFIG_FB=y -CONFIG_FB_S1D13XXX=y -# CONFIG_VGA_CONSOLE is not set -# CONFIG_USB_HID is not set -CONFIG_USB=y -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y -CONFIG_USB_MON=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_GADGET=y -CONFIG_MMC=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_AT91RM9200=y -CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y diff --git a/arch/arm/configs/ateb9200_defconfig b/arch/arm/configs/ateb9200_defconfig deleted file mode 100644 index 1b0e9a1689bb..000000000000 --- a/arch/arm/configs/ateb9200_defconfig +++ /dev/null @@ -1,131 +0,0 @@ -CONFIG_EXPERIMENTAL=y -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y -CONFIG_SLAB=y -CONFIG_PROFILING=y -CONFIG_OPROFILE=m -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_ARCH_AT91=y -CONFIG_MACH_ATEB9200=y -CONFIG_PCCARD=m -CONFIG_AT91_CF=m -CONFIG_PREEMPT=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_FPE_NWFPE=y -CONFIG_PM=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_NET_KEY=y -CONFIG_INET=y -# CONFIG_IPV6 is not set -CONFIG_BRIDGE=m -CONFIG_VLAN_8021Q=m -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK_RO=y -CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_NBD=m -CONFIG_SCSI=m -CONFIG_BLK_DEV_SD=m -CONFIG_BLK_DEV_SR=m -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=m -CONFIG_SCSI_MULTI_LUN=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=m -CONFIG_TUN=m -CONFIG_PHYLIB=y -CONFIG_DAVICOM_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -CONFIG_USB_USBNET=y -CONFIG_USB_NET_GL620A=y -CONFIG_USB_NET_PLUSB=y -CONFIG_USB_NET_RNDIS_HOST=y -CONFIG_USB_ALI_M5632=y -CONFIG_USB_AN2720=y -CONFIG_USB_EPSON2888=y -CONFIG_PPP=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -CONFIG_I2C=m -CONFIG_I2C_CHARDEV=m -CONFIG_I2C_GPIO=m -# CONFIG_VGA_CONSOLE is not set -CONFIG_SOUND=y -CONFIG_USB_HID=m -CONFIG_HID_PID=y -CONFIG_USB_HIDDEV=y -CONFIG_USB=y -CONFIG_USB_DEVICEFS=y -CONFIG_USB_MON=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_ACM=m -CONFIG_USB_PRINTER=m -CONFIG_USB_STORAGE=m -CONFIG_USB_STORAGE_DATAFAB=m -CONFIG_USB_STORAGE_FREECOM=m -CONFIG_USB_STORAGE_USBAT=m -CONFIG_USB_STORAGE_SDDR09=m -CONFIG_USB_STORAGE_SDDR55=m -CONFIG_USB_STORAGE_JUMPSHOT=m -CONFIG_USB_SERIAL=m -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_FTDI_SIO=m -CONFIG_USB_SERIAL_PL2303=m -CONFIG_USB_GADGET=m -CONFIG_USB_ETH=m -CONFIG_USB_GADGETFS=m -CONFIG_USB_FILE_STORAGE=m -CONFIG_USB_G_SERIAL=m -CONFIG_MMC=m -CONFIG_MMC_DEBUG=y -CONFIG_RTC_CLASS=y -# CONFIG_RTC_HCTOSYS is not set -CONFIG_RTC_DRV_AT91RM9200=y -CONFIG_EXT2_FS=m -CONFIG_EXT3_FS=m -CONFIG_REISERFS_FS=m -CONFIG_INOTIFY=y -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_NTFS_FS=m -CONFIG_NTFS_RW=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=m -CONFIG_NFS_V3=y -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=y -CONFIG_NFSD=m -CONFIG_NFSD_V4=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y -CONFIG_BSD_DISKLABEL=y -CONFIG_MINIX_SUBPARTITION=y -CONFIG_SOLARIS_X86_PARTITION=y -CONFIG_UNIXWARE_DISKLABEL=y -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_ASCII=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_UTF8=m -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_ARC4=m -CONFIG_CRC16=m -CONFIG_LIBCRC32C=m diff --git a/arch/arm/configs/carmeva_defconfig b/arch/arm/configs/carmeva_defconfig deleted file mode 100644 index ac64dbd8a49c..000000000000 --- a/arch/arm/configs/carmeva_defconfig +++ /dev/null @@ -1,47 +0,0 @@ -CONFIG_EXPERIMENTAL=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y -# CONFIG_HOTPLUG is not set -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_ARCH_AT91=y -CONFIG_MACH_CARMEVA=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_FPE_NWFPE=y -CONFIG_NET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -# CONFIG_IPV6 is not set -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_BLK_DEV_RAM=y -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -CONFIG_SERIO=m -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_MMC=m -CONFIG_MMC_DEBUG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -# CONFIG_DNOTIFY is not set -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_COMPRESSION_OPTIONS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_NFSD=y diff --git a/arch/arm/configs/cpuat91_defconfig b/arch/arm/configs/cpuat91_defconfig deleted file mode 100644 index 022aeb55b676..000000000000 --- a/arch/arm/configs/cpuat91_defconfig +++ /dev/null @@ -1,112 +0,0 @@ -CONFIG_EXPERIMENTAL=y -# CONFIG_LOCALVERSION_AUTO is not set -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_AT91=y -CONFIG_MACH_CPUAT91=y -CONFIG_AT91_TIMER_HZ=100 -# CONFIG_ARM_THUMB is not set -CONFIG_PREEMPT=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=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 -# CONFIG_IPV6 is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_PLATRAM=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_NBD=y -CONFIG_BLK_DEV_RAM=y -# CONFIG_MISC_DEVICES is not set -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_MULTI_LUN=y -# CONFIG_SCSI_LOWLEVEL is not set -CONFIG_NETDEVICES=y -CONFIG_PHYLIB=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -CONFIG_PPP=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_BSDCOMP=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -CONFIG_LEGACY_PTY_COUNT=32 -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_GPIO=y -CONFIG_GPIO_SYSFS=y -# CONFIG_HWMON is not set -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -CONFIG_AT91RM9200_WATCHDOG=y -# CONFIG_VGA_CONSOLE is not set -# CONFIG_HID_SUPPORT is not set -CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_STORAGE=y -CONFIG_USB_GADGET=y -CONFIG_USB_ETH=m -CONFIG_MMC=y -CONFIG_MMC_AT91=m -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_GPIO=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_TIMER=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=y -CONFIG_LEDS_TRIGGER_GPIO=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_RTC_CLASS=y -# CONFIG_RTC_HCTOSYS is not set -CONFIG_RTC_DRV_DS1307=y -CONFIG_RTC_DRV_PCF8563=y -CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_FS_XATTR is not set -CONFIG_INOTIFY=y -CONFIG_AUTOFS4_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_SUMMARY=y -CONFIG_CRAMFS=y -CONFIG_MINIX_FS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set diff --git a/arch/arm/configs/csb337_defconfig b/arch/arm/configs/csb337_defconfig deleted file mode 100644 index a24c448840c4..000000000000 --- a/arch/arm/configs/csb337_defconfig +++ /dev/null @@ -1,104 +0,0 @@ -CONFIG_EXPERIMENTAL=y -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_ARCH_AT91=y -CONFIG_MACH_CSB337=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y -# CONFIG_ARM_THUMB is not set -CONFIG_PCCARD=y -CONFIG_AT91_CF=y -CONFIG_LEDS=y -CONFIG_LEDS_CPU=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="mem=32M console=ttyS0,38400 initrd=0x20410000,3145728 root=/dev/ram0 rw" -CONFIG_FPE_NWFPE=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_INET_LRO is not set -# CONFIG_IPV6 is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_ATMEL_SSC=y -CONFIG_SCSI=y -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_GPIO=y -# CONFIG_HWMON is not set -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -CONFIG_AT91RM9200_WATCHDOG=y -# CONFIG_VGA_CONSOLE is not set -# CONFIG_USB_HID is not set -CONFIG_USB=y -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y -CONFIG_USB_MON=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CONSOLE=y -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_FTDI_SIO=y -CONFIG_USB_SERIAL_KEYSPAN=y -CONFIG_USB_SERIAL_KEYSPAN_MPR=y -CONFIG_USB_SERIAL_KEYSPAN_USA28=y -CONFIG_USB_SERIAL_KEYSPAN_USA28X=y -CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y -CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y -CONFIG_USB_SERIAL_KEYSPAN_USA19=y -CONFIG_USB_SERIAL_KEYSPAN_USA18X=y -CONFIG_USB_SERIAL_KEYSPAN_USA19W=y -CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y -CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y -CONFIG_USB_SERIAL_KEYSPAN_USA49W=y -CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y -CONFIG_USB_SERIAL_MCT_U232=y -CONFIG_USB_GADGET=y -CONFIG_MMC=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_HCTOSYS_DEVICE="rtc1" -# CONFIG_RTC_INTF_SYSFS is not set -CONFIG_RTC_DRV_DS1307=y -CONFIG_RTC_DRV_AT91RM9200=y -CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y diff --git a/arch/arm/configs/csb637_defconfig b/arch/arm/configs/csb637_defconfig deleted file mode 100644 index 98552adac5fb..000000000000 --- a/arch/arm/configs/csb637_defconfig +++ /dev/null @@ -1,98 +0,0 @@ -CONFIG_EXPERIMENTAL=y -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_ARCH_AT91=y -CONFIG_MACH_CSB637=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y -# CONFIG_ARM_THUMB is not set -CONFIG_PCCARD=y -CONFIG_AT91_CF=y -CONFIG_LEDS=y -CONFIG_LEDS_CPU=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="mem=32M console=ttyS0,38400 initrd=0x20410000,3145728 root=/dev/ram0 rw" -CONFIG_FPE_NWFPE=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_INET_LRO is not set -# CONFIG_IPV6 is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_SCSI=y -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -CONFIG_AT91RM9200_WATCHDOG=y -# CONFIG_VGA_CONSOLE is not set -# CONFIG_USB_HID is not set -CONFIG_USB=y -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y -CONFIG_USB_MON=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CONSOLE=y -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_FTDI_SIO=y -CONFIG_USB_SERIAL_KEYSPAN=y -CONFIG_USB_SERIAL_KEYSPAN_MPR=y -CONFIG_USB_SERIAL_KEYSPAN_USA28=y -CONFIG_USB_SERIAL_KEYSPAN_USA28X=y -CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y -CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y -CONFIG_USB_SERIAL_KEYSPAN_USA19=y -CONFIG_USB_SERIAL_KEYSPAN_USA18X=y -CONFIG_USB_SERIAL_KEYSPAN_USA19W=y -CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y -CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y -CONFIG_USB_SERIAL_KEYSPAN_USA49W=y -CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y -CONFIG_USB_SERIAL_MCT_U232=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_GPIO=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=y -CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y diff --git a/arch/arm/configs/ecbat91_defconfig b/arch/arm/configs/ecbat91_defconfig deleted file mode 100644 index 6bb6abdcea8c..000000000000 --- a/arch/arm/configs/ecbat91_defconfig +++ /dev/null @@ -1,99 +0,0 @@ -CONFIG_EXPERIMENTAL=y -CONFIG_SYSVIPC=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_AT91=y -CONFIG_MACH_ECBAT91=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y -CONFIG_PCCARD=y -CONFIG_AT91_CF=y -CONFIG_PREEMPT=y -CONFIG_LEDS=y -CONFIG_LEDS_CPU=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="rootfstype=reiserfs root=/dev/mmcblk0p1 console=ttyS0,115200n8 rootdelay=1" -CONFIG_FPE_NWFPE=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IPV6 is not set -CONFIG_CFG80211=y -CONFIG_MAC80211=y -# CONFIG_STANDALONE is not set -# CONFIG_PREVENT_FIRMWARE_BUILD is not set -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_AFS_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_DATAFLASH=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_SG=y -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -CONFIG_PPP=y -CONFIG_PPP_MULTILINK=y -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -CONFIG_HW_RANDOM=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_SPI=y -CONFIG_SPI_BITBANG=y -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -# CONFIG_VGA_CONSOLE is not set -# CONFIG_USB_HID is not set -CONFIG_USB=y -CONFIG_USB_DEVICEFS=y -# CONFIG_USB_DEVICE_CLASS is not set -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_PRINTER=y -CONFIG_USB_STORAGE=y -CONFIG_USB_GADGET=y -CONFIG_MMC=y -CONFIG_MMC_DEBUG=y -CONFIG_MMC_AT91=m -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_RTC_CLASS=y -# CONFIG_RTC_HCTOSYS is not set -CONFIG_RTC_DRV_AT91RM9200=y -CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y -CONFIG_REISERFS_FS=y -CONFIG_INOTIFY=y -CONFIG_TMPFS=y -CONFIG_CONFIGFS_FS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_DEBUG_USER=y -CONFIG_CRYPTO_PCBC=y -CONFIG_CRYPTO_SHA1=y diff --git a/arch/arm/configs/kafa_defconfig b/arch/arm/configs/kafa_defconfig deleted file mode 100644 index 896dbe00dc6e..000000000000 --- a/arch/arm/configs/kafa_defconfig +++ /dev/null @@ -1,61 +0,0 @@ -CONFIG_EXPERIMENTAL=y -# CONFIG_LOCALVERSION_AUTO is not set -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_AT91=y -CONFIG_MACH_KAFA=y -# CONFIG_ARM_THUMB is not set -CONFIG_PREEMPT=y -CONFIG_LEDS=y -CONFIG_LEDS_CPU=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20800000,10M root=/dev/ram0 rw" -CONFIG_FPE_NWFPE=y -CONFIG_BINFMT_MISC=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK_RO=y -CONFIG_NETDEVICES=y -CONFIG_PHYLIB=y -CONFIG_DAVICOM_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -CONFIG_LEGACY_PTY_COUNT=32 -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_GPIO=y -# CONFIG_HWMON is not set -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -CONFIG_AT91RM9200_WATCHDOG=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_RTC_CLASS=y -# CONFIG_RTC_HCTOSYS is not set -CONFIG_RTC_DRV_AT91RM9200=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_FS_XATTR is not set -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=m -CONFIG_NFS_V3=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_DES=y diff --git a/arch/arm/configs/kb9202_defconfig b/arch/arm/configs/kb9202_defconfig deleted file mode 100644 index 9f906a85f5c2..000000000000 --- a/arch/arm/configs/kb9202_defconfig +++ /dev/null @@ -1,127 +0,0 @@ -CONFIG_EXPERIMENTAL=y -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_AUDIT=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_EXTRA_PASS=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODVERSIONS=y -CONFIG_MODULE_SRCVERSION_ALL=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_IOSCHED_DEADLINE is not set -CONFIG_ARCH_AT91=y -CONFIG_MACH_KB9200=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_PREEMPT=y -CONFIG_AEABI=y -CONFIG_ZBOOT_ROM_TEXT=0x10000000 -CONFIG_ZBOOT_ROM_BSS=0x20040000 -CONFIG_CMDLINE="noinitrd root=/dev/mtdblock0 rootfstype=jffs2 mem=64M" -CONFIG_KEXEC=y -CONFIG_FPE_NWFPE=y -CONFIG_BINFMT_MISC=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=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 -# CONFIG_INET_LRO is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -# CONFIG_FIRMWARE_IN_KERNEL is not set -CONFIG_MTD=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_COMPLEX_MAPPINGS=y -CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_ATMEL=y -CONFIG_MTD_UBI=y -CONFIG_MTD_UBI_GLUEBI=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_ATMEL_TCLIB=y -CONFIG_ATMEL_SSC=y -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_SPI_ATTRS=m -# CONFIG_SCSI_LOWLEVEL is not set -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -CONFIG_WATCHDOG=y -CONFIG_AT91RM9200_WATCHDOG=y -CONFIG_FB=y -CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_TILEBLITTING=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -# CONFIG_LCD_CLASS_DEVICE is not set -CONFIG_BACKLIGHT_CLASS_DEVICE=y -# CONFIG_BACKLIGHT_GENERIC is not set -# CONFIG_VGA_CONSOLE is not set -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FONTS=y -CONFIG_FONT_MINI_4x6=y -# CONFIG_HID_SUPPORT is not set -CONFIG_USB=y -CONFIG_USB_DEVICEFS=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_STORAGE=y -CONFIG_USB_LIBUSUAL=y -CONFIG_MMC=y -CONFIG_MMC_AT91=m -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_AT91RM9200=y -CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y -# CONFIG_DNOTIFY is not set -CONFIG_INOTIFY=y -CONFIG_VFAT_FS=y -CONFIG_TMPFS=y -CONFIG_CONFIGFS_FS=y -CONFIG_JFFS2_FS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_UTF8=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -# CONFIG_SCHED_DEBUG is not set -# CONFIG_DEBUG_PREEMPT is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set diff --git a/arch/arm/configs/onearm_defconfig b/arch/arm/configs/onearm_defconfig deleted file mode 100644 index 1579857aeeaa..000000000000 --- a/arch/arm/configs/onearm_defconfig +++ /dev/null @@ -1,80 +0,0 @@ -CONFIG_EXPERIMENTAL=y -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_AT91=y -CONFIG_MACH_ONEARM=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y -# CONFIG_ARM_THUMB is not set -CONFIG_PCCARD=y -CONFIG_AT91_CF=y -CONFIG_LEDS=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp mem=64M" -CONFIG_FPE_NWFPE=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IPV6=y -# 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_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_NBD=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -CONFIG_AT91RM9200_WATCHDOG=y -# CONFIG_USB_HID is not set -CONFIG_USB=y -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y -CONFIG_USB_MON=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_GADGET=y -CONFIG_MMC=y -CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_NFS_V3_ACL=y -CONFIG_ROOT_NFS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y diff --git a/arch/arm/configs/picotux200_defconfig b/arch/arm/configs/picotux200_defconfig deleted file mode 100644 index 4c9afa478d57..000000000000 --- a/arch/arm/configs/picotux200_defconfig +++ /dev/null @@ -1,242 +0,0 @@ -CONFIG_EXPERIMENTAL=y -CONFIG_SYSVIPC=y -CONFIG_IKCONFIG=m -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y -# CONFIG_KALLSYMS is not set -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_AT91=y -CONFIG_MACH_PICOTUX2XX=y -CONFIG_AT91_PROGRAMMABLE_CLOCKS=y -CONFIG_AEABI=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_KEXEC=y -CONFIG_FPE_NWFPE=y -CONFIG_BINFMT_MISC=m -CONFIG_NET=y -CONFIG_PACKET=m -CONFIG_UNIX=y -CONFIG_XFRM_USER=m -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_IPCOMP=m -CONFIG_INET_XFRM_MODE_TRANSPORT=m -CONFIG_INET_XFRM_MODE_TUNNEL=m -CONFIG_INET_XFRM_MODE_BEET=m -CONFIG_INET_DIAG=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=m -CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m -CONFIG_IPV6_TUNNEL=m -CONFIG_BRIDGE=m -CONFIG_VLAN_8021Q=m -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 -CONFIG_FW_LOADER=m -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_LOOP=m -CONFIG_EEPROM_LEGACY=m -CONFIG_SCSI=m -CONFIG_BLK_DEV_SD=m -CONFIG_BLK_DEV_SR=m -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=m -CONFIG_NETDEVICES=y -CONFIG_TUN=m -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -CONFIG_USB_CATC=m -CONFIG_USB_KAWETH=m -CONFIG_USB_PEGASUS=m -CONFIG_USB_RTL8150=m -CONFIG_USB_USBNET=m -CONFIG_USB_NET_DM9601=m -CONFIG_USB_NET_GL620A=m -CONFIG_USB_NET_PLUSB=m -CONFIG_USB_NET_MCS7830=m -CONFIG_USB_NET_RNDIS_HOST=m -CONFIG_USB_ALI_M5632=y -CONFIG_USB_AN2720=y -CONFIG_USB_EPSON2888=y -CONFIG_USB_KC2190=y -CONFIG_PPP=m -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPP_MPPE=m -CONFIG_PPPOE=m -CONFIG_SLIP=m -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -CONFIG_SLIP_MODE_SLIP6=y -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set -CONFIG_I2C=m -CONFIG_I2C_CHARDEV=m -CONFIG_I2C_GPIO=m -CONFIG_HWMON=m -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_DS1621=m -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_PCF8591=m -CONFIG_SENSORS_SMSC47B397=m -CONFIG_SENSORS_W83781D=m -CONFIG_SENSORS_W83791D=m -CONFIG_SENSORS_W83792D=m -CONFIG_SENSORS_W83793=m -CONFIG_SENSORS_W83L785TS=m -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -CONFIG_AT91RM9200_WATCHDOG=m -CONFIG_HID=m -CONFIG_USB=m -CONFIG_USB_DEVICEFS=y -CONFIG_USB_OHCI_HCD=m -CONFIG_USB_ACM=m -CONFIG_USB_PRINTER=m -CONFIG_USB_STORAGE=m -CONFIG_USB_SERIAL=m -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_PL2303=m -CONFIG_MMC=m -CONFIG_MMC_AT91=m -CONFIG_RTC_CLASS=m -CONFIG_RTC_DRV_AT91RM9200=m -CONFIG_EXT2_FS=m -CONFIG_EXT3_FS=m -# CONFIG_EXT3_FS_XATTR is not set -CONFIG_INOTIFY=y -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y -CONFIG_UDF_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_NTFS_FS=m -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_SUMMARY=y -CONFIG_JFFS2_COMPRESSION_OPTIONS=y -CONFIG_NFS_FS=m -CONFIG_SMB_FS=m -CONFIG_CIFS=m -CONFIG_PARTITION_ADVANCED=y -CONFIG_AMIGA_PARTITION=y -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 -CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_BUGVERBOSE is not set -CONFIG_DEBUG_LL=y -CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_LRW=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_XCBC=m -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_SHA256=m -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_TGR192=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_CAMELLIA=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_FCRYPT=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_LIBCRC32C=m diff --git a/arch/arm/configs/yl9200_defconfig b/arch/arm/configs/yl9200_defconfig deleted file mode 100644 index 30c537f61089..000000000000 --- a/arch/arm/configs/yl9200_defconfig +++ /dev/null @@ -1,137 +0,0 @@ -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_AT91=y -CONFIG_ARCH_AT91RM9200DK=y -CONFIG_MACH_YL9200=y -# CONFIG_ARM_THUMB is not set -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw" -CONFIG_FPE_NWFPE=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=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 -# CONFIG_INET_LRO is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_MTD=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_COMPLEX_MAPPINGS=y -CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_PLATRAM=y -CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_ATMEL=y -CONFIG_MTD_NAND_PLATFORM=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=3 -CONFIG_BLK_DEV_RAM_SIZE=8192 -# CONFIG_MISC_DEVICES is not set -CONFIG_BLK_DEV_SD=y -CONFIG_ATA=y -CONFIG_NETDEVICES=y -CONFIG_PHYLIB=y -CONFIG_DAVICOM_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_ARM_AT91_ETHER=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -CONFIG_INPUT_MOUSEDEV_SCREEN_X=640 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480 -CONFIG_INPUT_EVDEV=y -# CONFIG_KEYBOARD_ATKBD is not set -CONFIG_KEYBOARD_GPIO=y -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_ADS7846=y -# CONFIG_SERIO_SERPORT is not set -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_SPI=y -CONFIG_SPI_DEBUG=y -CONFIG_SPI_ATMEL=y -CONFIG_FB=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_LCD_CLASS_DEVICE=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y -CONFIG_DISPLAY_SUPPORT=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_LOGO=y -# CONFIG_LOGO_LINUX_MONO is not set -# CONFIG_LOGO_LINUX_VGA16 is not set -CONFIG_USB=y -CONFIG_USB_DEBUG=y -CONFIG_USB_DEVICEFS=y -# CONFIG_USB_DEVICE_CLASS is not set -CONFIG_USB_MON=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_STORAGE=y -CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_M66592=y -CONFIG_USB_FILE_STORAGE=m -CONFIG_MMC=y -CONFIG_MMC_DEBUG=y -# CONFIG_MMC_BLOCK_BOUNCE is not set -CONFIG_MMC_AT91=m -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_GPIO=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_TIMER=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_AT91RM9200=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y -CONFIG_REISERFS_FS=y -CONFIG_INOTIFY=y -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_FS_DEBUG=1 -CONFIG_JFFS2_COMPRESSION_OPTIONS=y -CONFIG_JFFS2_RUBIN=y -CONFIG_CRAMFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ISO8859_1=y -# CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_SLUB_DEBUG_ON=y -CONFIG_DEBUG_KOBJECT=y -CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_LIST=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_ERRORS=y -CONFIG_DEBUG_LL=y diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 062b58c029ab..749bb6622404 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -238,7 +238,7 @@ @ Slightly optimised to avoid incrementing the pointer twice usraccoff \instr, \reg, \ptr, \inc, 0, \cond, \abort .if \rept == 2 - usraccoff \instr, \reg, \ptr, \inc, 4, \cond, \abort + usraccoff \instr, \reg, \ptr, \inc, \inc, \cond, \abort .endif add\cond \ptr, #\rept * \inc diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h index 68870c776671..b4ffe9d5b526 100644 --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h @@ -13,6 +13,10 @@ typedef struct { #ifdef CONFIG_CPU_HAS_ASID #define ASID(mm) ((mm)->context.id & 255) + +/* init_mm.context.id_lock should be initialized. */ +#define INIT_MM_CONTEXT(name) \ + .context.id_lock = __SPIN_LOCK_UNLOCKED(name.context.id_lock), #else #define ASID(mm) (0) #endif diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index b155414192da..53d1d5deb111 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -374,6 +374,9 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd) #define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd))) +/* we don't need complex calculations here as the pmd is folded into the pgd */ +#define pmd_addr_end(addr,end) (end) + /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index c09e3573c5de..bb96a7d4bbf5 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -911,7 +911,7 @@ __kuser_cmpxchg: @ 0xffff0fc0 * A special ghost syscall is used for that (see traps.c). */ stmfd sp!, {r7, lr} - ldr r7, =1f @ it's 20 bits + ldr r7, 1f @ it's 20 bits swi __ARM_NR_cmpxchg ldmfd sp!, {r7, pc} 1: .word __ARM_NR_cmpxchg diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index dd6b369ac69c..6bd82d25683c 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -85,9 +85,11 @@ ENTRY(stext) mrc p15, 0, r9, c0, c0 @ get processor id bl __lookup_processor_type @ r5=procinfo r9=cpuid movs r10, r5 @ invalid processor (r5=0)? + THUMB( it eq ) @ force fixup-able long branch encoding beq __error_p @ yes, error 'p' bl __lookup_machine_type @ r5=machinfo movs r8, r5 @ invalid machine (r5=0)? + THUMB( it eq ) @ force fixup-able long branch encoding beq __error_a @ yes, error 'a' bl __vet_atags #ifdef CONFIG_SMP_ON_UP @@ -262,6 +264,7 @@ __create_page_tables: mov pc, lr ENDPROC(__create_page_tables) .ltorg + .align __enable_mmu_loc: .long . .long __enable_mmu @@ -282,6 +285,7 @@ ENTRY(secondary_startup) bl __lookup_processor_type movs r10, r5 @ invalid processor? moveq r0, #'p' @ yes, error 'p' + THUMB( it eq ) @ force fixup-able long branch encoding beq __error_p /* @@ -308,6 +312,8 @@ ENTRY(__secondary_switched) b secondary_start_kernel ENDPROC(__secondary_switched) + .align + .type __secondary_data, %object __secondary_data: .long . @@ -413,6 +419,7 @@ __fixup_smp_on_up: mov pc, lr ENDPROC(__fixup_smp) + .align 1: .word . .word __smpalt_begin .word __smpalt_end diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S index fd26f8d65151..9cf4cbf8f95b 100644 --- a/arch/arm/kernel/relocate_kernel.S +++ b/arch/arm/kernel/relocate_kernel.S @@ -59,6 +59,8 @@ relocate_new_kernel: ldr r2,kexec_boot_atags mov pc,lr + .align + .globl kexec_start_address kexec_start_address: .long 0x0 diff --git a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S index 1e4cbd4e7be9..64f6bc1a9132 100644 --- a/arch/arm/lib/findbit.S +++ b/arch/arm/lib/findbit.S @@ -174,8 +174,8 @@ ENDPROC(_find_next_bit_be) */ .L_found: #if __LINUX_ARM_ARCH__ >= 5 - rsb r1, r3, #0 - and r3, r3, r1 + rsb r0, r3, #0 + and r3, r3, r0 clz r3, r3 rsb r3, r3, #31 add r0, r2, r3 @@ -190,5 +190,7 @@ ENDPROC(_find_next_bit_be) addeq r2, r2, #1 mov r0, r2 #endif + cmp r1, r0 @ Clamp to maxbit + movlo r0, r1 mov pc, lr diff --git a/arch/arm/mach-aaec2000/include/mach/vmalloc.h b/arch/arm/mach-aaec2000/include/mach/vmalloc.h index cff4e0a996ce..a6299e8321bd 100644 --- a/arch/arm/mach-aaec2000/include/mach/vmalloc.h +++ b/arch/arm/mach-aaec2000/include/mach/vmalloc.h @@ -11,6 +11,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H -#define VMALLOC_END 0xd0000000 +#define VMALLOC_END 0xd0000000UL #endif /* __ASM_ARCH_VMALLOC_H */ diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 821eb842795f..d13add71f72a 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -24,8 +24,8 @@ obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o # AT91RM9200 board-specific support obj-$(CONFIG_MACH_ONEARM) += board-1arm.o -obj-$(CONFIG_ARCH_AT91RM9200DK) += board-dk.o -obj-$(CONFIG_MACH_AT91RM9200EK) += board-ek.o +obj-$(CONFIG_ARCH_AT91RM9200DK) += board-rm9200dk.o +obj-$(CONFIG_MACH_AT91RM9200EK) += board-rm9200ek.o obj-$(CONFIG_MACH_CSB337) += board-csb337.o obj-$(CONFIG_MACH_CSB637) += board-csb637.o obj-$(CONFIG_MACH_CARMEVA) += board-carmeva.o @@ -65,7 +65,7 @@ obj-$(CONFIG_MACH_AT91SAM9G20EK) += board-sam9g20ek.o obj-$(CONFIG_MACH_CPU9G20) += board-cpu9krea.o obj-$(CONFIG_MACH_STAMP9G20) += board-stamp9g20.o obj-$(CONFIG_MACH_PORTUXG20) += board-stamp9g20.o -obj-$(CONFIG_MACH_PCONTROL_G20) += board-pcontrol-g20.o +obj-$(CONFIG_MACH_PCONTROL_G20) += board-pcontrol-g20.o board-stamp9g20.o # AT91SAM9260/AT91SAM9G20 board-specific support obj-$(CONFIG_MACH_SNAPPER_9260) += board-snapper9260.o diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 9338825cfcd7..7b539228e0ef 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -1106,51 +1106,6 @@ static inline void configure_usart3_pins(unsigned pins) static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */ struct platform_device *atmel_default_console_device; /* the serial console device */ -void __init __deprecated at91_init_serial(struct at91_uart_config *config) -{ - int i; - - /* Fill in list of supported UARTs */ - for (i = 0; i < config->nr_tty; i++) { - switch (config->tty_map[i]) { - case 0: - configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS); - at91_uarts[i] = &at91rm9200_uart0_device; - at91_clock_associate("usart0_clk", &at91rm9200_uart0_device.dev, "usart"); - break; - case 1: - configure_usart1_pins(ATMEL_UART_CTS | ATMEL_UART_RTS | ATMEL_UART_DSR | ATMEL_UART_DTR | ATMEL_UART_DCD | ATMEL_UART_RI); - at91_uarts[i] = &at91rm9200_uart1_device; - at91_clock_associate("usart1_clk", &at91rm9200_uart1_device.dev, "usart"); - break; - case 2: - configure_usart2_pins(0); - at91_uarts[i] = &at91rm9200_uart2_device; - at91_clock_associate("usart2_clk", &at91rm9200_uart2_device.dev, "usart"); - break; - case 3: - configure_usart3_pins(0); - at91_uarts[i] = &at91rm9200_uart3_device; - at91_clock_associate("usart3_clk", &at91rm9200_uart3_device.dev, "usart"); - break; - case 4: - configure_dbgu_pins(); - at91_uarts[i] = &at91rm9200_dbgu_device; - at91_clock_associate("mck", &at91rm9200_dbgu_device.dev, "usart"); - break; - default: - continue; - } - at91_uarts[i]->id = i; /* update ID number to mapped ID */ - } - - /* Set serial console device */ - if (config->console_tty < ATMEL_MAX_UART) - atmel_default_console_device = at91_uarts[config->console_tty]; - if (!atmel_default_console_device) - printk(KERN_INFO "AT91: No default serial console defined.\n"); -} - void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) { struct platform_device *pdev; diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c index 46bdc82d3fbf..8a3fc84847c1 100644 --- a/arch/arm/mach-at91/board-1arm.c +++ b/arch/arm/mach-at91/board-1arm.c @@ -39,24 +39,24 @@ #include "generic.h" -/* - * Serial port configuration. - * 0 .. 3 = USART0 .. USART3 - * 4 = DBGU - */ -static struct at91_uart_config __initdata onearm_uart_config = { - .console_tty = 0, /* ttyS0 */ - .nr_tty = 3, - .tty_map = { 4, 0, 1, -1, -1 }, /* ttyS0, ..., ttyS4 */ -}; - static void __init onearm_map_io(void) { /* Initialize processor: 18.432 MHz crystal */ at91rm9200_initialize(18432000, AT91RM9200_PQFP); - /* Setup the serial ports and console */ - at91_init_serial(&onearm_uart_config); + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); + + /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */ + at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); + + /* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ + at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS + | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD + | ATMEL_UART_RI); + + /* set serial console to ttyS0 (ie, DBGU) */ + at91_set_serial_console(0); } static void __init onearm_init_irq(void) diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c index c0ce79d431a0..d2e1f4ec1fcc 100644 --- a/arch/arm/mach-at91/board-kafa.c +++ b/arch/arm/mach-at91/board-kafa.c @@ -39,17 +39,6 @@ #include "generic.h" -/* - * Serial port configuration. - * 0 .. 3 = USART0 .. USART3 - * 4 = DBGU - */ -static struct at91_uart_config __initdata kafa_uart_config = { - .console_tty = 0, /* ttyS0 */ - .nr_tty = 2, - .tty_map = { 4, 0, -1, -1, -1 } /* ttyS0, ..., ttyS4 */ -}; - static void __init kafa_map_io(void) { /* Initialize processor: 18.432 MHz crystal */ @@ -58,8 +47,14 @@ static void __init kafa_map_io(void) /* Set up the LEDs */ at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4); - /* Setup the serial ports and console */ - at91_init_serial(&kafa_uart_config); + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); + + /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */ + at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); + + /* set serial console to ttyS0 (ie, DBGU) */ + at91_set_serial_console(0); } static void __init kafa_init_irq(void) diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c index bba5a560e02b..feb65787c30b 100644 --- a/arch/arm/mach-at91/board-pcontrol-g20.c +++ b/arch/arm/mach-at91/board-pcontrol-g20.c @@ -31,6 +31,7 @@ #include <mach/board.h> #include <mach/at91sam9_smc.h> +#include <mach/stamp9g20.h> #include "sam9_smc.h" #include "generic.h" @@ -38,11 +39,7 @@ static void __init pcontrol_g20_map_io(void) { - /* Initialize processor: 18.432 MHz crystal */ - at91sam9260_initialize(18432000); - - /* DGBU on ttyS0. (Rx, Tx) only TTL -> JTAG connector X7 17,19 ) */ - at91_register_uart(0, 0, 0); + stamp9g20_map_io(); /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback A2 */ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS @@ -54,9 +51,6 @@ static void __init pcontrol_g20_map_io(void) /* USART2 on ttyS3. (Rx, Tx) 9bit-Bus Multidrop-mode X4 */ at91_register_uart(AT91SAM9260_ID_US4, 3, 0); - - /* set serial console to ttyS0 (ie, DBGU) */ - at91_set_serial_console(0); } @@ -66,38 +60,6 @@ static void __init init_irq(void) } -/* - * NAND flash 512MiB 1,8V 8-bit, sector size 128 KiB - */ -static struct atmel_nand_data __initdata nand_data = { - .ale = 21, - .cle = 22, - .rdy_pin = AT91_PIN_PC13, - .enable_pin = AT91_PIN_PC14, -}; - -/* - * Bus timings; unit = 7.57ns - */ -static struct sam9_smc_config __initdata nand_smc_config = { - .ncs_read_setup = 0, - .nrd_setup = 2, - .ncs_write_setup = 0, - .nwe_setup = 2, - - .ncs_read_pulse = 4, - .nrd_pulse = 4, - .ncs_write_pulse = 4, - .nwe_pulse = 4, - - .read_cycle = 7, - .write_cycle = 7, - - .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE - | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8, - .tdf_cycles = 3, -}; - static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { { .ncs_read_setup = 16, .nrd_setup = 18, @@ -138,14 +100,6 @@ static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { { .tdf_cycles = 1, } }; -static void __init add_device_nand(void) -{ - /* configure chip-select 3 (NAND) */ - sam9_smc_configure(3, &nand_smc_config); - at91_add_device_nand(&nand_data); -} - - static void __init add_device_pcontrol(void) { /* configure chip-select 4 (IO compatible to 8051 X4 ) */ @@ -156,23 +110,6 @@ static void __init add_device_pcontrol(void) /* - * MCI (SD/MMC) - * det_pin, wp_pin and vcc_pin are not connected - */ -#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE) -static struct mci_platform_data __initdata mmc_data = { - .slot[0] = { - .bus_width = 4, - }, -}; -#else -static struct at91_mmc_data __initdata mmc_data = { - .wire4 = 1, -}; -#endif - - -/* * USB Host port */ static struct at91_usbh_data __initdata usbh_data = { @@ -265,42 +202,13 @@ static struct spi_board_info pcontrol_g20_spi_devices[] = { }; -/* - * Dallas 1-Wire DS2431 - */ -static struct w1_gpio_platform_data w1_gpio_pdata = { - .pin = AT91_PIN_PA29, - .is_open_drain = 1, -}; - -static struct platform_device w1_device = { - .name = "w1-gpio", - .id = -1, - .dev.platform_data = &w1_gpio_pdata, -}; - -static void add_wire1(void) -{ - at91_set_GPIO_periph(w1_gpio_pdata.pin, 1); - at91_set_multi_drive(w1_gpio_pdata.pin, 1); - platform_device_register(&w1_device); -} - - static void __init pcontrol_g20_board_init(void) { - at91_add_device_serial(); - add_device_nand(); -#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE) - at91_add_device_mci(0, &mmc_data); -#else - at91_add_device_mmc(0, &mmc_data); -#endif + stamp9g20_board_init(); at91_add_device_usbh(&usbh_data); at91_add_device_eth(&macb_data); at91_add_device_i2c(pcontrol_g20_i2c_devices, ARRAY_SIZE(pcontrol_g20_i2c_devices)); - add_wire1(); add_device_pcontrol(); at91_add_device_spi(pcontrol_g20_spi_devices, ARRAY_SIZE(pcontrol_g20_spi_devices)); diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c index 9d833bbc592d..55dad3a46547 100644 --- a/arch/arm/mach-at91/board-picotux200.c +++ b/arch/arm/mach-at91/board-picotux200.c @@ -43,24 +43,21 @@ #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); + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); + + /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ + at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS + | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD + | ATMEL_UART_RI); + + /* set serial console to ttyS0 (ie, DBGU) */ + at91_set_serial_console(0); } static void __init picotux200_init_irq(void) @@ -77,11 +74,6 @@ 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, @@ -89,21 +81,6 @@ static struct at91_mmc_data __initdata picotux200_mmc_data = { .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 SZ_4M @@ -135,21 +112,11 @@ static void __init picotux200_board_init(void) 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(NULL, 0); - /* 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); } diff --git a/arch/arm/mach-at91/board-dk.c b/arch/arm/mach-at91/board-rm9200dk.c index e14f0e165680..4c1047c8200d 100644 --- a/arch/arm/mach-at91/board-dk.c +++ b/arch/arm/mach-at91/board-rm9200dk.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91/board-dk.c + * linux/arch/arm/mach-at91/board-rm9200dk.c * * Copyright (C) 2005 SAN People * @@ -91,10 +91,12 @@ static struct at91_cf_data __initdata dk_cf_data = { // .vcc_pin = ... always powered }; +#ifndef CONFIG_MTD_AT91_DATAFLASH_CARD static struct at91_mmc_data __initdata dk_mmc_data = { .slot_b = 0, .wire4 = 1, }; +#endif static struct spi_board_info dk_spi_devices[] = { { /* DataFlash chip */ diff --git a/arch/arm/mach-at91/board-ek.c b/arch/arm/mach-at91/board-rm9200ek.c index 56e92c4bbc2a..9df1be8818c0 100644 --- a/arch/arm/mach-at91/board-ek.c +++ b/arch/arm/mach-at91/board-rm9200ek.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-at91/board-ek.c + * linux/arch/arm/mach-at91/board-rm9200ek.c * * Copyright (C) 2005 SAN People * @@ -84,12 +84,14 @@ static struct at91_udc_data __initdata ek_udc_data = { .pullup_pin = AT91_PIN_PD5, }; +#ifndef CONFIG_MTD_AT91_DATAFLASH_CARD static struct at91_mmc_data __initdata ek_mmc_data = { .det_pin = AT91_PIN_PB27, .slot_b = 0, .wire4 = 1, .wp_pin = AT91_PIN_PA17, }; +#endif static struct spi_board_info ek_spi_devices[] = { { /* DataFlash chip */ diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c index 5206eef4a67e..f8902b118960 100644 --- a/arch/arm/mach-at91/board-stamp9g20.c +++ b/arch/arm/mach-at91/board-stamp9g20.c @@ -32,7 +32,7 @@ #include "generic.h" -static void __init portuxg20_map_io(void) +void __init stamp9g20_map_io(void) { /* Initialize processor: 18.432 MHz crystal */ at91sam9260_initialize(18432000); @@ -40,6 +40,24 @@ static void __init portuxg20_map_io(void) /* DGBU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); + /* set serial console to ttyS0 (ie, DBGU) */ + at91_set_serial_console(0); +} + +static void __init stamp9g20evb_map_io(void) +{ + stamp9g20_map_io(); + + /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ + at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS + | ATMEL_UART_DTR | ATMEL_UART_DSR + | ATMEL_UART_DCD | ATMEL_UART_RI); +} + +static void __init portuxg20_map_io(void) +{ + stamp9g20_map_io(); + /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR @@ -56,26 +74,6 @@ static void __init portuxg20_map_io(void) /* USART5 on ttyS6. (Rx, Tx only) */ at91_register_uart(AT91SAM9260_ID_US5, 6, 0); - - /* set serial console to ttyS0 (ie, DBGU) */ - at91_set_serial_console(0); -} - -static void __init stamp9g20_map_io(void) -{ - /* Initialize processor: 18.432 MHz crystal */ - at91sam9260_initialize(18432000); - - /* DGBU on ttyS0. (Rx & Tx only) */ - at91_register_uart(0, 0, 0); - - /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ - at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS - | ATMEL_UART_DTR | ATMEL_UART_DSR - | ATMEL_UART_DCD | ATMEL_UART_RI); - - /* set serial console to ttyS0 (ie, DBGU) */ - at91_set_serial_console(0); } static void __init init_irq(void) @@ -156,7 +154,7 @@ static struct at91_udc_data __initdata portuxg20_udc_data = { .pullup_pin = 0, /* pull-up driven by UDC */ }; -static struct at91_udc_data __initdata stamp9g20_udc_data = { +static struct at91_udc_data __initdata stamp9g20evb_udc_data = { .vbus_pin = AT91_PIN_PA22, .pullup_pin = 0, /* pull-up driven by UDC */ }; @@ -190,7 +188,7 @@ static struct gpio_led portuxg20_leds[] = { } }; -static struct gpio_led stamp9g20_leds[] = { +static struct gpio_led stamp9g20evb_leds[] = { { .name = "D8", .gpio = AT91_PIN_PB18, @@ -250,7 +248,7 @@ void add_w1(void) } -static void __init generic_board_init(void) +void __init stamp9g20_board_init(void) { /* Serial */ at91_add_device_serial(); @@ -262,34 +260,40 @@ static void __init generic_board_init(void) #else at91_add_device_mmc(0, &mmc_data); #endif - /* USB Host */ - at91_add_device_usbh(&usbh_data); - /* Ethernet */ - at91_add_device_eth(&macb_data); - /* I2C */ - at91_add_device_i2c(NULL, 0); /* W1 */ add_w1(); } static void __init portuxg20_board_init(void) { - generic_board_init(); - /* SPI */ - at91_add_device_spi(portuxg20_spi_devices, ARRAY_SIZE(portuxg20_spi_devices)); + stamp9g20_board_init(); + /* USB Host */ + at91_add_device_usbh(&usbh_data); /* USB Device */ at91_add_device_udc(&portuxg20_udc_data); + /* Ethernet */ + at91_add_device_eth(&macb_data); + /* I2C */ + at91_add_device_i2c(NULL, 0); + /* SPI */ + at91_add_device_spi(portuxg20_spi_devices, ARRAY_SIZE(portuxg20_spi_devices)); /* LEDs */ at91_gpio_leds(portuxg20_leds, ARRAY_SIZE(portuxg20_leds)); } -static void __init stamp9g20_board_init(void) +static void __init stamp9g20evb_board_init(void) { - generic_board_init(); + stamp9g20_board_init(); + /* USB Host */ + at91_add_device_usbh(&usbh_data); /* USB Device */ - at91_add_device_udc(&stamp9g20_udc_data); + at91_add_device_udc(&stamp9g20evb_udc_data); + /* Ethernet */ + at91_add_device_eth(&macb_data); + /* I2C */ + at91_add_device_i2c(NULL, 0); /* LEDs */ - at91_gpio_leds(stamp9g20_leds, ARRAY_SIZE(stamp9g20_leds)); + at91_gpio_leds(stamp9g20evb_leds, ARRAY_SIZE(stamp9g20evb_leds)); } MACHINE_START(PORTUXG20, "taskit PortuxG20") @@ -305,7 +309,7 @@ MACHINE_START(STAMP9G20, "taskit Stamp9G20") /* Maintainer: taskit GmbH */ .boot_params = AT91_SDRAM_BASE + 0x100, .timer = &at91sam926x_timer, - .map_io = stamp9g20_map_io, + .map_io = stamp9g20evb_map_io, .init_irq = init_irq, - .init_machine = stamp9g20_board_init, + .init_machine = stamp9g20evb_board_init, MACHINE_END diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c index 89df00a9d2f7..e0f0080eb639 100644 --- a/arch/arm/mach-at91/board-yl-9200.c +++ b/arch/arm/mach-at91/board-yl-9200.c @@ -387,7 +387,7 @@ static struct spi_board_info yl9200_spi_devices[] = { * EPSON S1D13806 FB (discontinued chip) * EPSON S1D13506 FB */ -#if defined(CONFIG_FB_S1D135XX) || defined(CONFIG_FB_S1D13XXX_MODULE) +#if defined(CONFIG_FB_S1D13XXX) || defined(CONFIG_FB_S1D13XXX_MODULE) #include <video/s1d13xxxfb.h> diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index 7525cee3983f..9113da6845f1 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -658,7 +658,7 @@ static void __init at91_upll_usbfs_clock_init(unsigned long main_clock) /* Now set uhpck values */ uhpck.parent = &utmi_clk; uhpck.pmc_mask = AT91SAM926x_PMC_UHP; - uhpck.rate_hz = utmi_clk.parent->rate_hz; + uhpck.rate_hz = utmi_clk.rate_hz; uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8); } diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index 58528aa9c8a8..2b499eb343a1 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -137,13 +137,7 @@ extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_de extern void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins); extern void __init at91_set_serial_console(unsigned portnr); -struct at91_uart_config { - unsigned short console_tty; /* tty number of serial console */ - unsigned short nr_tty; /* number of serial tty's */ - short tty_map[]; /* map UART to tty number */ -}; extern struct platform_device *atmel_default_console_device; -extern void __init __deprecated at91_init_serial(struct at91_uart_config *config); struct atmel_uart_data { short use_dma_tx; /* use transmit DMA? */ diff --git a/arch/arm/mach-at91/include/mach/stamp9g20.h b/arch/arm/mach-at91/include/mach/stamp9g20.h new file mode 100644 index 000000000000..6120f9c46d59 --- /dev/null +++ b/arch/arm/mach-at91/include/mach/stamp9g20.h @@ -0,0 +1,7 @@ +#ifndef __MACH_STAMP9G20_H +#define __MACH_STAMP9G20_H + +void stamp9g20_map_io(void); +void stamp9g20_board_init(void); + +#endif diff --git a/arch/arm/mach-bcmring/include/mach/vmalloc.h b/arch/arm/mach-bcmring/include/mach/vmalloc.h index 3db3a09fd398..7397bd7817d9 100644 --- a/arch/arm/mach-bcmring/include/mach/vmalloc.h +++ b/arch/arm/mach-bcmring/include/mach/vmalloc.h @@ -22,4 +22,4 @@ * 0xe0000000 to 0xefffffff. This gives us 256 MB of vm space and handles * larger physical memory designs better. */ -#define VMALLOC_END 0xf0000000 +#define VMALLOC_END 0xf0000000UL diff --git a/arch/arm/mach-clps711x/include/mach/vmalloc.h b/arch/arm/mach-clps711x/include/mach/vmalloc.h index 30b3a287ed88..467b96137e47 100644 --- a/arch/arm/mach-clps711x/include/mach/vmalloc.h +++ b/arch/arm/mach-clps711x/include/mach/vmalloc.h @@ -17,4 +17,4 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define VMALLOC_END 0xd0000000 +#define VMALLOC_END 0xd0000000UL diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c index 38088c36936c..78defd71a829 100644 --- a/arch/arm/mach-cns3xxx/pcie.c +++ b/arch/arm/mach-cns3xxx/pcie.c @@ -369,7 +369,7 @@ static int __init cns3xxx_pcie_init(void) { int i; - hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, + hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, 0, "imprecise external abort"); for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) { diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 9be261beae7d..2652af124acd 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -359,8 +359,8 @@ static struct clk_lookup dm355_clks[] = { CLK(NULL, "uart1", &uart1_clk), CLK(NULL, "uart2", &uart2_clk), CLK("i2c_davinci.1", NULL, &i2c_clk), - CLK("davinci-asp.0", NULL, &asp0_clk), - CLK("davinci-asp.1", NULL, &asp1_clk), + CLK("davinci-mcbsp.0", NULL, &asp0_clk), + CLK("davinci-mcbsp.1", NULL, &asp1_clk), CLK("davinci_mmc.0", NULL, &mmcsd0_clk), CLK("davinci_mmc.1", NULL, &mmcsd1_clk), CLK("spi_davinci.0", NULL, &spi0_clk), @@ -664,7 +664,7 @@ static struct resource dm355_asp1_resources[] = { }; static struct platform_device dm355_asp1_device = { - .name = "davinci-asp", + .name = "davinci-mcbsp", .id = 1, .num_resources = ARRAY_SIZE(dm355_asp1_resources), .resource = dm355_asp1_resources, diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index a12065e87266..c466d710d3c1 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -459,7 +459,7 @@ static struct clk_lookup dm365_clks[] = { CLK(NULL, "usb", &usb_clk), CLK("davinci_emac.1", NULL, &emac_clk), CLK("davinci_voicecodec", NULL, &voicecodec_clk), - CLK("davinci-asp.0", NULL, &asp0_clk), + CLK("davinci-mcbsp", NULL, &asp0_clk), CLK(NULL, "rto", &rto_clk), CLK(NULL, "mjcp", &mjcp_clk), CLK(NULL, NULL, NULL), @@ -922,8 +922,8 @@ static struct resource dm365_asp_resources[] = { }; static struct platform_device dm365_asp_device = { - .name = "davinci-asp", - .id = 0, + .name = "davinci-mcbsp", + .id = -1, .num_resources = ARRAY_SIZE(dm365_asp_resources), .resource = dm365_asp_resources, }; diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 0608dd776a16..9a2376b3137c 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -302,7 +302,7 @@ static struct clk_lookup dm644x_clks[] = { CLK("davinci_emac.1", NULL, &emac_clk), CLK("i2c_davinci.1", NULL, &i2c_clk), CLK("palm_bk3710", NULL, &ide_clk), - CLK("davinci-asp", NULL, &asp_clk), + CLK("davinci-mcbsp", NULL, &asp_clk), CLK("davinci_mmc.0", NULL, &mmcsd_clk), CLK(NULL, "spi", &spi_clk), CLK(NULL, "gpio", &gpio_clk), @@ -580,7 +580,7 @@ static struct resource dm644x_asp_resources[] = { }; static struct platform_device dm644x_asp_device = { - .name = "davinci-asp", + .name = "davinci-mcbsp", .id = -1, .num_resources = ARRAY_SIZE(dm644x_asp_resources), .resource = dm644x_asp_resources, diff --git a/arch/arm/mach-ebsa110/include/mach/vmalloc.h b/arch/arm/mach-ebsa110/include/mach/vmalloc.h index 60bde56fba4c..ea141b7a3e03 100644 --- a/arch/arm/mach-ebsa110/include/mach/vmalloc.h +++ b/arch/arm/mach-ebsa110/include/mach/vmalloc.h @@ -7,4 +7,4 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#define VMALLOC_END 0xdf000000 +#define VMALLOC_END 0xdf000000UL diff --git a/arch/arm/mach-footbridge/include/mach/vmalloc.h b/arch/arm/mach-footbridge/include/mach/vmalloc.h index 0ffbb7c85e59..40ba78e5782b 100644 --- a/arch/arm/mach-footbridge/include/mach/vmalloc.h +++ b/arch/arm/mach-footbridge/include/mach/vmalloc.h @@ -7,4 +7,4 @@ */ -#define VMALLOC_END 0xf0000000 +#define VMALLOC_END 0xf0000000UL diff --git a/arch/arm/mach-h720x/include/mach/vmalloc.h b/arch/arm/mach-h720x/include/mach/vmalloc.h index a45915b88756..8520b4a4d4e6 100644 --- a/arch/arm/mach-h720x/include/mach/vmalloc.h +++ b/arch/arm/mach-h720x/include/mach/vmalloc.h @@ -5,6 +5,6 @@ #ifndef __ARCH_ARM_VMALLOC_H #define __ARCH_ARM_VMALLOC_H -#define VMALLOC_END 0xd0000000 +#define VMALLOC_END 0xd0000000UL #endif diff --git a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c index 026263c665ca..7e1e9dc2c8fc 100644 --- a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c +++ b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c @@ -250,9 +250,6 @@ static const struct imxuart_platform_data uart_pdata __initconst = { .flags = IMXUART_HAVE_RTSCTS, }; -#if defined(CONFIG_TOUCHSCREEN_ADS7846) \ - || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE) - #define ADS7846_PENDOWN (GPIO_PORTD | 25) static void ads7846_dev_init(void) @@ -273,9 +270,7 @@ static struct ads7846_platform_data ads7846_config __initdata = { .get_pendown_state = ads7846_get_pendown_state, .keep_vref_on = 1, }; -#endif -#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE) static struct spi_board_info eukrea_mbimx27_spi_board_info[] __initdata = { [0] = { .modalias = "ads7846", @@ -294,7 +289,6 @@ static const struct spi_imx_master eukrea_mbimx27_spi0_data __initconst = { .chipselect = eukrea_mbimx27_spi_cs, .num_chipselect = ARRAY_SIZE(eukrea_mbimx27_spi_cs), }; -#endif static struct i2c_board_info eukrea_mbimx27_i2c_devices[] = { { diff --git a/arch/arm/mach-integrator/include/mach/vmalloc.h b/arch/arm/mach-integrator/include/mach/vmalloc.h index e056e7cf5645..2f5a2bafb11f 100644 --- a/arch/arm/mach-integrator/include/mach/vmalloc.h +++ b/arch/arm/mach-integrator/include/mach/vmalloc.h @@ -17,4 +17,4 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define VMALLOC_END 0xd0000000 +#define VMALLOC_END 0xd0000000UL diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c index daf3993349f8..2e3dd08ccc3f 100644 --- a/arch/arm/mach-mmp/mmp2.c +++ b/arch/arm/mach-mmp/mmp2.c @@ -126,7 +126,6 @@ static APBC_CLK(twsi3, MMP2_TWSI3, 0, 26000000); static APBC_CLK(twsi4, MMP2_TWSI4, 0, 26000000); static APBC_CLK(twsi5, MMP2_TWSI5, 0, 26000000); static APBC_CLK(twsi6, MMP2_TWSI6, 0, 26000000); -static APBC_CLK(rtc, MMP2_RTC, 0, 32768); static APMU_CLK(nand, NAND, 0xbf, 100000000); diff --git a/arch/arm/mach-msm/include/mach/vmalloc.h b/arch/arm/mach-msm/include/mach/vmalloc.h index 31a32ad062dc..d138448eff16 100644 --- a/arch/arm/mach-msm/include/mach/vmalloc.h +++ b/arch/arm/mach-msm/include/mach/vmalloc.h @@ -16,7 +16,7 @@ #ifndef __ASM_ARCH_MSM_VMALLOC_H #define __ASM_ARCH_MSM_VMALLOC_H -#define VMALLOC_END 0xd0000000 +#define VMALLOC_END 0xd0000000UL #endif diff --git a/arch/arm/mach-mx25/devices-imx25.h b/arch/arm/mach-mx25/devices-imx25.h index 93afa10b13cf..d94d282fa676 100644 --- a/arch/arm/mach-mx25/devices-imx25.h +++ b/arch/arm/mach-mx25/devices-imx25.h @@ -42,9 +42,9 @@ extern const struct imx_mxc_nand_data imx25_mxc_nand_data __initconst; #define imx25_add_mxc_nand(pdata) \ imx_add_mxc_nand(&imx25_mxc_nand_data, pdata) -extern const struct imx_spi_imx_data imx25_spi_imx_data[] __initconst; +extern const struct imx_spi_imx_data imx25_cspi_data[] __initconst; #define imx25_add_spi_imx(id, pdata) \ - imx_add_spi_imx(&imx25_spi_imx_data[id], pdata) + imx_add_spi_imx(&imx25_cspi_data[id], pdata) #define imx25_add_spi_imx0(pdata) imx25_add_spi_imx(0, pdata) #define imx25_add_spi_imx1(pdata) imx25_add_spi_imx(1, pdata) #define imx25_add_spi_imx2(pdata) imx25_add_spi_imx(2, pdata) diff --git a/arch/arm/mach-mx3/mach-pcm037_eet.c b/arch/arm/mach-mx3/mach-pcm037_eet.c index 99e0894e07db..fda56545d2fd 100644 --- a/arch/arm/mach-mx3/mach-pcm037_eet.c +++ b/arch/arm/mach-mx3/mach-pcm037_eet.c @@ -14,6 +14,7 @@ #include <mach/common.h> #include <mach/iomux-mx3.h> +#include <mach/spi.h> #include <asm/mach-types.h> @@ -59,14 +60,12 @@ static struct spi_board_info pcm037_spi_dev[] = { }; /* Platform Data for MXC CSPI */ -#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE) static int pcm037_spi1_cs[] = {MXC_SPI_CS(1), IOMUX_TO_GPIO(MX31_PIN_KEY_COL7)}; static const struct spi_imx_master pcm037_spi1_pdata __initconst = { .chipselect = pcm037_spi1_cs, .num_chipselect = ARRAY_SIZE(pcm037_spi1_cs), }; -#endif /* GPIO-keys input device */ static struct gpio_keys_button pcm037_gpio_keys[] = { @@ -171,7 +170,7 @@ static struct platform_device pcm037_gpio_keys_device = { }, }; -static int eet_init_devices(void) +static int __init eet_init_devices(void) { if (!machine_is_pcm037() || pcm037_variant() != PCM037_EET) return 0; diff --git a/arch/arm/mach-netx/include/mach/vmalloc.h b/arch/arm/mach-netx/include/mach/vmalloc.h index 7cca3574308f..871f1ef7bff5 100644 --- a/arch/arm/mach-netx/include/mach/vmalloc.h +++ b/arch/arm/mach-netx/include/mach/vmalloc.h @@ -16,4 +16,4 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define VMALLOC_END 0xd0000000 +#define VMALLOC_END 0xd0000000UL diff --git a/arch/arm/mach-omap1/include/mach/vmalloc.h b/arch/arm/mach-omap1/include/mach/vmalloc.h index b001f67d695b..22ec4a479577 100644 --- a/arch/arm/mach-omap1/include/mach/vmalloc.h +++ b/arch/arm/mach-omap1/include/mach/vmalloc.h @@ -17,4 +17,4 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define VMALLOC_END 0xd8000000 +#define VMALLOC_END 0xd8000000UL diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c index 86c9b2102952..9db9203667df 100644 --- a/arch/arm/mach-omap2/board-zoom-peripherals.c +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@ -216,7 +216,7 @@ static struct omap2_hsmmc_info mmc[] __initdata = { { .name = "wl1271", .mmc = 3, - .caps = MMC_CAP_4_BIT_DATA, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD, .gpio_wp = -EINVAL, .gpio_cd = -EINVAL, .nonremovable = true, diff --git a/arch/arm/mach-omap2/include/mach/vmalloc.h b/arch/arm/mach-omap2/include/mach/vmalloc.h index 4da31e997efe..866319947760 100644 --- a/arch/arm/mach-omap2/include/mach/vmalloc.h +++ b/arch/arm/mach-omap2/include/mach/vmalloc.h @@ -17,4 +17,4 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define VMALLOC_END 0xf8000000 +#define VMALLOC_END 0xf8000000UL diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 40562ddd3ee4..a1939b1e6f82 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -297,7 +297,7 @@ static int __init _omap2_init_reprogram_sdrc(void) return 0; dpll3_m2_ck = clk_get(NULL, "dpll3_m2_ck"); - if (!dpll3_m2_ck) + if (IS_ERR(dpll3_m2_ck)) return -EINVAL; rate = clk_get_rate(dpll3_m2_ck); diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 5e81517a7af2..a8afb610c7d8 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -161,6 +161,23 @@ void omap2_pm_dump(int mode, int resume, unsigned int us) printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val); } +void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds) +{ + u32 tick_rate, cycles; + + if (!seconds && !milliseconds) + return; + + tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup)); + cycles = tick_rate * seconds + tick_rate * milliseconds / 1000; + omap_dm_timer_stop(gptimer_wakeup); + omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles); + + pr_info("PM: Resume timer in %u.%03u secs" + " (%d ticks at %d ticks/sec.)\n", + seconds, milliseconds, cycles, tick_rate); +} + #ifdef CONFIG_DEBUG_FS #include <linux/debugfs.h> #include <linux/seq_file.h> @@ -354,23 +371,6 @@ void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) pwrdm->timer = t; } -void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds) -{ - u32 tick_rate, cycles; - - if (!seconds && !milliseconds) - return; - - tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup)); - cycles = tick_rate * seconds + tick_rate * milliseconds / 1000; - omap_dm_timer_stop(gptimer_wakeup); - omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles); - - pr_info("PM: Resume timer in %u.%03u secs" - " (%d ticks at %d ticks/sec.)\n", - seconds, milliseconds, cycles, tick_rate); -} - static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) { struct seq_file *s = (struct seq_file *)user; diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index a40457d81927..aaeea49b9bdd 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -30,6 +30,7 @@ #include <linux/irq.h> #include <linux/time.h> #include <linux/gpio.h> +#include <linux/console.h> #include <asm/mach/time.h> #include <asm/mach/irq.h> @@ -52,6 +53,19 @@ #include <plat/powerdomain.h> #include <plat/clockdomain.h> +#ifdef CONFIG_SUSPEND +static suspend_state_t suspend_state = PM_SUSPEND_ON; +static inline bool is_suspending(void) +{ + return (suspend_state != PM_SUSPEND_ON); +} +#else +static inline bool is_suspending(void) +{ + return false; +} +#endif + static void (*omap2_sram_idle)(void); static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl, void __iomem *sdrc_power); @@ -118,6 +132,11 @@ static void omap2_enter_full_retention(void) if (omap_irq_pending()) goto no_sleep; + /* Block console output in case it is on one of the OMAP UARTs */ + if (!is_suspending()) + if (try_acquire_console_sem()) + goto no_sleep; + omap_uart_prepare_idle(0); omap_uart_prepare_idle(1); omap_uart_prepare_idle(2); @@ -131,6 +150,9 @@ static void omap2_enter_full_retention(void) omap_uart_resume_idle(1); omap_uart_resume_idle(0); + if (!is_suspending()) + release_console_sem(); + no_sleep: if (omap2_pm_debug) { unsigned long long tmp; @@ -277,6 +299,12 @@ out: local_irq_enable(); } +static int omap2_pm_begin(suspend_state_t state) +{ + suspend_state = state; + return 0; +} + static int omap2_pm_prepare(void) { /* We cannot sleep in idle until we have resumed */ @@ -326,10 +354,17 @@ static void omap2_pm_finish(void) enable_hlt(); } +static void omap2_pm_end(void) +{ + suspend_state = PM_SUSPEND_ON; +} + static struct platform_suspend_ops omap_pm_ops = { + .begin = omap2_pm_begin, .prepare = omap2_pm_prepare, .enter = omap2_pm_enter, .finish = omap2_pm_finish, + .end = omap2_pm_end, .valid = suspend_valid_only_mem, }; diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 75c0cd13ad8e..648b8c50d024 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -28,6 +28,7 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/console.h> #include <plat/sram.h> #include <plat/clockdomain.h> @@ -49,6 +50,19 @@ #include "sdrc.h" #include "control.h" +#ifdef CONFIG_SUSPEND +static suspend_state_t suspend_state = PM_SUSPEND_ON; +static inline bool is_suspending(void) +{ + return (suspend_state != PM_SUSPEND_ON); +} +#else +static inline bool is_suspending(void) +{ + return false; +} +#endif + /* Scratchpad offsets */ #define OMAP343X_TABLE_ADDRESS_OFFSET 0xc4 #define OMAP343X_TABLE_VALUE_OFFSET 0xc0 @@ -385,6 +399,13 @@ void omap_sram_idle(void) omap3_enable_io_chain(); } + /* Block console output in case it is on one of the OMAP UARTs */ + if (!is_suspending()) + if (per_next_state < PWRDM_POWER_ON || + core_next_state < PWRDM_POWER_ON) + if (try_acquire_console_sem()) + goto console_still_active; + /* PER */ if (per_next_state < PWRDM_POWER_ON) { omap_uart_prepare_idle(2); @@ -463,6 +484,10 @@ void omap_sram_idle(void) omap_uart_resume_idle(3); } + if (!is_suspending()) + release_console_sem(); + +console_still_active: /* Disable IO-PAD and IO-CHAIN wakeup */ if (omap3_has_io_wakeup() && (per_next_state < PWRDM_POWER_ON || @@ -504,8 +529,6 @@ out: } #ifdef CONFIG_SUSPEND -static suspend_state_t suspend_state; - static int omap3_pm_prepare(void) { disable_hlt(); diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index 298a22a754e2..f81acee4738d 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h @@ -243,13 +243,14 @@ #define OMAP24XX_EN_GPT1_MASK (1 << 0) /* PM_WKST_WKUP, CM_IDLEST_WKUP shared bits */ -#define OMAP24XX_ST_GPIOS_SHIFT (1 << 2) -#define OMAP24XX_ST_GPIOS_MASK 2 -#define OMAP24XX_ST_GPT1_SHIFT (1 << 0) -#define OMAP24XX_ST_GPT1_MASK 0 +#define OMAP24XX_ST_GPIOS_SHIFT 2 +#define OMAP24XX_ST_GPIOS_MASK (1 << 2) +#define OMAP24XX_ST_GPT1_SHIFT 0 +#define OMAP24XX_ST_GPT1_MASK (1 << 0) /* CM_IDLEST_MDM and PM_WKST_MDM shared bits */ -#define OMAP2430_ST_MDM_SHIFT (1 << 0) +#define OMAP2430_ST_MDM_SHIFT 0 +#define OMAP2430_ST_MDM_MASK (1 << 0) /* 3430 register bits shared between CM & PRM registers */ diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index becf0e38ef7e..d17960a1be25 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/serial_8250.h> #include <linux/pm_runtime.h> +#include <linux/console.h> #ifdef CONFIG_SERIAL_OMAP #include <plat/omap-serial.h> @@ -406,7 +407,7 @@ void omap_uart_resume_idle(int num) struct omap_uart_state *uart; list_for_each_entry(uart, &uart_list, node) { - if (num == uart->num) { + if (num == uart->num && uart->can_sleep) { omap_uart_enable_clocks(uart); /* Check for IO pad wakeup */ @@ -807,6 +808,8 @@ void __init omap_serial_init_port(int port) oh->dev_attr = uart; + acquire_console_sem(); /* in case the earlycon is on the UART */ + /* * Because of early UART probing, UART did not get idled * on init. Now that omap_device is ready, ensure full idle @@ -831,6 +834,8 @@ void __init omap_serial_init_port(int port) omap_uart_block_sleep(uart); uart->timeout = DEFAULT_TIMEOUT; + release_console_sem(); + if ((cpu_is_omap34xx() && uart->padconf) || (uart->wk_en && uart->wk_mask)) { device_init_wakeup(&od->pdev.dev, true); diff --git a/arch/arm/mach-pnx4008/include/mach/vmalloc.h b/arch/arm/mach-pnx4008/include/mach/vmalloc.h index 31b65ee07b0b..184913c71141 100644 --- a/arch/arm/mach-pnx4008/include/mach/vmalloc.h +++ b/arch/arm/mach-pnx4008/include/mach/vmalloc.h @@ -17,4 +17,4 @@ * The vmalloc() routines leaves a hole of 4kB between each vmalloced * area for the same reason. ;) */ -#define VMALLOC_END 0xd0000000 +#define VMALLOC_END 0xd0000000UL diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c index d2060a1d1d68..e5c9932b7588 100644 --- a/arch/arm/mach-pxa/palmtx.c +++ b/arch/arm/mach-pxa/palmtx.c @@ -241,7 +241,8 @@ static inline void palmtx_keys_init(void) {} /****************************************************************************** * NAND Flash ******************************************************************************/ -#if defined(CONFIG_MTD_NAND_GPIO) || defined(CONFIG_MTD_NAND_GPIO_MODULE) +#if defined(CONFIG_MTD_NAND_PLATFORM) || \ + defined(CONFIG_MTD_NAND_PLATFORM_MODULE) static void palmtx_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { diff --git a/arch/arm/mach-realview/headsmp.S b/arch/arm/mach-realview/headsmp.S index 4075473cf68a..b34be4554d40 100644 --- a/arch/arm/mach-realview/headsmp.S +++ b/arch/arm/mach-realview/headsmp.S @@ -35,5 +35,6 @@ pen: ldr r7, [r6] */ b secondary_startup + .align 1: .long . .long pen_release diff --git a/arch/arm/mach-rpc/include/mach/vmalloc.h b/arch/arm/mach-rpc/include/mach/vmalloc.h index 3bcd86fadb81..fb700228637a 100644 --- a/arch/arm/mach-rpc/include/mach/vmalloc.h +++ b/arch/arm/mach-rpc/include/mach/vmalloc.h @@ -7,4 +7,4 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#define VMALLOC_END 0xdc000000 +#define VMALLOC_END 0xdc000000UL diff --git a/arch/arm/mach-s3c2410/h1940-bluetooth.c b/arch/arm/mach-s3c2410/h1940-bluetooth.c index 8aa2f1902a94..6b86a722a7db 100644 --- a/arch/arm/mach-s3c2410/h1940-bluetooth.c +++ b/arch/arm/mach-s3c2410/h1940-bluetooth.c @@ -77,13 +77,13 @@ static int __devinit h1940bt_probe(struct platform_device *pdev) /* Configures BT serial port GPIOs */ s3c_gpio_cfgpin(S3C2410_GPH(0), S3C2410_GPH0_nCTS0); - s3c_gpio_cfgpull(S3C2410_GPH(0), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPH(0), S3C_GPIO_PULL_NONE); s3c_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_OUTPUT); - s3c_gpio_cfgpull(S3C2410_GPH(1), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPH(1), S3C_GPIO_PULL_NONE); s3c_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPH2_TXD0); - s3c_gpio_cfgpull(S3C2410_GPH(2), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPH(2), S3C_GPIO_PULL_NONE); s3c_gpio_cfgpin(S3C2410_GPH(3), S3C2410_GPH3_RXD0); - s3c_gpio_cfgpull(S3C2410_GPH(3), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPH(3), S3C_GPIO_PULL_NONE); rfk = rfkill_alloc(DRV_NAME, &pdev->dev, RFKILL_TYPE_BLUETOOTH, diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig index cef6a65637bd..6983cb4d4cae 100644 --- a/arch/arm/mach-s3c2412/Kconfig +++ b/arch/arm/mach-s3c2412/Kconfig @@ -16,7 +16,7 @@ config CPU_S3C2412 config CPU_S3C2412_ONLY bool depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \ - !CPU_2416 && !CPU_S3C2440 && !CPU_S3C2442 && \ + !CPU_S3C2416 && !CPU_S3C2440 && !CPU_S3C2442 && \ !CPU_S3C2443 && CPU_S3C2412 default y if CPU_S3C2412 @@ -28,9 +28,16 @@ config S3C2412_DMA config S3C2412_PM bool + select S3C2412_PM_SLEEP help Internal config node to apply S3C2412 power management +config S3C2412_PM_SLEEP + bool + help + Internal config node to apply sleep for S3C2412 power management. + Can be selected by another SoCs with similar sleep procedure. + # Note, the S3C2412 IOtiming support is in plat-s3c24xx config S3C2412_CPUFREQ diff --git a/arch/arm/mach-s3c2412/Makefile b/arch/arm/mach-s3c2412/Makefile index 530ec46cbaea..6c48a91ea39e 100644 --- a/arch/arm/mach-s3c2412/Makefile +++ b/arch/arm/mach-s3c2412/Makefile @@ -14,7 +14,8 @@ obj-$(CONFIG_CPU_S3C2412) += irq.o obj-$(CONFIG_CPU_S3C2412) += clock.o obj-$(CONFIG_CPU_S3C2412) += gpio.o obj-$(CONFIG_S3C2412_DMA) += dma.o -obj-$(CONFIG_S3C2412_PM) += pm.o sleep.o +obj-$(CONFIG_S3C2412_PM) += pm.o +obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep.o obj-$(CONFIG_S3C2412_CPUFREQ) += cpu-freq.o # Machine support diff --git a/arch/arm/mach-s3c2416/Kconfig b/arch/arm/mach-s3c2416/Kconfig index 87b9c9f003bd..df8d14974c90 100644 --- a/arch/arm/mach-s3c2416/Kconfig +++ b/arch/arm/mach-s3c2416/Kconfig @@ -27,6 +27,7 @@ config S3C2416_DMA config S3C2416_PM bool + select S3C2412_PM_SLEEP help Internal config node to apply S3C2416 power management @@ -35,9 +36,12 @@ menu "S3C2416 Machines" config MACH_SMDK2416 bool "SMDK2416" select CPU_S3C2416 + select MACH_SMDK select S3C_DEV_FB select S3C_DEV_HSMMC select S3C_DEV_HSMMC1 + select S3C_DEV_NAND + select S3C_DEV_USB_HOST select S3C2416_PM if PM help Say Y here if you are using an SMDK2416 diff --git a/arch/arm/mach-s3c2416/irq.c b/arch/arm/mach-s3c2416/irq.c index 084d121f368c..00174daf1526 100644 --- a/arch/arm/mach-s3c2416/irq.c +++ b/arch/arm/mach-s3c2416/irq.c @@ -168,12 +168,11 @@ static struct irq_chip s3c2416_irq_dma = { static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc) { - s3c2416_irq_demux(IRQ_S3C2443_UART3, 3); + s3c2416_irq_demux(IRQ_S3C2443_RX3, 3); } #define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0)) -#define SUBMSK_UART3 (0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0))) - +#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0))) static void s3c2416_irq_uart3_mask(unsigned int irqno) { diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig index ff024a6c0f85..a0cb2581894f 100644 --- a/arch/arm/mach-s3c2440/Kconfig +++ b/arch/arm/mach-s3c2440/Kconfig @@ -18,6 +18,7 @@ config CPU_S3C2440 config CPU_S3C2442 bool select CPU_ARM920T + select S3C_GPIO_PULL_DOWN select S3C2410_CLOCK select S3C2410_GPIO select S3C2410_PM if PM @@ -178,6 +179,9 @@ config MACH_MINI2440 bool "MINI2440 development board" select CPU_S3C2440 select EEPROM_AT24 + select NEW_LEDS + select LEDS_CLASS + select LEDS_TRIGGER select LEDS_TRIGGER_BACKLIGHT select S3C_DEV_NAND select S3C_DEV_USB_HOST diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c index d50f3ae6173d..f7663f731ea0 100644 --- a/arch/arm/mach-s3c2440/s3c2440.c +++ b/arch/arm/mach-s3c2440/s3c2440.c @@ -46,9 +46,6 @@ int __init s3c2440_init(void) { printk("S3C2440: Initialising architecture\n"); - s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1up; - s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1up; - /* change irq for watchdog */ s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT; @@ -58,3 +55,11 @@ int __init s3c2440_init(void) return sysdev_register(&s3c2440_sysdev); } + +void __init s3c2440_map_io(void) +{ + s3c244x_map_io(); + + s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1up; + s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1up; +} diff --git a/arch/arm/mach-s3c2440/s3c2442.c b/arch/arm/mach-s3c2440/s3c2442.c index 188ad1e57dc0..ecf813546554 100644 --- a/arch/arm/mach-s3c2440/s3c2442.c +++ b/arch/arm/mach-s3c2440/s3c2442.c @@ -32,6 +32,7 @@ #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/mutex.h> +#include <linux/gpio.h> #include <linux/clk.h> #include <linux/io.h> @@ -43,6 +44,11 @@ #include <plat/clock.h> #include <plat/cpu.h> +#include <plat/s3c244x.h> + +#include <plat/gpio-core.h> +#include <plat/gpio-cfg.h> +#include <plat/gpio-cfg-helpers.h> /* S3C2442 extended clock support */ @@ -163,3 +169,11 @@ int __init s3c2442_init(void) return sysdev_register(&s3c2442_sysdev); } + +void __init s3c2442_map_io(void) +{ + s3c244x_map_io(); + + s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1down; + s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1down; +} diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig index 4fef723126fa..31babec90cec 100644 --- a/arch/arm/mach-s3c2443/Kconfig +++ b/arch/arm/mach-s3c2443/Kconfig @@ -5,6 +5,7 @@ config CPU_S3C2443 bool depends on ARCH_S3C2410 + select CPU_ARM920T select S3C2443_DMA if S3C2410_DMA select CPU_LLSERIAL_S3C2440 select SAMSUNG_CLKSRC diff --git a/arch/arm/mach-s3c2443/irq.c b/arch/arm/mach-s3c2443/irq.c index 0e0d693f3974..893424767ce1 100644 --- a/arch/arm/mach-s3c2443/irq.c +++ b/arch/arm/mach-s3c2443/irq.c @@ -166,12 +166,11 @@ static struct irq_chip s3c2443_irq_dma = { static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc) { - s3c2443_irq_demux(IRQ_S3C2443_UART3, 3); + s3c2443_irq_demux(IRQ_S3C2443_RX3, 3); } #define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0)) -#define SUBMSK_UART3 (0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0))) - +#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0))) static void s3c2443_irq_uart3_mask(unsigned int irqno) { diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c index 249c62956471..89f35e02e883 100644 --- a/arch/arm/mach-s3c64xx/mach-mini6410.c +++ b/arch/arm/mach-s3c64xx/mach-mini6410.c @@ -45,7 +45,7 @@ #include <video/platform_lcd.h> -#define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK) +#define UCON S3C2410_UCON_DEFAULT #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB) #define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c index f9ef9b5c5f5a..4957ab0a0d4a 100644 --- a/arch/arm/mach-s3c64xx/mach-real6410.c +++ b/arch/arm/mach-s3c64xx/mach-real6410.c @@ -46,7 +46,7 @@ #include <video/platform_lcd.h> -#define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK) +#define UCON S3C2410_UCON_DEFAULT #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB) #define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c index 28677caf3613..461aa035afc0 100644 --- a/arch/arm/mach-s5pv210/mach-aquila.c +++ b/arch/arm/mach-s5pv210/mach-aquila.c @@ -378,6 +378,12 @@ static struct max8998_regulator_data aquila_regulators[] = { static struct max8998_platform_data aquila_max8998_pdata = { .num_regulators = ARRAY_SIZE(aquila_regulators), .regulators = aquila_regulators, + .buck1_set1 = S5PV210_GPH0(3), + .buck1_set2 = S5PV210_GPH0(4), + .buck2_set3 = S5PV210_GPH0(5), + .buck1_max_voltage1 = 1200000, + .buck1_max_voltage2 = 1200000, + .buck2_max_voltage = 1200000, }; #endif diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c index b1dcf964a768..e22d5112fd44 100644 --- a/arch/arm/mach-s5pv210/mach-goni.c +++ b/arch/arm/mach-s5pv210/mach-goni.c @@ -518,6 +518,12 @@ static struct max8998_regulator_data goni_regulators[] = { static struct max8998_platform_data goni_max8998_pdata = { .num_regulators = ARRAY_SIZE(goni_regulators), .regulators = goni_regulators, + .buck1_set1 = S5PV210_GPH0(3), + .buck1_set2 = S5PV210_GPH0(4), + .buck2_set3 = S5PV210_GPH0(5), + .buck1_max_voltage1 = 1200000, + .buck1_max_voltage2 = 1200000, + .buck2_max_voltage = 1200000, }; #endif diff --git a/arch/arm/mach-s5pv210/mach-smdkc110.c b/arch/arm/mach-s5pv210/mach-smdkc110.c index 0ad7924fe62e..5dd1681c069e 100644 --- a/arch/arm/mach-s5pv210/mach-smdkc110.c +++ b/arch/arm/mach-s5pv210/mach-smdkc110.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/serial_core.h> #include <linux/i2c.h> +#include <linux/sysdev.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c index bcd7a5d53401..1fbc45b2a432 100644 --- a/arch/arm/mach-s5pv210/mach-smdkv210.c +++ b/arch/arm/mach-s5pv210/mach-smdkv210.c @@ -13,6 +13,7 @@ #include <linux/i2c.h> #include <linux/init.h> #include <linux/serial_core.h> +#include <linux/sysdev.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> diff --git a/arch/arm/mach-shark/include/mach/vmalloc.h b/arch/arm/mach-shark/include/mach/vmalloc.h index 8e845b6a7cb5..b10df988526d 100644 --- a/arch/arm/mach-shark/include/mach/vmalloc.h +++ b/arch/arm/mach-shark/include/mach/vmalloc.h @@ -1,4 +1,4 @@ /* * arch/arm/mach-shark/include/mach/vmalloc.h */ -#define VMALLOC_END 0xd0000000 +#define VMALLOC_END 0xd0000000UL diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 9add606021f4..a054f0d450d8 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -572,38 +572,127 @@ static struct platform_device *qhd_devices[] __initdata = { /* FSI */ #define IRQ_FSI evt2irq(0x1840) +static int __fsi_set_rate(struct clk *clk, long rate, int enable) +{ + int ret = 0; + + if (rate <= 0) + return ret; + + if (enable) { + ret = clk_set_rate(clk, rate); + if (0 == ret) + ret = clk_enable(clk); + } else { + clk_disable(clk); + } + + return ret; +} + +static int __fsi_set_round_rate(struct clk *clk, long rate, int enable) +{ + return __fsi_set_rate(clk, clk_round_rate(clk, rate), enable); +} -static int fsi_set_rate(int is_porta, int rate) +static int fsi_ak4642_set_rate(struct device *dev, int rate, int enable) +{ + struct clk *fsia_ick; + struct clk *fsiack; + int ret = -EIO; + + fsia_ick = clk_get(dev, "icka"); + if (IS_ERR(fsia_ick)) + return PTR_ERR(fsia_ick); + + /* + * FSIACK is connected to AK4642, + * and use external clock pin from it. + * it is parent of fsia_ick now. + */ + fsiack = clk_get_parent(fsia_ick); + if (!fsiack) + goto fsia_ick_out; + + /* + * we get 1/1 divided clock by setting same rate to fsiack and fsia_ick + * + ** FIXME ** + * Because the freq_table of external clk (fsiack) are all 0, + * the return value of clk_round_rate became 0. + * So, it use __fsi_set_rate here. + */ + ret = __fsi_set_rate(fsiack, rate, enable); + if (ret < 0) + goto fsiack_out; + + ret = __fsi_set_round_rate(fsia_ick, rate, enable); + if ((ret < 0) && enable) + __fsi_set_round_rate(fsiack, rate, 0); /* disable FSI ACK */ + +fsiack_out: + clk_put(fsiack); + +fsia_ick_out: + clk_put(fsia_ick); + + return 0; +} + +static int fsi_hdmi_set_rate(struct device *dev, int rate, int enable) { struct clk *fsib_clk; struct clk *fdiv_clk = &sh7372_fsidivb_clk; + long fsib_rate = 0; + long fdiv_rate = 0; + int ackmd_bpfmd; int ret; - /* set_rate is not needed if port A */ - if (is_porta) - return 0; - - fsib_clk = clk_get(NULL, "fsib_clk"); - if (IS_ERR(fsib_clk)) - return -EINVAL; - switch (rate) { case 44100: - clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 11283000)); - ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; + fsib_rate = rate * 256; + ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; break; case 48000: - clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 85428000)); - clk_set_rate(fdiv_clk, clk_round_rate(fdiv_clk, 12204000)); - ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; + fsib_rate = 85428000; /* around 48kHz x 256 x 7 */ + fdiv_rate = rate * 256; + ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; break; default: pr_err("unsupported rate in FSI2 port B\n"); - ret = -EINVAL; - break; + return -EINVAL; } + /* FSI B setting */ + fsib_clk = clk_get(dev, "ickb"); + if (IS_ERR(fsib_clk)) + return -EIO; + + ret = __fsi_set_round_rate(fsib_clk, fsib_rate, enable); clk_put(fsib_clk); + if (ret < 0) + return ret; + + /* FSI DIV setting */ + ret = __fsi_set_round_rate(fdiv_clk, fdiv_rate, enable); + if (ret < 0) { + /* disable FSI B */ + if (enable) + __fsi_set_round_rate(fsib_clk, fsib_rate, 0); + return ret; + } + + return ackmd_bpfmd; +} + +static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) +{ + int ret; + + if (is_porta) + ret = fsi_ak4642_set_rate(dev, rate, enable); + else + ret = fsi_hdmi_set_rate(dev, rate, enable); return ret; } @@ -909,6 +998,11 @@ static int __init hdmi_init_pm_clock(void) goto out; } + ret = clk_enable(&sh7372_pllc2_clk); + if (ret < 0) { + pr_err("Cannot enable pllc2 clock\n"); + goto out; + } pr_debug("PLLC2 set frequency %lu\n", rate); ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk); @@ -925,23 +1019,11 @@ out: device_initcall(hdmi_init_pm_clock); -#define FSIACK_DUMMY_RATE 48000 static int __init fsi_init_pm_clock(void) { struct clk *fsia_ick; int ret; - /* - * FSIACK is connected to AK4642, - * and the rate is depend on playing sound rate. - * So, set dummy rate (= 48k) here - */ - ret = clk_set_rate(&sh7372_fsiack_clk, FSIACK_DUMMY_RATE); - if (ret < 0) { - pr_err("Cannot set FSIACK dummy rate: %d\n", ret); - return ret; - } - fsia_ick = clk_get(&fsi_device.dev, "icka"); if (IS_ERR(fsia_ick)) { ret = PTR_ERR(fsia_ick); @@ -950,16 +1032,9 @@ static int __init fsi_init_pm_clock(void) } ret = clk_set_parent(fsia_ick, &sh7372_fsiack_clk); - if (ret < 0) { - pr_err("Cannot set FSI-A parent: %d\n", ret); - goto out; - } - - ret = clk_set_rate(fsia_ick, FSIACK_DUMMY_RATE); if (ret < 0) - pr_err("Cannot set FSI-A rate: %d\n", ret); + pr_err("Cannot set FSI-A parent: %d\n", ret); -out: clk_put(fsia_ick); return ret; diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 7db31e6c6bf2..3aa026069435 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -220,8 +220,7 @@ static void pllc2_disable(struct clk *clk) __raw_writel(__raw_readl(PLLC2CR) & ~0x80000000, PLLC2CR); } -static int pllc2_set_rate(struct clk *clk, - unsigned long rate, int algo_id) +static int pllc2_set_rate(struct clk *clk, unsigned long rate) { unsigned long value; int idx; @@ -230,21 +229,13 @@ static int pllc2_set_rate(struct clk *clk, if (idx < 0) return idx; - if (rate == clk->parent->rate) { - pllc2_disable(clk); - return 0; - } + if (rate == clk->parent->rate) + return -EINVAL; value = __raw_readl(PLLC2CR) & ~(0x3f << 24); - if (value & 0x80000000) - pllc2_disable(clk); - __raw_writel((value & ~0x80000000) | ((idx + 19) << 24), PLLC2CR); - if (value & 0x80000000) - return pllc2_enable(clk); - return 0; } @@ -453,32 +444,24 @@ static int fsidiv_enable(struct clk *clk) unsigned long value; value = __raw_readl(clk->mapping->base) >> 16; - if (value < 2) { - fsidiv_disable(clk); - return -ENOENT; - } + if (value < 2) + return -EIO; __raw_writel((value << 16) | 0x3, clk->mapping->base); return 0; } -static int fsidiv_set_rate(struct clk *clk, - unsigned long rate, int algo_id) +static int fsidiv_set_rate(struct clk *clk, unsigned long rate) { int idx; - if (clk->parent->rate == rate) { - fsidiv_disable(clk); - return 0; - } - idx = (clk->parent->rate / rate) & 0xffff; if (idx < 2) - return -ENOENT; + return -EINVAL; __raw_writel(idx << 16, clk->mapping->base); - return fsidiv_enable(clk); + return 0; } static struct clk_ops fsidiv_clk_ops = { @@ -609,8 +592,6 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]), CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]), CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]), - CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FSIA]), - CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FSIB]), CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), @@ -647,8 +628,8 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */ CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */ CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ - CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */ - CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP323]), /* USB0 */ + CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */ + CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */ diff --git a/arch/arm/mach-shmobile/include/mach/entry-macro.S b/arch/arm/mach-shmobile/include/mach/entry-macro.S index a285d13c7416..f428c4db2b60 100644 --- a/arch/arm/mach-shmobile/include/mach/entry-macro.S +++ b/arch/arm/mach-shmobile/include/mach/entry-macro.S @@ -1,4 +1,5 @@ /* + * Copyright (C) 2010 Magnus Damm * Copyright (C) 2008 Renesas Solutions Corp. * * This program is free software; you can redistribute it and/or modify @@ -14,24 +15,45 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <mach/hardware.h> #include <mach/irqs.h> +#define INTCA_BASE 0xe6980000 +#define INTFLGA_OFFS 0x00000018 /* accept pending interrupt */ +#define INTEVTA_OFFS 0x00000020 /* vector number of accepted interrupt */ +#define INTLVLA_OFFS 0x00000030 /* priority level of accepted interrupt */ +#define INTLVLB_OFFS 0x00000034 /* previous priority level */ + .macro disable_fiq .endm .macro get_irqnr_preamble, base, tmp - ldr \base, =INTFLGA + ldr \base, =INTCA_BASE .endm .macro arch_ret_to_user, tmp1, tmp2 .endm .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - ldr \irqnr, [\base] + /* The single INTFLGA read access below results in the following: + * + * 1. INTLVLB is updated with old priority value from INTLVLA + * 2. Highest priority interrupt is accepted + * 3. INTLVLA is updated to contain priority of accepted interrupt + * 4. Accepted interrupt vector is stored in INTFLGA and INTEVTA + */ + ldr \irqnr, [\base, #INTFLGA_OFFS] + + /* Restore INTLVLA with the value saved in INTLVLB. + * This is required to support interrupt priorities properly. + */ + ldrb \tmp, [\base, #INTLVLB_OFFS] + strb \tmp, [\base, #INTLVLA_OFFS] + + /* Handle invalid vector number case */ cmp \irqnr, #0 beq 1000f - /* intevt to irq number */ + + /* Convert vector to irq number, same as the evt2irq() macro */ lsr \irqnr, \irqnr, #0x5 subs \irqnr, \irqnr, #16 diff --git a/arch/arm/mach-shmobile/include/mach/vmalloc.h b/arch/arm/mach-shmobile/include/mach/vmalloc.h index 4aecf6e3a859..2b8fd8b942fe 100644 --- a/arch/arm/mach-shmobile/include/mach/vmalloc.h +++ b/arch/arm/mach-shmobile/include/mach/vmalloc.h @@ -2,6 +2,6 @@ #define __ASM_MACH_VMALLOC_H /* Vmalloc at ... - 0xe5ffffff */ -#define VMALLOC_END 0xe6000000 +#define VMALLOC_END 0xe6000000UL #endif /* __ASM_MACH_VMALLOC_H */ diff --git a/arch/arm/mach-tegra/include/mach/debug-macro.S b/arch/arm/mach-tegra/include/mach/debug-macro.S index 8ea3bffb4e00..a0e7c12868bd 100644 --- a/arch/arm/mach-tegra/include/mach/debug-macro.S +++ b/arch/arm/mach-tegra/include/mach/debug-macro.S @@ -21,8 +21,8 @@ #include <mach/io.h> .macro addruart, rp, rv - ldreq \rp, =IO_APB_PHYS @ physical - ldrne \rv, =IO_APB_VIRT @ virtual + ldr \rp, =IO_APB_PHYS @ physical + ldr \rv, =IO_APB_VIRT @ virtual #if defined(CONFIG_TEGRA_DEBUG_UART_NONE) #error "A debug UART must be selected in the kernel config to use DEBUG_LL" #elif defined(CONFIG_TEGRA_DEBUG_UARTA) diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index 73fb1a551ec6..608a1372b172 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -75,14 +75,14 @@ void __init ux500_init_irq(void) static inline void ux500_cache_wait(void __iomem *reg, unsigned long mask) { /* wait for the operation to complete */ - while (readl(reg) & mask) + while (readl_relaxed(reg) & mask) ; } static inline void ux500_cache_sync(void) { void __iomem *base = __io_address(UX500_L2CC_BASE); - writel(0, base + L2X0_CACHE_SYNC); + writel_relaxed(0, base + L2X0_CACHE_SYNC); ux500_cache_wait(base + L2X0_CACHE_SYNC, 1); } @@ -107,7 +107,7 @@ static void ux500_l2x0_inv_all(void) uint32_t l2x0_way_mask = (1<<16) - 1; /* Bitmask of active ways */ /* invalidate all ways */ - writel(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); + writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); ux500_cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); ux500_cache_sync(); } diff --git a/arch/arm/mach-versatile/include/mach/vmalloc.h b/arch/arm/mach-versatile/include/mach/vmalloc.h index ebd8a2543d3b..7d8e069ad51b 100644 --- a/arch/arm/mach-versatile/include/mach/vmalloc.h +++ b/arch/arm/mach-versatile/include/mach/vmalloc.h @@ -18,4 +18,4 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define VMALLOC_END 0xd8000000 +#define VMALLOC_END 0xd8000000UL diff --git a/arch/arm/mach-vexpress/headsmp.S b/arch/arm/mach-vexpress/headsmp.S index 8a78ff68e1ee..7a3f0632947c 100644 --- a/arch/arm/mach-vexpress/headsmp.S +++ b/arch/arm/mach-vexpress/headsmp.S @@ -35,5 +35,6 @@ pen: ldr r7, [r6] */ b secondary_startup + .align 1: .long . .long pen_release diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index 99fa688dfadd..c96fa1b3f49f 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S @@ -203,6 +203,10 @@ ENTRY(v6_flush_kern_dcache_area) * - end - virtual end address of region */ v6_dma_inv_range: +#ifdef CONFIG_DMA_CACHE_RWFO + ldrb r2, [r0] @ read for ownership + strb r2, [r0] @ write for ownership +#endif tst r0, #D_CACHE_LINE_SIZE - 1 bic r0, r0, #D_CACHE_LINE_SIZE - 1 #ifdef HARVARD_CACHE @@ -211,6 +215,10 @@ v6_dma_inv_range: mcrne p15, 0, r0, c7, c11, 1 @ clean unified line #endif tst r1, #D_CACHE_LINE_SIZE - 1 +#ifdef CONFIG_DMA_CACHE_RWFO + ldrneb r2, [r1, #-1] @ read for ownership + strneb r2, [r1, #-1] @ write for ownership +#endif bic r1, r1, #D_CACHE_LINE_SIZE - 1 #ifdef HARVARD_CACHE mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D line @@ -218,10 +226,6 @@ v6_dma_inv_range: mcrne p15, 0, r1, c7, c15, 1 @ clean & invalidate unified line #endif 1: -#ifdef CONFIG_DMA_CACHE_RWFO - ldr r2, [r0] @ read for ownership - str r2, [r0] @ write for ownership -#endif #ifdef HARVARD_CACHE mcr p15, 0, r0, c7, c6, 1 @ invalidate D line #else @@ -229,6 +233,10 @@ v6_dma_inv_range: #endif add r0, r0, #D_CACHE_LINE_SIZE cmp r0, r1 +#ifdef CONFIG_DMA_CACHE_RWFO + ldrlo r2, [r0] @ read for ownership + strlo r2, [r0] @ write for ownership +#endif blo 1b mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer @@ -263,12 +271,12 @@ v6_dma_clean_range: * - end - virtual end address of region */ ENTRY(v6_dma_flush_range) - bic r0, r0, #D_CACHE_LINE_SIZE - 1 -1: #ifdef CONFIG_DMA_CACHE_RWFO - ldr r2, [r0] @ read for ownership - str r2, [r0] @ write for ownership + ldrb r2, [r0] @ read for ownership + strb r2, [r0] @ write for ownership #endif + bic r0, r0, #D_CACHE_LINE_SIZE - 1 +1: #ifdef HARVARD_CACHE mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line #else @@ -276,6 +284,10 @@ ENTRY(v6_dma_flush_range) #endif add r0, r0, #D_CACHE_LINE_SIZE cmp r0, r1 +#ifdef CONFIG_DMA_CACHE_RWFO + ldrlob r2, [r0] @ read for ownership + strlob r2, [r0] @ write for ownership +#endif blo 1b mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index a3ebf7a4f49b..6136e68ce953 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -173,15 +173,22 @@ ENTRY(v7_coherent_user_range) UNWIND(.fnstart ) dcache_line_size r2, r3 sub r3, r2, #1 - bic r0, r0, r3 + bic r12, r0, r3 1: - USER( mcr p15, 0, r0, c7, c11, 1 ) @ clean D line to the point of unification + USER( mcr p15, 0, r12, c7, c11, 1 ) @ clean D line to the point of unification + add r12, r12, r2 + cmp r12, r1 + blo 1b dsb - USER( mcr p15, 0, r0, c7, c5, 1 ) @ invalidate I line - add r0, r0, r2 + icache_line_size r2, r3 + sub r3, r2, #1 + bic r12, r0, r3 2: - cmp r0, r1 - blo 1b + USER( mcr p15, 0, r12, c7, c5, 1 ) @ invalidate I line + add r12, r12, r2 + cmp r12, r1 + blo 2b +3: mov r0, #0 ALT_SMP(mcr p15, 0, r0, c7, c1, 6) @ invalidate BTB Inner Shareable ALT_UP(mcr p15, 0, r0, c7, c5, 6) @ invalidate BTB @@ -194,10 +201,10 @@ ENTRY(v7_coherent_user_range) * isn't mapped, just try the next page. */ 9001: - mov r0, r0, lsr #12 - mov r0, r0, lsl #12 - add r0, r0, #4096 - b 2b + mov r12, r12, lsr #12 + mov r12, r12, lsl #12 + add r12, r12, #4096 + b 3b UNWIND(.fnend ) ENDPROC(v7_coherent_kern_range) ENDPROC(v7_coherent_user_range) diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 17e7b0b57e49..55c17a6fb22f 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -206,8 +206,8 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, */ if (pfn_valid(pfn)) { printk(KERN_WARNING "BUG: Your driver calls ioremap() on system memory. This leads\n" - KERN_WARNING "to architecturally unpredictable behaviour on ARMv6+, and ioremap()\n" - KERN_WARNING "will fail in the next kernel release. Please fix your driver.\n"); + "to architecturally unpredictable behaviour on ARMv6+, and ioremap()\n" + "will fail in the next kernel release. Please fix your driver.\n"); WARN_ON(1); } diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index 7d63beaf9745..b795afd0a2c6 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -61,17 +61,27 @@ .endm /* - * cache_line_size - get the cache line size from the CSIDR register - * (available on ARMv7+). It assumes that the CSSR register was configured - * to access the L1 data cache CSIDR. + * dcache_line_size - get the minimum D-cache line size from the CTR register + * on ARMv7. */ .macro dcache_line_size, reg, tmp - mrc p15, 1, \tmp, c0, c0, 0 @ read CSIDR - and \tmp, \tmp, #7 @ cache line size encoding - mov \reg, #16 @ size offset + mrc p15, 0, \tmp, c0, c0, 1 @ read ctr + lsr \tmp, \tmp, #16 + and \tmp, \tmp, #0xf @ cache line size encoding + mov \reg, #4 @ bytes per word mov \reg, \reg, lsl \tmp @ actual cache line size .endm +/* + * icache_line_size - get the minimum I-cache line size from the CTR register + * on ARMv7. + */ + .macro icache_line_size, reg, tmp + mrc p15, 0, \tmp, c0, c0, 1 @ read ctr + and \tmp, \tmp, #0xf @ cache line size encoding + mov \reg, #4 @ bytes per word + mov \reg, \reg, lsl \tmp @ actual cache line size + .endm /* * Sanity check the PTE configuration for the code below - which makes diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 53cbe2225153..9b9ff5d949fd 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -381,7 +381,7 @@ __v7_ca9mp_proc_info: PMD_SECT_XN | \ PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ - b __v7_ca9mp_setup + W(b) __v7_ca9mp_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS @@ -413,7 +413,7 @@ __v7_proc_info: PMD_SECT_XN | \ PMD_SECT_AP_WRITE | \ PMD_SECT_AP_READ - b __v7_setup + W(b) __v7_setup .long cpu_arch_name .long cpu_elf_name .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c index 85d3e55ca4a9..558cdfaf76b6 100644 --- a/arch/arm/plat-iop/time.c +++ b/arch/arm/plat-iop/time.c @@ -18,6 +18,7 @@ #include <linux/time.h> #include <linux/init.h> #include <linux/timex.h> +#include <linux/sched.h> #include <linux/io.h> #include <linux/clocksource.h> #include <linux/clockchips.h> @@ -36,7 +37,7 @@ /* * IOP clocksource (free-running timer 1). */ -static cycle_t iop_clocksource_read(struct clocksource *unused) +static cycle_t notrace iop_clocksource_read(struct clocksource *unused) { return 0xffffffffu - read_tcr1(); } diff --git a/arch/arm/plat-mxc/devices/platform-imx-dma.c b/arch/arm/plat-mxc/devices/platform-imx-dma.c index 02d989018059..3a705c7877dd 100644 --- a/arch/arm/plat-mxc/devices/platform-imx-dma.c +++ b/arch/arm/plat-mxc/devices/platform-imx-dma.c @@ -12,15 +12,7 @@ #include <mach/hardware.h> #include <mach/devices-common.h> -#ifdef SDMA_IS_MERGED #include <mach/sdma.h> -#else -struct sdma_platform_data { - int sdma_version; - char *cpu_name; - int to_version; -}; -#endif struct imx_imx_sdma_data { resource_size_t iobase; diff --git a/arch/arm/plat-mxc/devices/platform-spi_imx.c b/arch/arm/plat-mxc/devices/platform-spi_imx.c index e48340ec331e..17f724c9452d 100644 --- a/arch/arm/plat-mxc/devices/platform-spi_imx.c +++ b/arch/arm/plat-mxc/devices/platform-spi_imx.c @@ -27,6 +27,7 @@ const struct imx_spi_imx_data imx21_cspi_data[] __initconst = { imx_spi_imx_data_entry(MX21, CSPI, "imx21-cspi", _id, _hwid, SZ_4K) imx21_cspi_data_entry(0, 1), imx21_cspi_data_entry(1, 2), +}; #endif #ifdef CONFIG_ARCH_MX25 diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c index aedf9c1d645e..63cdc6025bd7 100644 --- a/arch/arm/plat-nomadik/timer.c +++ b/arch/arm/plat-nomadik/timer.c @@ -3,6 +3,7 @@ * * Copyright (C) 2008 STMicroelectronics * Copyright (C) 2010 Alessandro Rubini + * Copyright (C) 2010 Linus Walleij for ST-Ericsson * * 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 @@ -16,11 +17,13 @@ #include <linux/clk.h> #include <linux/jiffies.h> #include <linux/err.h> +#include <linux/cnt32_to_63.h> +#include <linux/timer.h> #include <asm/mach/time.h> #include <plat/mtu.h> -void __iomem *mtu_base; /* ssigned by machine code */ +void __iomem *mtu_base; /* Assigned by machine code */ /* * Kernel assumes that sched_clock can be called early @@ -48,16 +51,82 @@ static struct clocksource nmdk_clksrc = { /* * Override the global weak sched_clock symbol with this * local implementation which uses the clocksource to get some - * better resolution when scheduling the kernel. We accept that - * this wraps around for now, since it is just a relative time - * stamp. (Inspired by OMAP implementation.) + * better resolution when scheduling the kernel. + * + * Because the hardware timer period may be quite short + * (32.3 secs on the 133 MHz MTU timer selection on ux500) + * and because cnt32_to_63() needs to be called at least once per + * half period to work properly, a kernel keepwarm() timer is set up + * to ensure this requirement is always met. + * + * Also the sched_clock timer will wrap around at some point, + * here we set it to run continously for a year. */ +#define SCHED_CLOCK_MIN_WRAP 3600*24*365 +static struct timer_list cnt32_to_63_keepwarm_timer; +static u32 sched_mult; +static u32 sched_shift; + unsigned long long notrace sched_clock(void) { - return clocksource_cyc2ns(nmdk_clksrc.read( - &nmdk_clksrc), - nmdk_clksrc.mult, - nmdk_clksrc.shift); + u64 cycles; + + if (unlikely(!mtu_base)) + return 0; + + cycles = cnt32_to_63(-readl(mtu_base + MTU_VAL(0))); + /* + * sched_mult is guaranteed to be even so will + * shift out bit 63 + */ + return (cycles * sched_mult) >> sched_shift; +} + +/* Just kick sched_clock every so often */ +static void cnt32_to_63_keepwarm(unsigned long data) +{ + mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data)); + (void) sched_clock(); +} + +/* + * Set up a timer to keep sched_clock():s 32_to_63 algorithm warm + * once in half a 32bit timer wrap interval. + */ +static void __init nmdk_sched_clock_init(unsigned long rate) +{ + u32 v; + unsigned long delta; + u64 days; + + /* Find the apropriate mult and shift factors */ + clocks_calc_mult_shift(&sched_mult, &sched_shift, + rate, NSEC_PER_SEC, SCHED_CLOCK_MIN_WRAP); + /* We need to multiply by an even number to get rid of bit 63 */ + if (sched_mult & 1) + sched_mult++; + + /* Let's see what we get, take max counter and scale it */ + days = (0xFFFFFFFFFFFFFFFFLLU * sched_mult) >> sched_shift; + do_div(days, NSEC_PER_SEC); + do_div(days, (3600*24)); + + pr_info("sched_clock: using %d bits @ %lu Hz wrap in %lu days\n", + (64 - sched_shift), rate, (unsigned long) days); + + /* + * Program a timer to kick us at half 32bit wraparound + * Formula: seconds per wrap = (2^32) / f + */ + v = 0xFFFFFFFFUL / rate; + /* We want half of the wrap time to keep cnt32_to_63 warm */ + v /= 2; + pr_debug("sched_clock: prescaled timer rate: %lu Hz, " + "initialize keepwarm timer every %d seconds\n", rate, v); + /* Convert seconds to jiffies */ + delta = msecs_to_jiffies(v*1000); + setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, delta); + mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + delta)); } /* Clockevent device: use one-shot mode */ @@ -161,13 +230,15 @@ void __init nmdk_timer_init(void) writel(0, mtu_base + MTU_BGLR(0)); writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0)); - /* Now the scheduling clock is ready */ + /* Now the clock source is ready */ nmdk_clksrc.read = nmdk_read_timer; if (clocksource_register(&nmdk_clksrc)) pr_err("timer: failed to initialize clock source %s\n", nmdk_clksrc.name); + nmdk_sched_clock_init(rate); + /* Timer 1 is used for events */ clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE); diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c index 155fe43a672b..8722a136f3a5 100644 --- a/arch/arm/plat-omap/counter_32k.c +++ b/arch/arm/plat-omap/counter_32k.c @@ -16,6 +16,7 @@ #include <linux/init.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/err.h> #include <plat/common.h> #include <plat/board.h> @@ -164,7 +165,7 @@ static int __init omap_init_clocksource_32k(void) return -ENODEV; sync_32k_ick = clk_get(NULL, "omap_32ksync_ick"); - if (sync_32k_ick) + if (!IS_ERR(sync_32k_ick)) clk_enable(sync_32k_ick); clocksource_32k.mult = clocksource_hz2mult(32768, diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index e2c8eebe6b3a..74dac419d328 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -166,7 +166,7 @@ static void __init omap_detect_sram(void) cpu_is_omap1710()) omap_sram_size = 0x4000; /* 16K */ else if (cpu_is_omap1611()) - omap_sram_size = 0x3e800; /* 250K */ + omap_sram_size = SZ_256K; else { printk(KERN_ERR "Could not detect SRAM size\n"); omap_sram_size = 0x4000; diff --git a/arch/arm/plat-pxa/include/plat/sdhci.h b/arch/arm/plat-pxa/include/plat/sdhci.h index e49c5b6fc4e2..1ab332e37d7d 100644 --- a/arch/arm/plat-pxa/include/plat/sdhci.h +++ b/arch/arm/plat-pxa/include/plat/sdhci.h @@ -17,6 +17,9 @@ /* Require clock free running */ #define PXA_FLAG_DISABLE_CLOCK_GATING (1<<0) +/* Board design supports 8-bit data on SD/SDIO BUS */ +#define PXA_FLAG_SD_8_BIT_CAPABLE_SLOT (1<<2) + /* * struct pxa_sdhci_platdata() - Platform device data for PXA SDHCI * @max_speed: the maximum speed supported diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig index 5a27b1b538f2..eb105e61c746 100644 --- a/arch/arm/plat-s3c24xx/Kconfig +++ b/arch/arm/plat-s3c24xx/Kconfig @@ -8,7 +8,7 @@ config PLAT_S3C24XX default y select NO_IOPORT select ARCH_REQUIRE_GPIOLIB - select S3C_DEVICE_NAND + select S3C_DEV_NAND select S3C_GPIO_CFG_S3C24XX help Base platform code for any Samsung S3C24XX device diff --git a/arch/arm/plat-s3c24xx/cpu.c b/arch/arm/plat-s3c24xx/cpu.c index 76d0858c3cbb..4a10c0f684b2 100644 --- a/arch/arm/plat-s3c24xx/cpu.c +++ b/arch/arm/plat-s3c24xx/cpu.c @@ -88,7 +88,7 @@ static struct cpu_table cpu_ids[] __initdata = { { .idcode = 0x32440000, .idmask = 0xffffffff, - .map_io = s3c244x_map_io, + .map_io = s3c2440_map_io, .init_clocks = s3c244x_init_clocks, .init_uarts = s3c244x_init_uarts, .init = s3c2440_init, @@ -97,7 +97,7 @@ static struct cpu_table cpu_ids[] __initdata = { { .idcode = 0x32440001, .idmask = 0xffffffff, - .map_io = s3c244x_map_io, + .map_io = s3c2440_map_io, .init_clocks = s3c244x_init_clocks, .init_uarts = s3c244x_init_uarts, .init = s3c2440_init, @@ -106,7 +106,7 @@ static struct cpu_table cpu_ids[] __initdata = { { .idcode = 0x32440aaa, .idmask = 0xffffffff, - .map_io = s3c244x_map_io, + .map_io = s3c2442_map_io, .init_clocks = s3c244x_init_clocks, .init_uarts = s3c244x_init_uarts, .init = s3c2442_init, @@ -115,7 +115,7 @@ static struct cpu_table cpu_ids[] __initdata = { { .idcode = 0x32440aab, .idmask = 0xffffffff, - .map_io = s3c244x_map_io, + .map_io = s3c2442_map_io, .init_clocks = s3c244x_init_clocks, .init_uarts = s3c244x_init_uarts, .init = s3c2442_init, diff --git a/arch/arm/plat-s3c24xx/gpiolib.c b/arch/arm/plat-s3c24xx/gpiolib.c index 24c6f5a30596..243b6411050d 100644 --- a/arch/arm/plat-s3c24xx/gpiolib.c +++ b/arch/arm/plat-s3c24xx/gpiolib.c @@ -82,8 +82,6 @@ static struct s3c_gpio_cfg s3c24xx_gpiocfg_banka = { struct s3c_gpio_cfg s3c24xx_gpiocfg_default = { .set_config = s3c_gpio_setcfg_s3c24xx, .get_config = s3c_gpio_getcfg_s3c24xx, - .set_pull = s3c_gpio_setpull_1up, - .get_pull = s3c_gpio_getpull_1up, }; struct s3c_gpio_chip s3c24xx_gpios[] = { diff --git a/arch/arm/plat-s3c24xx/include/plat/s3c244x.h b/arch/arm/plat-s3c24xx/include/plat/s3c244x.h index 307248d1ccbb..89e8d0a25f87 100644 --- a/arch/arm/plat-s3c24xx/include/plat/s3c244x.h +++ b/arch/arm/plat-s3c24xx/include/plat/s3c244x.h @@ -21,17 +21,22 @@ extern void s3c244x_init_clocks(int xtal); #else #define s3c244x_init_clocks NULL #define s3c244x_init_uarts NULL -#define s3c244x_map_io NULL #endif #ifdef CONFIG_CPU_S3C2440 extern int s3c2440_init(void); + +extern void s3c2440_map_io(void); #else #define s3c2440_init NULL +#define s3c2440_map_io NULL #endif #ifdef CONFIG_CPU_S3C2442 extern int s3c2442_init(void); + +extern void s3c2442_map_io(void); #else #define s3c2442_init NULL +#define s3c2442_map_io NULL #endif diff --git a/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c index 9793544a6ace..704175b0573f 100644 --- a/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c +++ b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c @@ -29,8 +29,8 @@ void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi, } else { s3c_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPIO_INPUT); s3c_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPIO_INPUT); - s3c_gpio_cfgpull(S3C2410_GPE(11), S3C_GPIO_PULL_NONE); - s3c_gpio_cfgpull(S3C2410_GPE(12), S3C_GPIO_PULL_NONE); - s3c_gpio_cfgpull(S3C2410_GPE(13), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPE(11), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPE(12), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPE(13), S3C_GPIO_PULL_NONE); } } diff --git a/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c b/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c index db9e9e477ec1..72457afd6255 100644 --- a/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c +++ b/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c @@ -31,8 +31,8 @@ void s3c24xx_spi_gpiocfg_bus1_gpd8_9_10(struct s3c2410_spi_info *spi, } else { s3c_gpio_cfgpin(S3C2410_GPD(8), S3C2410_GPIO_INPUT); s3c_gpio_cfgpin(S3C2410_GPD(9), S3C2410_GPIO_INPUT); - s3c_gpio_cfgpull(S3C2410_GPD(10), S3C_GPIO_PULL_NONE); - s3c_gpio_cfgpull(S3C2410_GPD(9), S3C_GPIO_PULL_NONE); - s3c_gpio_cfgpull(S3C2410_GPD(8), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPD(10), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPD(9), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPD(8), S3C_GPIO_PULL_NONE); } } diff --git a/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c index 8ea663a438bb..c3972b645d13 100644 --- a/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c +++ b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c @@ -29,8 +29,8 @@ void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi, } else { s3c_gpio_cfgpin(S3C2410_GPG(7), S3C2410_GPIO_INPUT); s3c_gpio_cfgpin(S3C2410_GPG(5), S3C2410_GPIO_INPUT); - s3c_gpio_cfgpull(S3C2410_GPG(5), S3C_GPIO_PULL_NONE); - s3c_gpio_cfgpull(S3C2410_GPG(6), S3C_GPIO_PULL_NONE); - s3c_gpio_cfgpull(S3C2410_GPG(7), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPG(5), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPG(6), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPG(7), S3C_GPIO_PULL_NONE); } } diff --git a/arch/arm/plat-samsung/gpio-config.c b/arch/arm/plat-samsung/gpio-config.c index b732b773b9af..0aa32f242ee4 100644 --- a/arch/arm/plat-samsung/gpio-config.c +++ b/arch/arm/plat-samsung/gpio-config.c @@ -280,18 +280,17 @@ s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip, } #endif -#ifdef CONFIG_S3C_GPIO_PULL_UP -int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip, - unsigned int off, s3c_gpio_pull_t pull) +#if defined(CONFIG_S3C_GPIO_PULL_UP) || defined(CONFIG_S3C_GPIO_PULL_DOWN) +static int s3c_gpio_setpull_1(struct s3c_gpio_chip *chip, + unsigned int off, s3c_gpio_pull_t pull, + s3c_gpio_pull_t updown) { void __iomem *reg = chip->base + 0x08; u32 pup = __raw_readl(reg); - pup = __raw_readl(reg); - - if (pup == S3C_GPIO_PULL_UP) + if (pull == updown) pup &= ~(1 << off); - else if (pup == S3C_GPIO_PULL_NONE) + else if (pull == S3C_GPIO_PULL_NONE) pup |= (1 << off); else return -EINVAL; @@ -300,17 +299,45 @@ int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip, return 0; } -s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip, - unsigned int off) +static s3c_gpio_pull_t s3c_gpio_getpull_1(struct s3c_gpio_chip *chip, + unsigned int off, s3c_gpio_pull_t updown) { void __iomem *reg = chip->base + 0x08; u32 pup = __raw_readl(reg); pup &= (1 << off); - return pup ? S3C_GPIO_PULL_NONE : S3C_GPIO_PULL_UP; + return pup ? S3C_GPIO_PULL_NONE : updown; +} +#endif /* CONFIG_S3C_GPIO_PULL_UP || CONFIG_S3C_GPIO_PULL_DOWN */ + +#ifdef CONFIG_S3C_GPIO_PULL_UP +s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip, + unsigned int off) +{ + return s3c_gpio_getpull_1(chip, off, S3C_GPIO_PULL_UP); +} + +int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip, + unsigned int off, s3c_gpio_pull_t pull) +{ + return s3c_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_UP); } #endif /* CONFIG_S3C_GPIO_PULL_UP */ +#ifdef CONFIG_S3C_GPIO_PULL_DOWN +s3c_gpio_pull_t s3c_gpio_getpull_1down(struct s3c_gpio_chip *chip, + unsigned int off) +{ + return s3c_gpio_getpull_1(chip, off, S3C_GPIO_PULL_DOWN); +} + +int s3c_gpio_setpull_1down(struct s3c_gpio_chip *chip, + unsigned int off, s3c_gpio_pull_t pull) +{ + return s3c_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN); +} +#endif /* CONFIG_S3C_GPIO_PULL_DOWN */ + #ifdef CONFIG_S5P_GPIO_DRVSTR s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin) { diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h b/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h index 8fd65d8b5863..0d2c5703f1ee 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h @@ -210,6 +210,17 @@ extern s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip, unsigned int off); /** + * s3c_gpio_getpull_1down() - Get configuration for choice of down or none + * @chip: The gpio chip that the GPIO pin belongs to + * @off: The offset to the pin to get the configuration of. + * + * This helper function reads the state of the pull-down resistor for the + * given GPIO in the same case as s3c_gpio_setpull_1down. +*/ +extern s3c_gpio_pull_t s3c_gpio_getpull_1down(struct s3c_gpio_chip *chip, + unsigned int off); + +/** * s3c_gpio_setpull_s3c2443() - Pull configuration for s3c2443. * @chip: The gpio chip that is being configured. * @off: The offset for the GPIO being configured. diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 55590a4d87c9..2fea897ebeb1 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -12,7 +12,7 @@ # # http://www.arm.linux.org.uk/developer/machines/?action=new # -# Last update: Thu Sep 9 22:43:01 2010 +# Last update: Sun Dec 12 23:24:27 2010 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -2321,7 +2321,7 @@ mx31txtr MACH_MX31TXTR MX31TXTR 2332 u380 MACH_U380 U380 2333 oamp3_hualu MACH_HUALU_BOARD HUALU_BOARD 2334 npcmx50 MACH_NPCMX50 NPCMX50 2335 -mx51_lange51 MACH_MX51_LANGE51 MX51_LANGE51 2336 +mx51_efikamx MACH_MX51_EFIKAMX MX51_EFIKAMX 2336 mx51_lange52 MACH_MX51_LANGE52 MX51_LANGE52 2337 riom MACH_RIOM RIOM 2338 comcas MACH_COMCAS COMCAS 2339 @@ -2355,7 +2355,7 @@ at91sam9263cs MACH_AT91SAM9263CS AT91SAM9263CS 2366 csb732 MACH_CSB732 CSB732 2367 u8500 MACH_U8500 U8500 2368 huqiu MACH_HUQIU HUQIU 2369 -mx51_kunlun MACH_MX51_KUNLUN MX51_KUNLUN 2370 +mx51_efikasb MACH_MX51_EFIKASB MX51_EFIKASB 2370 pmt1g MACH_PMT1G PMT1G 2371 htcelf MACH_HTCELF HTCELF 2372 armadillo420 MACH_ARMADILLO420 ARMADILLO420 2373 @@ -2971,7 +2971,7 @@ premierwave_en MACH_PREMIERWAVE_EN PREMIERWAVE_EN 2985 wasabi MACH_WASABI WASABI 2986 vivow MACH_VIVOW VIVOW 2987 mx50_rdp MACH_MX50_RDP MX50_RDP 2988 -universal MACH_UNIVERSAL UNIVERSAL 2989 +universal_c210 MACH_UNIVERSAL_C210 UNIVERSAL_C210 2989 real6410 MACH_REAL6410 REAL6410 2990 spx_sakura MACH_SPX_SAKURA SPX_SAKURA 2991 ij3k_2440 MACH_IJ3K_2440 IJ3K_2440 2992 @@ -3044,3 +3044,178 @@ harvest_desoto MACH_HARVEST_DESOTO HARVEST_DESOTO 3059 msm8x60_qrdc MACH_MSM8X60_QRDC MSM8X60_QRDC 3060 spear900 MACH_SPEAR900 SPEAR900 3061 pcontrol_g20 MACH_PCONTROL_G20 PCONTROL_G20 3062 +rdstor MACH_RDSTOR RDSTOR 3063 +usdloader MACH_USDLOADER USDLOADER 3064 +tsoploader MACH_TSOPLOADER TSOPLOADER 3065 +kronos MACH_KRONOS KRONOS 3066 +ffcore MACH_FFCORE FFCORE 3067 +mone MACH_MONE MONE 3068 +unit2s MACH_UNIT2S UNIT2S 3069 +acer_a5 MACH_ACER_A5 ACER_A5 3070 +etherpro_isp MACH_ETHERPRO_ISP ETHERPRO_ISP 3071 +stretchs7000 MACH_STRETCHS7000 STRETCHS7000 3072 +p87_smartsim MACH_P87_SMARTSIM P87_SMARTSIM 3073 +tulip MACH_TULIP TULIP 3074 +sunflower MACH_SUNFLOWER SUNFLOWER 3075 +rib MACH_RIB RIB 3076 +clod MACH_CLOD CLOD 3077 +rump MACH_RUMP RUMP 3078 +tenderloin MACH_TENDERLOIN TENDERLOIN 3079 +shortloin MACH_SHORTLOIN SHORTLOIN 3080 +crespo MACH_CRESPO CRESPO 3081 +antares MACH_ANTARES ANTARES 3082 +wb40n MACH_WB40N WB40N 3083 +herring MACH_HERRING HERRING 3084 +naxy400 MACH_NAXY400 NAXY400 3085 +naxy1200 MACH_NAXY1200 NAXY1200 3086 +vpr200 MACH_VPR200 VPR200 3087 +bug20 MACH_BUG20 BUG20 3088 +goflexnet MACH_GOFLEXNET GOFLEXNET 3089 +torbreck MACH_TORBRECK TORBRECK 3090 +saarb_mg1 MACH_SAARB_MG1 SAARB_MG1 3091 +callisto MACH_CALLISTO CALLISTO 3092 +multhsu MACH_MULTHSU MULTHSU 3093 +saluda MACH_SALUDA SALUDA 3094 +pemp_omap3_apollo MACH_PEMP_OMAP3_APOLLO PEMP_OMAP3_APOLLO 3095 +vc0718 MACH_VC0718 VC0718 3096 +mvblx MACH_MVBLX MVBLX 3097 +inhand_apeiron MACH_INHAND_APEIRON INHAND_APEIRON 3098 +inhand_fury MACH_INHAND_FURY INHAND_FURY 3099 +inhand_siren MACH_INHAND_SIREN INHAND_SIREN 3100 +hdnvp MACH_HDNVP HDNVP 3101 +softwinner MACH_SOFTWINNER SOFTWINNER 3102 +prima2_evb MACH_PRIMA2_EVB PRIMA2_EVB 3103 +nas6210 MACH_NAS6210 NAS6210 3104 +unisdev MACH_UNISDEV UNISDEV 3105 +sbca11 MACH_SBCA11 SBCA11 3106 +saga MACH_SAGA SAGA 3107 +ns_k330 MACH_NS_K330 NS_K330 3108 +tanna MACH_TANNA TANNA 3109 +imate8502 MACH_IMATE8502 IMATE8502 3110 +aspen MACH_ASPEN ASPEN 3111 +daintree_cwac MACH_DAINTREE_CWAC DAINTREE_CWAC 3112 +zmx25 MACH_ZMX25 ZMX25 3113 +maple1 MACH_MAPLE1 MAPLE1 3114 +qsd8x72_surf MACH_QSD8X72_SURF QSD8X72_SURF 3115 +qsd8x72_ffa MACH_QSD8X72_FFA QSD8X72_FFA 3116 +abilene MACH_ABILENE ABILENE 3117 +eigen_ttr MACH_EIGEN_TTR EIGEN_TTR 3118 +iomega_ix2_200 MACH_IOMEGA_IX2_200 IOMEGA_IX2_200 3119 +coretec_vcx7400 MACH_CORETEC_VCX7400 CORETEC_VCX7400 3120 +santiago MACH_SANTIAGO SANTIAGO 3121 +mx257sol MACH_MX257SOL MX257SOL 3122 +strasbourg MACH_STRASBOURG STRASBOURG 3123 +msm8x60_fluid MACH_MSM8X60_FLUID MSM8X60_FLUID 3124 +smartqv5 MACH_SMARTQV5 SMARTQV5 3125 +smartqv3 MACH_SMARTQV3 SMARTQV3 3126 +smartqv7 MACH_SMARTQV7 SMARTQV7 3127 +paz00 MACH_PAZ00 PAZ00 3128 +acmenetusfoxg20 MACH_ACMENETUSFOXG20 ACMENETUSFOXG20 3129 +htcwillow MACH_HTCWILLOW HTCWILLOW 3130 +fwbd_0404 MACH_FWBD_0404 FWBD_0404 3131 +hdgu MACH_HDGU HDGU 3132 +pyramid MACH_PYRAMID PYRAMID 3133 +epiphan MACH_EPIPHAN EPIPHAN 3134 +omap_bender MACH_OMAP_BENDER OMAP_BENDER 3135 +gurnard MACH_GURNARD GURNARD 3136 +gtl_it5100 MACH_GTL_IT5100 GTL_IT5100 3137 +bcm2708 MACH_BCM2708 BCM2708 3138 +mx51_ggc MACH_MX51_GGC MX51_GGC 3139 +sharespace MACH_SHARESPACE SHARESPACE 3140 +haba_knx_explorer MACH_HABA_KNX_EXPLORER HABA_KNX_EXPLORER 3141 +simtec_kirkmod MACH_SIMTEC_KIRKMOD SIMTEC_KIRKMOD 3142 +crux MACH_CRUX CRUX 3143 +mx51_bravo MACH_MX51_BRAVO MX51_BRAVO 3144 +charon MACH_CHARON CHARON 3145 +picocom3 MACH_PICOCOM3 PICOCOM3 3146 +picocom4 MACH_PICOCOM4 PICOCOM4 3147 +serrano MACH_SERRANO SERRANO 3148 +doubleshot MACH_DOUBLESHOT DOUBLESHOT 3149 +evsy MACH_EVSY EVSY 3150 +huashan MACH_HUASHAN HUASHAN 3151 +lausanne MACH_LAUSANNE LAUSANNE 3152 +emerald MACH_EMERALD EMERALD 3153 +tqma35 MACH_TQMA35 TQMA35 3154 +marvel MACH_MARVEL MARVEL 3155 +manuae MACH_MANUAE MANUAE 3156 +chacha MACH_CHACHA CHACHA 3157 +lemon MACH_LEMON LEMON 3158 +csc MACH_CSC CSC 3159 +gira_knxip_router MACH_GIRA_KNXIP_ROUTER GIRA_KNXIP_ROUTER 3160 +t20 MACH_T20 T20 3161 +hdmini MACH_HDMINI HDMINI 3162 +sciphone_g2 MACH_SCIPHONE_G2 SCIPHONE_G2 3163 +express MACH_EXPRESS EXPRESS 3164 +express_kt MACH_EXPRESS_KT EXPRESS_KT 3165 +maximasp MACH_MAXIMASP MAXIMASP 3166 +nitrogen_imx51 MACH_NITROGEN_IMX51 NITROGEN_IMX51 3167 +nitrogen_imx53 MACH_NITROGEN_IMX53 NITROGEN_IMX53 3168 +sunfire MACH_SUNFIRE SUNFIRE 3169 +arowana MACH_AROWANA AROWANA 3170 +tegra_daytona MACH_TEGRA_DAYTONA TEGRA_DAYTONA 3171 +tegra_swordfish MACH_TEGRA_SWORDFISH TEGRA_SWORDFISH 3172 +edison MACH_EDISON EDISON 3173 +svp8500v1 MACH_SVP8500V1 SVP8500V1 3174 +svp8500v2 MACH_SVP8500V2 SVP8500V2 3175 +svp5500 MACH_SVP5500 SVP5500 3176 +b5500 MACH_B5500 B5500 3177 +s5500 MACH_S5500 S5500 3178 +icon MACH_ICON ICON 3179 +elephant MACH_ELEPHANT ELEPHANT 3180 +msm8x60_fusion MACH_MSM8X60_FUSION MSM8X60_FUSION 3181 +shooter MACH_SHOOTER SHOOTER 3182 +spade_lte MACH_SPADE_LTE SPADE_LTE 3183 +philhwani MACH_PHILHWANI PHILHWANI 3184 +gsncomm MACH_GSNCOMM GSNCOMM 3185 +strasbourg_a2 MACH_STRASBOURG_A2 STRASBOURG_A2 3186 +mmm MACH_MMM MMM 3187 +davinci_dm365_bv MACH_DAVINCI_DM365_BV DAVINCI_DM365_BV 3188 +ag5evm MACH_AG5EVM AG5EVM 3189 +sc575plc MACH_SC575PLC SC575PLC 3190 +sc575hmi MACH_SC575IPC SC575IPC 3191 +omap3_tdm3730 MACH_OMAP3_TDM3730 OMAP3_TDM3730 3192 +g7 MACH_G7 G7 3193 +top9000_eval MACH_TOP9000_EVAL TOP9000_EVAL 3194 +top9000_su MACH_TOP9000_SU TOP9000_SU 3195 +utm300 MACH_UTM300 UTM300 3196 +tsunagi MACH_TSUNAGI TSUNAGI 3197 +ts75xx MACH_TS75XX TS75XX 3198 +msm8x60_fusn_ffa MACH_MSM8X60_FUSN_FFA MSM8X60_FUSN_FFA 3199 +ts47xx MACH_TS47XX TS47XX 3200 +da850_k5 MACH_DA850_K5 DA850_K5 3201 +ax502 MACH_AX502 AX502 3202 +igep0032 MACH_IGEP0032 IGEP0032 3203 +antero MACH_ANTERO ANTERO 3204 +synergy MACH_SYNERGY SYNERGY 3205 +ics_if_voip MACH_ICS_IF_VOIP ICS_IF_VOIP 3206 +wlf_cragg_6410 MACH_WLF_CRAGG_6410 WLF_CRAGG_6410 3207 +punica MACH_PUNICA PUNICA 3208 +sbc_nt250 MACH_SBC_NT250 SBC_NT250 3209 +mx27_wmultra MACH_MX27_WMULTRA MX27_WMULTRA 3210 +mackerel MACH_MACKEREL MACKEREL 3211 +fa9x27 MACH_FA9X27 FA9X27 3213 +ns2816tb MACH_NS2816TB NS2816TB 3214 +ns2816_ntpad MACH_NS2816_NTPAD NS2816_NTPAD 3215 +ns2816_ntnb MACH_NS2816_NTNB NS2816_NTNB 3216 +kaen MACH_KAEN KAEN 3217 +nv1000 MACH_NV1000 NV1000 3218 +nuc950ts MACH_NUC950TS NUC950TS 3219 +nokia_rm680 MACH_NOKIA_RM680 NOKIA_RM680 3220 +ast2200 MACH_AST2200 AST2200 3221 +lead MACH_LEAD LEAD 3222 +unino1 MACH_UNINO1 UNINO1 3223 +greeco MACH_GREECO GREECO 3224 +verdi MACH_VERDI VERDI 3225 +dm6446_adbox MACH_DM6446_ADBOX DM6446_ADBOX 3226 +quad_salsa MACH_QUAD_SALSA QUAD_SALSA 3227 +abb_gma_1_1 MACH_ABB_GMA_1_1 ABB_GMA_1_1 3228 +svcid MACH_SVCID SVCID 3229 +msm8960_sim MACH_MSM8960_SIM MSM8960_SIM 3230 +msm8960_rumi3 MACH_MSM8960_RUMI3 MSM8960_RUMI3 3231 +icon_g MACH_ICON_G ICON_G 3232 +mb3 MACH_MB3 MB3 3233 +gsia18s MACH_GSIA18S GSIA18S 3234 +pivicc MACH_PIVICC PIVICC 3235 +pcm048 MACH_PCM048 PCM048 3236 +dds MACH_DDS DDS 3237 +chalten_xa1 MACH_CHALTEN_XA1 CHALTEN_XA1 3238 diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index d66cead97d28..9897dcfc16d6 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -206,6 +206,7 @@ ENTRY(vfp_save_state) mov pc, lr ENDPROC(vfp_save_state) + .align last_VFP_context_address: .word last_VFP_context diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 67a2fa2caa49..0a9b5b8b2a19 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -19,6 +19,8 @@ config MIPS select GENERIC_ATOMIC64 if !64BIT select HAVE_DMA_ATTRS select HAVE_DMA_API_DEBUG + select HAVE_GENERIC_HARDIRQS + select GENERIC_IRQ_PROBE menu "Machine selection" @@ -1664,6 +1666,28 @@ config PAGE_SIZE_64KB endchoice +config FORCE_MAX_ZONEORDER + int "Maximum zone order" + range 13 64 if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_32KB + default "13" if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_32KB + range 12 64 if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_16KB + default "12" if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_16KB + range 11 64 + default "11" + help + The kernel memory allocator divides physically contiguous memory + blocks into "zones", where each zone is a power of two number of + pages. This option selects the largest power of two that the kernel + keeps in the memory allocator. If you need to allocate very large + blocks of physically contiguous memory, then you may need to + increase this value. + + This config option is actually maximum order plus one. For example, + a value of 11 means that the largest free memory block is 2^10 pages. + + The page size is not necessarily 4KB. Keep this in mind + when choosing a value for this option. + config BOARD_SCACHE bool @@ -1922,20 +1946,6 @@ config CPU_R4400_WORKAROUNDS bool # -# Use the generic interrupt handling code in kernel/irq/: -# -config GENERIC_HARDIRQS - bool - default y - -config GENERIC_IRQ_PROBE - bool - default y - -config IRQ_PER_CPU - bool - -# # - Highmem only makes sense for the 32-bit kernel. # - The current highmem code will only work properly on physically indexed # caches such as R3000, SB1, R7000 or those that look like they're virtually diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c index 3691630931d6..9e7814db3d03 100644 --- a/arch/mips/alchemy/common/platform.c +++ b/arch/mips/alchemy/common/platform.c @@ -27,6 +27,7 @@ static void alchemy_8250_pm(struct uart_port *port, unsigned int state, unsigned int old_state) { +#ifdef CONFIG_SERIAL_8250 switch (state) { case 0: if ((__raw_readl(port->membase + UART_MOD_CNTRL) & 3) != 3) { @@ -49,6 +50,7 @@ static void alchemy_8250_pm(struct uart_port *port, unsigned int state, serial8250_do_pm(port, state, old_state); break; } +#endif } #define PORT(_base, _irq) \ diff --git a/arch/mips/alchemy/devboards/prom.c b/arch/mips/alchemy/devboards/prom.c index b30df5c97ad3..baeb21385058 100644 --- a/arch/mips/alchemy/devboards/prom.c +++ b/arch/mips/alchemy/devboards/prom.c @@ -54,10 +54,9 @@ void __init prom_init(void) prom_init_cmdline(); memsize_str = prom_getenv("memsize"); - if (!memsize_str) + if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize)) memsize = ALCHEMY_BOARD_DEFAULT_MEMSIZE; - else - strict_strtoul(memsize_str, 0, &memsize); + add_memory_region(0, memsize, BOOT_MEM_RAM); } diff --git a/arch/mips/ar7/clock.c b/arch/mips/ar7/clock.c index fc0e7154e8d6..2ca4ada1c291 100644 --- a/arch/mips/ar7/clock.c +++ b/arch/mips/ar7/clock.c @@ -239,12 +239,12 @@ static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock, calculate(base_clock, frequency, &prediv, &postdiv, &mul); writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl); - msleep(1); + mdelay(1); writel(4, &clock->pll); while (readl(&clock->pll) & PLL_STATUS) ; writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll); - msleep(75); + mdelay(75); } static void __init tnetd7300_init_clocks(void) @@ -456,7 +456,7 @@ void clk_put(struct clk *clk) } EXPORT_SYMBOL(clk_put); -int __init ar7_init_clocks(void) +void __init ar7_init_clocks(void) { switch (ar7_chip_id()) { case AR7_CHIP_7100: @@ -472,7 +472,4 @@ int __init ar7_init_clocks(void) } /* adjust vbus clock rate */ vbus_clk.rate = bus_clk.rate / 2; - - return 0; } -arch_initcall(ar7_init_clocks); diff --git a/arch/mips/ar7/time.c b/arch/mips/ar7/time.c index 5fb8a0134085..22c93213b233 100644 --- a/arch/mips/ar7/time.c +++ b/arch/mips/ar7/time.c @@ -30,6 +30,9 @@ void __init plat_time_init(void) { struct clk *cpu_clk; + /* Initialize ar7 clocks so the CPU clock frequency is correct */ + ar7_init_clocks(); + cpu_clk = clk_get(NULL, "cpu"); if (IS_ERR(cpu_clk)) { printk(KERN_ERR "unable to get cpu clock\n"); diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index b1aee33efd11..c95f90bf734c 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -32,7 +32,6 @@ #include <asm/reboot.h> #include <asm/time.h> #include <bcm47xx.h> -#include <asm/fw/cfe/cfe_api.h> #include <asm/mach-bcm47xx/nvram.h> struct ssb_bus ssb_bcm47xx; @@ -57,68 +56,112 @@ static void bcm47xx_machine_halt(void) cpu_relax(); } -static void str2eaddr(char *str, char *dest) -{ - int i = 0; +#define READ_FROM_NVRAM(_outvar, name, buf) \ + if (nvram_getenv(name, buf, sizeof(buf)) >= 0)\ + sprom->_outvar = simple_strtoul(buf, NULL, 0); - if (str == NULL) { - memset(dest, 0, 6); - return; +static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) +{ + char buf[100]; + u32 boardflags; + + memset(sprom, 0, sizeof(struct ssb_sprom)); + + sprom->revision = 1; /* Fallback: Old hardware does not define this. */ + READ_FROM_NVRAM(revision, "sromrev", buf); + if (nvram_getenv("il0macaddr", buf, sizeof(buf)) >= 0) + nvram_parse_macaddr(buf, sprom->il0mac); + if (nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0) + nvram_parse_macaddr(buf, sprom->et0mac); + if (nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0) + nvram_parse_macaddr(buf, sprom->et1mac); + READ_FROM_NVRAM(et0phyaddr, "et0phyaddr", buf); + READ_FROM_NVRAM(et1phyaddr, "et1phyaddr", buf); + READ_FROM_NVRAM(et0mdcport, "et0mdcport", buf); + READ_FROM_NVRAM(et1mdcport, "et1mdcport", buf); + READ_FROM_NVRAM(board_rev, "boardrev", buf); + READ_FROM_NVRAM(country_code, "ccode", buf); + READ_FROM_NVRAM(ant_available_a, "aa5g", buf); + READ_FROM_NVRAM(ant_available_bg, "aa2g", buf); + READ_FROM_NVRAM(pa0b0, "pa0b0", buf); + READ_FROM_NVRAM(pa0b1, "pa0b1", buf); + READ_FROM_NVRAM(pa0b2, "pa0b2", buf); + READ_FROM_NVRAM(pa1b0, "pa1b0", buf); + READ_FROM_NVRAM(pa1b1, "pa1b1", buf); + READ_FROM_NVRAM(pa1b2, "pa1b2", buf); + READ_FROM_NVRAM(pa1lob0, "pa1lob0", buf); + READ_FROM_NVRAM(pa1lob2, "pa1lob1", buf); + READ_FROM_NVRAM(pa1lob1, "pa1lob2", buf); + READ_FROM_NVRAM(pa1hib0, "pa1hib0", buf); + READ_FROM_NVRAM(pa1hib2, "pa1hib1", buf); + READ_FROM_NVRAM(pa1hib1, "pa1hib2", buf); + READ_FROM_NVRAM(gpio0, "wl0gpio0", buf); + READ_FROM_NVRAM(gpio1, "wl0gpio1", buf); + READ_FROM_NVRAM(gpio2, "wl0gpio2", buf); + READ_FROM_NVRAM(gpio3, "wl0gpio3", buf); + READ_FROM_NVRAM(maxpwr_bg, "pa0maxpwr", buf); + READ_FROM_NVRAM(maxpwr_al, "pa1lomaxpwr", buf); + READ_FROM_NVRAM(maxpwr_a, "pa1maxpwr", buf); + READ_FROM_NVRAM(maxpwr_ah, "pa1himaxpwr", buf); + READ_FROM_NVRAM(itssi_a, "pa1itssit", buf); + READ_FROM_NVRAM(itssi_bg, "pa0itssit", buf); + READ_FROM_NVRAM(tri2g, "tri2g", buf); + READ_FROM_NVRAM(tri5gl, "tri5gl", buf); + READ_FROM_NVRAM(tri5g, "tri5g", buf); + READ_FROM_NVRAM(tri5gh, "tri5gh", buf); + READ_FROM_NVRAM(rxpo2g, "rxpo2g", buf); + READ_FROM_NVRAM(rxpo5g, "rxpo5g", buf); + READ_FROM_NVRAM(rssisav2g, "rssisav2g", buf); + READ_FROM_NVRAM(rssismc2g, "rssismc2g", buf); + READ_FROM_NVRAM(rssismf2g, "rssismf2g", buf); + READ_FROM_NVRAM(bxa2g, "bxa2g", buf); + READ_FROM_NVRAM(rssisav5g, "rssisav5g", buf); + READ_FROM_NVRAM(rssismc5g, "rssismc5g", buf); + READ_FROM_NVRAM(rssismf5g, "rssismf5g", buf); + READ_FROM_NVRAM(bxa5g, "bxa5g", buf); + READ_FROM_NVRAM(cck2gpo, "cck2gpo", buf); + READ_FROM_NVRAM(ofdm2gpo, "ofdm2gpo", buf); + READ_FROM_NVRAM(ofdm5glpo, "ofdm5glpo", buf); + READ_FROM_NVRAM(ofdm5gpo, "ofdm5gpo", buf); + READ_FROM_NVRAM(ofdm5ghpo, "ofdm5ghpo", buf); + + if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0) { + boardflags = simple_strtoul(buf, NULL, 0); + if (boardflags) { + sprom->boardflags_lo = (boardflags & 0x0000FFFFU); + sprom->boardflags_hi = (boardflags & 0xFFFF0000U) >> 16; + } } - - for (;;) { - dest[i++] = (char) simple_strtoul(str, NULL, 16); - str += 2; - if (!*str++ || i == 6) - break; + if (nvram_getenv("boardflags2", buf, sizeof(buf)) >= 0) { + boardflags = simple_strtoul(buf, NULL, 0); + if (boardflags) { + sprom->boardflags2_lo = (boardflags & 0x0000FFFFU); + sprom->boardflags2_hi = (boardflags & 0xFFFF0000U) >> 16; + } } } static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv) { - char buf[100]; + char buf[20]; /* Fill boardinfo structure */ memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo)); - if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0 || - nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0) - iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); - if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0 || - nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) + if (nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0) + iv->boardinfo.vendor = (u16)simple_strtoul(buf, NULL, 0); + else + iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; + if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); - if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0 || - nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) + if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); - /* Fill sprom structure */ - memset(&(iv->sprom), 0, sizeof(struct ssb_sprom)); - iv->sprom.revision = 3; - - if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0 || - nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0) - str2eaddr(buf, iv->sprom.et0mac); + bcm47xx_fill_sprom(&iv->sprom); - if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0 || - nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0) - str2eaddr(buf, iv->sprom.et1mac); - - if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 || - nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0) - iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0); - - if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 || - nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) - iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0); - - if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0 || - nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0) - iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10); - - if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0 || - nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0) - iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10); + if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) + iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10); return 0; } @@ -126,12 +169,28 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus, void __init plat_mem_setup(void) { int err; + char buf[100]; + struct ssb_mipscore *mcore; err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, bcm47xx_get_invariants); if (err) panic("Failed to initialize SSB bus (err %d)\n", err); + mcore = &ssb_bcm47xx.mipscore; + if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) { + if (strstr(buf, "console=ttyS1")) { + struct ssb_serial_port port; + + printk(KERN_DEBUG "Swapping serial ports!\n"); + /* swap serial ports */ + memcpy(&port, &mcore->serial_ports[0], sizeof(port)); + memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], + sizeof(port)); + memcpy(&mcore->serial_ports[1], &port, sizeof(port)); + } + } + _machine_restart = bcm47xx_machine_restart; _machine_halt = bcm47xx_machine_halt; pm_power_off = bcm47xx_machine_halt; diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 06d59dcbe243..86877539c6e8 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -111,8 +111,8 @@ * These are the PRID's for when 23:16 == PRID_COMP_BROADCOM */ -#define PRID_IMP_BMIPS4KC 0x4000 -#define PRID_IMP_BMIPS32 0x8000 +#define PRID_IMP_BMIPS32_REV4 0x4000 +#define PRID_IMP_BMIPS32_REV8 0x8000 #define PRID_IMP_BMIPS3300 0x9000 #define PRID_IMP_BMIPS3300_ALT 0x9100 #define PRID_IMP_BMIPS3300_BUG 0x0000 diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index fd1d39eb7431..455c0ac7d4ea 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -249,7 +249,8 @@ extern struct mips_abi mips_abi_n32; #define SET_PERSONALITY(ex) \ do { \ - set_personality(PER_LINUX); \ + if (personality(current->personality) != PER_LINUX) \ + set_personality(PER_LINUX); \ \ current->thread.abi = &mips_abi; \ } while (0) @@ -296,6 +297,8 @@ do { \ #define SET_PERSONALITY(ex) \ do { \ + unsigned int p; \ + \ clear_thread_flag(TIF_32BIT_REGS); \ clear_thread_flag(TIF_32BIT_ADDR); \ \ @@ -304,7 +307,8 @@ do { \ else \ current->thread.abi = &mips_abi; \ \ - if (current->personality != PER_LINUX32) \ + p = personality(current->personality); \ + if (p != PER_LINUX32 && p != PER_LINUX) \ set_personality(PER_LINUX); \ } while (0) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index c98bf514ec7d..5b017f23e243 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -329,10 +329,14 @@ static inline void pfx##write##bwlq(type val, \ "dsrl32 %L0, %L0, 0" "\n\t" \ "dsll32 %M0, %M0, 0" "\n\t" \ "or %L0, %L0, %M0" "\n\t" \ + ".set push" "\n\t" \ + ".set noreorder" "\n\t" \ + ".set nomacro" "\n\t" \ "sd %L0, %2" "\n\t" \ + ".set pop" "\n\t" \ ".set mips0" "\n" \ : "=r" (__tmp) \ - : "0" (__val), "m" (*__mem)); \ + : "0" (__val), "R" (*__mem)); \ if (irq) \ local_irq_restore(__flags); \ } else \ @@ -355,12 +359,16 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \ local_irq_save(__flags); \ __asm__ __volatile__( \ ".set mips3" "\t\t# __readq" "\n\t" \ + ".set push" "\n\t" \ + ".set noreorder" "\n\t" \ + ".set nomacro" "\n\t" \ "ld %L0, %1" "\n\t" \ + ".set pop" "\n\t" \ "dsra32 %M0, %L0, 0" "\n\t" \ "sll %L0, %L0, 0" "\n\t" \ ".set mips0" "\n" \ : "=r" (__val) \ - : "m" (*__mem)); \ + : "R" (*__mem)); \ if (irq) \ local_irq_restore(__flags); \ } else { \ diff --git a/arch/mips/include/asm/mach-ar7/ar7.h b/arch/mips/include/asm/mach-ar7/ar7.h index 7919d76186bf..07d3fadb2443 100644 --- a/arch/mips/include/asm/mach-ar7/ar7.h +++ b/arch/mips/include/asm/mach-ar7/ar7.h @@ -201,7 +201,6 @@ static inline void ar7_device_off(u32 bit) } int __init ar7_gpio_init(void); - -int __init ar7_gpio_init(void); +void __init ar7_init_clocks(void); #endif /* __AR7_H__ */ diff --git a/arch/mips/include/asm/mach-bcm47xx/nvram.h b/arch/mips/include/asm/mach-bcm47xx/nvram.h index c58ebd8bc155..9759588ba3cf 100644 --- a/arch/mips/include/asm/mach-bcm47xx/nvram.h +++ b/arch/mips/include/asm/mach-bcm47xx/nvram.h @@ -12,6 +12,7 @@ #define __NVRAM_H #include <linux/types.h> +#include <linux/kernel.h> struct nvram_header { u32 magic; @@ -36,4 +37,10 @@ struct nvram_header { extern int nvram_getenv(char *name, char *val, size_t val_len); +static inline void nvram_parse_macaddr(char *buf, u8 *macaddr) +{ + sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1], + &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); +} + #endif diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 5742bb4d78f4..5c0a3575877c 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -5,7 +5,7 @@ * * Copyright (c) 2009 Qi Hardware inc., * Author: Xiangfu Liu <xiangfu@qi-hardware.com> - * Copyright 2010, Lars-Petrer Clausen <lars@metafoo.de> + * Copyright 2010, Lars-Peter Clausen <lars@metafoo.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 or later @@ -235,7 +235,7 @@ static const unsigned int qi_lb60_keypad_rows[] = { QI_LB60_GPIO_KEYIN(3), QI_LB60_GPIO_KEYIN(4), QI_LB60_GPIO_KEYIN(5), - QI_LB60_GPIO_KEYIN(7), + QI_LB60_GPIO_KEYIN(6), QI_LB60_GPIO_KEYIN8, }; diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c index 95bc2b5b14f1..1cc9e544d16b 100644 --- a/arch/mips/jz4740/platform.c +++ b/arch/mips/jz4740/platform.c @@ -208,7 +208,7 @@ struct platform_device jz4740_i2s_device = { /* PCM */ struct platform_device jz4740_pcm_device = { - .name = "jz4740-pcm", + .name = "jz4740-pcm-audio", .id = -1, }; diff --git a/arch/mips/jz4740/prom.c b/arch/mips/jz4740/prom.c index cfeac15eb2e4..4a70407f55bb 100644 --- a/arch/mips/jz4740/prom.c +++ b/arch/mips/jz4740/prom.c @@ -23,7 +23,7 @@ #include <asm/bootinfo.h> #include <asm/mach-jz4740/base.h> -void jz4740_init_cmdline(int argc, char *argv[]) +static __init void jz4740_init_cmdline(int argc, char *argv[]) { unsigned int count = COMMAND_LINE_SIZE - 1; int i; diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index 2f4d7a99bcc2..98c5a9737c14 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -32,7 +32,7 @@ static int mips_next_event(unsigned long delta, cnt = read_c0_count(); cnt += delta; write_c0_compare(cnt); - res = ((int)(read_c0_count() - cnt) > 0) ? -ETIME : 0; + res = ((int)(read_c0_count() - cnt) >= 0) ? -ETIME : 0; return res; } diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 71620e19827a..68dae7b6b5db 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -905,7 +905,8 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) { decode_configs(c); switch (c->processor_id & 0xff00) { - case PRID_IMP_BMIPS32: + case PRID_IMP_BMIPS32_REV4: + case PRID_IMP_BMIPS32_REV8: c->cputype = CPU_BMIPS32; __cpu_name[cpu] = "Broadcom BMIPS32"; break; @@ -933,10 +934,6 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "Broadcom BMIPS5000"; c->options |= MIPS_CPU_ULRI; break; - case PRID_IMP_BMIPS4KC: - c->cputype = CPU_4KC; - __cpu_name[cpu] = "MIPS 4Kc"; - break; } } diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 6343b4a5b835..876a75cc376f 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -251,14 +251,15 @@ SYSCALL_DEFINE5(n32_msgrcv, int, msqid, u32, msgp, size_t, msgsz, SYSCALL_DEFINE1(32_personality, unsigned long, personality) { + unsigned int p = personality & 0xffffffff; int ret; - personality &= 0xffffffff; + if (personality(current->personality) == PER_LINUX32 && - personality == PER_LINUX) - personality = PER_LINUX32; - ret = sys_personality(personality); - if (ret == PER_LINUX32) - ret = PER_LINUX; + personality(p) == PER_LINUX) + p = (p & ~PER_MASK) | PER_LINUX32; + ret = sys_personality(p); + if (ret != -1 && personality(ret) == PER_LINUX32) + ret = (ret & ~PER_MASK) | PER_LINUX; return ret; } diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 99960940d4a4..ae167df73ddd 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -142,7 +142,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, childregs->regs[7] = 0; /* Clear error flag */ childregs->regs[2] = 0; /* Child gets zero as return value */ - regs->regs[2] = p->pid; if (childregs->cp0_status & ST0_CU0) { childregs->regs[28] = (unsigned long) ti; diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index e000b278f024..9dbe58368953 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -100,7 +100,7 @@ void __init device_tree_init(void) return; base = virt_to_phys((void *)initial_boot_params); - size = initial_boot_params->totalsize; + size = be32_to_cpu(initial_boot_params->totalsize); /* Before we do anything, lets reserve the dt blob */ reserve_mem_mach(base, size); diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 43e7cdc5ded2..c0e81418ba21 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -153,7 +153,7 @@ static void __cpuinit vsmp_init_secondary(void) { extern int gic_present; - /* This is Malta specific: IPI,performance and timer inetrrupts */ + /* This is Malta specific: IPI,performance and timer interrupts */ if (gic_present) change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 | STATUSF_IP7); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 8e9fbe75894e..e97104302541 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -83,7 +83,8 @@ extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, - struct mips_fpu_struct *ctx, int has_fpu); + struct mips_fpu_struct *ctx, int has_fpu, + void *__user *fault_addr); void (*board_be_init)(void); int (*board_be_handler)(struct pt_regs *regs, int is_fixup); @@ -661,12 +662,36 @@ asmlinkage void do_ov(struct pt_regs *regs) force_sig_info(SIGFPE, &info, current); } +static int process_fpemu_return(int sig, void __user *fault_addr) +{ + if (sig == SIGSEGV || sig == SIGBUS) { + struct siginfo si = {0}; + si.si_addr = fault_addr; + si.si_signo = sig; + if (sig == SIGSEGV) { + if (find_vma(current->mm, (unsigned long)fault_addr)) + si.si_code = SEGV_ACCERR; + else + si.si_code = SEGV_MAPERR; + } else { + si.si_code = BUS_ADRERR; + } + force_sig_info(sig, &si, current); + return 1; + } else if (sig) { + force_sig(sig, current); + return 1; + } else { + return 0; + } +} + /* * XXX Delayed fp exceptions when doing a lazy ctx switch XXX */ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) { - siginfo_t info; + siginfo_t info = {0}; if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE) == NOTIFY_STOP) @@ -675,6 +700,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) if (fcr31 & FPU_CSR_UNI_X) { int sig; + void __user *fault_addr = NULL; /* * Unimplemented operation exception. If we've got the full @@ -690,7 +716,8 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) lose_fpu(1); /* Run the emulator */ - sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1); + sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, + &fault_addr); /* * We can't allow the emulated instruction to leave any of @@ -702,8 +729,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) own_fpu(1); /* Using the FPU again. */ /* If something went wrong, signal */ - if (sig) - force_sig(sig, current); + process_fpemu_return(sig, fault_addr); return; } else if (fcr31 & FPU_CSR_INV_X) @@ -996,11 +1022,11 @@ asmlinkage void do_cpu(struct pt_regs *regs) if (!raw_cpu_has_fpu) { int sig; + void __user *fault_addr = NULL; sig = fpu_emulator_cop1Handler(regs, - ¤t->thread.fpu, 0); - if (sig) - force_sig(sig, current); - else + ¤t->thread.fpu, + 0, &fault_addr); + if (!process_fpemu_return(sig, fault_addr)) mt_ase_fp_affinity(); } diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 3eb3cde2f661..6a1fdfef8fde 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -1092,6 +1092,10 @@ static int vpe_open(struct inode *inode, struct file *filp) /* this of-course trashes what was there before... */ v->pbuffer = vmalloc(P_SIZE); + if (!v->pbuffer) { + pr_warning("VPE loader: unable to allocate memory\n"); + return -ENOMEM; + } v->plen = P_SIZE; v->load_addr = NULL; v->len = 0; @@ -1149,10 +1153,9 @@ static int vpe_release(struct inode *inode, struct file *filp) if (ret < 0) v->shared_ptr = NULL; - // cleanup any temp buffers - if (v->pbuffer) - vfree(v->pbuffer); + vfree(v->pbuffer); v->plen = 0; + return ret; } @@ -1169,11 +1172,6 @@ static ssize_t vpe_write(struct file *file, const char __user * buffer, if (v == NULL) return -ENODEV; - if (v->pbuffer == NULL) { - printk(KERN_ERR "VPE loader: no buffer for program\n"); - return -ENOMEM; - } - if ((count + v->len) > v->plen) { printk(KERN_WARNING "VPE loader: elf size too big. Perhaps strip uneeded symbols\n"); diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 77dc3b20110a..606c8a9efe3b 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -161,16 +161,16 @@ FEXPORT(__bzero) .Lfwd_fixup: PTR_L t0, TI_TASK($28) - LONG_L t0, THREAD_BUADDR(t0) andi a2, 0x3f + LONG_L t0, THREAD_BUADDR(t0) LONG_ADDU a2, t1 jr ra LONG_SUBU a2, t0 .Lpartial_fixup: PTR_L t0, TI_TASK($28) - LONG_L t0, THREAD_BUADDR(t0) andi a2, LONGMASK + LONG_L t0, THREAD_BUADDR(t0) LONG_ADDU a2, t1 jr ra LONG_SUBU a2, t0 diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c index ae4cff97a56c..11b193f848f8 100644 --- a/arch/mips/loongson/common/env.c +++ b/arch/mips/loongson/common/env.c @@ -29,9 +29,9 @@ unsigned long memsize, highmemsize; #define parse_even_earlier(res, option, p) \ do { \ + int ret; \ if (strncmp(option, (char *)p, strlen(option)) == 0) \ - strict_strtol((char *)p + strlen(option"="), \ - 10, &res); \ + ret = strict_strtol((char *)p + strlen(option"="), 10, &res); \ } while (0) void __init prom_init_env(void) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index b2ad1b0910ff..d32cb0503110 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -64,7 +64,7 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, #if __mips >= 4 && __mips != 32 static int fpux_emu(struct pt_regs *, - struct mips_fpu_struct *, mips_instruction); + struct mips_fpu_struct *, mips_instruction, void *__user *); #endif /* Further private data for which no space exists in mips_fpu_struct */ @@ -208,16 +208,23 @@ static inline int cop1_64bit(struct pt_regs *xcp) * Two instructions if the instruction is in a branch delay slot. */ -static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) +static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + void *__user *fault_addr) { mips_instruction ir; unsigned long emulpc, contpc; unsigned int cond; - if (get_user(ir, (mips_instruction __user *) xcp->cp0_epc)) { + if (!access_ok(VERIFY_READ, xcp->cp0_epc, sizeof(mips_instruction))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = (mips_instruction __user *)xcp->cp0_epc; return SIGBUS; } + if (__get_user(ir, (mips_instruction __user *) xcp->cp0_epc)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = (mips_instruction __user *)xcp->cp0_epc; + return SIGSEGV; + } /* XXX NEC Vr54xx bug workaround */ if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir)) @@ -245,10 +252,16 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) #endif return SIGILL; } - if (get_user(ir, (mips_instruction __user *) emulpc)) { + if (!access_ok(VERIFY_READ, emulpc, sizeof(mips_instruction))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = (mips_instruction __user *)emulpc; return SIGBUS; } + if (__get_user(ir, (mips_instruction __user *) emulpc)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = (mips_instruction __user *)emulpc; + return SIGSEGV; + } /* __compute_return_epc() will have updated cp0_epc */ contpc = xcp->cp0_epc; /* In order not to confuse ptrace() et al, tweak context */ @@ -269,10 +282,17 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) u64 val; MIPS_FPU_EMU_INC_STATS(loads); - if (get_user(val, va)) { + + if (!access_ok(VERIFY_READ, va, sizeof(u64))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; return SIGBUS; } + if (__get_user(val, va)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; + return SIGSEGV; + } DITOREG(val, MIPSInst_RT(ir)); break; } @@ -284,10 +304,16 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) MIPS_FPU_EMU_INC_STATS(stores); DIFROMREG(val, MIPSInst_RT(ir)); - if (put_user(val, va)) { + if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; return SIGBUS; } + if (__put_user(val, va)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; + return SIGSEGV; + } break; } @@ -297,10 +323,16 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) u32 val; MIPS_FPU_EMU_INC_STATS(loads); - if (get_user(val, va)) { + if (!access_ok(VERIFY_READ, va, sizeof(u32))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; return SIGBUS; } + if (__get_user(val, va)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; + return SIGSEGV; + } SITOREG(val, MIPSInst_RT(ir)); break; } @@ -312,10 +344,16 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) MIPS_FPU_EMU_INC_STATS(stores); SIFROMREG(val, MIPSInst_RT(ir)); - if (put_user(val, va)) { + if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; return SIGBUS; } + if (__put_user(val, va)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; + return SIGSEGV; + } break; } @@ -440,11 +478,18 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) contpc = (xcp->cp0_epc + (MIPSInst_SIMM(ir) << 2)); - if (get_user(ir, - (mips_instruction __user *) xcp->cp0_epc)) { + if (!access_ok(VERIFY_READ, xcp->cp0_epc, + sizeof(mips_instruction))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = (mips_instruction __user *)xcp->cp0_epc; return SIGBUS; } + if (__get_user(ir, + (mips_instruction __user *) xcp->cp0_epc)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = (mips_instruction __user *)xcp->cp0_epc; + return SIGSEGV; + } switch (MIPSInst_OPCODE(ir)) { case lwc1_op: @@ -506,9 +551,8 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) #if __mips >= 4 && __mips != 32 case cop1x_op:{ - int sig; - - if ((sig = fpux_emu(xcp, ctx, ir))) + int sig = fpux_emu(xcp, ctx, ir, fault_addr); + if (sig) return sig; break; } @@ -604,7 +648,7 @@ DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - mips_instruction ir) + mips_instruction ir, void *__user *fault_addr) { unsigned rcsr = 0; /* resulting csr */ @@ -624,10 +668,16 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, xcp->regs[MIPSInst_FT(ir)]); MIPS_FPU_EMU_INC_STATS(loads); - if (get_user(val, va)) { + if (!access_ok(VERIFY_READ, va, sizeof(u32))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; return SIGBUS; } + if (__get_user(val, va)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; + return SIGSEGV; + } SITOREG(val, MIPSInst_FD(ir)); break; @@ -638,10 +688,16 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, MIPS_FPU_EMU_INC_STATS(stores); SIFROMREG(val, MIPSInst_FS(ir)); - if (put_user(val, va)) { + if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; return SIGBUS; } + if (put_user(val, va)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; + return SIGSEGV; + } break; case madd_s_op: @@ -701,10 +757,16 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, xcp->regs[MIPSInst_FT(ir)]); MIPS_FPU_EMU_INC_STATS(loads); - if (get_user(val, va)) { + if (!access_ok(VERIFY_READ, va, sizeof(u64))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; return SIGBUS; } + if (__get_user(val, va)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; + return SIGSEGV; + } DITOREG(val, MIPSInst_FD(ir)); break; @@ -714,10 +776,16 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, MIPS_FPU_EMU_INC_STATS(stores); DIFROMREG(val, MIPSInst_FS(ir)); - if (put_user(val, va)) { + if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; return SIGBUS; } + if (__put_user(val, va)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = va; + return SIGSEGV; + } break; case madd_d_op: @@ -1242,7 +1310,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, } int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, - int has_fpu) + int has_fpu, void *__user *fault_addr) { unsigned long oldepc, prevepc; mips_instruction insn; @@ -1252,10 +1320,16 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, do { prevepc = xcp->cp0_epc; - if (get_user(insn, (mips_instruction __user *) xcp->cp0_epc)) { + if (!access_ok(VERIFY_READ, xcp->cp0_epc, sizeof(mips_instruction))) { MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = (mips_instruction __user *)xcp->cp0_epc; return SIGBUS; } + if (__get_user(insn, (mips_instruction __user *) xcp->cp0_epc)) { + MIPS_FPU_EMU_INC_STATS(errors); + *fault_addr = (mips_instruction __user *)xcp->cp0_epc; + return SIGSEGV; + } if (insn == 0) xcp->cp0_epc += 4; /* skip nops */ else { @@ -1267,7 +1341,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, */ /* convert to ieee library modes */ ieee754_csr.rm = ieee_rm[ieee754_csr.rm]; - sig = cop1Emulate(xcp, ctx); + sig = cop1Emulate(xcp, ctx, fault_addr); /* revert to mips rounding mode */ ieee754_csr.rm = mips_rm[ieee754_csr.rm]; } diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 4fc1a0fbe007..21ea14efb837 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -288,7 +288,7 @@ int mips_dma_supported(struct device *dev, u64 mask) return plat_dma_supported(dev, mask); } -void mips_dma_cache_sync(struct device *dev, void *vaddr, size_t size, +void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { BUG_ON(direction == DMA_NONE); @@ -298,6 +298,8 @@ void mips_dma_cache_sync(struct device *dev, void *vaddr, size_t size, __dma_sync((unsigned long)vaddr, size, direction); } +EXPORT_SYMBOL(dma_cache_sync); + static struct dma_map_ops mips_default_dma_map_ops = { .alloc_coherent = mips_dma_alloc_coherent, .free_coherent = mips_dma_free_coherent, diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 505fecad4684..9cca8de00545 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -68,6 +68,9 @@ static struct bcache_ops mips_sc_ops = { */ static inline int mips_sc_is_activated(struct cpuinfo_mips *c) { + unsigned int config2 = read_c0_config2(); + unsigned int tmp; + /* Check the bypass bit (L2B) */ switch (c->cputype) { case CPU_34K: @@ -83,6 +86,7 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c) c->scache.linesz = 2 << tmp; else return 0; + return 1; } static inline int __init mips_sc_probe(void) diff --git a/arch/mips/pmc-sierra/yosemite/py-console.c b/arch/mips/pmc-sierra/yosemite/py-console.c index b7f1d9c4a8a3..434d7b1a8c6a 100644 --- a/arch/mips/pmc-sierra/yosemite/py-console.c +++ b/arch/mips/pmc-sierra/yosemite/py-console.c @@ -65,11 +65,15 @@ static unsigned char readb_outer_space(unsigned long long phys) __asm__ __volatile__ ( " .set mips3 \n" + " .set push \n" + " .set noreorder \n" + " .set nomacro \n" " ld %0, %1 \n" + " .set pop \n" " lbu %0, (%0) \n" " .set mips0 \n" : "=r" (res) - : "m" (vaddr)); + : "R" (vaddr)); write_c0_status(sr); ssnop_4(); @@ -89,11 +93,15 @@ static void writeb_outer_space(unsigned long long phys, unsigned char c) __asm__ __volatile__ ( " .set mips3 \n" + " .set push \n" + " .set noreorder \n" + " .set nomacro \n" " ld %0, %1 \n" + " .set pop \n" " sb %2, (%0) \n" " .set mips0 \n" : "=&r" (tmp) - : "m" (vaddr), "r" (c)); + : "R" (vaddr), "r" (c)); write_c0_status(sr); ssnop_4(); diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c index c308989fc464..41707a245dea 100644 --- a/arch/mips/sibyte/swarm/setup.c +++ b/arch/mips/sibyte/swarm/setup.c @@ -82,7 +82,7 @@ int swarm_be_handler(struct pt_regs *regs, int is_fixup) enum swarm_rtc_type { RTC_NONE, RTC_XICOR, - RTC_M4LT81 + RTC_M41T81, }; enum swarm_rtc_type swarm_rtc_type; @@ -96,7 +96,7 @@ void read_persistent_clock(struct timespec *ts) sec = xicor_get_time(); break; - case RTC_M4LT81: + case RTC_M41T81: sec = m41t81_get_time(); break; @@ -115,7 +115,7 @@ int rtc_mips_set_time(unsigned long sec) case RTC_XICOR: return xicor_set_time(sec); - case RTC_M4LT81: + case RTC_M41T81: return m41t81_set_time(sec); case RTC_NONE: @@ -141,7 +141,7 @@ void __init plat_mem_setup(void) if (xicor_probe()) swarm_rtc_type = RTC_XICOR; if (m41t81_probe()) - swarm_rtc_type = RTC_M4LT81; + swarm_rtc_type = RTC_M41T81; #ifdef CONFIG_VT screen_info = (struct screen_info) { diff --git a/arch/mn10300/include/asm/syscall.h b/arch/mn10300/include/asm/syscall.h new file mode 100644 index 000000000000..b44b0bb75a01 --- /dev/null +++ b/arch/mn10300/include/asm/syscall.h @@ -0,0 +1,117 @@ +/* Access to user system call parameters and results + * + * See asm-generic/syscall.h for function descriptions. + * + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef _ASM_SYSCALL_H +#define _ASM_SYSCALL_H + +#include <linux/sched.h> +#include <linux/err.h> + +extern const unsigned long sys_call_table[]; + +static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) +{ + return regs->orig_d0; +} + +static inline void syscall_rollback(struct task_struct *task, + struct pt_regs *regs) +{ + regs->d0 = regs->orig_d0; +} + +static inline long syscall_get_error(struct task_struct *task, + struct pt_regs *regs) +{ + unsigned long error = regs->d0; + return IS_ERR_VALUE(error) ? error : 0; +} + +static inline long syscall_get_return_value(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->d0; +} + +static inline void syscall_set_return_value(struct task_struct *task, + struct pt_regs *regs, + int error, long val) +{ + regs->d0 = (long) error ?: val; +} + +static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + unsigned long *args) +{ + switch (i) { + case 0: + if (!n--) break; + *args++ = regs->a0; + case 1: + if (!n--) break; + *args++ = regs->d1; + case 2: + if (!n--) break; + *args++ = regs->a3; + case 3: + if (!n--) break; + *args++ = regs->a2; + case 4: + if (!n--) break; + *args++ = regs->d3; + case 5: + if (!n--) break; + *args++ = regs->d2; + case 6: + if (!n--) break; + default: + BUG(); + break; + } +} + +static inline void syscall_set_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + const unsigned long *args) +{ + switch (i) { + case 0: + if (!n--) break; + regs->a0 = *args++; + case 1: + if (!n--) break; + regs->d1 = *args++; + case 2: + if (!n--) break; + regs->a3 = *args++; + case 3: + if (!n--) break; + regs->a2 = *args++; + case 4: + if (!n--) break; + regs->d3 = *args++; + case 5: + if (!n--) break; + regs->d2 = *args++; + case 6: + if (!n--) break; + default: + BUG(); + break; + } +} + +#endif /* _ASM_SYSCALL_H */ diff --git a/arch/mn10300/kernel/gdb-io-serial.c b/arch/mn10300/kernel/gdb-io-serial.c index 0d5d63c91dc3..f28dc99c6f72 100644 --- a/arch/mn10300/kernel/gdb-io-serial.c +++ b/arch/mn10300/kernel/gdb-io-serial.c @@ -73,7 +73,8 @@ void gdbstub_io_init(void) GDBPORT_SERIAL_IER = UART_IER_RDI | UART_IER_RLSI; /* permit level 0 IRQs to take place */ - local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); + arch_local_change_intr_mask_level( + NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); } /* diff --git a/arch/mn10300/kernel/gdb-io-ttysm.c b/arch/mn10300/kernel/gdb-io-ttysm.c index 97dfda23342c..abdeea153c89 100644 --- a/arch/mn10300/kernel/gdb-io-ttysm.c +++ b/arch/mn10300/kernel/gdb-io-ttysm.c @@ -87,7 +87,8 @@ void __init gdbstub_io_init(void) tmp = *gdbstub_port->_control; /* permit level 0 IRQs only */ - local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); + arch_local_change_intr_mask_level( + NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); } /* diff --git a/arch/mn10300/kernel/gdb-stub.c b/arch/mn10300/kernel/gdb-stub.c index a5fc3f05309b..b169d99d9f20 100644 --- a/arch/mn10300/kernel/gdb-stub.c +++ b/arch/mn10300/kernel/gdb-stub.c @@ -1194,7 +1194,8 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep) asm volatile("mov mdr,%0" : "=d"(mdr)); local_save_flags(epsw); - local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); + arch_local_change_intr_mask_level( + NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); gdbstub_store_fpu(); diff --git a/arch/mn10300/kernel/time.c b/arch/mn10300/kernel/time.c index f860a340acc9..75da468090b9 100644 --- a/arch/mn10300/kernel/time.c +++ b/arch/mn10300/kernel/time.c @@ -40,21 +40,17 @@ unsigned long long sched_clock(void) unsigned long long ll; unsigned l[2]; } tsc64, result; - unsigned long tsc, tmp; + unsigned long tmp; unsigned product[3]; /* 96-bit intermediate value */ /* cnt32_to_63() is not safe with preemption */ preempt_disable(); - /* read the TSC value - */ - tsc = get_cycles(); - - /* expand to 64-bits. + /* expand the tsc to 64-bits. * - sched_clock() must be called once a minute or better or the * following will go horribly wrong - see cnt32_to_63() */ - tsc64.ll = cnt32_to_63(tsc) & 0x7fffffffffffffffULL; + tsc64.ll = cnt32_to_63(get_cycles()) & 0x7fffffffffffffffULL; preempt_enable(); diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 5024f643b3b1..d7d94b845dc2 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -75,9 +75,6 @@ static void cpu_unmask_irq(unsigned int irq) smp_send_all_nop(); } -void no_ack_irq(unsigned int irq) { } -void no_end_irq(unsigned int irq) { } - void cpu_ack_irq(unsigned int irq) { unsigned long mask = EIEM_MASK(irq); @@ -241,7 +238,7 @@ int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data) /* for iosapic interrupts */ if (type) { - set_irq_chip_and_handler(irq, type, handle_level_irq); + set_irq_chip_and_handler(irq, type, handle_percpu_irq); set_irq_chip_data(irq, data); cpu_unmask_irq(irq); } @@ -392,7 +389,7 @@ static void claim_cpu_irqs(void) int i; for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) { set_irq_chip_and_handler(i, &cpu_interrupt_type, - handle_level_irq); + handle_percpu_irq); } set_irq_handler(TIMER_IRQ, handle_percpu_irq); diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 35c827e94e31..609a331878e7 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -98,7 +98,6 @@ void sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) { struct rt_sigframe __user *frame; - struct siginfo si; sigset_t set; unsigned long usp = (regs->gr[30] & ~(0x01UL)); unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE; @@ -178,13 +177,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) give_sigsegv: DBG(1,"sys_rt_sigreturn: Sending SIGSEGV\n"); - si.si_signo = SIGSEGV; - si.si_errno = 0; - si.si_code = SI_KERNEL; - si.si_pid = task_pid_vnr(current); - si.si_uid = current_uid(); - si.si_addr = &frame->uc; - force_sig_info(SIGSEGV, &si, current); + force_sig(SIGSEGV, current); return; } diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index b6447190e1a2..e625e9e034ae 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -4,6 +4,10 @@ config PPC32 bool default y if !PPC64 +config 32BIT + bool + default y if PPC32 + config 64BIT bool default y if PPC64 diff --git a/arch/powerpc/boot/div64.S b/arch/powerpc/boot/div64.S index 722f360a32a9..d271ab542673 100644 --- a/arch/powerpc/boot/div64.S +++ b/arch/powerpc/boot/div64.S @@ -33,9 +33,10 @@ __div64_32: cntlzw r0,r5 # we are shifting the dividend right li r10,-1 # to make it < 2^32, and shifting srw r10,r10,r0 # the divisor right the same amount, - add r9,r4,r10 # rounding up (so the estimate cannot + addc r9,r4,r10 # rounding up (so the estimate cannot andc r11,r6,r10 # ever be too large, only too small) andc r9,r9,r10 + addze r9,r9 or r11,r5,r11 rotlw r9,r9,r0 rotlw r11,r11,r0 diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 7a9db64f3f04..42850ee00ada 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -337,7 +337,7 @@ char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) /* FP registers 32 -> 63 */ #if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE) if (current) - memcpy(mem, current->thread.evr[regno-32], + memcpy(mem, ¤t->thread.evr[regno-32], dbg_reg_def[regno].size); #else /* fp registers not used by kernel, leave zero */ @@ -362,7 +362,7 @@ int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) if (regno >= 32 && regno < 64) { /* FP registers 32 -> 63 */ #if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE) - memcpy(current->thread.evr[regno-32], mem, + memcpy(¤t->thread.evr[regno-32], mem, dbg_reg_def[regno].size); #else /* fp registers not used by kernel, leave zero */ diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 2a178b0ebcdf..ce6f61c6f871 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -497,9 +497,8 @@ static void __init emergency_stack_init(void) } /* - * Called into from start_kernel, after lock_kernel has been called. - * Initializes bootmem, which is unsed to manage page allocation until - * mem_init is called. + * Called into from start_kernel this initializes bootmem, which is used + * to manage page allocation until mem_init is called. */ void __init setup_arch(char **cmdline_p) { diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 83f534d862db..5e9584405c45 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -1123,7 +1123,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, else #endif /* CONFIG_PPC_HAS_HASH_64K */ rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize, - subpage_protection(pgdir, ea)); + subpage_protection(mm, ea)); /* Dump some info in case of hash insertion failure, they should * never happen so it is really useful to know if/when they do diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index 2c7e801ab20b..6a3997f98dfb 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c @@ -92,7 +92,7 @@ static void pte_free_rcu_callback(struct rcu_head *head) static void pte_free_submit(struct pte_freelist_batch *batch) { - call_rcu(&batch->rcu, pte_free_rcu_callback); + call_rcu_sched(&batch->rcu, pte_free_rcu_callback); } void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift) diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S index 8b04c54e596f..8526bd9d2aa3 100644 --- a/arch/powerpc/mm/tlb_low_64e.S +++ b/arch/powerpc/mm/tlb_low_64e.S @@ -138,8 +138,11 @@ cmpldi cr0,r15,0 /* Check for user region */ std r14,EX_TLB_ESR(r12) /* write crazy -1 to frame */ beq normal_tlb_miss + + li r11,_PAGE_PRESENT|_PAGE_BAP_SX /* Base perm */ + oris r11,r11,_PAGE_ACCESSED@h /* XXX replace the RMW cycles with immediate loads + writes */ -1: mfspr r10,SPRN_MAS1 + mfspr r10,SPRN_MAS1 cmpldi cr0,r15,8 /* Check for vmalloc region */ rlwinm r10,r10,0,16,1 /* Clear TID */ mtspr SPRN_MAS1,r10 diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index 36c0c449a899..2a030d89bbc6 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -585,6 +585,6 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base, ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000); /* Finally limit subsequent allocations */ - memblock_set_current_limit(ppc64_memblock_base + ppc64_rma_size); + memblock_set_current_limit(first_memblock_base + ppc64_rma_size); } #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index c667f0f02c34..3139814f6439 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -47,6 +47,12 @@ config LPARCFG config PPC_PSERIES_DEBUG depends on PPC_PSERIES && PPC_EARLY_DEBUG bool "Enable extra debug logging in platforms/pseries" + help + Say Y here if you want the pseries core to produce a bunch of + debug messages to the system log. Select this if you are having a + problem with the pseries core and want to see more of what is + going on. This does not enable debugging in lpar.c, which must + be manually done due to its verbosity. default y config PPC_SMLPAR diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 34b7dc12e731..17a11c82e6f8 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -21,8 +21,6 @@ * Please address comments and feedback to Linas Vepstas <linas@austin.ibm.com> */ -#undef DEBUG - #include <linux/delay.h> #include <linux/init.h> #include <linux/list.h> diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 4b7a062dee15..5fcc92a12d3e 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -25,8 +25,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#undef DEBUG - #include <linux/pci.h> #include <asm/pci-bridge.h> #include <asm/ppc-pci.h> diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index ac151399ef34..1995c1712fc8 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -95,7 +95,6 @@ EXPORT_SYMBOL_GPL(s390_handle_mcck); static int notrace s390_revalidate_registers(struct mci *mci) { int kill_task; - u64 tmpclock; u64 zero; void *fpt_save_area, *fpt_creg_save_area; @@ -214,11 +213,10 @@ static int notrace s390_revalidate_registers(struct mci *mci) : "0", "cc"); #endif /* Revalidate clock comparator register */ - asm volatile( - " stck 0(%1)\n" - " sckc 0(%1)" - : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory"); - + if (S390_lowcore.clock_comparator == -1) + set_clock_comparator(S390_lowcore.mcck_clock); + else + set_clock_comparator(S390_lowcore.clock_comparator); /* Check if old PSW is valid */ if (!mci->wp) /* diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 56c8687b29b3..7eff9b7347c0 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -19,6 +19,7 @@ #include <linux/kernel_stat.h> #include <linux/rcupdate.h> #include <linux/posix-timers.h> +#include <linux/cpu.h> #include <asm/s390_ext.h> #include <asm/timer.h> @@ -566,6 +567,23 @@ void init_cpu_vtimer(void) __ctl_set_bit(0,10); } +static int __cpuinit s390_nohz_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + struct s390_idle_data *idle; + long cpu = (long) hcpu; + + idle = &per_cpu(s390_idle, cpu); + switch (action) { + case CPU_DYING: + case CPU_DYING_FROZEN: + idle->nohz_delay = 0; + default: + break; + } + return NOTIFY_OK; +} + void __init vtime_init(void) { /* request the cpu timer external interrupt */ @@ -574,5 +592,6 @@ void __init vtime_init(void) /* Enable cpu timer interrupts on the boot cpu. */ init_cpu_vtimer(); + cpu_notifier(s390_nohz_notify, 0); } diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 752b362bf651..7c37ec359ec2 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -29,17 +29,21 @@ static void __udelay_disabled(unsigned long long usecs) { unsigned long mask, cr0, cr0_saved; u64 clock_saved; + u64 end; + mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT; + end = get_clock() + (usecs << 12); clock_saved = local_tick_disable(); - set_clock_comparator(get_clock() + (usecs << 12)); __ctl_store(cr0_saved, 0, 0); cr0 = (cr0_saved & 0xffff00e0) | 0x00000800; __ctl_load(cr0 , 0, 0); - mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT; lockdep_off(); - trace_hardirqs_on(); - __load_psw_mask(mask); - local_irq_disable(); + do { + set_clock_comparator(end); + trace_hardirqs_on(); + __load_psw_mask(mask); + local_irq_disable(); + } while (get_clock() < end); lockdep_on(); __ctl_load(cr0_saved, 0, 0); local_tick_enable(clock_saved); diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 7f217b3a50a8..2e9d78d21fd3 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -22,7 +22,8 @@ config SUPERH select HAVE_SPARSE_IRQ select RTC_LIB select GENERIC_ATOMIC64 - select GENERIC_HARDIRQS_NO_DEPRECATED + # Support the deprecated APIs until MFD and GPIOLIB catch up. + select GENERIC_HARDIRQS_NO_DEPRECATED if !MFD_SUPPORT && !GPIOLIB help The SuperH is a RISC processor targeted for use in embedded systems and consumer electronics; it was also used in the Sega Dreamcast diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 2eaeb9e59585..f48c492a68d3 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -720,32 +720,6 @@ static struct platform_device camera_devices[] = { }; /* FSI */ -/* - * FSI-B use external clock which came from da7210. - * So, we should change parent of fsi - */ -#define FCLKBCR 0xa415000c -static void fsimck_init(struct clk *clk) -{ - u32 status = __raw_readl(clk->enable_reg); - - /* use external clock */ - status &= ~0x000000ff; - status |= 0x00000080; - - __raw_writel(status, clk->enable_reg); -} - -static struct clk_ops fsimck_clk_ops = { - .init = fsimck_init, -}; - -static struct clk fsimckb_clk = { - .ops = &fsimck_clk_ops, - .enable_reg = (void __iomem *)FCLKBCR, - .rate = 0, /* unknown */ -}; - static struct sh_fsi_platform_info fsi_info = { .portb_flags = SH_FSI_BRS_INV | SH_FSI_OUT_SLAVE_MODE | @@ -1264,10 +1238,10 @@ static int __init arch_setup(void) /* change parent of FSI B */ clk = clk_get(NULL, "fsib_clk"); if (!IS_ERR(clk)) { - clk_register(&fsimckb_clk); - clk_set_parent(clk, &fsimckb_clk); - clk_set_rate(clk, 11000); - clk_set_rate(&fsimckb_clk, 11000); + /* 48kHz dummy clock was used to make sure 1/1 divide */ + clk_set_rate(&sh7724_fsimckb_clk, 48000); + clk_set_parent(clk, &sh7724_fsimckb_clk); + clk_set_rate(clk, 48000); clk_put(clk); } diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index c31d228fdfc6..527a0cd956b5 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -283,31 +283,6 @@ static struct platform_device ceu1_device = { }; /* FSI */ -/* - * FSI-A use external clock which came from ak464x. - * So, we should change parent of fsi - */ -#define FCLKACR 0xa4150008 -static void fsimck_init(struct clk *clk) -{ - u32 status = __raw_readl(clk->enable_reg); - - /* use external clock */ - status &= ~0x000000ff; - status |= 0x00000080; - __raw_writel(status, clk->enable_reg); -} - -static struct clk_ops fsimck_clk_ops = { - .init = fsimck_init, -}; - -static struct clk fsimcka_clk = { - .ops = &fsimck_clk_ops, - .enable_reg = (void __iomem *)FCLKACR, - .rate = 0, /* unknown */ -}; - /* change J20, J21, J22 pin to 1-2 connection to use slave mode */ static struct sh_fsi_platform_info fsi_info = { .porta_flags = SH_FSI_BRS_INV | @@ -852,37 +827,29 @@ static int __init devices_setup(void) gpio_request(GPIO_FN_KEYOUT0, NULL); /* enable FSI */ - gpio_request(GPIO_FN_FSIMCKB, NULL); gpio_request(GPIO_FN_FSIMCKA, NULL); + gpio_request(GPIO_FN_FSIIASD, NULL); gpio_request(GPIO_FN_FSIOASD, NULL); gpio_request(GPIO_FN_FSIIABCK, NULL); gpio_request(GPIO_FN_FSIIALRCK, NULL); gpio_request(GPIO_FN_FSIOABCK, NULL); gpio_request(GPIO_FN_FSIOALRCK, NULL); gpio_request(GPIO_FN_CLKAUDIOAO, NULL); - gpio_request(GPIO_FN_FSIIBSD, NULL); - gpio_request(GPIO_FN_FSIOBSD, NULL); - gpio_request(GPIO_FN_FSIIBBCK, NULL); - gpio_request(GPIO_FN_FSIIBLRCK, NULL); - gpio_request(GPIO_FN_FSIOBBCK, NULL); - gpio_request(GPIO_FN_FSIOBLRCK, NULL); - gpio_request(GPIO_FN_CLKAUDIOBO, NULL); - gpio_request(GPIO_FN_FSIIASD, NULL); /* set SPU2 clock to 83.4 MHz */ clk = clk_get(NULL, "spu_clk"); - if (clk) { + if (!IS_ERR(clk)) { clk_set_rate(clk, clk_round_rate(clk, 83333333)); clk_put(clk); } /* change parent of FSI A */ clk = clk_get(NULL, "fsia_clk"); - if (clk) { - clk_register(&fsimcka_clk); - clk_set_parent(clk, &fsimcka_clk); - clk_set_rate(clk, 11000); - clk_set_rate(&fsimcka_clk, 11000); + if (!IS_ERR(clk)) { + /* 48kHz dummy clock was used to make sure 1/1 divide */ + clk_set_rate(&sh7724_fsimcka_clk, 48000); + clk_set_parent(clk, &sh7724_fsimcka_clk); + clk_set_rate(clk, 48000); clk_put(clk); } diff --git a/arch/sh/include/asm/cacheflush.h b/arch/sh/include/asm/cacheflush.h index 1f4e562c5e8c..82e1eabeac98 100644 --- a/arch/sh/include/asm/cacheflush.h +++ b/arch/sh/include/asm/cacheflush.h @@ -96,7 +96,7 @@ void kmap_coherent_init(void); void *kmap_coherent(struct page *page, unsigned long addr); void kunmap_coherent(void *kvaddr); -#define PG_dcache_dirty PG_arch_1 +#define PG_dcache_clean PG_arch_1 void cpu_cache_init(void); diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index 46d5179c9f49..e3c73cdd8c90 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h @@ -199,10 +199,13 @@ extern unsigned long get_wchan(struct task_struct *p); #define ARCH_HAS_PREFETCHW static inline void prefetch(void *x) { - __asm__ __volatile__ ("pref @%0\n\t" : : "r" (x) : "memory"); + __builtin_prefetch(x, 0, 3); } -#define prefetchw(x) prefetch(x) +static inline void prefetchw(void *x) +{ + __builtin_prefetch(x, 1, 3); +} #endif #endif /* __KERNEL__ */ diff --git a/arch/sh/include/asm/unistd_32.h b/arch/sh/include/asm/unistd_32.h index 903cd618eb74..d6741fca89a4 100644 --- a/arch/sh/include/asm/unistd_32.h +++ b/arch/sh/include/asm/unistd_32.h @@ -368,8 +368,9 @@ #define __NR_sendmsg 355 #define __NR_recvmsg 356 #define __NR_recvmmsg 357 +#define __NR_accept4 358 -#define NR_syscalls 358 +#define NR_syscalls 359 #ifdef __KERNEL__ diff --git a/arch/sh/include/cpu-sh4/cpu/sh7724.h b/arch/sh/include/cpu-sh4/cpu/sh7724.h index 4c27b68789b3..7eb435999426 100644 --- a/arch/sh/include/cpu-sh4/cpu/sh7724.h +++ b/arch/sh/include/cpu-sh4/cpu/sh7724.h @@ -303,4 +303,7 @@ enum { SHDMA_SLAVE_SDHI1_RX, }; +extern struct clk sh7724_fsimcka_clk; +extern struct clk sh7724_fsimckb_clk; + #endif /* __ASM_SH7724_H__ */ diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c index 4eabc68cd753..b601fa3978d1 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c +++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c @@ -110,7 +110,7 @@ static int shoc_clk_verify_rate(struct clk *clk, unsigned long rate) return 0; } -static int shoc_clk_set_rate(struct clk *clk, unsigned long rate, int algo_id) +static int shoc_clk_set_rate(struct clk *clk, unsigned long rate) { unsigned long frqcr3; unsigned int tmp; diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c index 0fe2e9329cb2..271c0b325a9a 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c @@ -111,12 +111,21 @@ static struct clk div3_clk = { .parent = &pll_clk, }; +/* External input clock (pin name: FSIMCKA/FSIMCKB ) */ +struct clk sh7724_fsimcka_clk = { +}; + +struct clk sh7724_fsimckb_clk = { +}; + static struct clk *main_clks[] = { &r_clk, &extal_clk, &fll_clk, &pll_clk, &div3_clk, + &sh7724_fsimcka_clk, + &sh7724_fsimckb_clk, }; static void div4_kick(struct clk *clk) @@ -154,16 +163,38 @@ struct clk div4_clks[DIV4_NR] = { [DIV4_M1] = DIV4(FRQCRB, 4, 0x2f7c, CLK_ENABLE_ON_INIT), }; -enum { DIV6_V, DIV6_FA, DIV6_FB, DIV6_I, DIV6_S, DIV6_NR }; +enum { DIV6_V, DIV6_I, DIV6_S, DIV6_NR }; static struct clk div6_clks[DIV6_NR] = { [DIV6_V] = SH_CLK_DIV6(&div3_clk, VCLKCR, 0), - [DIV6_FA] = SH_CLK_DIV6(&div3_clk, FCLKACR, 0), - [DIV6_FB] = SH_CLK_DIV6(&div3_clk, FCLKBCR, 0), [DIV6_I] = SH_CLK_DIV6(&div3_clk, IRDACLKCR, 0), [DIV6_S] = SH_CLK_DIV6(&div3_clk, SPUCLKCR, CLK_ENABLE_ON_INIT), }; +enum { DIV6_FA, DIV6_FB, DIV6_REPARENT_NR }; + +/* Indices are important - they are the actual src selecting values */ +static struct clk *fclkacr_parent[] = { + [0] = &div3_clk, + [1] = NULL, + [2] = &sh7724_fsimcka_clk, + [3] = NULL, +}; + +static struct clk *fclkbcr_parent[] = { + [0] = &div3_clk, + [1] = NULL, + [2] = &sh7724_fsimckb_clk, + [3] = NULL, +}; + +static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = { + [DIV6_FA] = SH_CLK_DIV6_EXT(&div3_clk, FCLKACR, 0, + fclkacr_parent, ARRAY_SIZE(fclkacr_parent), 6, 2), + [DIV6_FB] = SH_CLK_DIV6_EXT(&div3_clk, FCLKBCR, 0, + fclkbcr_parent, ARRAY_SIZE(fclkbcr_parent), 6, 2), +}; + static struct clk mstp_clks[HWBLK_NR] = { SH_HWBLK_CLK(HWBLK_TLB, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT), SH_HWBLK_CLK(HWBLK_IC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT), @@ -240,8 +271,8 @@ static struct clk_lookup lookups[] = { /* DIV6 clocks */ CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]), - CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FA]), - CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FB]), + CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FA]), + CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FB]), CLKDEV_CON_ID("irda_clk", &div6_clks[DIV6_I]), CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_S]), @@ -376,6 +407,9 @@ int __init arch_clk_init(void) ret = sh_clk_div6_register(div6_clks, DIV6_NR); if (!ret) + ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR); + + if (!ret) ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR); return ret; diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index 81f58371613d..8c6a350df751 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c @@ -88,7 +88,7 @@ asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len, int op) } if (op & CACHEFLUSH_I) - flush_cache_all(); + flush_icache_range(addr, addr+len); up_read(¤t->mm->mmap_sem); return 0; diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S index e872e81add8a..6fc347ebe59d 100644 --- a/arch/sh/kernel/syscalls_32.S +++ b/arch/sh/kernel/syscalls_32.S @@ -375,3 +375,4 @@ ENTRY(sys_call_table) .long sys_sendmsg /* 355 */ .long sys_recvmsg .long sys_recvmmsg + .long sys_accept4 diff --git a/arch/sh/kernel/vsyscall/vsyscall-trapa.S b/arch/sh/kernel/vsyscall/vsyscall-trapa.S index 3b6eb34c43fa..3e70f851cdc6 100644 --- a/arch/sh/kernel/vsyscall/vsyscall-trapa.S +++ b/arch/sh/kernel/vsyscall/vsyscall-trapa.S @@ -8,9 +8,9 @@ __kernel_vsyscall: * fill out .eh_frame -- PFM. */ .LEND_vsyscall: .size __kernel_vsyscall,.-.LSTART_vsyscall - .previous .section .eh_frame,"a",@progbits + .previous .LCIE: .ualong .LCIE_end - .LCIE_start .LCIE_start: diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 2cfae81914aa..92eb98633ab0 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -114,7 +114,7 @@ static void sh4_flush_dcache_page(void *arg) struct address_space *mapping = page_mapping(page); if (mapping && !mapping_mapped(mapping)) - set_bit(PG_dcache_dirty, &page->flags); + clear_bit(PG_dcache_clean, &page->flags); else #endif flush_cache_one(CACHE_OC_ADDRESS_ARRAY | @@ -239,7 +239,7 @@ static void sh4_flush_cache_page(void *args) * another ASID than the current one. */ map_coherent = (current_cpu_data.dcache.n_aliases && - !test_bit(PG_dcache_dirty, &page->flags) && + test_bit(PG_dcache_clean, &page->flags) && page_mapped(page)); if (map_coherent) vaddr = kmap_coherent(page, address); diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index f498da1cce7a..7729cca727eb 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c @@ -139,7 +139,7 @@ static void sh7705_flush_dcache_page(void *arg) struct address_space *mapping = page_mapping(page); if (mapping && !mapping_mapped(mapping)) - set_bit(PG_dcache_dirty, &page->flags); + clear_bit(PG_dcache_clean, &page->flags); else __flush_dcache_page(__pa(page_address(page))); } diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index ba401d137bb9..88d3dc3d30d5 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -60,14 +60,14 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page, unsigned long len) { if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && - !test_bit(PG_dcache_dirty, &page->flags)) { + test_bit(PG_dcache_clean, &page->flags)) { void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); memcpy(vto, src, len); kunmap_coherent(vto); } else { memcpy(dst, src, len); if (boot_cpu_data.dcache.n_aliases) - set_bit(PG_dcache_dirty, &page->flags); + clear_bit(PG_dcache_clean, &page->flags); } if (vma->vm_flags & VM_EXEC) @@ -79,14 +79,14 @@ void copy_from_user_page(struct vm_area_struct *vma, struct page *page, unsigned long len) { if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && - !test_bit(PG_dcache_dirty, &page->flags)) { + test_bit(PG_dcache_clean, &page->flags)) { void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); memcpy(dst, vfrom, len); kunmap_coherent(vfrom); } else { memcpy(dst, src, len); if (boot_cpu_data.dcache.n_aliases) - set_bit(PG_dcache_dirty, &page->flags); + clear_bit(PG_dcache_clean, &page->flags); } } @@ -98,7 +98,7 @@ void copy_user_highpage(struct page *to, struct page *from, vto = kmap_atomic(to, KM_USER1); if (boot_cpu_data.dcache.n_aliases && page_mapped(from) && - !test_bit(PG_dcache_dirty, &from->flags)) { + test_bit(PG_dcache_clean, &from->flags)) { vfrom = kmap_coherent(from, vaddr); copy_page(vto, vfrom); kunmap_coherent(vfrom); @@ -141,7 +141,7 @@ void __update_cache(struct vm_area_struct *vma, page = pfn_to_page(pfn); if (pfn_valid(pfn)) { - int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); + int dirty = !test_and_set_bit(PG_dcache_clean, &page->flags); if (dirty) __flush_purge_region(page_address(page), PAGE_SIZE); } @@ -153,7 +153,7 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr) if (pages_do_alias(addr, vmaddr)) { if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && - !test_bit(PG_dcache_dirty, &page->flags)) { + test_bit(PG_dcache_clean, &page->flags)) { void *kaddr; kaddr = kmap_coherent(page, vmaddr); diff --git a/arch/sh/mm/kmap.c b/arch/sh/mm/kmap.c index 15d74ea42094..ec29e14ec5a8 100644 --- a/arch/sh/mm/kmap.c +++ b/arch/sh/mm/kmap.c @@ -34,7 +34,7 @@ void *kmap_coherent(struct page *page, unsigned long addr) enum fixed_addresses idx; unsigned long vaddr; - BUG_ON(test_bit(PG_dcache_dirty, &page->flags)); + BUG_ON(!test_bit(PG_dcache_clean, &page->flags)); pagefault_disable(); diff --git a/arch/sparc/include/asm/openprom.h b/arch/sparc/include/asm/openprom.h index 81cd43432dc0..47eaafad15ce 100644 --- a/arch/sparc/include/asm/openprom.h +++ b/arch/sparc/include/asm/openprom.h @@ -39,7 +39,7 @@ struct linux_dev_v2_funcs { int (*v2_dev_open)(char *devpath); void (*v2_dev_close)(int d); int (*v2_dev_read)(int d, char *buf, int nbytes); - int (*v2_dev_write)(int d, char *buf, int nbytes); + int (*v2_dev_write)(int d, const char *buf, int nbytes); int (*v2_dev_seek)(int d, int hi, int lo); /* Never issued (multistage load support) */ diff --git a/arch/sparc/include/asm/oplib_32.h b/arch/sparc/include/asm/oplib_32.h index 51296a6f5005..9e5c64084b86 100644 --- a/arch/sparc/include/asm/oplib_32.h +++ b/arch/sparc/include/asm/oplib_32.h @@ -60,25 +60,6 @@ extern char *prom_getbootargs(void); extern char *prom_mapio(char *virt_hint, int io_space, unsigned int phys_addr, unsigned int num_bytes); extern void prom_unmapio(char *virt_addr, unsigned int num_bytes); -/* Device operations. */ - -/* Open the device described by the passed string. Note, that the format - * of the string is different on V0 vs. V2->higher proms. The caller must - * know what he/she is doing! Returns the device descriptor, an int. - */ -extern int prom_devopen(char *device_string); - -/* Close a previously opened device described by the passed integer - * descriptor. - */ -extern int prom_devclose(int device_handle); - -/* Do a seek operation on the device described by the passed integer - * descriptor. - */ -extern void prom_seek(int device_handle, unsigned int seek_hival, - unsigned int seek_lowval); - /* Miscellaneous routines, don't really fit in any category per se. */ /* Reboot the machine with the command line passed. */ @@ -121,19 +102,8 @@ extern int prom_getrev(void); /* Get the prom firmware revision. */ extern int prom_getprev(void); -/* Character operations to/from the console.... */ - -/* Non-blocking get character from console. */ -extern int prom_nbgetchar(void); - -/* Non-blocking put character to console. */ -extern int prom_nbputchar(char character); - -/* Blocking get character from console. */ -extern char prom_getchar(void); - -/* Blocking put character to console. */ -extern void prom_putchar(char character); +/* Write a buffer of characters to the console. */ +extern void prom_console_write_buf(const char *buf, int len); /* Prom's internal routines, don't use in kernel/boot code. */ extern void prom_printf(const char *fmt, ...); @@ -238,7 +208,6 @@ extern int prom_node_has_property(phandle node, char *property); extern int prom_setprop(phandle node, const char *prop_name, char *prop_value, int value_size); -extern phandle prom_pathtoinode(char *path); extern phandle prom_inst2pkg(int); /* Dorking with Bus ranges... */ diff --git a/arch/sparc/include/asm/oplib_64.h b/arch/sparc/include/asm/oplib_64.h index c9cc078e3e31..8cd0df34e82b 100644 --- a/arch/sparc/include/asm/oplib_64.h +++ b/arch/sparc/include/asm/oplib_64.h @@ -67,27 +67,6 @@ extern void prom_init(void *cif_handler, void *cif_stack); /* Boot argument acquisition, returns the boot command line string. */ extern char *prom_getbootargs(void); -/* Device utilities. */ - -/* Device operations. */ - -/* Open the device described by the passed string. Note, that the format - * of the string is different on V0 vs. V2->higher proms. The caller must - * know what he/she is doing! Returns the device descriptor, an int. - */ -extern int prom_devopen(const char *device_string); - -/* Close a previously opened device described by the passed integer - * descriptor. - */ -extern int prom_devclose(int device_handle); - -/* Do a seek operation on the device described by the passed integer - * descriptor. - */ -extern void prom_seek(int device_handle, unsigned int seek_hival, - unsigned int seek_lowval); - /* Miscellaneous routines, don't really fit in any category per se. */ /* Reboot the machine with the command line passed. */ @@ -109,33 +88,14 @@ extern void prom_halt(void) __attribute__ ((noreturn)); /* Halt and power-off the machine. */ extern void prom_halt_power_off(void) __attribute__ ((noreturn)); -/* Set the PROM 'sync' callback function to the passed function pointer. - * When the user gives the 'sync' command at the prom prompt while the - * kernel is still active, the prom will call this routine. - * - */ -typedef int (*callback_func_t)(long *cmd); -extern void prom_setcallback(callback_func_t func_ptr); - /* Acquire the IDPROM of the root node in the prom device tree. This * gets passed a buffer where you would like it stuffed. The return value * is the format type of this idprom or 0xff on error. */ extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size); -/* Character operations to/from the console.... */ - -/* Non-blocking get character from console. */ -extern int prom_nbgetchar(void); - -/* Non-blocking put character to console. */ -extern int prom_nbputchar(char character); - -/* Blocking get character from console. */ -extern char prom_getchar(void); - -/* Blocking put character to console. */ -extern void prom_putchar(char character); +/* Write a buffer of characters to the console. */ +extern void prom_console_write_buf(const char *buf, int len); /* Prom's internal routines, don't use in kernel/boot code. */ extern void prom_printf(const char *fmt, ...); @@ -279,9 +239,7 @@ extern phandle prom_finddevice(const char *name); extern int prom_setprop(phandle node, const char *prop_name, char *prop_value, int value_size); -extern phandle prom_pathtoinode(const char *path); extern phandle prom_inst2pkg(int); -extern int prom_service_exists(const char *service_name); extern void prom_sun4v_guest_soft_state(void); extern int prom_ihandle2path(int handle, char *buffer, int bufsize); diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 2d51527d810f..f01c42661ee5 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -114,7 +114,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) if (leon3_gptimer_regs && leon3_irqctrl_regs) { LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].val, 0); LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].rld, - (((1000000 / 100) - 1))); + (((1000000 / HZ) - 1))); LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0); #ifdef CONFIG_SMP @@ -128,7 +128,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) } LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].val, 0); - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/100) - 1))); + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/HZ) - 1))); LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0); # endif diff --git a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile index 1b8c073adb44..816c0fa12dc0 100644 --- a/arch/sparc/prom/Makefile +++ b/arch/sparc/prom/Makefile @@ -6,7 +6,6 @@ ccflags := -Werror lib-y := bootstr_$(BITS).o lib-$(CONFIG_SPARC32) += devmap.o -lib-y += devops_$(BITS).o lib-y += init_$(BITS).o lib-$(CONFIG_SPARC32) += memory.o lib-y += misc_$(BITS).o diff --git a/arch/sparc/prom/console_32.c b/arch/sparc/prom/console_32.c index 5340264b78f5..48863108a44c 100644 --- a/arch/sparc/prom/console_32.c +++ b/arch/sparc/prom/console_32.c @@ -16,63 +16,26 @@ extern void restore_current(void); -/* Non blocking get character from console input device, returns -1 - * if no input was taken. This can be used for polling. - */ -int -prom_nbgetchar(void) -{ - static char inc; - int i = -1; - unsigned long flags; - - spin_lock_irqsave(&prom_lock, flags); - switch(prom_vers) { - case PROM_V0: - i = (*(romvec->pv_nbgetchar))(); - break; - case PROM_V2: - case PROM_V3: - if( (*(romvec->pv_v2devops).v2_dev_read)(*romvec->pv_v2bootargs.fd_stdin , &inc, 0x1) == 1) { - i = inc; - } else { - i = -1; - } - break; - default: - i = -1; - break; - }; - restore_current(); - spin_unlock_irqrestore(&prom_lock, flags); - return i; /* Ugh, we could spin forever on unsupported proms ;( */ -} - /* Non blocking put character to console device, returns -1 if * unsuccessful. */ -int -prom_nbputchar(char c) +static int prom_nbputchar(const char *buf) { - static char outc; unsigned long flags; int i = -1; spin_lock_irqsave(&prom_lock, flags); switch(prom_vers) { case PROM_V0: - i = (*(romvec->pv_nbputchar))(c); + i = (*(romvec->pv_nbputchar))(*buf); break; case PROM_V2: case PROM_V3: - outc = c; - if( (*(romvec->pv_v2devops).v2_dev_write)(*romvec->pv_v2bootargs.fd_stdout, &outc, 0x1) == 1) + if ((*(romvec->pv_v2devops).v2_dev_write)(*romvec->pv_v2bootargs.fd_stdout, + buf, 0x1) == 1) i = 0; - else - i = -1; break; default: - i = -1; break; }; restore_current(); @@ -80,18 +43,14 @@ prom_nbputchar(char c) return i; /* Ugh, we could spin forever on unsupported proms ;( */ } -/* Blocking version of get character routine above. */ -char -prom_getchar(void) +void prom_console_write_buf(const char *buf, int len) { - int character; - while((character = prom_nbgetchar()) == -1) ; - return (char) character; + while (len) { + int n = prom_nbputchar(buf); + if (n) + continue; + len--; + buf++; + } } -/* Blocking version of put character routine above. */ -void -prom_putchar(char c) -{ - while(prom_nbputchar(c) == -1) ; -} diff --git a/arch/sparc/prom/console_64.c b/arch/sparc/prom/console_64.c index 10322dc2f557..ed39e75828bd 100644 --- a/arch/sparc/prom/console_64.c +++ b/arch/sparc/prom/console_64.c @@ -15,85 +15,34 @@ extern int prom_stdin, prom_stdout; -/* Non blocking get character from console input device, returns -1 - * if no input was taken. This can be used for polling. - */ -inline int -prom_nbgetchar(void) -{ - unsigned long args[7]; - char inc; - - args[0] = (unsigned long) "read"; - args[1] = 3; - args[2] = 1; - args[3] = (unsigned int) prom_stdin; - args[4] = (unsigned long) &inc; - args[5] = 1; - args[6] = (unsigned long) -1; - - p1275_cmd_direct(args); - - if (args[6] == 1) - return inc; - return -1; -} - -/* Non blocking put character to console device, returns -1 if - * unsuccessful. - */ -inline int -prom_nbputchar(char c) +static int __prom_console_write_buf(const char *buf, int len) { unsigned long args[7]; - char outc; - - outc = c; + int ret; args[0] = (unsigned long) "write"; args[1] = 3; args[2] = 1; args[3] = (unsigned int) prom_stdout; - args[4] = (unsigned long) &outc; - args[5] = 1; + args[4] = (unsigned long) buf; + args[5] = (unsigned int) len; args[6] = (unsigned long) -1; p1275_cmd_direct(args); - if (args[6] == 1) - return 0; - else + ret = (int) args[6]; + if (ret < 0) return -1; + return ret; } -/* Blocking version of get character routine above. */ -char -prom_getchar(void) -{ - int character; - while((character = prom_nbgetchar()) == -1) ; - return (char) character; -} - -/* Blocking version of put character routine above. */ -void -prom_putchar(char c) +void prom_console_write_buf(const char *buf, int len) { - prom_nbputchar(c); -} - -void -prom_puts(const char *s, int len) -{ - unsigned long args[7]; - - args[0] = (unsigned long) "write"; - args[1] = 3; - args[2] = 1; - args[3] = (unsigned int) prom_stdout; - args[4] = (unsigned long) s; - args[5] = len; - args[6] = (unsigned long) -1; - - p1275_cmd_direct(args); + while (len) { + int n = __prom_console_write_buf(buf, len); + if (n < 0) + continue; + len -= n; + buf += len; + } } diff --git a/arch/sparc/prom/devops_32.c b/arch/sparc/prom/devops_32.c deleted file mode 100644 index 9c5d4687242a..000000000000 --- a/arch/sparc/prom/devops_32.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * devops.c: Device operations using the PROM. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/sched.h> - -#include <asm/openprom.h> -#include <asm/oplib.h> - -extern void restore_current(void); - -/* Open the device described by the string 'dstr'. Returns the handle - * to that device used for subsequent operations on that device. - * Returns -1 on failure. - */ -int -prom_devopen(char *dstr) -{ - int handle; - unsigned long flags; - spin_lock_irqsave(&prom_lock, flags); - switch(prom_vers) { - case PROM_V0: - handle = (*(romvec->pv_v0devops.v0_devopen))(dstr); - if(handle == 0) handle = -1; - break; - case PROM_V2: - case PROM_V3: - handle = (*(romvec->pv_v2devops.v2_dev_open))(dstr); - break; - default: - handle = -1; - break; - }; - restore_current(); - spin_unlock_irqrestore(&prom_lock, flags); - - return handle; -} - -/* Close the device described by device handle 'dhandle'. */ -int -prom_devclose(int dhandle) -{ - unsigned long flags; - spin_lock_irqsave(&prom_lock, flags); - switch(prom_vers) { - case PROM_V0: - (*(romvec->pv_v0devops.v0_devclose))(dhandle); - break; - case PROM_V2: - case PROM_V3: - (*(romvec->pv_v2devops.v2_dev_close))(dhandle); - break; - default: - break; - }; - restore_current(); - spin_unlock_irqrestore(&prom_lock, flags); - return 0; -} - -/* Seek to specified location described by 'seekhi' and 'seeklo' - * for device 'dhandle'. - */ -void -prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) -{ - unsigned long flags; - spin_lock_irqsave(&prom_lock, flags); - switch(prom_vers) { - case PROM_V0: - (*(romvec->pv_v0devops.v0_seekdev))(dhandle, seekhi, seeklo); - break; - case PROM_V2: - case PROM_V3: - (*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo); - break; - default: - break; - }; - restore_current(); - spin_unlock_irqrestore(&prom_lock, flags); -} diff --git a/arch/sparc/prom/devops_64.c b/arch/sparc/prom/devops_64.c deleted file mode 100644 index a017119e7ef1..000000000000 --- a/arch/sparc/prom/devops_64.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * devops.c: Device operations using the PROM. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - */ -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/sched.h> - -#include <asm/openprom.h> -#include <asm/oplib.h> - -/* Open the device described by the string 'dstr'. Returns the handle - * to that device used for subsequent operations on that device. - * Returns 0 on failure. - */ -int -prom_devopen(const char *dstr) -{ - unsigned long args[5]; - - args[0] = (unsigned long) "open"; - args[1] = 1; - args[2] = 1; - args[3] = (unsigned long) dstr; - args[4] = (unsigned long) -1; - - p1275_cmd_direct(args); - - return (int) args[4]; -} - -/* Close the device described by device handle 'dhandle'. */ -int -prom_devclose(int dhandle) -{ - unsigned long args[4]; - - args[0] = (unsigned long) "close"; - args[1] = 1; - args[2] = 0; - args[3] = (unsigned int) dhandle; - - p1275_cmd_direct(args); - - return 0; -} - -/* Seek to specified location described by 'seekhi' and 'seeklo' - * for device 'dhandle'. - */ -void -prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) -{ - unsigned long args[7]; - - args[0] = (unsigned long) "seek"; - args[1] = 3; - args[2] = 1; - args[3] = (unsigned int) dhandle; - args[4] = seekhi; - args[5] = seeklo; - args[6] = (unsigned long) -1; - - p1275_cmd_direct(args); -} diff --git a/arch/sparc/prom/misc_64.c b/arch/sparc/prom/misc_64.c index d24bc44e361e..e4f31d4d3715 100644 --- a/arch/sparc/prom/misc_64.c +++ b/arch/sparc/prom/misc_64.c @@ -18,7 +18,7 @@ #include <asm/system.h> #include <asm/ldc.h> -int prom_service_exists(const char *service_name) +static int prom_service_exists(const char *service_name) { unsigned long args[5]; @@ -150,20 +150,6 @@ void prom_halt_power_off(void) prom_halt(); } -/* Set prom sync handler to call function 'funcp'. */ -void prom_setcallback(callback_func_t funcp) -{ - unsigned long args[5]; - if (!funcp) - return; - args[0] = (unsigned long) "set-callback"; - args[1] = 1; - args[2] = 1; - args[3] = (unsigned long) funcp; - args[4] = (unsigned long) -1; - p1275_cmd_direct(args); -} - /* Get the idprom and stuff it into buffer 'idbuf'. Returns the * format type. 'num_bytes' is the number of bytes that your idbuf * has space for. Returns 0xff on error. diff --git a/arch/sparc/prom/printf.c b/arch/sparc/prom/printf.c index ca869266b9f3..d9682f06b3b0 100644 --- a/arch/sparc/prom/printf.c +++ b/arch/sparc/prom/printf.c @@ -15,22 +15,45 @@ #include <linux/kernel.h> #include <linux/compiler.h> +#include <linux/spinlock.h> #include <asm/openprom.h> #include <asm/oplib.h> +#define CONSOLE_WRITE_BUF_SIZE 1024 + static char ppbuf[1024]; +static char console_write_buf[CONSOLE_WRITE_BUF_SIZE]; +static DEFINE_RAW_SPINLOCK(console_write_lock); void notrace prom_write(const char *buf, unsigned int n) { - char ch; + unsigned int dest_len; + unsigned long flags; + char *dest; + + dest = console_write_buf; + raw_spin_lock_irqsave(&console_write_lock, flags); - while (n != 0) { - --n; - if ((ch = *buf++) == '\n') - prom_putchar('\r'); - prom_putchar(ch); + dest_len = 0; + while (n-- != 0) { + char ch = *buf++; + if (ch == '\n') { + *dest++ = '\r'; + dest_len++; + } + *dest++ = ch; + dest_len++; + if (dest_len >= CONSOLE_WRITE_BUF_SIZE - 1) { + prom_console_write_buf(console_write_buf, dest_len); + dest = console_write_buf; + dest_len = 0; + } } + if (dest_len) + prom_console_write_buf(console_write_buf, dest_len); + + raw_spin_unlock_irqrestore(&console_write_lock, flags); } void notrace prom_printf(const char *fmt, ...) diff --git a/arch/sparc/prom/tree_32.c b/arch/sparc/prom/tree_32.c index 63e08e149774..535e2e69ac1d 100644 --- a/arch/sparc/prom/tree_32.c +++ b/arch/sparc/prom/tree_32.c @@ -342,19 +342,3 @@ phandle prom_inst2pkg(int inst) if (node == -1) return 0; return node; } - -/* Return 'node' assigned to a particular prom 'path' - * FIXME: Should work for v0 as well - */ -phandle prom_pathtoinode(char *path) -{ - phandle node; - int inst; - - inst = prom_devopen (path); - if (inst == -1) return 0; - node = prom_inst2pkg (inst); - prom_devclose (inst); - if (node == -1) return 0; - return node; -} diff --git a/arch/sparc/prom/tree_64.c b/arch/sparc/prom/tree_64.c index 691be68932f8..d93660048376 100644 --- a/arch/sparc/prom/tree_64.c +++ b/arch/sparc/prom/tree_64.c @@ -374,24 +374,6 @@ inline phandle prom_inst2pkg(int inst) return node; } -/* Return 'node' assigned to a particular prom 'path' - * FIXME: Should work for v0 as well - */ -phandle prom_pathtoinode(const char *path) -{ - phandle node; - int inst; - - inst = prom_devopen (path); - if (inst == 0) - return 0; - node = prom_inst2pkg(inst); - prom_devclose(inst); - if (node == -1) - return 0; - return node; -} - int prom_ihandle2path(int handle, char *buffer, int bufsize) { unsigned long args[7]; diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 07ec8a865c1d..e11b5fcb70eb 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -329,6 +329,18 @@ endmenu # Tilera-specific configuration menu "Bus options" +config PCI + bool "PCI support" + default y + select PCI_DOMAINS + ---help--- + Enable PCI root complex support, so PCIe endpoint devices can + be attached to the Tile chip. Many, but not all, PCI devices + are supported under Tilera's root complex driver. + +config PCI_DOMAINS + bool + config NO_IOMEM def_bool !PCI diff --git a/arch/tile/include/asm/cacheflush.h b/arch/tile/include/asm/cacheflush.h index c5741da4eeac..14a3f8556ace 100644 --- a/arch/tile/include/asm/cacheflush.h +++ b/arch/tile/include/asm/cacheflush.h @@ -137,4 +137,56 @@ static inline void finv_buffer(void *buffer, size_t size) mb_incoherent(); } +/* + * Flush & invalidate a VA range that is homed remotely on a single core, + * waiting until the memory controller holds the flushed values. + */ +static inline void finv_buffer_remote(void *buffer, size_t size) +{ + char *p; + int i; + + /* + * Flush and invalidate the buffer out of the local L1/L2 + * and request the home cache to flush and invalidate as well. + */ + __finv_buffer(buffer, size); + + /* + * Wait for the home cache to acknowledge that it has processed + * all the flush-and-invalidate requests. This does not mean + * that the flushed data has reached the memory controller yet, + * but it does mean the home cache is processing the flushes. + */ + __insn_mf(); + + /* + * Issue a load to the last cache line, which can't complete + * until all the previously-issued flushes to the same memory + * controller have also completed. If we weren't striping + * memory, that one load would be sufficient, but since we may + * be, we also need to back up to the last load issued to + * another memory controller, which would be the point where + * we crossed an 8KB boundary (the granularity of striping + * across memory controllers). Keep backing up and doing this + * until we are before the beginning of the buffer, or have + * hit all the controllers. + */ + for (i = 0, p = (char *)buffer + size - 1; + i < (1 << CHIP_LOG_NUM_MSHIMS()) && p >= (char *)buffer; + ++i) { + const unsigned long STRIPE_WIDTH = 8192; + + /* Force a load instruction to issue. */ + *(volatile char *)p; + + /* Jump to end of previous stripe. */ + p -= STRIPE_WIDTH; + p = (char *)((unsigned long)p | (STRIPE_WIDTH - 1)); + } + + /* Wait for the loads (and thus flushes) to have completed. */ + __insn_mf(); +} + #endif /* _ASM_TILE_CACHEFLUSH_H */ diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h index ee43328713ab..d3cbb9b14cbe 100644 --- a/arch/tile/include/asm/io.h +++ b/arch/tile/include/asm/io.h @@ -55,9 +55,6 @@ extern void iounmap(volatile void __iomem *addr); #define ioremap_writethrough(physaddr, size) ioremap(physaddr, size) #define ioremap_fullcache(physaddr, size) ioremap(physaddr, size) -void __iomem *ioport_map(unsigned long port, unsigned int len); -extern inline void ioport_unmap(void __iomem *addr) {} - #define mmiowb() /* Conversion between virtual and physical mappings. */ @@ -189,12 +186,22 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, * we never run, uses them unconditionally. */ -static inline int ioport_panic(void) +static inline long ioport_panic(void) { panic("inb/outb and friends do not exist on tile"); return 0; } +static inline void __iomem *ioport_map(unsigned long port, unsigned int len) +{ + return (void __iomem *) ioport_panic(); +} + +static inline void ioport_unmap(void __iomem *addr) +{ + ioport_panic(); +} + static inline u8 inb(unsigned long addr) { return ioport_panic(); diff --git a/arch/tile/include/asm/pci-bridge.h b/arch/tile/include/asm/pci-bridge.h deleted file mode 100644 index e853b0e2793b..000000000000 --- a/arch/tile/include/asm/pci-bridge.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2010 Tilera 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, version 2. - * - * 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. - */ - -#ifndef _ASM_TILE_PCI_BRIDGE_H -#define _ASM_TILE_PCI_BRIDGE_H - -#include <linux/ioport.h> -#include <linux/pci.h> - -struct device_node; -struct pci_controller; - -/* - * pci_io_base returns the memory address at which you can access - * the I/O space for PCI bus number `bus' (or NULL on error). - */ -extern void __iomem *pci_bus_io_base(unsigned int bus); -extern unsigned long pci_bus_io_base_phys(unsigned int bus); -extern unsigned long pci_bus_mem_base_phys(unsigned int bus); - -/* Allocate a new PCI host bridge structure */ -extern struct pci_controller *pcibios_alloc_controller(void); - -/* Helper function for setting up resources */ -extern void pci_init_resource(struct resource *res, unsigned long start, - unsigned long end, int flags, char *name); - -/* Get the PCI host controller for a bus */ -extern struct pci_controller *pci_bus_to_hose(int bus); - -/* - * Structure of a PCI controller (host bridge) - */ -struct pci_controller { - int index; /* PCI domain number */ - struct pci_bus *root_bus; - - int first_busno; - int last_busno; - - int hv_cfg_fd[2]; /* config{0,1} fds for this PCIe controller */ - int hv_mem_fd; /* fd to Hypervisor for MMIO operations */ - - struct pci_ops *ops; - - int irq_base; /* Base IRQ from the Hypervisor */ - int plx_gen1; /* flag for PLX Gen 1 configuration */ - - /* Address ranges that are routed to this controller/bridge. */ - struct resource mem_resources[3]; -}; - -static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus) -{ - return bus->sysdata; -} - -extern void setup_indirect_pci_nomap(struct pci_controller *hose, - void __iomem *cfg_addr, void __iomem *cfg_data); -extern void setup_indirect_pci(struct pci_controller *hose, - u32 cfg_addr, u32 cfg_data); -extern void setup_grackle(struct pci_controller *hose); - -extern unsigned char common_swizzle(struct pci_dev *, unsigned char *); - -/* - * The following code swizzles for exactly one bridge. The routine - * common_swizzle below handles multiple bridges. But there are a - * some boards that don't follow the PCI spec's suggestion so we - * break this piece out separately. - */ -static inline unsigned char bridge_swizzle(unsigned char pin, - unsigned char idsel) -{ - return (((pin-1) + idsel) % 4) + 1; -} - -/* - * The following macro is used to lookup irqs in a standard table - * format for those PPC systems that do not already have PCI - * interrupts properly routed. - */ -/* FIXME - double check this */ -#define PCI_IRQ_TABLE_LOOKUP ({ \ - long _ctl_ = -1; \ - if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot) \ - _ctl_ = pci_irq_table[idsel - min_idsel][pin-1]; \ - _ctl_; \ -}) - -/* - * Scan the buses below a given PCI host bridge and assign suitable - * resources to all devices found. - */ -extern int pciauto_bus_scan(struct pci_controller *, int); - -#ifdef CONFIG_PCI -extern unsigned long pci_address_to_pio(phys_addr_t address); -#else -static inline unsigned long pci_address_to_pio(phys_addr_t address) -{ - return (unsigned long)-1; -} -#endif - -#endif /* _ASM_TILE_PCI_BRIDGE_H */ diff --git a/arch/tile/include/asm/pci.h b/arch/tile/include/asm/pci.h index b0c15da2d5d5..c3fc458a0d32 100644 --- a/arch/tile/include/asm/pci.h +++ b/arch/tile/include/asm/pci.h @@ -15,7 +15,29 @@ #ifndef _ASM_TILE_PCI_H #define _ASM_TILE_PCI_H -#include <asm/pci-bridge.h> +#include <linux/pci.h> + +/* + * Structure of a PCI controller (host bridge) + */ +struct pci_controller { + int index; /* PCI domain number */ + struct pci_bus *root_bus; + + int first_busno; + int last_busno; + + int hv_cfg_fd[2]; /* config{0,1} fds for this PCIe controller */ + int hv_mem_fd; /* fd to Hypervisor for MMIO operations */ + + struct pci_ops *ops; + + int irq_base; /* Base IRQ from the Hypervisor */ + int plx_gen1; /* flag for PLX Gen 1 configuration */ + + /* Address ranges that are routed to this controller/bridge. */ + struct resource mem_resources[3]; +}; /* * The hypervisor maps the entirety of CPA-space as bus addresses, so @@ -24,56 +46,12 @@ */ #define PCI_DMA_BUS_IS_PHYS 1 -struct pci_controller *pci_bus_to_hose(int bus); -unsigned char __init common_swizzle(struct pci_dev *dev, unsigned char *pinp); int __init tile_pci_init(void); -void pci_iounmap(struct pci_dev *dev, void __iomem *addr); -void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); -void __devinit pcibios_fixup_bus(struct pci_bus *bus); -int __devinit _tile_cfg_read(struct pci_controller *hose, - int bus, - int slot, - int function, - int offset, - int size, - u32 *val); -int __devinit _tile_cfg_write(struct pci_controller *hose, - int bus, - int slot, - int function, - int offset, - int size, - u32 val); +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); +static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {} -/* - * These are used to to config reads and writes in the early stages of - * setup before the driver infrastructure has been set up enough to be - * able to do config reads and writes. - */ -#define early_cfg_read(where, size, value) \ - _tile_cfg_read(controller, \ - current_bus, \ - pci_slot, \ - pci_fn, \ - where, \ - size, \ - value) - -#define early_cfg_write(where, size, value) \ - _tile_cfg_write(controller, \ - current_bus, \ - pci_slot, \ - pci_fn, \ - where, \ - size, \ - value) - - - -#define PCICFG_BYTE 1 -#define PCICFG_WORD 2 -#define PCICFG_DWORD 4 +void __devinit pcibios_fixup_bus(struct pci_bus *bus); #define TILE_NUM_PCIE 2 @@ -88,33 +66,33 @@ static inline int pci_proc_domain(struct pci_bus *bus) } /* - * I/O space is currently not supported. + * pcibios_assign_all_busses() tells whether or not the bus numbers + * should be reassigned, in case the BIOS didn't do it correctly, or + * in case we don't have a BIOS and we want to let Linux do it. */ +static inline int pcibios_assign_all_busses(void) +{ + return 1; +} -#define TILE_PCIE_LOWER_IO 0x0 -#define TILE_PCIE_UPPER_IO 0x10000 -#define TILE_PCIE_PCIE_IO_SIZE 0x0000FFFF - -#define _PAGE_NO_CACHE 0 -#define _PAGE_GUARDED 0 - - -#define pcibios_assign_all_busses() pci_assign_all_buses -extern int pci_assign_all_buses; - +/* + * No special bus mastering setup handling. + */ static inline void pcibios_set_master(struct pci_dev *dev) { - /* No special bus mastering setup handling */ } #define PCIBIOS_MIN_MEM 0 -#define PCIBIOS_MIN_IO TILE_PCIE_LOWER_IO +#define PCIBIOS_MIN_IO 0 /* * This flag tells if the platform is TILEmpower that needs * special configuration for the PLX switch chip. */ -extern int blade_pci; +extern int tile_plx_gen1; + +/* Use any cpu for PCI. */ +#define cpumask_of_pcibus(bus) cpu_online_mask /* implement the pci_ DMA API in terms of the generic device dma_ one */ #include <asm-generic/pci-dma-compat.h> @@ -122,7 +100,4 @@ extern int blade_pci; /* generic pci stuff */ #include <asm-generic/pci.h> -/* Use any cpu for PCI. */ -#define cpumask_of_pcibus(bus) cpu_online_mask - #endif /* _ASM_TILE_PCI_H */ diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h index 1747ff3946b2..a9e7c8760334 100644 --- a/arch/tile/include/asm/processor.h +++ b/arch/tile/include/asm/processor.h @@ -292,8 +292,18 @@ extern int kstack_hash; /* Are we using huge pages in the TLB for kernel data? */ extern int kdata_huge; +/* Support standard Linux prefetching. */ +#define ARCH_HAS_PREFETCH +#define prefetch(x) __builtin_prefetch(x) #define PREFETCH_STRIDE CHIP_L2_LINE_SIZE() +/* Bring a value into the L1D, faulting the TLB if necessary. */ +#ifdef __tilegx__ +#define prefetch_L1(x) __insn_prefetch_l1_fault((void *)(x)) +#else +#define prefetch_L1(x) __insn_prefetch_L1((void *)(x)) +#endif + #else /* __ASSEMBLY__ */ /* Do some slow action (e.g. read a slow SPR). */ diff --git a/arch/tile/include/asm/signal.h b/arch/tile/include/asm/signal.h index c1ee1d61d44c..81d92a45cd4b 100644 --- a/arch/tile/include/asm/signal.h +++ b/arch/tile/include/asm/signal.h @@ -25,7 +25,7 @@ #if defined(__KERNEL__) && !defined(__ASSEMBLY__) struct pt_regs; -int restore_sigcontext(struct pt_regs *, struct sigcontext __user *, long *); +int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); int setup_sigcontext(struct sigcontext __user *, struct pt_regs *); void do_signal(struct pt_regs *regs); #endif diff --git a/arch/tile/include/hv/drv_xgbe_impl.h b/arch/tile/include/hv/drv_xgbe_impl.h new file mode 100644 index 000000000000..3a73b2b44913 --- /dev/null +++ b/arch/tile/include/hv/drv_xgbe_impl.h @@ -0,0 +1,300 @@ +/* + * Copyright 2010 Tilera 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, version 2. + * + * 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. + */ + +/** + * @file drivers/xgbe/impl.h + * Implementation details for the NetIO library. + */ + +#ifndef __DRV_XGBE_IMPL_H__ +#define __DRV_XGBE_IMPL_H__ + +#include <hv/netio_errors.h> +#include <hv/netio_intf.h> +#include <hv/drv_xgbe_intf.h> + + +/** How many groups we have (log2). */ +#define LOG2_NUM_GROUPS (12) +/** How many groups we have. */ +#define NUM_GROUPS (1 << LOG2_NUM_GROUPS) + +/** Number of output requests we'll buffer per tile. */ +#define EPP_REQS_PER_TILE (32) + +/** Words used in an eDMA command without checksum acceleration. */ +#define EDMA_WDS_NO_CSUM 8 +/** Words used in an eDMA command with checksum acceleration. */ +#define EDMA_WDS_CSUM 10 +/** Total available words in the eDMA command FIFO. */ +#define EDMA_WDS_TOTAL 128 + + +/* + * FIXME: These definitions are internal and should have underscores! + * NOTE: The actual numeric values here are intentional and allow us to + * optimize the concept "if small ... else if large ... else ...", by + * checking for the low bit being set, and then for non-zero. + * These are used as array indices, so they must have the values (0, 1, 2) + * in some order. + */ +#define SIZE_SMALL (1) /**< Small packet queue. */ +#define SIZE_LARGE (2) /**< Large packet queue. */ +#define SIZE_JUMBO (0) /**< Jumbo packet queue. */ + +/** The number of "SIZE_xxx" values. */ +#define NETIO_NUM_SIZES 3 + + +/* + * Default numbers of packets for IPP drivers. These values are chosen + * such that CIPP1 will not overflow its L2 cache. + */ + +/** The default number of small packets. */ +#define NETIO_DEFAULT_SMALL_PACKETS 2750 +/** The default number of large packets. */ +#define NETIO_DEFAULT_LARGE_PACKETS 2500 +/** The default number of jumbo packets. */ +#define NETIO_DEFAULT_JUMBO_PACKETS 250 + + +/** Log2 of the size of a memory arena. */ +#define NETIO_ARENA_SHIFT 24 /* 16 MB */ +/** Size of a memory arena. */ +#define NETIO_ARENA_SIZE (1 << NETIO_ARENA_SHIFT) + + +/** A queue of packets. + * + * This structure partially defines a queue of packets waiting to be + * processed. The queue as a whole is written to by an interrupt handler and + * read by non-interrupt code; this data structure is what's touched by the + * interrupt handler. The other part of the queue state, the read offset, is + * kept in user space, not in hypervisor space, so it is in a separate data + * structure. + * + * The read offset (__packet_receive_read in the user part of the queue + * structure) points to the next packet to be read. When the read offset is + * equal to the write offset, the queue is empty; therefore the queue must + * contain one more slot than the required maximum queue size. + * + * Here's an example of all 3 state variables and what they mean. All + * pointers move left to right. + * + * @code + * I I V V V V I I I I + * 0 1 2 3 4 5 6 7 8 9 10 + * ^ ^ ^ ^ + * | | | + * | | __last_packet_plus_one + * | __buffer_write + * __packet_receive_read + * @endcode + * + * This queue has 10 slots, and thus can hold 9 packets (_last_packet_plus_one + * = 10). The read pointer is at 2, and the write pointer is at 6; thus, + * there are valid, unread packets in slots 2, 3, 4, and 5. The remaining + * slots are invalid (do not contain a packet). + */ +typedef struct { + /** Byte offset of the next notify packet to be written: zero for the first + * packet on the queue, sizeof (netio_pkt_t) for the second packet on the + * queue, etc. */ + volatile uint32_t __packet_write; + + /** Offset of the packet after the last valid packet (i.e., when any + * pointer is incremented to this value, it wraps back to zero). */ + uint32_t __last_packet_plus_one; +} +__netio_packet_queue_t; + + +/** A queue of buffers. + * + * This structure partially defines a queue of empty buffers which have been + * obtained via requests to the IPP. (The elements of the queue are packet + * handles, which are transformed into a full netio_pkt_t when the buffer is + * retrieved.) The queue as a whole is written to by an interrupt handler and + * read by non-interrupt code; this data structure is what's touched by the + * interrupt handler. The other parts of the queue state, the read offset and + * requested write offset, are kept in user space, not in hypervisor space, so + * they are in a separate data structure. + * + * The read offset (__buffer_read in the user part of the queue structure) + * points to the next buffer to be read. When the read offset is equal to the + * write offset, the queue is empty; therefore the queue must contain one more + * slot than the required maximum queue size. + * + * The requested write offset (__buffer_requested_write in the user part of + * the queue structure) points to the slot which will hold the next buffer we + * request from the IPP, once we get around to sending such a request. When + * the requested write offset is equal to the write offset, no requests for + * new buffers are outstanding; when the requested write offset is one greater + * than the read offset, no more requests may be sent. + * + * Note that, unlike the packet_queue, the buffer_queue places incoming + * buffers at decreasing addresses. This makes the check for "is it time to + * wrap the buffer pointer" cheaper in the assembly code which receives new + * buffers, and means that the value which defines the queue size, + * __last_buffer, is different than in the packet queue. Also, the offset + * used in the packet_queue is already scaled by the size of a packet; here we + * use unscaled slot indices for the offsets. (These differences are + * historical, and in the future it's possible that the packet_queue will look + * more like this queue.) + * + * @code + * Here's an example of all 4 state variables and what they mean. Remember: + * all pointers move right to left. + * + * V V V I I R R V V V + * 0 1 2 3 4 5 6 7 8 9 + * ^ ^ ^ ^ + * | | | | + * | | | __last_buffer + * | | __buffer_write + * | __buffer_requested_write + * __buffer_read + * @endcode + * + * This queue has 10 slots, and thus can hold 9 buffers (_last_buffer = 9). + * The read pointer is at 2, and the write pointer is at 6; thus, there are + * valid, unread buffers in slots 2, 1, 0, 9, 8, and 7. The requested write + * pointer is at 4; thus, requests have been made to the IPP for buffers which + * will be placed in slots 6 and 5 when they arrive. Finally, the remaining + * slots are invalid (do not contain a buffer). + */ +typedef struct +{ + /** Ordinal number of the next buffer to be written: 0 for the first slot in + * the queue, 1 for the second slot in the queue, etc. */ + volatile uint32_t __buffer_write; + + /** Ordinal number of the last buffer (i.e., when any pointer is decremented + * below zero, it is reloaded with this value). */ + uint32_t __last_buffer; +} +__netio_buffer_queue_t; + + +/** + * An object for providing Ethernet packets to a process. + */ +typedef struct __netio_queue_impl_t +{ + /** The queue of packets waiting to be received. */ + __netio_packet_queue_t __packet_receive_queue; + /** The intr bit mask that IDs this device. */ + unsigned int __intr_id; + /** Offset to queues of empty buffers, one per size. */ + uint32_t __buffer_queue[NETIO_NUM_SIZES]; + /** The address of the first EPP tile, or -1 if no EPP. */ + /* ISSUE: Actually this is always "0" or "~0". */ + uint32_t __epp_location; + /** The queue ID that this queue represents. */ + unsigned int __queue_id; + /** Number of acknowledgements received. */ + volatile uint32_t __acks_received; + /** Last completion number received for packet_sendv. */ + volatile uint32_t __last_completion_rcv; + /** Number of packets allowed to be outstanding. */ + uint32_t __max_outstanding; + /** First VA available for packets. */ + void* __va_0; + /** First VA in second range available for packets. */ + void* __va_1; + /** Padding to align the "__packets" field to the size of a netio_pkt_t. */ + uint32_t __padding[3]; + /** The packets themselves. */ + netio_pkt_t __packets[0]; +} +netio_queue_impl_t; + + +/** + * An object for managing the user end of a NetIO queue. + */ +typedef struct __netio_queue_user_impl_t +{ + /** The next incoming packet to be read. */ + uint32_t __packet_receive_read; + /** The next empty buffers to be read, one index per size. */ + uint8_t __buffer_read[NETIO_NUM_SIZES]; + /** Where the empty buffer we next request from the IPP will go, one index + * per size. */ + uint8_t __buffer_requested_write[NETIO_NUM_SIZES]; + /** PCIe interface flag. */ + uint8_t __pcie; + /** Number of packets left to be received before we send a credit update. */ + uint32_t __receive_credit_remaining; + /** Value placed in __receive_credit_remaining when it reaches zero. */ + uint32_t __receive_credit_interval; + /** First fast I/O routine index. */ + uint32_t __fastio_index; + /** Number of acknowledgements expected. */ + uint32_t __acks_outstanding; + /** Last completion number requested. */ + uint32_t __last_completion_req; + /** File descriptor for driver. */ + int __fd; +} +netio_queue_user_impl_t; + + +#define NETIO_GROUP_CHUNK_SIZE 64 /**< Max # groups in one IPP request */ +#define NETIO_BUCKET_CHUNK_SIZE 64 /**< Max # buckets in one IPP request */ + + +/** Internal structure used to convey packet send information to the + * hypervisor. FIXME: Actually, it's not used for that anymore, but + * netio_packet_send() still uses it internally. + */ +typedef struct +{ + uint16_t flags; /**< Packet flags (__NETIO_SEND_FLG_xxx) */ + uint16_t transfer_size; /**< Size of packet */ + uint32_t va; /**< VA of start of packet */ + __netio_pkt_handle_t handle; /**< Packet handle */ + uint32_t csum0; /**< First checksum word */ + uint32_t csum1; /**< Second checksum word */ +} +__netio_send_cmd_t; + + +/** Flags used in two contexts: + * - As the "flags" member in the __netio_send_cmd_t, above; used only + * for netio_pkt_send_{prepare,commit}. + * - As part of the flags passed to the various send packet fast I/O calls. + */ + +/** Need acknowledgement on this packet. Note that some code in the + * normal send_pkt fast I/O handler assumes that this is equal to 1. */ +#define __NETIO_SEND_FLG_ACK 0x1 + +/** Do checksum on this packet. (Only used with the __netio_send_cmd_t; + * normal packet sends use a special fast I/O index to denote checksumming, + * and multi-segment sends test the checksum descriptor.) */ +#define __NETIO_SEND_FLG_CSUM 0x2 + +/** Get a completion on this packet. Only used with multi-segment sends. */ +#define __NETIO_SEND_FLG_COMPLETION 0x4 + +/** Position of the number-of-extra-segments value in the flags word. + Only used with multi-segment sends. */ +#define __NETIO_SEND_FLG_XSEG_SHIFT 3 + +/** Width of the number-of-extra-segments value in the flags word. */ +#define __NETIO_SEND_FLG_XSEG_WIDTH 2 + +#endif /* __DRV_XGBE_IMPL_H__ */ diff --git a/arch/tile/include/hv/drv_xgbe_intf.h b/arch/tile/include/hv/drv_xgbe_intf.h new file mode 100644 index 000000000000..146e47d5334b --- /dev/null +++ b/arch/tile/include/hv/drv_xgbe_intf.h @@ -0,0 +1,615 @@ +/* + * Copyright 2010 Tilera 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, version 2. + * + * 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. + */ + +/** + * @file drv_xgbe_intf.h + * Interface to the hypervisor XGBE driver. + */ + +#ifndef __DRV_XGBE_INTF_H__ +#define __DRV_XGBE_INTF_H__ + +/** + * An object for forwarding VAs and PAs to the hypervisor. + * @ingroup types + * + * This allows the supervisor to specify a number of areas of memory to + * store packet buffers. + */ +typedef struct +{ + /** The physical address of the memory. */ + HV_PhysAddr pa; + /** Page table entry for the memory. This is only used to derive the + * memory's caching mode; the PA bits are ignored. */ + HV_PTE pte; + /** The virtual address of the memory. */ + HV_VirtAddr va; + /** Size (in bytes) of the memory area. */ + int size; + +} +netio_ipp_address_t; + +/** The various pread/pwrite offsets into the hypervisor-level driver. + * @ingroup types + */ +typedef enum +{ + /** Inform the Linux driver of the address of the NetIO arena memory. + * This offset is actually only used to convey information from netio + * to the Linux driver; it never makes it from there to the hypervisor. + * Write-only; takes a uint32_t specifying the VA address. */ + NETIO_FIXED_ADDR = 0x5000000000000000ULL, + + /** Inform the Linux driver of the size of the NetIO arena memory. + * This offset is actually only used to convey information from netio + * to the Linux driver; it never makes it from there to the hypervisor. + * Write-only; takes a uint32_t specifying the VA size. */ + NETIO_FIXED_SIZE = 0x5100000000000000ULL, + + /** Register current tile with IPP. Write then read: write, takes a + * netio_input_config_t, read returns a pointer to a netio_queue_impl_t. */ + NETIO_IPP_INPUT_REGISTER_OFF = 0x6000000000000000ULL, + + /** Unregister current tile from IPP. Write-only, takes a dummy argument. */ + NETIO_IPP_INPUT_UNREGISTER_OFF = 0x6100000000000000ULL, + + /** Start packets flowing. Write-only, takes a dummy argument. */ + NETIO_IPP_INPUT_INIT_OFF = 0x6200000000000000ULL, + + /** Stop packets flowing. Write-only, takes a dummy argument. */ + NETIO_IPP_INPUT_UNINIT_OFF = 0x6300000000000000ULL, + + /** Configure group (typically we group on VLAN). Write-only: takes an + * array of netio_group_t's, low 24 bits of the offset is the base group + * number times the size of a netio_group_t. */ + NETIO_IPP_INPUT_GROUP_CFG_OFF = 0x6400000000000000ULL, + + /** Configure bucket. Write-only: takes an array of netio_bucket_t's, low + * 24 bits of the offset is the base bucket number times the size of a + * netio_bucket_t. */ + NETIO_IPP_INPUT_BUCKET_CFG_OFF = 0x6500000000000000ULL, + + /** Get/set a parameter. Read or write: read or write data is the parameter + * value, low 32 bits of the offset is a __netio_getset_offset_t. */ + NETIO_IPP_PARAM_OFF = 0x6600000000000000ULL, + + /** Get fast I/O index. Read-only; returns a 4-byte base index value. */ + NETIO_IPP_GET_FASTIO_OFF = 0x6700000000000000ULL, + + /** Configure hijack IP address. Packets with this IPv4 dest address + * go to bucket NETIO_NUM_BUCKETS - 1. Write-only: takes an IP address + * in some standard form. FIXME: Define the form! */ + NETIO_IPP_INPUT_HIJACK_CFG_OFF = 0x6800000000000000ULL, + + /** + * Offsets beyond this point are reserved for the supervisor (although that + * enforcement must be done by the supervisor driver itself). + */ + NETIO_IPP_USER_MAX_OFF = 0x6FFFFFFFFFFFFFFFULL, + + /** Register I/O memory. Write-only, takes a netio_ipp_address_t. */ + NETIO_IPP_IOMEM_REGISTER_OFF = 0x7000000000000000ULL, + + /** Unregister I/O memory. Write-only, takes a netio_ipp_address_t. */ + NETIO_IPP_IOMEM_UNREGISTER_OFF = 0x7100000000000000ULL, + + /* Offsets greater than 0x7FFFFFFF can't be used directly from Linux + * userspace code due to limitations in the pread/pwrite syscalls. */ + + /** Drain LIPP buffers. */ + NETIO_IPP_DRAIN_OFF = 0xFA00000000000000ULL, + + /** Supply a netio_ipp_address_t to be used as shared memory for the + * LEPP command queue. */ + NETIO_EPP_SHM_OFF = 0xFB00000000000000ULL, + + /* 0xFC... is currently unused. */ + + /** Stop IPP/EPP tiles. Write-only, takes a dummy argument. */ + NETIO_IPP_STOP_SHIM_OFF = 0xFD00000000000000ULL, + + /** Start IPP/EPP tiles. Write-only, takes a dummy argument. */ + NETIO_IPP_START_SHIM_OFF = 0xFE00000000000000ULL, + + /** Supply packet arena. Write-only, takes an array of + * netio_ipp_address_t values. */ + NETIO_IPP_ADDRESS_OFF = 0xFF00000000000000ULL, +} netio_hv_offset_t; + +/** Extract the base offset from an offset */ +#define NETIO_BASE_OFFSET(off) ((off) & 0xFF00000000000000ULL) +/** Extract the local offset from an offset */ +#define NETIO_LOCAL_OFFSET(off) ((off) & 0x00FFFFFFFFFFFFFFULL) + + +/** + * Get/set offset. + */ +typedef union +{ + struct + { + uint64_t addr:48; /**< Class-specific address */ + unsigned int class:8; /**< Class (e.g., NETIO_PARAM) */ + unsigned int opcode:8; /**< High 8 bits of NETIO_IPP_PARAM_OFF */ + } + bits; /**< Bitfields */ + uint64_t word; /**< Aggregated value to use as the offset */ +} +__netio_getset_offset_t; + +/** + * Fast I/O index offsets (must be contiguous). + */ +typedef enum +{ + NETIO_FASTIO_ALLOCATE = 0, /**< Get empty packet buffer */ + NETIO_FASTIO_FREE_BUFFER = 1, /**< Give buffer back to IPP */ + NETIO_FASTIO_RETURN_CREDITS = 2, /**< Give credits to IPP */ + NETIO_FASTIO_SEND_PKT_NOCK = 3, /**< Send a packet, no checksum */ + NETIO_FASTIO_SEND_PKT_CK = 4, /**< Send a packet, with checksum */ + NETIO_FASTIO_SEND_PKT_VEC = 5, /**< Send a vector of packets */ + NETIO_FASTIO_SENDV_PKT = 6, /**< Sendv one packet */ + NETIO_FASTIO_NUM_INDEX = 7, /**< Total number of fast I/O indices */ +} netio_fastio_index_t; + +/** 3-word return type for Fast I/O call. */ +typedef struct +{ + int err; /**< Error code. */ + uint32_t val0; /**< Value. Meaning depends upon the specific call. */ + uint32_t val1; /**< Value. Meaning depends upon the specific call. */ +} netio_fastio_rv3_t; + +/** 0-argument fast I/O call */ +int __netio_fastio0(uint32_t fastio_index); +/** 1-argument fast I/O call */ +int __netio_fastio1(uint32_t fastio_index, uint32_t arg0); +/** 3-argument fast I/O call, 2-word return value */ +netio_fastio_rv3_t __netio_fastio3_rv3(uint32_t fastio_index, uint32_t arg0, + uint32_t arg1, uint32_t arg2); +/** 4-argument fast I/O call */ +int __netio_fastio4(uint32_t fastio_index, uint32_t arg0, uint32_t arg1, + uint32_t arg2, uint32_t arg3); +/** 6-argument fast I/O call */ +int __netio_fastio6(uint32_t fastio_index, uint32_t arg0, uint32_t arg1, + uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5); +/** 9-argument fast I/O call */ +int __netio_fastio9(uint32_t fastio_index, uint32_t arg0, uint32_t arg1, + uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5, + uint32_t arg6, uint32_t arg7, uint32_t arg8); + +/** Allocate an empty packet. + * @param fastio_index Fast I/O index. + * @param size Size of the packet to allocate. + */ +#define __netio_fastio_allocate(fastio_index, size) \ + __netio_fastio1((fastio_index) + NETIO_FASTIO_ALLOCATE, size) + +/** Free a buffer. + * @param fastio_index Fast I/O index. + * @param handle Handle for the packet to free. + */ +#define __netio_fastio_free_buffer(fastio_index, handle) \ + __netio_fastio1((fastio_index) + NETIO_FASTIO_FREE_BUFFER, handle) + +/** Increment our receive credits. + * @param fastio_index Fast I/O index. + * @param credits Number of credits to add. + */ +#define __netio_fastio_return_credits(fastio_index, credits) \ + __netio_fastio1((fastio_index) + NETIO_FASTIO_RETURN_CREDITS, credits) + +/** Send packet, no checksum. + * @param fastio_index Fast I/O index. + * @param ackflag Nonzero if we want an ack. + * @param size Size of the packet. + * @param va Virtual address of start of packet. + * @param handle Packet handle. + */ +#define __netio_fastio_send_pkt_nock(fastio_index, ackflag, size, va, handle) \ + __netio_fastio4((fastio_index) + NETIO_FASTIO_SEND_PKT_NOCK, ackflag, \ + size, va, handle) + +/** Send packet, calculate checksum. + * @param fastio_index Fast I/O index. + * @param ackflag Nonzero if we want an ack. + * @param size Size of the packet. + * @param va Virtual address of start of packet. + * @param handle Packet handle. + * @param csum0 Shim checksum header. + * @param csum1 Checksum seed. + */ +#define __netio_fastio_send_pkt_ck(fastio_index, ackflag, size, va, handle, \ + csum0, csum1) \ + __netio_fastio6((fastio_index) + NETIO_FASTIO_SEND_PKT_CK, ackflag, \ + size, va, handle, csum0, csum1) + + +/** Format for the "csum0" argument to the __netio_fastio_send routines + * and LEPP. Note that this is currently exactly identical to the + * ShimProtocolOffloadHeader. + */ +typedef union +{ + struct + { + unsigned int start_byte:7; /**< The first byte to be checksummed */ + unsigned int count:14; /**< Number of bytes to be checksummed. */ + unsigned int destination_byte:7; /**< The byte to write the checksum to. */ + unsigned int reserved:4; /**< Reserved. */ + } bits; /**< Decomposed method of access. */ + unsigned int word; /**< To send out the IDN. */ +} __netio_checksum_header_t; + + +/** Sendv packet with 1 or 2 segments. + * @param fastio_index Fast I/O index. + * @param flags Ack/csum/notify flags in low 3 bits; number of segments minus + * 1 in next 2 bits; expected checksum in high 16 bits. + * @param confno Confirmation number to request, if notify flag set. + * @param csum0 Checksum descriptor; if zero, no checksum. + * @param va_F Virtual address of first segment. + * @param va_L Virtual address of last segment, if 2 segments. + * @param len_F_L Length of first segment in low 16 bits; length of last + * segment, if 2 segments, in high 16 bits. + */ +#define __netio_fastio_sendv_pkt_1_2(fastio_index, flags, confno, csum0, \ + va_F, va_L, len_F_L) \ + __netio_fastio6((fastio_index) + NETIO_FASTIO_SENDV_PKT, flags, confno, \ + csum0, va_F, va_L, len_F_L) + +/** Send packet on PCIe interface. + * @param fastio_index Fast I/O index. + * @param flags Ack/csum/notify flags in low 3 bits. + * @param confno Confirmation number to request, if notify flag set. + * @param csum0 Checksum descriptor; Hard wired 0, not needed for PCIe. + * @param va_F Virtual address of the packet buffer. + * @param va_L Virtual address of last segment, if 2 segments. Hard wired 0. + * @param len_F_L Length of the packet buffer in low 16 bits. + */ +#define __netio_fastio_send_pcie_pkt(fastio_index, flags, confno, csum0, \ + va_F, va_L, len_F_L) \ + __netio_fastio6((fastio_index) + PCIE_FASTIO_SENDV_PKT, flags, confno, \ + csum0, va_F, va_L, len_F_L) + +/** Sendv packet with 3 or 4 segments. + * @param fastio_index Fast I/O index. + * @param flags Ack/csum/notify flags in low 3 bits; number of segments minus + * 1 in next 2 bits; expected checksum in high 16 bits. + * @param confno Confirmation number to request, if notify flag set. + * @param csum0 Checksum descriptor; if zero, no checksum. + * @param va_F Virtual address of first segment. + * @param va_L Virtual address of last segment (third segment if 3 segments, + * fourth segment if 4 segments). + * @param len_F_L Length of first segment in low 16 bits; length of last + * segment in high 16 bits. + * @param va_M0 Virtual address of "middle 0" segment; this segment is sent + * second when there are three segments, and third if there are four. + * @param va_M1 Virtual address of "middle 1" segment; this segment is sent + * second when there are four segments. + * @param len_M0_M1 Length of middle 0 segment in low 16 bits; length of middle + * 1 segment, if 4 segments, in high 16 bits. + */ +#define __netio_fastio_sendv_pkt_3_4(fastio_index, flags, confno, csum0, va_F, \ + va_L, len_F_L, va_M0, va_M1, len_M0_M1) \ + __netio_fastio9((fastio_index) + NETIO_FASTIO_SENDV_PKT, flags, confno, \ + csum0, va_F, va_L, len_F_L, va_M0, va_M1, len_M0_M1) + +/** Send vector of packets. + * @param fastio_index Fast I/O index. + * @param seqno Number of packets transmitted so far on this interface; + * used to decide which packets should be acknowledged. + * @param nentries Number of entries in vector. + * @param va Virtual address of start of vector entry array. + * @return 3-word netio_fastio_rv3_t structure. The structure's err member + * is an error code, or zero if no error. The val0 member is the + * updated value of seqno; it has been incremented by 1 for each + * packet sent. That increment may be less than nentries if an + * error occured, or if some of the entries in the vector contain + * handles equal to NETIO_PKT_HANDLE_NONE. The val1 member is the + * updated value of nentries; it has been decremented by 1 for each + * vector entry processed. Again, that decrement may be less than + * nentries (leaving the returned value positive) if an error + * occurred. + */ +#define __netio_fastio_send_pkt_vec(fastio_index, seqno, nentries, va) \ + __netio_fastio3_rv3((fastio_index) + NETIO_FASTIO_SEND_PKT_VEC, seqno, \ + nentries, va) + + +/** An egress DMA command for LEPP. */ +typedef struct +{ + /** Is this a TSO transfer? + * + * NOTE: This field is always 0, to distinguish it from + * lepp_tso_cmd_t. It must come first! + */ + uint8_t tso : 1; + + /** Unused padding bits. */ + uint8_t _unused : 3; + + /** Should this packet be sent directly from caches instead of DRAM, + * using hash-for-home to locate the packet data? + */ + uint8_t hash_for_home : 1; + + /** Should we compute a checksum? */ + uint8_t compute_checksum : 1; + + /** Is this the final buffer for this packet? + * + * A single packet can be split over several input buffers (a "gather" + * operation). This flag indicates that this is the last buffer + * in a packet. + */ + uint8_t end_of_packet : 1; + + /** Should LEPP advance 'comp_busy' when this DMA is fully finished? */ + uint8_t send_completion : 1; + + /** High bits of Client Physical Address of the start of the buffer + * to be egressed. + * + * NOTE: Only 6 bits are actually needed here, as CPAs are + * currently 38 bits. So two bits could be scavenged from this. + */ + uint8_t cpa_hi; + + /** The number of bytes to be egressed. */ + uint16_t length; + + /** Low 32 bits of Client Physical Address of the start of the buffer + * to be egressed. + */ + uint32_t cpa_lo; + + /** Checksum information (only used if 'compute_checksum'). */ + __netio_checksum_header_t checksum_data; + +} lepp_cmd_t; + + +/** A chunk of physical memory for a TSO egress. */ +typedef struct +{ + /** The low bits of the CPA. */ + uint32_t cpa_lo; + /** The high bits of the CPA. */ + uint16_t cpa_hi : 15; + /** Should this packet be sent directly from caches instead of DRAM, + * using hash-for-home to locate the packet data? + */ + uint16_t hash_for_home : 1; + /** The length in bytes. */ + uint16_t length; +} lepp_frag_t; + + +/** An LEPP command that handles TSO. */ +typedef struct +{ + /** Is this a TSO transfer? + * + * NOTE: This field is always 1, to distinguish it from + * lepp_cmd_t. It must come first! + */ + uint8_t tso : 1; + + /** Unused padding bits. */ + uint8_t _unused : 7; + + /** Size of the header[] array in bytes. It must be in the range + * [40, 127], which are the smallest header for a TCP packet over + * Ethernet and the maximum possible prepend size supported by + * hardware, respectively. Note that the array storage must be + * padded out to a multiple of four bytes so that the following + * LEPP command is aligned properly. + */ + uint8_t header_size; + + /** Byte offset of the IP header in header[]. */ + uint8_t ip_offset; + + /** Byte offset of the TCP header in header[]. */ + uint8_t tcp_offset; + + /** The number of bytes to use for the payload of each packet, + * except of course the last one, which may not have enough bytes. + * This means that each Ethernet packet except the last will have a + * size of header_size + payload_size. + */ + uint16_t payload_size; + + /** The length of the 'frags' array that follows this struct. */ + uint16_t num_frags; + + /** The actual frags. */ + lepp_frag_t frags[0 /* Variable-sized; num_frags entries. */]; + + /* + * The packet header template logically follows frags[], + * but you can't declare that in C. + * + * uint32_t header[header_size_in_words_rounded_up]; + */ + +} lepp_tso_cmd_t; + + +/** An LEPP completion ring entry. */ +typedef void* lepp_comp_t; + + +/** Maximum number of frags for one TSO command. This is adapted from + * linux's "MAX_SKB_FRAGS", and presumably over-estimates by one, for + * our page size of exactly 65536. We add one for a "body" fragment. + */ +#define LEPP_MAX_FRAGS (65536 / HV_PAGE_SIZE_SMALL + 2 + 1) + +/** Total number of bytes needed for an lepp_tso_cmd_t. */ +#define LEPP_TSO_CMD_SIZE(num_frags, header_size) \ + (sizeof(lepp_tso_cmd_t) + \ + (num_frags) * sizeof(lepp_frag_t) + \ + (((header_size) + 3) & -4)) + +/** The size of the lepp "cmd" queue. */ +#define LEPP_CMD_QUEUE_BYTES \ + (((CHIP_L2_CACHE_SIZE() - 2 * CHIP_L2_LINE_SIZE()) / \ + (sizeof(lepp_cmd_t) + sizeof(lepp_comp_t))) * sizeof(lepp_cmd_t)) + +/** The largest possible command that can go in lepp_queue_t::cmds[]. */ +#define LEPP_MAX_CMD_SIZE LEPP_TSO_CMD_SIZE(LEPP_MAX_FRAGS, 128) + +/** The largest possible value of lepp_queue_t::cmd_{head, tail} (inclusive). + */ +#define LEPP_CMD_LIMIT \ + (LEPP_CMD_QUEUE_BYTES - LEPP_MAX_CMD_SIZE) + +/** The maximum number of completions in an LEPP queue. */ +#define LEPP_COMP_QUEUE_SIZE \ + ((LEPP_CMD_LIMIT + sizeof(lepp_cmd_t) - 1) / sizeof(lepp_cmd_t)) + +/** Increment an index modulo the queue size. */ +#define LEPP_QINC(var) \ + (var = __insn_mnz(var - (LEPP_COMP_QUEUE_SIZE - 1), var + 1)) + +/** A queue used to convey egress commands from the client to LEPP. */ +typedef struct +{ + /** Index of first completion not yet processed by user code. + * If this is equal to comp_busy, there are no such completions. + * + * NOTE: This is only read/written by the user. + */ + unsigned int comp_head; + + /** Index of first completion record not yet completed. + * If this is equal to comp_tail, there are no such completions. + * This index gets advanced (modulo LEPP_QUEUE_SIZE) whenever + * a command with the 'completion' bit set is finished. + * + * NOTE: This is only written by LEPP, only read by the user. + */ + volatile unsigned int comp_busy; + + /** Index of the first empty slot in the completion ring. + * Entries from this up to but not including comp_head (in ring order) + * can be filled in with completion data. + * + * NOTE: This is only read/written by the user. + */ + unsigned int comp_tail; + + /** Byte index of first command enqueued for LEPP but not yet processed. + * + * This is always divisible by sizeof(void*) and always <= LEPP_CMD_LIMIT. + * + * NOTE: LEPP advances this counter as soon as it no longer needs + * the cmds[] storage for this entry, but the transfer is not actually + * complete (i.e. the buffer pointed to by the command is no longer + * needed) until comp_busy advances. + * + * If this is equal to cmd_tail, the ring is empty. + * + * NOTE: This is only written by LEPP, only read by the user. + */ + volatile unsigned int cmd_head; + + /** Byte index of first empty slot in the command ring. This field can + * be incremented up to but not equal to cmd_head (because that would + * mean the ring is empty). + * + * This is always divisible by sizeof(void*) and always <= LEPP_CMD_LIMIT. + * + * NOTE: This is read/written by the user, only read by LEPP. + */ + volatile unsigned int cmd_tail; + + /** A ring of variable-sized egress DMA commands. + * + * NOTE: Only written by the user, only read by LEPP. + */ + char cmds[LEPP_CMD_QUEUE_BYTES] + __attribute__((aligned(CHIP_L2_LINE_SIZE()))); + + /** A ring of user completion data. + * NOTE: Only read/written by the user. + */ + lepp_comp_t comps[LEPP_COMP_QUEUE_SIZE] + __attribute__((aligned(CHIP_L2_LINE_SIZE()))); +} lepp_queue_t; + + +/** An internal helper function for determining the number of entries + * available in a ring buffer, given that there is one sentinel. + */ +static inline unsigned int +_lepp_num_free_slots(unsigned int head, unsigned int tail) +{ + /* + * One entry is reserved for use as a sentinel, to distinguish + * "empty" from "full". So we compute + * (head - tail - 1) % LEPP_QUEUE_SIZE, but without using a slow % operation. + */ + return (head - tail - 1) + ((head <= tail) ? LEPP_COMP_QUEUE_SIZE : 0); +} + + +/** Returns how many new comp entries can be enqueued. */ +static inline unsigned int +lepp_num_free_comp_slots(const lepp_queue_t* q) +{ + return _lepp_num_free_slots(q->comp_head, q->comp_tail); +} + +static inline int +lepp_qsub(int v1, int v2) +{ + int delta = v1 - v2; + return delta + ((delta >> 31) & LEPP_COMP_QUEUE_SIZE); +} + + +/** FIXME: Check this from linux, via a new "pwrite()" call. */ +#define LIPP_VERSION 1 + + +/** We use exactly two bytes of alignment padding. */ +#define LIPP_PACKET_PADDING 2 + +/** The minimum size of a "small" buffer (including the padding). */ +#define LIPP_SMALL_PACKET_SIZE 128 + +/* + * NOTE: The following two values should total to less than around + * 13582, to keep the total size used for "lipp_state_t" below 64K. + */ + +/** The maximum number of "small" buffers. + * This is enough for 53 network cpus with 128 credits. Note that + * if these are exhausted, we will fall back to using large buffers. + */ +#define LIPP_SMALL_BUFFERS 6785 + +/** The maximum number of "large" buffers. + * This is enough for 53 network cpus with 128 credits. + */ +#define LIPP_LARGE_BUFFERS 6785 + +#endif /* __DRV_XGBE_INTF_H__ */ diff --git a/arch/tile/include/hv/netio_errors.h b/arch/tile/include/hv/netio_errors.h new file mode 100644 index 000000000000..e1591bff61b5 --- /dev/null +++ b/arch/tile/include/hv/netio_errors.h @@ -0,0 +1,122 @@ +/* + * Copyright 2010 Tilera 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, version 2. + * + * 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. + */ + +/** + * Error codes returned from NetIO routines. + */ + +#ifndef __NETIO_ERRORS_H__ +#define __NETIO_ERRORS_H__ + +/** + * @addtogroup error + * + * @brief The error codes returned by NetIO functions. + * + * NetIO functions return 0 (defined as ::NETIO_NO_ERROR) on success, and + * a negative value if an error occurs. + * + * In cases where a NetIO function failed due to a error reported by + * system libraries, the error code will be the negation of the + * system errno at the time of failure. The @ref netio_strerror() + * function will deliver error strings for both NetIO and system error + * codes. + * + * @{ + */ + +/** The set of all NetIO errors. */ +typedef enum +{ + /** Operation successfully completed. */ + NETIO_NO_ERROR = 0, + + /** A packet was successfully retrieved from an input queue. */ + NETIO_PKT = 0, + + /** Largest NetIO error number. */ + NETIO_ERR_MAX = -701, + + /** The tile is not registered with the IPP. */ + NETIO_NOT_REGISTERED = -701, + + /** No packet was available to retrieve from the input queue. */ + NETIO_NOPKT = -702, + + /** The requested function is not implemented. */ + NETIO_NOT_IMPLEMENTED = -703, + + /** On a registration operation, the target queue already has the maximum + * number of tiles registered for it, and no more may be added. On a + * packet send operation, the output queue is full and nothing more can + * be queued until some of the queued packets are actually transmitted. */ + NETIO_QUEUE_FULL = -704, + + /** The calling process or thread is not bound to exactly one CPU. */ + NETIO_BAD_AFFINITY = -705, + + /** Cannot allocate memory on requested controllers. */ + NETIO_CANNOT_HOME = -706, + + /** On a registration operation, the IPP specified is not configured + * to support the options requested; for instance, the application + * wants a specific type of tagged headers which the configured IPP + * doesn't support. Or, the supplied configuration information is + * not self-consistent, or is out of range; for instance, specifying + * both NETIO_RECV and NETIO_NO_RECV, or asking for more than + * NETIO_MAX_SEND_BUFFERS to be preallocated. On a VLAN or bucket + * configure operation, the number of items, or the base item, was + * out of range. + */ + NETIO_BAD_CONFIG = -707, + + /** Too many tiles have registered to transmit packets. */ + NETIO_TOOMANY_XMIT = -708, + + /** Packet transmission was attempted on a queue which was registered + with transmit disabled. */ + NETIO_UNREG_XMIT = -709, + + /** This tile is already registered with the IPP. */ + NETIO_ALREADY_REGISTERED = -710, + + /** The Ethernet link is down. The application should try again later. */ + NETIO_LINK_DOWN = -711, + + /** An invalid memory buffer has been specified. This may be an unmapped + * virtual address, or one which does not meet alignment requirements. + * For netio_input_register(), this error may be returned when multiple + * processes specify different memory regions to be used for NetIO + * buffers. That can happen if these processes specify explicit memory + * regions with the ::NETIO_FIXED_BUFFER_VA flag, or if tmc_cmem_init() + * has not been called by a common ancestor of the processes. + */ + NETIO_FAULT = -712, + + /** Cannot combine user-managed shared memory and cache coherence. */ + NETIO_BAD_CACHE_CONFIG = -713, + + /** Smallest NetIO error number. */ + NETIO_ERR_MIN = -713, + +#ifndef __DOXYGEN__ + /** Used internally to mean that no response is needed; never returned to + * an application. */ + NETIO_NO_RESPONSE = 1 +#endif +} netio_error_t; + +/** @} */ + +#endif /* __NETIO_ERRORS_H__ */ diff --git a/arch/tile/include/hv/netio_intf.h b/arch/tile/include/hv/netio_intf.h new file mode 100644 index 000000000000..8d20972aba2c --- /dev/null +++ b/arch/tile/include/hv/netio_intf.h @@ -0,0 +1,2975 @@ +/* + * Copyright 2010 Tilera 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, version 2. + * + * 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. + */ + +/** + * NetIO interface structures and macros. + */ + +#ifndef __NETIO_INTF_H__ +#define __NETIO_INTF_H__ + +#include <hv/netio_errors.h> + +#ifdef __KERNEL__ +#include <linux/types.h> +#else +#include <stdint.h> +#endif + +#if !defined(__HV__) && !defined(__BOGUX__) && !defined(__KERNEL__) +#include <assert.h> +#define netio_assert assert /**< Enable assertions from macros */ +#else +#define netio_assert(...) ((void)(0)) /**< Disable assertions from macros */ +#endif + +/* + * If none of these symbols are defined, we're building libnetio in an + * environment where we have pthreads, so we'll enable locking. + */ +#if !defined(__HV__) && !defined(__BOGUX__) && !defined(__KERNEL__) && \ + !defined(__NEWLIB__) +#define _NETIO_PTHREAD /**< Include a mutex in netio_queue_t below */ + +/* + * If NETIO_UNLOCKED is defined, we don't do use per-cpu locks on + * per-packet NetIO operations. We still do pthread locking on things + * like netio_input_register, though. This is used for building + * libnetio_unlocked. + */ +#ifndef NETIO_UNLOCKED + +/* Avoid PLT overhead by using our own inlined per-cpu lock. */ +#include <sched.h> +typedef int _netio_percpu_mutex_t; + +static __inline int +_netio_percpu_mutex_init(_netio_percpu_mutex_t* lock) +{ + *lock = 0; + return 0; +} + +static __inline int +_netio_percpu_mutex_lock(_netio_percpu_mutex_t* lock) +{ + while (__builtin_expect(__insn_tns(lock), 0)) + sched_yield(); + return 0; +} + +static __inline int +_netio_percpu_mutex_unlock(_netio_percpu_mutex_t* lock) +{ + *lock = 0; + return 0; +} + +#else /* NETIO_UNLOCKED */ + +/* Don't do any locking for per-packet NetIO operations. */ +typedef int _netio_percpu_mutex_t; +#define _netio_percpu_mutex_init(L) +#define _netio_percpu_mutex_lock(L) +#define _netio_percpu_mutex_unlock(L) + +#endif /* NETIO_UNLOCKED */ +#endif /* !__HV__, !__BOGUX, !__KERNEL__, !__NEWLIB__ */ + +/** How many tiles can register for a given queue. + * @ingroup setup */ +#define NETIO_MAX_TILES_PER_QUEUE 64 + + +/** Largest permissible queue identifier. + * @ingroup setup */ +#define NETIO_MAX_QUEUE_ID 255 + + +#ifndef __DOXYGEN__ + +/* Metadata packet checksum/ethertype flags. */ + +/** The L4 checksum has not been calculated. */ +#define _NETIO_PKT_NO_L4_CSUM_SHIFT 0 +#define _NETIO_PKT_NO_L4_CSUM_RMASK 1 +#define _NETIO_PKT_NO_L4_CSUM_MASK \ + (_NETIO_PKT_NO_L4_CSUM_RMASK << _NETIO_PKT_NO_L4_CSUM_SHIFT) + +/** The L3 checksum has not been calculated. */ +#define _NETIO_PKT_NO_L3_CSUM_SHIFT 1 +#define _NETIO_PKT_NO_L3_CSUM_RMASK 1 +#define _NETIO_PKT_NO_L3_CSUM_MASK \ + (_NETIO_PKT_NO_L3_CSUM_RMASK << _NETIO_PKT_NO_L3_CSUM_SHIFT) + +/** The L3 checksum is incorrect (or perhaps has not been calculated). */ +#define _NETIO_PKT_BAD_L3_CSUM_SHIFT 2 +#define _NETIO_PKT_BAD_L3_CSUM_RMASK 1 +#define _NETIO_PKT_BAD_L3_CSUM_MASK \ + (_NETIO_PKT_BAD_L3_CSUM_RMASK << _NETIO_PKT_BAD_L3_CSUM_SHIFT) + +/** The Ethernet packet type is unrecognized. */ +#define _NETIO_PKT_TYPE_UNRECOGNIZED_SHIFT 3 +#define _NETIO_PKT_TYPE_UNRECOGNIZED_RMASK 1 +#define _NETIO_PKT_TYPE_UNRECOGNIZED_MASK \ + (_NETIO_PKT_TYPE_UNRECOGNIZED_RMASK << \ + _NETIO_PKT_TYPE_UNRECOGNIZED_SHIFT) + +/* Metadata packet type flags. */ + +/** Where the packet type bits are; this field is the index into + * _netio_pkt_info. */ +#define _NETIO_PKT_TYPE_SHIFT 4 +#define _NETIO_PKT_TYPE_RMASK 0x3F + +/** How many VLAN tags the packet has, and, if we have two, which one we + * actually grouped on. A VLAN within a proprietary (Marvell or Broadcom) + * tag is counted here. */ +#define _NETIO_PKT_VLAN_SHIFT 4 +#define _NETIO_PKT_VLAN_RMASK 0x3 +#define _NETIO_PKT_VLAN_MASK \ + (_NETIO_PKT_VLAN_RMASK << _NETIO_PKT_VLAN_SHIFT) +#define _NETIO_PKT_VLAN_NONE 0 /* No VLAN tag. */ +#define _NETIO_PKT_VLAN_ONE 1 /* One VLAN tag. */ +#define _NETIO_PKT_VLAN_TWO_OUTER 2 /* Two VLAN tags, outer one used. */ +#define _NETIO_PKT_VLAN_TWO_INNER 3 /* Two VLAN tags, inner one used. */ + +/** Which proprietary tags the packet has. */ +#define _NETIO_PKT_TAG_SHIFT 6 +#define _NETIO_PKT_TAG_RMASK 0x3 +#define _NETIO_PKT_TAG_MASK \ + (_NETIO_PKT_TAG_RMASK << _NETIO_PKT_TAG_SHIFT) +#define _NETIO_PKT_TAG_NONE 0 /* No proprietary tags. */ +#define _NETIO_PKT_TAG_MRVL 1 /* Marvell HyperG.Stack tags. */ +#define _NETIO_PKT_TAG_MRVL_EXT 2 /* HyperG.Stack extended tags. */ +#define _NETIO_PKT_TAG_BRCM 3 /* Broadcom HiGig tags. */ + +/** Whether a packet has an LLC + SNAP header. */ +#define _NETIO_PKT_SNAP_SHIFT 8 +#define _NETIO_PKT_SNAP_RMASK 0x1 +#define _NETIO_PKT_SNAP_MASK \ + (_NETIO_PKT_SNAP_RMASK << _NETIO_PKT_SNAP_SHIFT) + +/* NOTE: Bits 9 and 10 are unused. */ + +/** Length of any custom data before the L2 header, in words. */ +#define _NETIO_PKT_CUSTOM_LEN_SHIFT 11 +#define _NETIO_PKT_CUSTOM_LEN_RMASK 0x1F +#define _NETIO_PKT_CUSTOM_LEN_MASK \ + (_NETIO_PKT_CUSTOM_LEN_RMASK << _NETIO_PKT_CUSTOM_LEN_SHIFT) + +/** The L4 checksum is incorrect (or perhaps has not been calculated). */ +#define _NETIO_PKT_BAD_L4_CSUM_SHIFT 16 +#define _NETIO_PKT_BAD_L4_CSUM_RMASK 0x1 +#define _NETIO_PKT_BAD_L4_CSUM_MASK \ + (_NETIO_PKT_BAD_L4_CSUM_RMASK << _NETIO_PKT_BAD_L4_CSUM_SHIFT) + +/** Length of the L2 header, in words. */ +#define _NETIO_PKT_L2_LEN_SHIFT 17 +#define _NETIO_PKT_L2_LEN_RMASK 0x1F +#define _NETIO_PKT_L2_LEN_MASK \ + (_NETIO_PKT_L2_LEN_RMASK << _NETIO_PKT_L2_LEN_SHIFT) + + +/* Flags in minimal packet metadata. */ + +/** We need an eDMA checksum on this packet. */ +#define _NETIO_PKT_NEED_EDMA_CSUM_SHIFT 0 +#define _NETIO_PKT_NEED_EDMA_CSUM_RMASK 1 +#define _NETIO_PKT_NEED_EDMA_CSUM_MASK \ + (_NETIO_PKT_NEED_EDMA_CSUM_RMASK << _NETIO_PKT_NEED_EDMA_CSUM_SHIFT) + +/* Data within the packet information table. */ + +/* Note that, for efficiency, code which uses these fields assumes that none + * of the shift values below are zero. See uses below for an explanation. */ + +/** Offset within the L2 header of the innermost ethertype (in halfwords). */ +#define _NETIO_PKT_INFO_ETYPE_SHIFT 6 +#define _NETIO_PKT_INFO_ETYPE_RMASK 0x1F + +/** Offset within the L2 header of the VLAN tag (in halfwords). */ +#define _NETIO_PKT_INFO_VLAN_SHIFT 11 +#define _NETIO_PKT_INFO_VLAN_RMASK 0x1F + +#endif + + +/** The size of a memory buffer representing a small packet. + * @ingroup egress */ +#define SMALL_PACKET_SIZE 256 + +/** The size of a memory buffer representing a large packet. + * @ingroup egress */ +#define LARGE_PACKET_SIZE 2048 + +/** The size of a memory buffer representing a jumbo packet. + * @ingroup egress */ +#define JUMBO_PACKET_SIZE (12 * 1024) + + +/* Common ethertypes. + * @ingroup ingress */ +/** @{ */ +/** The ethertype of IPv4. */ +#define ETHERTYPE_IPv4 (0x0800) +/** The ethertype of ARP. */ +#define ETHERTYPE_ARP (0x0806) +/** The ethertype of VLANs. */ +#define ETHERTYPE_VLAN (0x8100) +/** The ethertype of a Q-in-Q header. */ +#define ETHERTYPE_Q_IN_Q (0x9100) +/** The ethertype of IPv6. */ +#define ETHERTYPE_IPv6 (0x86DD) +/** The ethertype of MPLS. */ +#define ETHERTYPE_MPLS (0x8847) +/** @} */ + + +/** The possible return values of NETIO_PKT_STATUS. + * @ingroup ingress + */ +typedef enum +{ + /** No problems were detected with this packet. */ + NETIO_PKT_STATUS_OK, + /** The packet is undersized; this is expected behavior if the packet's + * ethertype is unrecognized, but otherwise the packet is likely corrupt. */ + NETIO_PKT_STATUS_UNDERSIZE, + /** The packet is oversized and some trailing bytes have been discarded. + This is expected behavior for short packets, since it's impossible to + precisely determine the amount of padding which may have been added to + them to make them meet the minimum Ethernet packet size. */ + NETIO_PKT_STATUS_OVERSIZE, + /** The packet was judged to be corrupt by hardware (for instance, it had + a bad CRC, or part of it was discarded due to lack of buffer space in + the I/O shim) and should be discarded. */ + NETIO_PKT_STATUS_BAD +} netio_pkt_status_t; + + +/** Log2 of how many buckets we have. */ +#define NETIO_LOG2_NUM_BUCKETS (10) + +/** How many buckets we have. + * @ingroup ingress */ +#define NETIO_NUM_BUCKETS (1 << NETIO_LOG2_NUM_BUCKETS) + + +/** + * @brief A group-to-bucket identifier. + * + * @ingroup setup + * + * This tells us what to do with a given group. + */ +typedef union { + /** The header broken down into bits. */ + struct { + /** Whether we should balance on L4, if available */ + unsigned int __balance_on_l4:1; + /** Whether we should balance on L3, if available */ + unsigned int __balance_on_l3:1; + /** Whether we should balance on L2, if available */ + unsigned int __balance_on_l2:1; + /** Reserved for future use */ + unsigned int __reserved:1; + /** The base bucket to use to send traffic */ + unsigned int __bucket_base:NETIO_LOG2_NUM_BUCKETS; + /** The mask to apply to the balancing value. This must be one less + * than a power of two, e.g. 0x3 or 0xFF. + */ + unsigned int __bucket_mask:NETIO_LOG2_NUM_BUCKETS; + /** Pad to 32 bits */ + unsigned int __padding:(32 - 4 - 2 * NETIO_LOG2_NUM_BUCKETS); + } bits; + /** To send out the IDN. */ + unsigned int word; +} +netio_group_t; + + +/** + * @brief A VLAN-to-bucket identifier. + * + * @ingroup setup + * + * This tells us what to do with a given VLAN. + */ +typedef netio_group_t netio_vlan_t; + + +/** + * A bucket-to-queue mapping. + * @ingroup setup + */ +typedef unsigned char netio_bucket_t; + + +/** + * A packet size can always fit in a netio_size_t. + * @ingroup setup + */ +typedef unsigned int netio_size_t; + + +/** + * @brief Ethernet standard (ingress) packet metadata. + * + * @ingroup ingress + * + * This is additional data associated with each packet. + * This structure is opaque and accessed through the @ref ingress. + * + * Also, the buffer population operation currently assumes that standard + * metadata is at least as large as minimal metadata, and will need to be + * modified if that is no longer the case. + */ +typedef struct +{ +#ifdef __DOXYGEN__ + /** This structure is opaque. */ + unsigned char opaque[24]; +#else + /** The overall ordinal of the packet */ + unsigned int __packet_ordinal; + /** The ordinal of the packet within the group */ + unsigned int __group_ordinal; + /** The best flow hash IPP could compute. */ + unsigned int __flow_hash; + /** Flags pertaining to checksum calculation, packet type, etc. */ + unsigned int __flags; + /** The first word of "user data". */ + unsigned int __user_data_0; + /** The second word of "user data". */ + unsigned int __user_data_1; +#endif +} +netio_pkt_metadata_t; + + +/** To ensure that the L3 header is aligned mod 4, the L2 header should be + * aligned mod 4 plus 2, since every supported L2 header is 4n + 2 bytes + * long. The standard way to do this is to simply add 2 bytes of padding + * before the L2 header. + */ +#define NETIO_PACKET_PADDING 2 + + + +/** + * @brief Ethernet minimal (egress) packet metadata. + * + * @ingroup egress + * + * This structure represents information about packets which have + * been processed by @ref netio_populate_buffer() or + * @ref netio_populate_prepend_buffer(). This structure is opaque + * and accessed through the @ref egress. + * + * @internal This structure is actually copied into the memory used by + * standard metadata, which is assumed to be large enough. + */ +typedef struct +{ +#ifdef __DOXYGEN__ + /** This structure is opaque. */ + unsigned char opaque[14]; +#else + /** The offset of the L2 header from the start of the packet data. */ + unsigned short l2_offset; + /** The offset of the L3 header from the start of the packet data. */ + unsigned short l3_offset; + /** Where to write the checksum. */ + unsigned char csum_location; + /** Where to start checksumming from. */ + unsigned char csum_start; + /** Flags pertaining to checksum calculation etc. */ + unsigned short flags; + /** The L2 length of the packet. */ + unsigned short l2_length; + /** The checksum with which to seed the checksum generator. */ + unsigned short csum_seed; + /** How much to checksum. */ + unsigned short csum_length; +#endif +} +netio_pkt_minimal_metadata_t; + + +#ifndef __DOXYGEN__ + +/** + * @brief An I/O notification header. + * + * This is the first word of data received from an I/O shim in a notification + * packet. It contains framing and status information. + */ +typedef union +{ + unsigned int word; /**< The whole word. */ + /** The various fields. */ + struct + { + unsigned int __channel:7; /**< Resource channel. */ + unsigned int __type:4; /**< Type. */ + unsigned int __ack:1; /**< Whether an acknowledgement is needed. */ + unsigned int __reserved:1; /**< Reserved. */ + unsigned int __protocol:1; /**< A protocol-specific word is added. */ + unsigned int __status:2; /**< Status of the transfer. */ + unsigned int __framing:2; /**< Framing of the transfer. */ + unsigned int __transfer_size:14; /**< Transfer size in bytes (total). */ + } bits; +} +__netio_pkt_notif_t; + + +/** + * Returns the base address of the packet. + */ +#define _NETIO_PKT_HANDLE_BASE(p) \ + ((unsigned char*)((p).word & 0xFFFFFFC0)) + +/** + * Returns the base address of the packet. + */ +#define _NETIO_PKT_BASE(p) \ + _NETIO_PKT_HANDLE_BASE(p->__packet) + +/** + * @brief An I/O notification packet (second word) + * + * This is the second word of data received from an I/O shim in a notification + * packet. This is the virtual address of the packet buffer, plus some flag + * bits. (The virtual address of the packet is always 256-byte aligned so we + * have room for 8 bits' worth of flags in the low 8 bits.) + * + * @internal + * NOTE: The low two bits must contain "__queue", so the "packet size" + * (SIZE_SMALL, SIZE_LARGE, or SIZE_JUMBO) can be determined quickly. + * + * If __addr or __offset are moved, _NETIO_PKT_BASE + * (defined right below this) must be changed. + */ +typedef union +{ + unsigned int word; /**< The whole word. */ + /** The various fields. */ + struct + { + /** Which queue the packet will be returned to once it is sent back to + the IPP. This is one of the SIZE_xxx values. */ + unsigned int __queue:2; + + /** The IPP handle of the sending IPP. */ + unsigned int __ipp_handle:2; + + /** Reserved for future use. */ + unsigned int __reserved:1; + + /** If 1, this packet has minimal (egress) metadata; otherwise, it + has standard (ingress) metadata. */ + unsigned int __minimal:1; + + /** Offset of the metadata within the packet. This value is multiplied + * by 64 and added to the base packet address to get the metadata + * address. Note that this field is aligned within the word such that + * you can easily extract the metadata address with a 26-bit mask. */ + unsigned int __offset:2; + + /** The top 24 bits of the packet's virtual address. */ + unsigned int __addr:24; + } bits; +} +__netio_pkt_handle_t; + +#endif /* !__DOXYGEN__ */ + + +/** + * @brief A handle for an I/O packet's storage. + * @ingroup ingress + * + * netio_pkt_handle_t encodes the concept of a ::netio_pkt_t with its + * packet metadata removed. It is a much smaller type that exists to + * facilitate applications where the full ::netio_pkt_t type is too + * large, such as those that cache enormous numbers of packets or wish + * to transmit packet descriptors over the UDN. + * + * Because there is no metadata, most ::netio_pkt_t operations cannot be + * performed on a netio_pkt_handle_t. It supports only + * netio_free_handle() (to free the buffer) and + * NETIO_PKT_CUSTOM_DATA_H() (to access a pointer to its contents). + * The application must acquire any additional metadata it wants from the + * original ::netio_pkt_t and record it separately. + * + * A netio_pkt_handle_t can be extracted from a ::netio_pkt_t by calling + * NETIO_PKT_HANDLE(). An invalid handle (analogous to NULL) can be + * created by assigning the value ::NETIO_PKT_HANDLE_NONE. A handle can + * be tested for validity with NETIO_PKT_HANDLE_IS_VALID(). + */ +typedef struct +{ + unsigned int word; /**< Opaque bits. */ +} netio_pkt_handle_t; + +/** + * @brief A packet descriptor. + * + * @ingroup ingress + * @ingroup egress + * + * This data structure represents a packet. The structure is manipulated + * through the @ref ingress and the @ref egress. + * + * While the contents of a netio_pkt_t are opaque, the structure itself is + * portable. This means that it may be shared between all tiles which have + * done a netio_input_register() call for the interface on which the pkt_t + * was initially received (via netio_get_packet()) or retrieved (via + * netio_get_buffer()). The contents of a netio_pkt_t can be transmitted to + * another tile via shared memory, or via a UDN message, or by other means. + * The destination tile may then use the pkt_t as if it had originally been + * received locally; it may read or write the packet's data, read its + * metadata, free the packet, send the packet, transfer the netio_pkt_t to + * yet another tile, and so forth. + * + * Once a netio_pkt_t has been transferred to a second tile, the first tile + * should not reference the original copy; in particular, if more than one + * tile frees or sends the same netio_pkt_t, the IPP's packet free lists will + * become corrupted. Note also that each tile which reads or modifies + * packet data must obey the memory coherency rules outlined in @ref input. + */ +typedef struct +{ +#ifdef __DOXYGEN__ + /** This structure is opaque. */ + unsigned char opaque[32]; +#else + /** For an ingress packet (one with standard metadata), this is the + * notification header we got from the I/O shim. For an egress packet + * (one with minimal metadata), this word is zero if the packet has not + * been populated, and nonzero if it has. */ + __netio_pkt_notif_t __notif_header; + + /** Virtual address of the packet buffer, plus state flags. */ + __netio_pkt_handle_t __packet; + + /** Metadata associated with the packet. */ + netio_pkt_metadata_t __metadata; +#endif +} +netio_pkt_t; + + +#ifndef __DOXYGEN__ + +#define __NETIO_PKT_NOTIF_HEADER(pkt) ((pkt)->__notif_header) +#define __NETIO_PKT_IPP_HANDLE(pkt) ((pkt)->__packet.bits.__ipp_handle) +#define __NETIO_PKT_QUEUE(pkt) ((pkt)->__packet.bits.__queue) +#define __NETIO_PKT_NOTIF_HEADER_M(mda, pkt) ((pkt)->__notif_header) +#define __NETIO_PKT_IPP_HANDLE_M(mda, pkt) ((pkt)->__packet.bits.__ipp_handle) +#define __NETIO_PKT_MINIMAL(pkt) ((pkt)->__packet.bits.__minimal) +#define __NETIO_PKT_QUEUE_M(mda, pkt) ((pkt)->__packet.bits.__queue) +#define __NETIO_PKT_FLAGS_M(mda, pkt) ((mda)->__flags) + +/* Packet information table, used by the attribute access functions below. */ +extern const uint16_t _netio_pkt_info[]; + +#endif /* __DOXYGEN__ */ + + +#ifndef __DOXYGEN__ +/* These macros are deprecated and will disappear in a future MDE release. */ +#define NETIO_PKT_GOOD_CHECKSUM(pkt) \ + NETIO_PKT_L4_CSUM_CORRECT(pkt) +#define NETIO_PKT_GOOD_CHECKSUM_M(mda, pkt) \ + NETIO_PKT_L4_CSUM_CORRECT_M(mda, pkt) +#endif /* __DOXYGEN__ */ + + +/* Packet attribute access functions. */ + +/** Return a pointer to the metadata for a packet. + * @ingroup ingress + * + * Calling this function once and passing the result to other retrieval + * functions with a "_M" suffix usually improves performance. This + * function must be called on an 'ingress' packet (i.e. one retrieved + * by @ref netio_get_packet(), on which @ref netio_populate_buffer() or + * @ref netio_populate_prepend_buffer have not been called). Use of this + * function on an 'egress' packet will cause an assertion failure. + * + * @param[in] pkt Packet on which to operate. + * @return A pointer to the packet's standard metadata. + */ +static __inline netio_pkt_metadata_t* +NETIO_PKT_METADATA(netio_pkt_t* pkt) +{ + netio_assert(!pkt->__packet.bits.__minimal); + return &pkt->__metadata; +} + + +/** Return a pointer to the minimal metadata for a packet. + * @ingroup egress + * + * Calling this function once and passing the result to other retrieval + * functions with a "_MM" suffix usually improves performance. This + * function must be called on an 'egress' packet (i.e. one on which + * @ref netio_populate_buffer() or @ref netio_populate_prepend_buffer() + * have been called, or one retrieved by @ref netio_get_buffer()). Use of + * this function on an 'ingress' packet will cause an assertion failure. + * + * @param[in] pkt Packet on which to operate. + * @return A pointer to the packet's standard metadata. + */ +static __inline netio_pkt_minimal_metadata_t* +NETIO_PKT_MINIMAL_METADATA(netio_pkt_t* pkt) +{ + netio_assert(pkt->__packet.bits.__minimal); + return (netio_pkt_minimal_metadata_t*) &pkt->__metadata; +} + + +/** Determine whether a packet has 'minimal' metadata. + * @ingroup pktfuncs + * + * This function will return nonzero if the packet is an 'egress' + * packet (i.e. one on which @ref netio_populate_buffer() or + * @ref netio_populate_prepend_buffer() have been called, or one + * retrieved by @ref netio_get_buffer()), and zero if the packet + * is an 'ingress' packet (i.e. one retrieved by @ref netio_get_packet(), + * which has not been converted into an 'egress' packet). + * + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the packet has minimal metadata. + */ +static __inline unsigned int +NETIO_PKT_IS_MINIMAL(netio_pkt_t* pkt) +{ + return pkt->__packet.bits.__minimal; +} + + +/** Return a handle for a packet's storage. + * @ingroup pktfuncs + * + * @param[in] pkt Packet on which to operate. + * @return A handle for the packet's storage. + */ +static __inline netio_pkt_handle_t +NETIO_PKT_HANDLE(netio_pkt_t* pkt) +{ + netio_pkt_handle_t h; + h.word = pkt->__packet.word; + return h; +} + + +/** A special reserved value indicating the absence of a packet handle. + * + * @ingroup pktfuncs + */ +#define NETIO_PKT_HANDLE_NONE ((netio_pkt_handle_t) { 0 }) + + +/** Test whether a packet handle is valid. + * + * Applications may wish to use the reserved value NETIO_PKT_HANDLE_NONE + * to indicate no packet at all. This function tests to see if a packet + * handle is a real handle, not this special reserved value. + * + * @ingroup pktfuncs + * + * @param[in] handle Handle on which to operate. + * @return One if the packet handle is valid, else zero. + */ +static __inline unsigned int +NETIO_PKT_HANDLE_IS_VALID(netio_pkt_handle_t handle) +{ + return handle.word != 0; +} + + + +/** Return a pointer to the start of the packet's custom header. + * A custom header may or may not be present, depending upon the IPP; its + * contents and alignment are also IPP-dependent. Currently, none of the + * standard IPPs supplied by Tilera produce a custom header. If present, + * the custom header precedes the L2 header in the packet buffer. + * @ingroup ingress + * + * @param[in] handle Handle on which to operate. + * @return A pointer to start of the packet. + */ +static __inline unsigned char* +NETIO_PKT_CUSTOM_DATA_H(netio_pkt_handle_t handle) +{ + return _NETIO_PKT_HANDLE_BASE(handle) + NETIO_PACKET_PADDING; +} + + +/** Return the length of the packet's custom header. + * A custom header may or may not be present, depending upon the IPP; its + * contents and alignment are also IPP-dependent. Currently, none of the + * standard IPPs supplied by Tilera produce a custom header. If present, + * the custom header precedes the L2 header in the packet buffer. + * + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The length of the packet's custom header, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_CUSTOM_HEADER_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + /* + * Note that we effectively need to extract a quantity from the flags word + * which is measured in words, and then turn it into bytes by shifting + * it left by 2. We do this all at once by just shifting right two less + * bits, and shifting the mask up two bits. + */ + return ((mda->__flags >> (_NETIO_PKT_CUSTOM_LEN_SHIFT - 2)) & + (_NETIO_PKT_CUSTOM_LEN_RMASK << 2)); +} + + +/** Return the length of the packet, starting with the custom header. + * A custom header may or may not be present, depending upon the IPP; its + * contents and alignment are also IPP-dependent. Currently, none of the + * standard IPPs supplied by Tilera produce a custom header. If present, + * the custom header precedes the L2 header in the packet buffer. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The length of the packet, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_CUSTOM_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return (__NETIO_PKT_NOTIF_HEADER(pkt).bits.__transfer_size - + NETIO_PACKET_PADDING); +} + + +/** Return a pointer to the start of the packet's custom header. + * A custom header may or may not be present, depending upon the IPP; its + * contents and alignment are also IPP-dependent. Currently, none of the + * standard IPPs supplied by Tilera produce a custom header. If present, + * the custom header precedes the L2 header in the packet buffer. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return A pointer to start of the packet. + */ +static __inline unsigned char* +NETIO_PKT_CUSTOM_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return NETIO_PKT_CUSTOM_DATA_H(NETIO_PKT_HANDLE(pkt)); +} + + +/** Return the length of the packet's L2 (Ethernet plus VLAN or SNAP) header. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The length of the packet's L2 header, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_L2_HEADER_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + /* + * Note that we effectively need to extract a quantity from the flags word + * which is measured in words, and then turn it into bytes by shifting + * it left by 2. We do this all at once by just shifting right two less + * bits, and shifting the mask up two bits. We then add two bytes. + */ + return ((mda->__flags >> (_NETIO_PKT_L2_LEN_SHIFT - 2)) & + (_NETIO_PKT_L2_LEN_RMASK << 2)) + 2; +} + + +/** Return the length of the packet, starting with the L2 (Ethernet) header. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The length of the packet, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_L2_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return (NETIO_PKT_CUSTOM_LENGTH_M(mda, pkt) - + NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda,pkt)); +} + + +/** Return a pointer to the start of the packet's L2 (Ethernet) header. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return A pointer to start of the packet. + */ +static __inline unsigned char* +NETIO_PKT_L2_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return (NETIO_PKT_CUSTOM_DATA_M(mda, pkt) + + NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt)); +} + + +/** Retrieve the length of the packet, starting with the L3 (generally, + * the IP) header. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return Length of the packet's L3 header and data, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_L3_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return (NETIO_PKT_L2_LENGTH_M(mda, pkt) - + NETIO_PKT_L2_HEADER_LENGTH_M(mda,pkt)); +} + + +/** Return a pointer to the packet's L3 (generally, the IP) header. + * @ingroup ingress + * + * Note that we guarantee word alignment of the L3 header. + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return A pointer to the packet's L3 header. + */ +static __inline unsigned char* +NETIO_PKT_L3_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return (NETIO_PKT_L2_DATA_M(mda, pkt) + + NETIO_PKT_L2_HEADER_LENGTH_M(mda, pkt)); +} + + +/** Return the ordinal of the packet. + * @ingroup ingress + * + * Each packet is given an ordinal number when it is delivered by the IPP. + * In the medium term, the ordinal is unique and monotonically increasing, + * being incremented by 1 for each packet; the ordinal of the first packet + * delivered after the IPP starts is zero. (Since the ordinal is of finite + * size, given enough input packets, it will eventually wrap around to zero; + * in the long term, therefore, ordinals are not unique.) The ordinals + * handed out by different IPPs are not disjoint, so two packets from + * different IPPs may have identical ordinals. Packets dropped by the + * IPP or by the I/O shim are not assigned ordinals. + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The packet's per-IPP packet ordinal. + */ +static __inline unsigned int +NETIO_PKT_ORDINAL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return mda->__packet_ordinal; +} + + +/** Return the per-group ordinal of the packet. + * @ingroup ingress + * + * Each packet is given a per-group ordinal number when it is + * delivered by the IPP. By default, the group is the packet's VLAN, + * although IPP can be recompiled to use different values. In + * the medium term, the ordinal is unique and monotonically + * increasing, being incremented by 1 for each packet; the ordinal of + * the first packet distributed to a particular group is zero. + * (Since the ordinal is of finite size, given enough input packets, + * it will eventually wrap around to zero; in the long term, + * therefore, ordinals are not unique.) The ordinals handed out by + * different IPPs are not disjoint, so two packets from different IPPs + * may have identical ordinals; similarly, packets distributed to + * different groups may have identical ordinals. Packets dropped by + * the IPP or by the I/O shim are not assigned ordinals. + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The packet's per-IPP, per-group ordinal. + */ +static __inline unsigned int +NETIO_PKT_GROUP_ORDINAL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return mda->__group_ordinal; +} + + +/** Return the VLAN ID assigned to the packet. + * @ingroup ingress + * + * This value is usually contained within the packet header. + * + * This value will be zero if the packet does not have a VLAN tag, or if + * this value was not extracted from the packet. + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The packet's VLAN ID. + */ +static __inline unsigned short +NETIO_PKT_VLAN_ID_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + int vl = (mda->__flags >> _NETIO_PKT_VLAN_SHIFT) & _NETIO_PKT_VLAN_RMASK; + unsigned short* pkt_p; + int index; + unsigned short val; + + if (vl == _NETIO_PKT_VLAN_NONE) + return 0; + + pkt_p = (unsigned short*) NETIO_PKT_L2_DATA_M(mda, pkt); + index = (mda->__flags >> _NETIO_PKT_TYPE_SHIFT) & _NETIO_PKT_TYPE_RMASK; + + val = pkt_p[(_netio_pkt_info[index] >> _NETIO_PKT_INFO_VLAN_SHIFT) & + _NETIO_PKT_INFO_VLAN_RMASK]; + +#ifdef __TILECC__ + return (__insn_bytex(val) >> 16) & 0xFFF; +#else + return (__builtin_bswap32(val) >> 16) & 0xFFF; +#endif +} + + +/** Return the ethertype of the packet. + * @ingroup ingress + * + * This value is usually contained within the packet header. + * + * This value is reliable if @ref NETIO_PKT_ETHERTYPE_RECOGNIZED_M() + * returns true, and otherwise, may not be well defined. + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The packet's ethertype. + */ +static __inline unsigned short +NETIO_PKT_ETHERTYPE_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + unsigned short* pkt_p = (unsigned short*) NETIO_PKT_L2_DATA_M(mda, pkt); + int index = (mda->__flags >> _NETIO_PKT_TYPE_SHIFT) & _NETIO_PKT_TYPE_RMASK; + + unsigned short val = + pkt_p[(_netio_pkt_info[index] >> _NETIO_PKT_INFO_ETYPE_SHIFT) & + _NETIO_PKT_INFO_ETYPE_RMASK]; + + return __builtin_bswap32(val) >> 16; +} + + +/** Return the flow hash computed on the packet. + * @ingroup ingress + * + * For TCP and UDP packets, this hash is calculated by hashing together + * the "5-tuple" values, specifically the source IP address, destination + * IP address, protocol type, source port and destination port. + * The hash value is intended to be helpful for millions of distinct + * flows. + * + * For IPv4 or IPv6 packets which are neither TCP nor UDP, the flow hash is + * derived by hashing together the source and destination IP addresses. + * + * For MPLS-encapsulated packets, the flow hash is derived by hashing + * the first MPLS label. + * + * For all other packets the flow hash is computed from the source + * and destination Ethernet addresses. + * + * The hash is symmetric, meaning it produces the same value if the + * source and destination are swapped. The only exceptions are + * tunneling protocols 0x04 (IP in IP Encapsulation), 0x29 (Simple + * Internet Protocol), 0x2F (General Routing Encapsulation) and 0x32 + * (Encap Security Payload), which use only the destination address + * since the source address is not meaningful. + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The packet's 32-bit flow hash. + */ +static __inline unsigned int +NETIO_PKT_FLOW_HASH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return mda->__flow_hash; +} + + +/** Return the first word of "user data" for the packet. + * + * The contents of the user data words depend on the IPP. + * + * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the first + * word of user data contains the least significant bits of the 64-bit + * arrival cycle count (see @c get_cycle_count_low()). + * + * See the <em>System Programmer's Guide</em> for details. + * + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The packet's first word of "user data". + */ +static __inline unsigned int +NETIO_PKT_USER_DATA_0_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return mda->__user_data_0; +} + + +/** Return the second word of "user data" for the packet. + * + * The contents of the user data words depend on the IPP. + * + * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the second + * word of user data contains the most significant bits of the 64-bit + * arrival cycle count (see @c get_cycle_count_high()). + * + * See the <em>System Programmer's Guide</em> for details. + * + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The packet's second word of "user data". + */ +static __inline unsigned int +NETIO_PKT_USER_DATA_1_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return mda->__user_data_1; +} + + +/** Determine whether the L4 (TCP/UDP) checksum was calculated. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the L4 checksum was calculated. + */ +static __inline unsigned int +NETIO_PKT_L4_CSUM_CALCULATED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return !(mda->__flags & _NETIO_PKT_NO_L4_CSUM_MASK); +} + + +/** Determine whether the L4 (TCP/UDP) checksum was calculated and found to + * be correct. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the checksum was calculated and is correct. + */ +static __inline unsigned int +NETIO_PKT_L4_CSUM_CORRECT_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return !(mda->__flags & + (_NETIO_PKT_BAD_L4_CSUM_MASK | _NETIO_PKT_NO_L4_CSUM_MASK)); +} + + +/** Determine whether the L3 (IP) checksum was calculated. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the L3 (IP) checksum was calculated. +*/ +static __inline unsigned int +NETIO_PKT_L3_CSUM_CALCULATED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return !(mda->__flags & _NETIO_PKT_NO_L3_CSUM_MASK); +} + + +/** Determine whether the L3 (IP) checksum was calculated and found to be + * correct. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the checksum was calculated and is correct. + */ +static __inline unsigned int +NETIO_PKT_L3_CSUM_CORRECT_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return !(mda->__flags & + (_NETIO_PKT_BAD_L3_CSUM_MASK | _NETIO_PKT_NO_L3_CSUM_MASK)); +} + + +/** Determine whether the ethertype was recognized and L3 packet data was + * processed. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the ethertype was recognized and L3 packet data was + * processed. + */ +static __inline unsigned int +NETIO_PKT_ETHERTYPE_RECOGNIZED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return !(mda->__flags & _NETIO_PKT_TYPE_UNRECOGNIZED_MASK); +} + + +/** Retrieve the status of a packet and any errors that may have occurred + * during ingress processing (length mismatches, CRC errors, etc.). + * @ingroup ingress + * + * Note that packets for which @ref NETIO_PKT_ETHERTYPE_RECOGNIZED() + * returns zero are always reported as underlength, as there is no a priori + * means to determine their length. Normally, applications should use + * @ref NETIO_PKT_BAD_M() instead of explicitly checking status with this + * function. + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return The packet's status. + */ +static __inline netio_pkt_status_t +NETIO_PKT_STATUS_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return (netio_pkt_status_t) __NETIO_PKT_NOTIF_HEADER(pkt).bits.__status; +} + + +/** Report whether a packet is bad (i.e., was shorter than expected based on + * its headers, or had a bad CRC). + * @ingroup ingress + * + * Note that this function does not verify L3 or L4 checksums. + * + * @param[in] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the packet is bad and should be discarded. + */ +static __inline unsigned int +NETIO_PKT_BAD_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return ((NETIO_PKT_STATUS_M(mda, pkt) & 1) && + (NETIO_PKT_ETHERTYPE_RECOGNIZED_M(mda, pkt) || + NETIO_PKT_STATUS_M(mda, pkt) == NETIO_PKT_STATUS_BAD)); +} + + +/** Return the length of the packet, starting with the L2 (Ethernet) header. + * @ingroup egress + * + * @param[in] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + * @return The length of the packet, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_L2_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt) +{ + return mmd->l2_length; +} + + +/** Return the length of the L2 (Ethernet) header. + * @ingroup egress + * + * @param[in] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + * @return The length of the packet's L2 header, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_L2_HEADER_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, + netio_pkt_t* pkt) +{ + return mmd->l3_offset - mmd->l2_offset; +} + + +/** Return the length of the packet, starting with the L3 (IP) header. + * @ingroup egress + * + * @param[in] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + * @return Length of the packet's L3 header and data, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_L3_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt) +{ + return (NETIO_PKT_L2_LENGTH_MM(mmd, pkt) - + NETIO_PKT_L2_HEADER_LENGTH_MM(mmd, pkt)); +} + + +/** Return a pointer to the packet's L3 (generally, the IP) header. + * @ingroup egress + * + * Note that we guarantee word alignment of the L3 header. + * + * @param[in] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + * @return A pointer to the packet's L3 header. + */ +static __inline unsigned char* +NETIO_PKT_L3_DATA_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt) +{ + return _NETIO_PKT_BASE(pkt) + mmd->l3_offset; +} + + +/** Return a pointer to the packet's L2 (Ethernet) header. + * @ingroup egress + * + * @param[in] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + * @return A pointer to start of the packet. + */ +static __inline unsigned char* +NETIO_PKT_L2_DATA_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt) +{ + return _NETIO_PKT_BASE(pkt) + mmd->l2_offset; +} + + +/** Retrieve the status of a packet and any errors that may have occurred + * during ingress processing (length mismatches, CRC errors, etc.). + * @ingroup ingress + * + * Note that packets for which @ref NETIO_PKT_ETHERTYPE_RECOGNIZED() + * returns zero are always reported as underlength, as there is no a priori + * means to determine their length. Normally, applications should use + * @ref NETIO_PKT_BAD() instead of explicitly checking status with this + * function. + * + * @param[in] pkt Packet on which to operate. + * @return The packet's status. + */ +static __inline netio_pkt_status_t +NETIO_PKT_STATUS(netio_pkt_t* pkt) +{ + netio_assert(!pkt->__packet.bits.__minimal); + + return (netio_pkt_status_t) __NETIO_PKT_NOTIF_HEADER(pkt).bits.__status; +} + + +/** Report whether a packet is bad (i.e., was shorter than expected based on + * its headers, or had a bad CRC). + * @ingroup ingress + * + * Note that this function does not verify L3 or L4 checksums. + * + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the packet is bad and should be discarded. + */ +static __inline unsigned int +NETIO_PKT_BAD(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_BAD_M(mda, pkt); +} + + +/** Return the length of the packet's custom header. + * A custom header may or may not be present, depending upon the IPP; its + * contents and alignment are also IPP-dependent. Currently, none of the + * standard IPPs supplied by Tilera produce a custom header. If present, + * the custom header precedes the L2 header in the packet buffer. + * @ingroup pktfuncs + * + * @param[in] pkt Packet on which to operate. + * @return The length of the packet's custom header, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_CUSTOM_HEADER_LENGTH(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt); +} + + +/** Return the length of the packet, starting with the custom header. + * A custom header may or may not be present, depending upon the IPP; its + * contents and alignment are also IPP-dependent. Currently, none of the + * standard IPPs supplied by Tilera produce a custom header. If present, + * the custom header precedes the L2 header in the packet buffer. + * @ingroup pktfuncs + * + * @param[in] pkt Packet on which to operate. + * @return The length of the packet, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_CUSTOM_LENGTH(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_CUSTOM_LENGTH_M(mda, pkt); +} + + +/** Return a pointer to the packet's custom header. + * A custom header may or may not be present, depending upon the IPP; its + * contents and alignment are also IPP-dependent. Currently, none of the + * standard IPPs supplied by Tilera produce a custom header. If present, + * the custom header precedes the L2 header in the packet buffer. + * @ingroup pktfuncs + * + * @param[in] pkt Packet on which to operate. + * @return A pointer to start of the packet. + */ +static __inline unsigned char* +NETIO_PKT_CUSTOM_DATA(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_CUSTOM_DATA_M(mda, pkt); +} + + +/** Return the length of the packet's L2 (Ethernet plus VLAN or SNAP) header. + * @ingroup pktfuncs + * + * @param[in] pkt Packet on which to operate. + * @return The length of the packet's L2 header, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_L2_HEADER_LENGTH(netio_pkt_t* pkt) +{ + if (NETIO_PKT_IS_MINIMAL(pkt)) + { + netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); + + return NETIO_PKT_L2_HEADER_LENGTH_MM(mmd, pkt); + } + else + { + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_L2_HEADER_LENGTH_M(mda, pkt); + } +} + + +/** Return the length of the packet, starting with the L2 (Ethernet) header. + * @ingroup pktfuncs + * + * @param[in] pkt Packet on which to operate. + * @return The length of the packet, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_L2_LENGTH(netio_pkt_t* pkt) +{ + if (NETIO_PKT_IS_MINIMAL(pkt)) + { + netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); + + return NETIO_PKT_L2_LENGTH_MM(mmd, pkt); + } + else + { + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_L2_LENGTH_M(mda, pkt); + } +} + + +/** Return a pointer to the packet's L2 (Ethernet) header. + * @ingroup pktfuncs + * + * @param[in] pkt Packet on which to operate. + * @return A pointer to start of the packet. + */ +static __inline unsigned char* +NETIO_PKT_L2_DATA(netio_pkt_t* pkt) +{ + if (NETIO_PKT_IS_MINIMAL(pkt)) + { + netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); + + return NETIO_PKT_L2_DATA_MM(mmd, pkt); + } + else + { + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_L2_DATA_M(mda, pkt); + } +} + + +/** Retrieve the length of the packet, starting with the L3 (generally, the IP) + * header. + * @ingroup pktfuncs + * + * @param[in] pkt Packet on which to operate. + * @return Length of the packet's L3 header and data, in bytes. + */ +static __inline netio_size_t +NETIO_PKT_L3_LENGTH(netio_pkt_t* pkt) +{ + if (NETIO_PKT_IS_MINIMAL(pkt)) + { + netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); + + return NETIO_PKT_L3_LENGTH_MM(mmd, pkt); + } + else + { + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_L3_LENGTH_M(mda, pkt); + } +} + + +/** Return a pointer to the packet's L3 (generally, the IP) header. + * @ingroup pktfuncs + * + * Note that we guarantee word alignment of the L3 header. + * + * @param[in] pkt Packet on which to operate. + * @return A pointer to the packet's L3 header. + */ +static __inline unsigned char* +NETIO_PKT_L3_DATA(netio_pkt_t* pkt) +{ + if (NETIO_PKT_IS_MINIMAL(pkt)) + { + netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); + + return NETIO_PKT_L3_DATA_MM(mmd, pkt); + } + else + { + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_L3_DATA_M(mda, pkt); + } +} + + +/** Return the ordinal of the packet. + * @ingroup ingress + * + * Each packet is given an ordinal number when it is delivered by the IPP. + * In the medium term, the ordinal is unique and monotonically increasing, + * being incremented by 1 for each packet; the ordinal of the first packet + * delivered after the IPP starts is zero. (Since the ordinal is of finite + * size, given enough input packets, it will eventually wrap around to zero; + * in the long term, therefore, ordinals are not unique.) The ordinals + * handed out by different IPPs are not disjoint, so two packets from + * different IPPs may have identical ordinals. Packets dropped by the + * IPP or by the I/O shim are not assigned ordinals. + * + * + * @param[in] pkt Packet on which to operate. + * @return The packet's per-IPP packet ordinal. + */ +static __inline unsigned int +NETIO_PKT_ORDINAL(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_ORDINAL_M(mda, pkt); +} + + +/** Return the per-group ordinal of the packet. + * @ingroup ingress + * + * Each packet is given a per-group ordinal number when it is + * delivered by the IPP. By default, the group is the packet's VLAN, + * although IPP can be recompiled to use different values. In + * the medium term, the ordinal is unique and monotonically + * increasing, being incremented by 1 for each packet; the ordinal of + * the first packet distributed to a particular group is zero. + * (Since the ordinal is of finite size, given enough input packets, + * it will eventually wrap around to zero; in the long term, + * therefore, ordinals are not unique.) The ordinals handed out by + * different IPPs are not disjoint, so two packets from different IPPs + * may have identical ordinals; similarly, packets distributed to + * different groups may have identical ordinals. Packets dropped by + * the IPP or by the I/O shim are not assigned ordinals. + * + * @param[in] pkt Packet on which to operate. + * @return The packet's per-IPP, per-group ordinal. + */ +static __inline unsigned int +NETIO_PKT_GROUP_ORDINAL(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_GROUP_ORDINAL_M(mda, pkt); +} + + +/** Return the VLAN ID assigned to the packet. + * @ingroup ingress + * + * This is usually also contained within the packet header. If the packet + * does not have a VLAN tag, the VLAN ID returned by this function is zero. + * + * @param[in] pkt Packet on which to operate. + * @return The packet's VLAN ID. + */ +static __inline unsigned short +NETIO_PKT_VLAN_ID(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_VLAN_ID_M(mda, pkt); +} + + +/** Return the ethertype of the packet. + * @ingroup ingress + * + * This value is reliable if @ref NETIO_PKT_ETHERTYPE_RECOGNIZED() + * returns true, and otherwise, may not be well defined. + * + * @param[in] pkt Packet on which to operate. + * @return The packet's ethertype. + */ +static __inline unsigned short +NETIO_PKT_ETHERTYPE(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_ETHERTYPE_M(mda, pkt); +} + + +/** Return the flow hash computed on the packet. + * @ingroup ingress + * + * For TCP and UDP packets, this hash is calculated by hashing together + * the "5-tuple" values, specifically the source IP address, destination + * IP address, protocol type, source port and destination port. + * The hash value is intended to be helpful for millions of distinct + * flows. + * + * For IPv4 or IPv6 packets which are neither TCP nor UDP, the flow hash is + * derived by hashing together the source and destination IP addresses. + * + * For MPLS-encapsulated packets, the flow hash is derived by hashing + * the first MPLS label. + * + * For all other packets the flow hash is computed from the source + * and destination Ethernet addresses. + * + * The hash is symmetric, meaning it produces the same value if the + * source and destination are swapped. The only exceptions are + * tunneling protocols 0x04 (IP in IP Encapsulation), 0x29 (Simple + * Internet Protocol), 0x2F (General Routing Encapsulation) and 0x32 + * (Encap Security Payload), which use only the destination address + * since the source address is not meaningful. + * + * @param[in] pkt Packet on which to operate. + * @return The packet's 32-bit flow hash. + */ +static __inline unsigned int +NETIO_PKT_FLOW_HASH(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_FLOW_HASH_M(mda, pkt); +} + + +/** Return the first word of "user data" for the packet. + * + * The contents of the user data words depend on the IPP. + * + * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the first + * word of user data contains the least significant bits of the 64-bit + * arrival cycle count (see @c get_cycle_count_low()). + * + * See the <em>System Programmer's Guide</em> for details. + * + * @ingroup ingress + * + * @param[in] pkt Packet on which to operate. + * @return The packet's first word of "user data". + */ +static __inline unsigned int +NETIO_PKT_USER_DATA_0(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_USER_DATA_0_M(mda, pkt); +} + + +/** Return the second word of "user data" for the packet. + * + * The contents of the user data words depend on the IPP. + * + * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the second + * word of user data contains the most significant bits of the 64-bit + * arrival cycle count (see @c get_cycle_count_high()). + * + * See the <em>System Programmer's Guide</em> for details. + * + * @ingroup ingress + * + * @param[in] pkt Packet on which to operate. + * @return The packet's second word of "user data". + */ +static __inline unsigned int +NETIO_PKT_USER_DATA_1(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_USER_DATA_1_M(mda, pkt); +} + + +/** Determine whether the L4 (TCP/UDP) checksum was calculated. + * @ingroup ingress + * + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the L4 checksum was calculated. + */ +static __inline unsigned int +NETIO_PKT_L4_CSUM_CALCULATED(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_L4_CSUM_CALCULATED_M(mda, pkt); +} + + +/** Determine whether the L4 (TCP/UDP) checksum was calculated and found to + * be correct. + * @ingroup ingress + * + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the checksum was calculated and is correct. + */ +static __inline unsigned int +NETIO_PKT_L4_CSUM_CORRECT(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_L4_CSUM_CORRECT_M(mda, pkt); +} + + +/** Determine whether the L3 (IP) checksum was calculated. + * @ingroup ingress + * + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the L3 (IP) checksum was calculated. +*/ +static __inline unsigned int +NETIO_PKT_L3_CSUM_CALCULATED(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_L3_CSUM_CALCULATED_M(mda, pkt); +} + + +/** Determine whether the L3 (IP) checksum was calculated and found to be + * correct. + * @ingroup ingress + * + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the checksum was calculated and is correct. + */ +static __inline unsigned int +NETIO_PKT_L3_CSUM_CORRECT(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_L3_CSUM_CORRECT_M(mda, pkt); +} + + +/** Determine whether the Ethertype was recognized and L3 packet data was + * processed. + * @ingroup ingress + * + * @param[in] pkt Packet on which to operate. + * @return Nonzero if the Ethertype was recognized and L3 packet data was + * processed. + */ +static __inline unsigned int +NETIO_PKT_ETHERTYPE_RECOGNIZED(netio_pkt_t* pkt) +{ + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_ETHERTYPE_RECOGNIZED_M(mda, pkt); +} + + +/** Set an egress packet's L2 length, using a metadata pointer to speed the + * computation. + * @ingroup egress + * + * @param[in,out] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + * @param[in] len Packet L2 length, in bytes. + */ +static __inline void +NETIO_PKT_SET_L2_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt, + int len) +{ + mmd->l2_length = len; +} + + +/** Set an egress packet's L2 length. + * @ingroup egress + * + * @param[in,out] pkt Packet on which to operate. + * @param[in] len Packet L2 length, in bytes. + */ +static __inline void +NETIO_PKT_SET_L2_LENGTH(netio_pkt_t* pkt, int len) +{ + netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); + + NETIO_PKT_SET_L2_LENGTH_MM(mmd, pkt, len); +} + + +/** Set an egress packet's L2 header length, using a metadata pointer to + * speed the computation. + * @ingroup egress + * + * It is not normally necessary to call this routine; only the L2 length, + * not the header length, is needed to transmit a packet. It may be useful if + * the egress packet will later be processed by code which expects to use + * functions like @ref NETIO_PKT_L3_DATA() to get a pointer to the L3 payload. + * + * @param[in,out] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + * @param[in] len Packet L2 header length, in bytes. + */ +static __inline void +NETIO_PKT_SET_L2_HEADER_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, + netio_pkt_t* pkt, int len) +{ + mmd->l3_offset = mmd->l2_offset + len; +} + + +/** Set an egress packet's L2 header length. + * @ingroup egress + * + * It is not normally necessary to call this routine; only the L2 length, + * not the header length, is needed to transmit a packet. It may be useful if + * the egress packet will later be processed by code which expects to use + * functions like @ref NETIO_PKT_L3_DATA() to get a pointer to the L3 payload. + * + * @param[in,out] pkt Packet on which to operate. + * @param[in] len Packet L2 header length, in bytes. + */ +static __inline void +NETIO_PKT_SET_L2_HEADER_LENGTH(netio_pkt_t* pkt, int len) +{ + netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); + + NETIO_PKT_SET_L2_HEADER_LENGTH_MM(mmd, pkt, len); +} + + +/** Set up an egress packet for hardware checksum computation, using a + * metadata pointer to speed the operation. + * @ingroup egress + * + * NetIO provides the ability to automatically calculate a standard + * 16-bit Internet checksum on transmitted packets. The application + * may specify the point in the packet where the checksum starts, the + * number of bytes to be checksummed, and the two bytes in the packet + * which will be replaced with the completed checksum. (If the range + * of bytes to be checksummed includes the bytes to be replaced, the + * initial values of those bytes will be included in the checksum.) + * + * For some protocols, the packet checksum covers data which is not present + * in the packet, or is at least not contiguous to the main data payload. + * For instance, the TCP checksum includes a "pseudo-header" which includes + * the source and destination IP addresses of the packet. To accommodate + * this, the checksum engine may be "seeded" with an initial value, which + * the application would need to compute based on the specific protocol's + * requirements. Note that the seed is given in host byte order (little- + * endian), not network byte order (big-endian); code written to compute a + * pseudo-header checksum in network byte order will need to byte-swap it + * before use as the seed. + * + * Note that the checksum is computed as part of the transmission process, + * so it will not be present in the packet upon completion of this routine. + * + * @param[in,out] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + * @param[in] start Offset within L2 packet of the first byte to include in + * the checksum. + * @param[in] length Number of bytes to include in the checksum. + * the checksum. + * @param[in] location Offset within L2 packet of the first of the two bytes + * to be replaced with the calculated checksum. + * @param[in] seed Initial value of the running checksum before any of the + * packet data is added. + */ +static __inline void +NETIO_PKT_DO_EGRESS_CSUM_MM(netio_pkt_minimal_metadata_t* mmd, + netio_pkt_t* pkt, int start, int length, + int location, uint16_t seed) +{ + mmd->csum_start = start; + mmd->csum_length = length; + mmd->csum_location = location; + mmd->csum_seed = seed; + mmd->flags |= _NETIO_PKT_NEED_EDMA_CSUM_MASK; +} + + +/** Set up an egress packet for hardware checksum computation. + * @ingroup egress + * + * NetIO provides the ability to automatically calculate a standard + * 16-bit Internet checksum on transmitted packets. The application + * may specify the point in the packet where the checksum starts, the + * number of bytes to be checksummed, and the two bytes in the packet + * which will be replaced with the completed checksum. (If the range + * of bytes to be checksummed includes the bytes to be replaced, the + * initial values of those bytes will be included in the checksum.) + * + * For some protocols, the packet checksum covers data which is not present + * in the packet, or is at least not contiguous to the main data payload. + * For instance, the TCP checksum includes a "pseudo-header" which includes + * the source and destination IP addresses of the packet. To accommodate + * this, the checksum engine may be "seeded" with an initial value, which + * the application would need to compute based on the specific protocol's + * requirements. Note that the seed is given in host byte order (little- + * endian), not network byte order (big-endian); code written to compute a + * pseudo-header checksum in network byte order will need to byte-swap it + * before use as the seed. + * + * Note that the checksum is computed as part of the transmission process, + * so it will not be present in the packet upon completion of this routine. + * + * @param[in,out] pkt Packet on which to operate. + * @param[in] start Offset within L2 packet of the first byte to include in + * the checksum. + * @param[in] length Number of bytes to include in the checksum. + * the checksum. + * @param[in] location Offset within L2 packet of the first of the two bytes + * to be replaced with the calculated checksum. + * @param[in] seed Initial value of the running checksum before any of the + * packet data is added. + */ +static __inline void +NETIO_PKT_DO_EGRESS_CSUM(netio_pkt_t* pkt, int start, int length, + int location, uint16_t seed) +{ + netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); + + NETIO_PKT_DO_EGRESS_CSUM_MM(mmd, pkt, start, length, location, seed); +} + + +/** Return the number of bytes which could be prepended to a packet, using a + * metadata pointer to speed the operation. + * See @ref netio_populate_prepend_buffer() to get a full description of + * prepending. + * + * @param[in,out] mda Pointer to packet's standard metadata. + * @param[in] pkt Packet on which to operate. + */ +static __inline int +NETIO_PKT_PREPEND_AVAIL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ + return (pkt->__packet.bits.__offset << 6) + + NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt); +} + + +/** Return the number of bytes which could be prepended to a packet, using a + * metadata pointer to speed the operation. + * See @ref netio_populate_prepend_buffer() to get a full description of + * prepending. + * @ingroup egress + * + * @param[in,out] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + */ +static __inline int +NETIO_PKT_PREPEND_AVAIL_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt) +{ + return (pkt->__packet.bits.__offset << 6) + mmd->l2_offset; +} + + +/** Return the number of bytes which could be prepended to a packet. + * See @ref netio_populate_prepend_buffer() to get a full description of + * prepending. + * @ingroup egress + * + * @param[in] pkt Packet on which to operate. + */ +static __inline int +NETIO_PKT_PREPEND_AVAIL(netio_pkt_t* pkt) +{ + if (NETIO_PKT_IS_MINIMAL(pkt)) + { + netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); + + return NETIO_PKT_PREPEND_AVAIL_MM(mmd, pkt); + } + else + { + netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); + + return NETIO_PKT_PREPEND_AVAIL_M(mda, pkt); + } +} + + +/** Flush a packet's minimal metadata from the cache, using a metadata pointer + * to speed the operation. + * @ingroup egress + * + * @param[in] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_FLUSH_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd, + netio_pkt_t* pkt) +{ +} + + +/** Invalidate a packet's minimal metadata from the cache, using a metadata + * pointer to speed the operation. + * @ingroup egress + * + * @param[in] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_INV_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd, + netio_pkt_t* pkt) +{ +} + + +/** Flush and then invalidate a packet's minimal metadata from the cache, + * using a metadata pointer to speed the operation. + * @ingroup egress + * + * @param[in] mmd Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_FLUSH_INV_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd, + netio_pkt_t* pkt) +{ +} + + +/** Flush a packet's metadata from the cache, using a metadata pointer + * to speed the operation. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's minimal metadata. + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_FLUSH_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ +} + + +/** Invalidate a packet's metadata from the cache, using a metadata + * pointer to speed the operation. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's metadata. + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_INV_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ +} + + +/** Flush and then invalidate a packet's metadata from the cache, + * using a metadata pointer to speed the operation. + * @ingroup ingress + * + * @param[in] mda Pointer to packet's metadata. + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_FLUSH_INV_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) +{ +} + + +/** Flush a packet's minimal metadata from the cache. + * @ingroup egress + * + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_FLUSH_MINIMAL_METADATA(netio_pkt_t* pkt) +{ +} + + +/** Invalidate a packet's minimal metadata from the cache. + * @ingroup egress + * + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_INV_MINIMAL_METADATA(netio_pkt_t* pkt) +{ +} + + +/** Flush and then invalidate a packet's minimal metadata from the cache. + * @ingroup egress + * + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_FLUSH_INV_MINIMAL_METADATA(netio_pkt_t* pkt) +{ +} + + +/** Flush a packet's metadata from the cache. + * @ingroup ingress + * + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_FLUSH_METADATA(netio_pkt_t* pkt) +{ +} + + +/** Invalidate a packet's metadata from the cache. + * @ingroup ingress + * + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_INV_METADATA(netio_pkt_t* pkt) +{ +} + + +/** Flush and then invalidate a packet's metadata from the cache. + * @ingroup ingress + * + * @param[in] pkt Packet on which to operate. + */ +static __inline void +NETIO_PKT_FLUSH_INV_METADATA(netio_pkt_t* pkt) +{ +} + +/** Number of NUMA nodes we can distribute buffers to. + * @ingroup setup */ +#define NETIO_NUM_NODE_WEIGHTS 16 + +/** + * @brief An object for specifying the characteristics of NetIO communication + * endpoint. + * + * @ingroup setup + * + * The @ref netio_input_register() function uses this structure to define + * how an application tile will communicate with an IPP. + * + * + * Future updates to NetIO may add new members to this structure, + * which can affect the success of the registration operation. Thus, + * if dynamically initializing the structure, applications are urged to + * zero it out first, for example: + * + * @code + * netio_input_config_t config; + * memset(&config, 0, sizeof (config)); + * config.flags = NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE; + * config.num_receive_packets = NETIO_MAX_RECEIVE_PKTS; + * config.queue_id = 0; + * . + * . + * . + * @endcode + * + * since that guarantees that any unused structure members, including + * members which did not exist when the application was first developed, + * will not have unexpected values. + * + * If statically initializing the structure, we strongly recommend use of + * C99-style named initializers, for example: + * + * @code + * netio_input_config_t config = { + * .flags = NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE, + * .num_receive_packets = NETIO_MAX_RECEIVE_PKTS, + * .queue_id = 0, + * }, + * @endcode + * + * instead of the old-style structure initialization: + * + * @code + * // Bad example! Currently equivalent to the above, but don't do this. + * netio_input_config_t config = { + * NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE, NETIO_MAX_RECEIVE_PKTS, 0 + * }, + * @endcode + * + * since the C99 style requires no changes to the code if elements of the + * config structure are rearranged. (It also makes the initialization much + * easier to understand.) + * + * Except for items which address a particular tile's transmit or receive + * characteristics, such as the ::NETIO_RECV flag, applications are advised + * to specify the same set of configuration data on all registrations. + * This prevents differing results if multiple tiles happen to do their + * registration operations in a different order on different invocations of + * the application. This is particularly important for things like link + * management flags, and buffer size and homing specifications. + * + * Unless the ::NETIO_FIXED_BUFFER_VA flag is specified in flags, the NetIO + * buffer pool is automatically created and mapped into the application's + * virtual address space at an address chosen by the operating system, + * using the common memory (cmem) facility in the Tilera Multicore + * Components library. The cmem facility allows multiple processes to gain + * access to shared memory which is mapped into each process at an + * identical virtual address. In order for this to work, the processes + * must have a common ancestor, which must create the common memory using + * tmc_cmem_init(). + * + * In programs using the iLib process creation API, or in programs which use + * only one process (which include programs using the pthreads library), + * tmc_cmem_init() is called automatically. All other applications + * must call it explicitly, before any child processes which might call + * netio_input_register() are created. + */ +typedef struct +{ + /** Registration characteristics. + + This value determines several characteristics of the registration; + flags for different types of behavior are ORed together to make the + final flag value. Generally applications should specify exactly + one flag from each of the following categories: + + - Whether the application will be receiving packets on this queue + (::NETIO_RECV or ::NETIO_NO_RECV). + + - Whether the application will be transmitting packets on this queue, + and if so, whether it will request egress checksum calculation + (::NETIO_XMIT, ::NETIO_XMIT_CSUM, or ::NETIO_NO_XMIT). It is + legal to call netio_get_buffer() without one of the XMIT flags, + as long as ::NETIO_RECV is specified; in this case, the retrieved + buffers must be passed to another tile for transmission. + + - Whether the application expects any vendor-specific tags in + its packets' L2 headers (::NETIO_TAG_NONE, ::NETIO_TAG_BRCM, + or ::NETIO_TAG_MRVL). This must match the configuration of the + target IPP. + + To accommodate applications written to previous versions of the NetIO + interface, none of the flags above are currently required; if omitted, + NetIO behaves more or less as if ::NETIO_RECV | ::NETIO_XMIT_CSUM | + ::NETIO_TAG_NONE were used. However, explicit specification of + the relevant flags allows NetIO to do a better job of resource + allocation, allows earlier detection of certain configuration errors, + and may enable advanced features or higher performance in the future, + so their use is strongly recommended. + + Note that specifying ::NETIO_NO_RECV along with ::NETIO_NO_XMIT + is a special case, intended primarily for use by programs which + retrieve network statistics or do link management operations. + When these flags are both specified, the resulting queue may not + be used with NetIO routines other than netio_get(), netio_set(), + and netio_input_unregister(). See @ref link for more information + on link management. + + Other flags are optional; their use is described below. + */ + int flags; + + /** Interface name. This is a string which identifies the specific + Ethernet controller hardware to be used. The format of the string + is a device type and a device index, separated by a slash; so, + the first 10 Gigabit Ethernet controller is named "xgbe/0", while + the second 10/100/1000 Megabit Ethernet controller is named "gbe/1". + */ + const char* interface; + + /** Receive packet queue size. This specifies the maximum number + of ingress packets that can be received on this queue without + being retrieved by @ref netio_get_packet(). If the IPP's distribution + algorithm calls for a packet to be sent to this queue, and this + number of packets are already pending there, the new packet + will either be discarded, or sent to another tile registered + for the same queue_id (see @ref drops). This value must + be at least ::NETIO_MIN_RECEIVE_PKTS, can always be at least + ::NETIO_MAX_RECEIVE_PKTS, and may be larger than that on certain + interfaces. + */ + int num_receive_packets; + + /** The queue ID being requested. Legal values for this range from 0 + to ::NETIO_MAX_QUEUE_ID, inclusive. ::NETIO_MAX_QUEUE_ID is always + greater than or equal to the number of tiles; this allows one queue + for each tile, plus at least one additional queue. Some applications + may wish to use the additional queue as a destination for unwanted + packets, since packets delivered to queues for which no tiles have + registered are discarded. + */ + unsigned int queue_id; + + /** Maximum number of small send buffers to be held in the local empty + buffer cache. This specifies the size of the area which holds + empty small egress buffers requested from the IPP but not yet + retrieved via @ref netio_get_buffer(). This value must be greater + than zero if the application will ever use @ref netio_get_buffer() + to allocate empty small egress buffers; it may be no larger than + ::NETIO_MAX_SEND_BUFFERS. See @ref epp for more details on empty + buffer caching. + */ + int num_send_buffers_small_total; + + /** Number of small send buffers to be preallocated at registration. + If this value is nonzero, the specified number of empty small egress + buffers will be requested from the IPP during the netio_input_register + operation; this may speed the execution of @ref netio_get_buffer(). + This may be no larger than @ref num_send_buffers_small_total. See @ref + epp for more details on empty buffer caching. + */ + int num_send_buffers_small_prealloc; + + /** Maximum number of large send buffers to be held in the local empty + buffer cache. This specifies the size of the area which holds empty + large egress buffers requested from the IPP but not yet retrieved via + @ref netio_get_buffer(). This value must be greater than zero if the + application will ever use @ref netio_get_buffer() to allocate empty + large egress buffers; it may be no larger than ::NETIO_MAX_SEND_BUFFERS. + See @ref epp for more details on empty buffer caching. + */ + int num_send_buffers_large_total; + + /** Number of large send buffers to be preallocated at registration. + If this value is nonzero, the specified number of empty large egress + buffers will be requested from the IPP during the netio_input_register + operation; this may speed the execution of @ref netio_get_buffer(). + This may be no larger than @ref num_send_buffers_large_total. See @ref + epp for more details on empty buffer caching. + */ + int num_send_buffers_large_prealloc; + + /** Maximum number of jumbo send buffers to be held in the local empty + buffer cache. This specifies the size of the area which holds empty + jumbo egress buffers requested from the IPP but not yet retrieved via + @ref netio_get_buffer(). This value must be greater than zero if the + application will ever use @ref netio_get_buffer() to allocate empty + jumbo egress buffers; it may be no larger than ::NETIO_MAX_SEND_BUFFERS. + See @ref epp for more details on empty buffer caching. + */ + int num_send_buffers_jumbo_total; + + /** Number of jumbo send buffers to be preallocated at registration. + If this value is nonzero, the specified number of empty jumbo egress + buffers will be requested from the IPP during the netio_input_register + operation; this may speed the execution of @ref netio_get_buffer(). + This may be no larger than @ref num_send_buffers_jumbo_total. See @ref + epp for more details on empty buffer caching. + */ + int num_send_buffers_jumbo_prealloc; + + /** Total packet buffer size. This determines the total size, in bytes, + of the NetIO buffer pool. Note that the maximum number of available + buffers of each size is determined during hypervisor configuration + (see the <em>System Programmer's Guide</em> for details); this just + influences how much host memory is allocated for those buffers. + + The buffer pool is allocated from common memory, which will be + automatically initialized if needed. If your buffer pool is larger + than 240 MB, you might need to explicitly call @c tmc_cmem_init(), + as described in the Application Libraries Reference Manual (UG227). + + Packet buffers are currently allocated in chunks of 16 MB; this + value will be rounded up to the next larger multiple of 16 MB. + If this value is zero, a default of 32 MB will be used; this was + the value used by previous versions of NetIO. Note that taking this + default also affects the placement of buffers on Linux NUMA nodes. + See @ref buffer_node_weights for an explanation of buffer placement. + + In order to successfully allocate packet buffers, Linux must have + available huge pages on the relevant Linux NUMA nodes. See the + <em>System Programmer's Guide</em> for information on configuring + huge page support in Linux. + */ + uint64_t total_buffer_size; + + /** Buffer placement weighting factors. + + This array specifies the relative amount of buffering to place + on each of the available Linux NUMA nodes. This array is + indexed by the NUMA node, and the values in the array are + proportional to the amount of buffer space to allocate on that + node. + + If memory striping is enabled in the Hypervisor, then there is + only one logical NUMA node (node 0). In that case, NetIO will by + default ignore the suggested buffer node weights, and buffers + will be striped across the physical memory controllers. See + UG209 System Programmer's Guide for a description of the + hypervisor option that controls memory striping. + + If memory striping is disabled, then there are up to four NUMA + nodes, corresponding to the four DDRAM controllers in the TILE + processor architecture. See UG100 Tile Processor Architecture + Overview for a diagram showing the location of each of the DDRAM + controllers relative to the tile array. + + For instance, if memory striping is disabled, the following + configuration strucure: + + @code + netio_input_config_t config = { + . + . + . + .total_buffer_size = 4 * 16 * 1024 * 1024; + .buffer_node_weights = { 1, 0, 1, 0 }, + }, + @endcode + + would result in 32 MB of buffers being placed on controller 0, and + 32 MB on controller 2. (Since buffers are allocated in units of + 16 MB, some sets of weights will not be able to be matched exactly.) + + For the weights to be effective, @ref total_buffer_size must be + nonzero. If @ref total_buffer_size is zero, causing the default + 32 MB of buffer space to be used, then any specified weights will + be ignored, and buffers will positioned as they were in previous + versions of NetIO: + + - For xgbe/0 and gbe/0, 16 MB of buffers will be placed on controller 1, + and the other 16 MB will be placed on controller 2. + + - For xgbe/1 and gbe/1, 16 MB of buffers will be placed on controller 2, + and the other 16 MB will be placed on controller 3. + + If @ref total_buffer_size is nonzero, but all weights are zero, + then all buffer space will be allocated on Linux NUMA node zero. + + By default, the specified buffer placement is treated as a hint; + if sufficient free memory is not available on the specified + controllers, the buffers will be allocated elsewhere. However, + if the ::NETIO_STRICT_HOMING flag is specified in @ref flags, then a + failure to allocate buffer space exactly as requested will cause the + registration operation to fail with an error of ::NETIO_CANNOT_HOME. + + Note that maximal network performance cannot be achieved with + only one memory controller. + */ + uint8_t buffer_node_weights[NETIO_NUM_NODE_WEIGHTS]; + + /** Fixed virtual address for packet buffers. Only valid when + ::NETIO_FIXED_BUFFER_VA is specified in @ref flags; see the + description of that flag for details. + */ + void* fixed_buffer_va; + + /** + Maximum number of outstanding send packet requests. This value is + only relevant when an EPP is in use; it determines the number of + slots in the EPP's outgoing packet queue which this tile is allowed + to consume, and thus the number of packets which may be sent before + the sending tile must wait for an acknowledgment from the EPP. + Modifying this value is generally only helpful when using @ref + netio_send_packet_vector(), where it can help improve performance by + allowing a single vector send operation to process more packets. + Typically it is not specified, and the default, which divides the + outgoing packet slots evenly between all tiles on the chip, is used. + + If a registration asks for more outgoing packet queue slots than are + available, ::NETIO_TOOMANY_XMIT will be returned. The total number + of packet queue slots which are available for all tiles for each EPP + is subject to change, but is currently ::NETIO_TOTAL_SENDS_OUTSTANDING. + + + This value is ignored if ::NETIO_XMIT is not specified in flags. + If you want to specify a large value here for a specific tile, you are + advised to specify NETIO_NO_XMIT on other, non-transmitting tiles so + that they do not consume a default number of packet slots. Any tile + transmitting is required to have at least ::NETIO_MIN_SENDS_OUTSTANDING + slots allocated to it; values less than that will be silently + increased by the NetIO library. + */ + int num_sends_outstanding; +} +netio_input_config_t; + + +/** Registration flags; used in the @ref netio_input_config_t structure. + * @addtogroup setup + */ +/** @{ */ + +/** Fail a registration request if we can't put packet buffers + on the specified memory controllers. */ +#define NETIO_STRICT_HOMING 0x00000002 + +/** This application expects no tags on its L2 headers. */ +#define NETIO_TAG_NONE 0x00000004 + +/** This application expects Marvell extended tags on its L2 headers. */ +#define NETIO_TAG_MRVL 0x00000008 + +/** This application expects Broadcom tags on its L2 headers. */ +#define NETIO_TAG_BRCM 0x00000010 + +/** This registration may call routines which receive packets. */ +#define NETIO_RECV 0x00000020 + +/** This registration may not call routines which receive packets. */ +#define NETIO_NO_RECV 0x00000040 + +/** This registration may call routines which transmit packets. */ +#define NETIO_XMIT 0x00000080 + +/** This registration may call routines which transmit packets with + checksum acceleration. */ +#define NETIO_XMIT_CSUM 0x00000100 + +/** This registration may not call routines which transmit packets. */ +#define NETIO_NO_XMIT 0x00000200 + +/** This registration wants NetIO buffers mapped at an application-specified + virtual address. + + NetIO buffers are by default created by the TMC common memory facility, + which must be configured by a common ancestor of all processes sharing + a network interface. When this flag is specified, NetIO buffers are + instead mapped at an address chosen by the application (and specified + in @ref netio_input_config_t::fixed_buffer_va). This allows multiple + unrelated but cooperating processes to share a NetIO interface. + All processes sharing the same interface must specify this flag, + and all must specify the same fixed virtual address. + + @ref netio_input_config_t::fixed_buffer_va must be a + multiple of 16 MB, and the packet buffers will occupy @ref + netio_input_config_t::total_buffer_size bytes of virtual address + space, beginning at that address. If any of those virtual addresses + are currently occupied by other memory objects, like application or + shared library code or data, @ref netio_input_register() will return + ::NETIO_FAULT. While it is impossible to provide a fixed_buffer_va + which will work for all applications, a good first guess might be to + use 0xb0000000 minus @ref netio_input_config_t::total_buffer_size. + If that fails, it might be helpful to consult the running application's + virtual address description file (/proc/<em>pid</em>/maps) to see + which regions of virtual address space are available. + */ +#define NETIO_FIXED_BUFFER_VA 0x00000400 + +/** This registration call will not complete unless the network link + is up. The process will wait several seconds for this to happen (the + precise interval is link-dependent), but if the link does not come up, + ::NETIO_LINK_DOWN will be returned. This flag is the default if + ::NETIO_NOREQUIRE_LINK_UP is not specified. Note that this flag by + itself does not request that the link be brought up; that can be done + with the ::NETIO_AUTO_LINK_UPDN or ::NETIO_AUTO_LINK_UP flags (the + latter is the default if no NETIO_AUTO_LINK_xxx flags are specified), + or by explicitly setting the link's desired state via netio_set(). + If the link is not brought up by one of those methods, and this flag + is specified, the registration operation will return ::NETIO_LINK_DOWN. + This flag is ignored if it is specified along with ::NETIO_NO_XMIT and + ::NETIO_NO_RECV. See @ref link for more information on link + management. + */ +#define NETIO_REQUIRE_LINK_UP 0x00000800 + +/** This registration call will complete even if the network link is not up. + Whenever the link is not up, packets will not be sent or received: + netio_get_packet() will return ::NETIO_NOPKT once all queued packets + have been drained, and netio_send_packet() and similar routines will + return NETIO_QUEUE_FULL once the outgoing packet queue in the EPP + or the I/O shim is full. See @ref link for more information on link + management. + */ +#define NETIO_NOREQUIRE_LINK_UP 0x00001000 + +#ifndef __DOXYGEN__ +/* + * These are part of the implementation of the NETIO_AUTO_LINK_xxx flags, + * but should not be used directly by applications, and are thus not + * documented. + */ +#define _NETIO_AUTO_UP 0x00002000 +#define _NETIO_AUTO_DN 0x00004000 +#define _NETIO_AUTO_PRESENT 0x00008000 +#endif + +/** Set the desired state of the link to up, allowing any speeds which are + supported by the link hardware, as part of this registration operation. + Do not take down the link automatically. This is the default if + no other NETIO_AUTO_LINK_xxx flags are specified. This flag is ignored + if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV. + See @ref link for more information on link management. + */ +#define NETIO_AUTO_LINK_UP (_NETIO_AUTO_PRESENT | _NETIO_AUTO_UP) + +/** Set the desired state of the link to up, allowing any speeds which are + supported by the link hardware, as part of this registration operation. + Set the desired state of the link to down the next time no tiles are + registered for packet reception or transmission. This flag is ignored + if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV. + See @ref link for more information on link management. + */ +#define NETIO_AUTO_LINK_UPDN (_NETIO_AUTO_PRESENT | _NETIO_AUTO_UP | \ + _NETIO_AUTO_DN) + +/** Set the desired state of the link to down the next time no tiles are + registered for packet reception or transmission. This flag is ignored + if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV. + See @ref link for more information on link management. + */ +#define NETIO_AUTO_LINK_DN (_NETIO_AUTO_PRESENT | _NETIO_AUTO_DN) + +/** Do not bring up the link automatically as part of this registration + operation. Do not take down the link automatically. This flag + is ignored if it is specified along with ::NETIO_NO_XMIT and + ::NETIO_NO_RECV. See @ref link for more information on link management. + */ +#define NETIO_AUTO_LINK_NONE _NETIO_AUTO_PRESENT + + +/** Minimum number of receive packets. */ +#define NETIO_MIN_RECEIVE_PKTS 16 + +/** Lower bound on the maximum number of receive packets; may be higher + than this on some interfaces. */ +#define NETIO_MAX_RECEIVE_PKTS 128 + +/** Maximum number of send buffers, per packet size. */ +#define NETIO_MAX_SEND_BUFFERS 16 + +/** Number of EPP queue slots, and thus outstanding sends, per EPP. */ +#define NETIO_TOTAL_SENDS_OUTSTANDING 2015 + +/** Minimum number of EPP queue slots, and thus outstanding sends, per + * transmitting tile. */ +#define NETIO_MIN_SENDS_OUTSTANDING 16 + + +/**@}*/ + +#ifndef __DOXYGEN__ + +/** + * An object for providing Ethernet packets to a process. + */ +struct __netio_queue_impl_t; + +/** + * An object for managing the user end of a NetIO queue. + */ +struct __netio_queue_user_impl_t; + +#endif /* !__DOXYGEN__ */ + + +/** A netio_queue_t describes a NetIO communications endpoint. + * @ingroup setup + */ +typedef struct +{ +#ifdef __DOXYGEN__ + uint8_t opaque[8]; /**< This is an opaque structure. */ +#else + struct __netio_queue_impl_t* __system_part; /**< The system part. */ + struct __netio_queue_user_impl_t* __user_part; /**< The user part. */ +#ifdef _NETIO_PTHREAD + _netio_percpu_mutex_t lock; /**< Queue lock. */ +#endif +#endif +} +netio_queue_t; + + +/** + * @brief Packet send context. + * + * @ingroup egress + * + * Packet send context for use with netio_send_packet_prepare and _commit. + */ +typedef struct +{ +#ifdef __DOXYGEN__ + uint8_t opaque[44]; /**< This is an opaque structure. */ +#else + uint8_t flags; /**< Defined below */ + uint8_t datalen; /**< Number of valid words pointed to by data. */ + uint32_t request[9]; /**< Request to be sent to the EPP or shim. Note + that this is smaller than the 11-word maximum + request size, since some constant values are + not saved in the context. */ + uint32_t *data; /**< Data to be sent to the EPP or shim via IDN. */ +#endif +} +netio_send_pkt_context_t; + + +#ifndef __DOXYGEN__ +#define SEND_PKT_CTX_USE_EPP 1 /**< We're sending to an EPP. */ +#define SEND_PKT_CTX_SEND_CSUM 2 /**< Request includes a checksum. */ +#endif + +/** + * @brief Packet vector entry. + * + * @ingroup egress + * + * This data structure is used with netio_send_packet_vector() to send multiple + * packets with one NetIO call. The structure should be initialized by + * calling netio_pkt_vector_set(), rather than by setting the fields + * directly. + * + * This structure is guaranteed to be a power of two in size, no + * bigger than one L2 cache line, and to be aligned modulo its size. + */ +typedef struct +#ifndef __DOXYGEN__ +__attribute__((aligned(8))) +#endif +{ + /** Reserved for use by the user application. When initialized with + * the netio_set_pkt_vector_entry() function, this field is guaranteed + * to be visible to readers only after all other fields are already + * visible. This way it can be used as a valid flag or generation + * counter. */ + uint8_t user_data; + + /* Structure members below this point should not be accessed directly by + * applications, as they may change in the future. */ + + /** Low 8 bits of the packet address to send. The high bits are + * acquired from the 'handle' field. */ + uint8_t buffer_address_low; + + /** Number of bytes to transmit. */ + uint16_t size; + + /** The raw handle from a netio_pkt_t. If this is NETIO_PKT_HANDLE_NONE, + * this vector entry will be skipped and no packet will be transmitted. */ + netio_pkt_handle_t handle; +} +netio_pkt_vector_entry_t; + + +/** + * @brief Initialize fields in a packet vector entry. + * + * @ingroup egress + * + * @param[out] v Pointer to the vector entry to be initialized. + * @param[in] pkt Packet to be transmitted when the vector entry is passed to + * netio_send_packet_vector(). Note that the packet's attributes + * (e.g., its L2 offset and length) are captured at the time this + * routine is called; subsequent changes in those attributes will not + * be reflected in the packet which is actually transmitted. + * Changes in the packet's contents, however, will be so reflected. + * If this is NULL, no packet will be transmitted. + * @param[in] user_data User data to be set in the vector entry. + * This function guarantees that the "user_data" field will become + * visible to a reader only after all other fields have become visible. + * This allows a structure in a ring buffer to be written and read + * by a polling reader without any locks or other synchronization. + */ +static __inline void +netio_pkt_vector_set(volatile netio_pkt_vector_entry_t* v, netio_pkt_t* pkt, + uint8_t user_data) +{ + if (pkt) + { + if (NETIO_PKT_IS_MINIMAL(pkt)) + { + netio_pkt_minimal_metadata_t* mmd = + (netio_pkt_minimal_metadata_t*) &pkt->__metadata; + v->buffer_address_low = (uintptr_t) NETIO_PKT_L2_DATA_MM(mmd, pkt) & 0xFF; + v->size = NETIO_PKT_L2_LENGTH_MM(mmd, pkt); + } + else + { + netio_pkt_metadata_t* mda = &pkt->__metadata; + v->buffer_address_low = (uintptr_t) NETIO_PKT_L2_DATA_M(mda, pkt) & 0xFF; + v->size = NETIO_PKT_L2_LENGTH_M(mda, pkt); + } + v->handle.word = pkt->__packet.word; + } + else + { + v->handle.word = 0; /* Set handle to NETIO_PKT_HANDLE_NONE. */ + } + + __asm__("" : : : "memory"); + + v->user_data = user_data; +} + + +/** + * Flags and structures for @ref netio_get() and @ref netio_set(). + * @ingroup config + */ + +/** @{ */ +/** Parameter class; addr is a NETIO_PARAM_xxx value. */ +#define NETIO_PARAM 0 +/** Interface MAC address. This address is only valid with @ref netio_get(). + * The value is a 6-byte MAC address. Depending upon the overall system + * design, a MAC address may or may not be available for each interface. */ +#define NETIO_PARAM_MAC 0 + +/** Determine whether to suspend output on the receipt of pause frames. + * If the value is nonzero, the I/O shim will suspend output when a pause + * frame is received. If the value is zero, pause frames will be ignored. */ +#define NETIO_PARAM_PAUSE_IN 1 + +/** Determine whether to send pause frames if the I/O shim packet FIFOs are + * nearly full. If the value is zero, pause frames are not sent. If + * the value is nonzero, it is the delay value which will be sent in any + * pause frames which are output, in units of 512 bit times. */ +#define NETIO_PARAM_PAUSE_OUT 2 + +/** Jumbo frame support. The value is a 4-byte integer. If the value is + * nonzero, the MAC will accept frames of up to 10240 bytes. If the value + * is zero, the MAC will only accept frames of up to 1544 bytes. */ +#define NETIO_PARAM_JUMBO 3 + +/** I/O shim's overflow statistics register. The value is two 16-bit integers. + * The first 16-bit value (or the low 16 bits, if the value is treated as a + * 32-bit number) is the count of packets which were completely dropped and + * not delivered by the shim. The second 16-bit value (or the high 16 bits, + * if the value is treated as a 32-bit number) is the count of packets + * which were truncated and thus only partially delivered by the shim. This + * register is automatically reset to zero after it has been read. + */ +#define NETIO_PARAM_OVERFLOW 4 + +/** IPP statistics. This address is only valid with @ref netio_get(). The + * value is a netio_stat_t structure. Unlike the I/O shim statistics, the + * IPP statistics are not all reset to zero on read; see the description + * of the netio_stat_t for details. */ +#define NETIO_PARAM_STAT 5 + +/** Possible link state. The value is a combination of "NETIO_LINK_xxx" + * flags. With @ref netio_get(), this will indicate which flags are + * actually supported by the hardware. + * + * For historical reasons, specifying this value to netio_set() will have + * the same behavior as using ::NETIO_PARAM_LINK_CONFIG, but this usage is + * discouraged. + */ +#define NETIO_PARAM_LINK_POSSIBLE_STATE 6 + +/** Link configuration. The value is a combination of "NETIO_LINK_xxx" flags. + * With @ref netio_set(), this will attempt to immediately bring up the + * link using whichever of the requested flags are supported by the + * hardware, or take down the link if the flags are zero; if this is + * not possible, an error will be returned. Many programs will want + * to use ::NETIO_PARAM_LINK_DESIRED_STATE instead. + * + * For historical reasons, specifying this value to netio_get() will + * have the same behavior as using ::NETIO_PARAM_LINK_POSSIBLE_STATE, + * but this usage is discouraged. + */ +#define NETIO_PARAM_LINK_CONFIG NETIO_PARAM_LINK_POSSIBLE_STATE + +/** Current link state. This address is only valid with @ref netio_get(). + * The value is zero or more of the "NETIO_LINK_xxx" flags, ORed together. + * If the link is down, the value ANDed with NETIO_LINK_SPEED will be + * zero; if the link is up, the value ANDed with NETIO_LINK_SPEED will + * result in exactly one of the NETIO_LINK_xxx values, indicating the + * current speed. */ +#define NETIO_PARAM_LINK_CURRENT_STATE 7 + +/** Variant symbol for current state, retained for compatibility with + * pre-MDE-2.1 programs. */ +#define NETIO_PARAM_LINK_STATUS NETIO_PARAM_LINK_CURRENT_STATE + +/** Packet Coherence protocol. This address is only valid with @ref netio_get(). + * The value is nonzero if the interface is configured for cache-coherent DMA. + */ +#define NETIO_PARAM_COHERENT 8 + +/** Desired link state. The value is a conbination of "NETIO_LINK_xxx" + * flags, which specify the desired state for the link. With @ref + * netio_set(), this will, in the background, attempt to bring up the link + * using whichever of the requested flags are reasonable, or take down the + * link if the flags are zero. The actual link up or down operation may + * happen after this call completes. If the link state changes in the + * future, the system will continue to try to get back to the desired link + * state; for instance, if the link is brought up successfully, and then + * the network cable is disconnected, the link will go down. However, the + * desired state of the link is still up, so if the cable is reconnected, + * the link will be brought up again. + * + * With @ref netio_get(), this will indicate the desired state for the + * link, as set with a previous netio_set() call, or implicitly by a + * netio_input_register() or netio_input_unregister() operation. This may + * not reflect the current state of the link; to get that, use + * ::NETIO_PARAM_LINK_CURRENT_STATE. */ +#define NETIO_PARAM_LINK_DESIRED_STATE 9 + +/** NetIO statistics structure. Retrieved using the ::NETIO_PARAM_STAT + * address passed to @ref netio_get(). */ +typedef struct +{ + /** Number of packets which have been received by the IPP and forwarded + * to a tile's receive queue for processing. This value wraps at its + * maximum, and is not cleared upon read. */ + uint32_t packets_received; + + /** Number of packets which have been dropped by the IPP, because they could + * not be received, or could not be forwarded to a tile. The former happens + * when the IPP does not have a free packet buffer of suitable size for an + * incoming frame. The latter happens when all potential destination tiles + * for a packet, as defined by the group, bucket, and queue configuration, + * have full receive queues. This value wraps at its maximum, and is not + * cleared upon read. */ + uint32_t packets_dropped; + + /* + * Note: the #defines after each of the following four one-byte values + * denote their location within the third word of the netio_stat_t. They + * are intended for use only by the IPP implementation and are thus omitted + * from the Doxygen output. + */ + + /** Number of packets dropped because no worker was able to accept a new + * packet. This value saturates at its maximum, and is cleared upon + * read. */ + uint8_t drops_no_worker; +#ifndef __DOXYGEN__ +#define NETIO_STAT_DROPS_NO_WORKER 0 +#endif + + /** Number of packets dropped because no small buffers were available. + * This value saturates at its maximum, and is cleared upon read. */ + uint8_t drops_no_smallbuf; +#ifndef __DOXYGEN__ +#define NETIO_STAT_DROPS_NO_SMALLBUF 1 +#endif + + /** Number of packets dropped because no large buffers were available. + * This value saturates at its maximum, and is cleared upon read. */ + uint8_t drops_no_largebuf; +#ifndef __DOXYGEN__ +#define NETIO_STAT_DROPS_NO_LARGEBUF 2 +#endif + + /** Number of packets dropped because no jumbo buffers were available. + * This value saturates at its maximum, and is cleared upon read. */ + uint8_t drops_no_jumbobuf; +#ifndef __DOXYGEN__ +#define NETIO_STAT_DROPS_NO_JUMBOBUF 3 +#endif +} +netio_stat_t; + + +/** Link can run, should run, or is running at 10 Mbps. */ +#define NETIO_LINK_10M 0x01 + +/** Link can run, should run, or is running at 100 Mbps. */ +#define NETIO_LINK_100M 0x02 + +/** Link can run, should run, or is running at 1 Gbps. */ +#define NETIO_LINK_1G 0x04 + +/** Link can run, should run, or is running at 10 Gbps. */ +#define NETIO_LINK_10G 0x08 + +/** Link should run at the highest speed supported by the link and by + * the device connected to the link. Only usable as a value for + * the link's desired state; never returned as a value for the current + * or possible states. */ +#define NETIO_LINK_ANYSPEED 0x10 + +/** All legal link speeds. */ +#define NETIO_LINK_SPEED (NETIO_LINK_10M | \ + NETIO_LINK_100M | \ + NETIO_LINK_1G | \ + NETIO_LINK_10G | \ + NETIO_LINK_ANYSPEED) + + +/** MAC register class. Addr is a register offset within the MAC. + * Registers within the XGbE and GbE MACs are documented in the Tile + * Processor I/O Device Guide (UG104). MAC registers start at address + * 0x4000, and do not include the MAC_INTERFACE registers. */ +#define NETIO_MAC 1 + +/** MDIO register class (IEEE 802.3 clause 22 format). Addr is the "addr" + * member of a netio_mdio_addr_t structure. */ +#define NETIO_MDIO 2 + +/** MDIO register class (IEEE 802.3 clause 45 format). Addr is the "addr" + * member of a netio_mdio_addr_t structure. */ +#define NETIO_MDIO_CLAUSE45 3 + +/** NetIO MDIO address type. Retrieved or provided using the ::NETIO_MDIO + * address passed to @ref netio_get() or @ref netio_set(). */ +typedef union +{ + struct + { + unsigned int reg:16; /**< MDIO register offset. For clause 22 access, + must be less than 32. */ + unsigned int phy:5; /**< Which MDIO PHY to access. */ + unsigned int dev:5; /**< Which MDIO device to access within that PHY. + Applicable for clause 45 access only; ignored + for clause 22 access. */ + } + bits; /**< Container for bitfields. */ + uint64_t addr; /**< Value to pass to @ref netio_get() or + * @ref netio_set(). */ +} +netio_mdio_addr_t; + +/** @} */ + +#endif /* __NETIO_INTF_H__ */ diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile index 112b1e248f05..b4c8e8ec45dc 100644 --- a/arch/tile/kernel/Makefile +++ b/arch/tile/kernel/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_SMP) += smpboot.o smp.o tlb.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o +obj-$(CONFIG_PCI) += pci.o diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c index 543d6a33aa26..dbb0dfc7bece 100644 --- a/arch/tile/kernel/compat_signal.c +++ b/arch/tile/kernel/compat_signal.c @@ -290,12 +290,12 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, return ret; } +/* The assembly shim for this function arranges to ignore the return value. */ long compat_sys_rt_sigreturn(struct pt_regs *regs) { struct compat_rt_sigframe __user *frame = (struct compat_rt_sigframe __user *) compat_ptr(regs->sp); sigset_t set; - long r0; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; @@ -308,13 +308,13 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) + if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0) goto badframe; - return r0; + return 0; badframe: force_sig(SIGSEGV, current); diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S index f5821626247f..5eed4a02bf62 100644 --- a/arch/tile/kernel/intvec_32.S +++ b/arch/tile/kernel/intvec_32.S @@ -1342,8 +1342,8 @@ handle_syscall: lw r20, r20 /* Jump to syscall handler. */ - jalr r20; .Lhandle_syscall_link: - FEEDBACK_REENTER(handle_syscall) + jalr r20 +.Lhandle_syscall_link: /* value of "lr" after "jalr r20" above */ /* * Write our r0 onto the stack so it gets restored instead @@ -1352,6 +1352,9 @@ handle_syscall: PTREGS_PTR(r29, PTREGS_OFFSET_REG(0)) sw r29, r0 +.Lsyscall_sigreturn_skip: + FEEDBACK_REENTER(handle_syscall) + /* Do syscall trace again, if requested. */ lw r30, r31 andi r30, r30, _TIF_SYSCALL_TRACE @@ -1536,9 +1539,24 @@ STD_ENTRY_LOCAL(bad_intr) }; \ STD_ENDPROC(_##x) +/* + * Special-case sigreturn to not write r0 to the stack on return. + * This is technically more efficient, but it also avoids difficulties + * in the 64-bit OS when handling 32-bit compat code, since we must not + * sign-extend r0 for the sigreturn return-value case. + */ +#define PTREGS_SYSCALL_SIGRETURN(x, reg) \ + STD_ENTRY(_##x); \ + addli lr, lr, .Lsyscall_sigreturn_skip - .Lhandle_syscall_link; \ + { \ + PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \ + j x \ + }; \ + STD_ENDPROC(_##x) + PTREGS_SYSCALL(sys_execve, r3) PTREGS_SYSCALL(sys_sigaltstack, r2) -PTREGS_SYSCALL(sys_rt_sigreturn, r0) +PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0) PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1) /* Save additional callee-saves to pt_regs, put address in r4 and jump. */ diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c new file mode 100644 index 000000000000..a1ee25be9ad9 --- /dev/null +++ b/arch/tile/kernel/pci.c @@ -0,0 +1,621 @@ +/* + * Copyright 2010 Tilera 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, version 2. + * + * 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. + */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/capability.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/bootmem.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/uaccess.h> + +#include <asm/processor.h> +#include <asm/sections.h> +#include <asm/byteorder.h> +#include <asm/hv_driver.h> +#include <hv/drv_pcie_rc_intf.h> + + +/* + * Initialization flow and process + * ------------------------------- + * + * This files containes the routines to search for PCI buses, + * enumerate the buses, and configure any attached devices. + * + * There are two entry points here: + * 1) tile_pci_init + * This sets up the pci_controller structs, and opens the + * FDs to the hypervisor. This is called from setup_arch() early + * in the boot process. + * 2) pcibios_init + * This probes the PCI bus(es) for any attached hardware. It's + * called by subsys_initcall. All of the real work is done by the + * generic Linux PCI layer. + * + */ + +/* + * This flag tells if the platform is TILEmpower that needs + * special configuration for the PLX switch chip. + */ +int __write_once tile_plx_gen1; + +static struct pci_controller controllers[TILE_NUM_PCIE]; +static int num_controllers; + +static struct pci_ops tile_cfg_ops; + + +/* + * We don't need to worry about the alignment of resources. + */ +resource_size_t pcibios_align_resource(void *data, const struct resource *res, + resource_size_t size, resource_size_t align) +{ + return res->start; +} +EXPORT_SYMBOL(pcibios_align_resource); + +/* + * Open a FD to the hypervisor PCI device. + * + * controller_id is the controller number, config type is 0 or 1 for + * config0 or config1 operations. + */ +static int __init tile_pcie_open(int controller_id, int config_type) +{ + char filename[32]; + int fd; + + sprintf(filename, "pcie/%d/config%d", controller_id, config_type); + + fd = hv_dev_open((HV_VirtAddr)filename, 0); + + return fd; +} + + +/* + * Get the IRQ numbers from the HV and set up the handlers for them. + */ +static int __init tile_init_irqs(int controller_id, + struct pci_controller *controller) +{ + char filename[32]; + int fd; + int ret; + int x; + struct pcie_rc_config rc_config; + + sprintf(filename, "pcie/%d/ctl", controller_id); + fd = hv_dev_open((HV_VirtAddr)filename, 0); + if (fd < 0) { + pr_err("PCI: hv_dev_open(%s) failed\n", filename); + return -1; + } + ret = hv_dev_pread(fd, 0, (HV_VirtAddr)(&rc_config), + sizeof(rc_config), PCIE_RC_CONFIG_MASK_OFF); + hv_dev_close(fd); + if (ret != sizeof(rc_config)) { + pr_err("PCI: wanted %zd bytes, got %d\n", + sizeof(rc_config), ret); + return -1; + } + /* Record irq_base so that we can map INTx to IRQ # later. */ + controller->irq_base = rc_config.intr; + + for (x = 0; x < 4; x++) + tile_irq_activate(rc_config.intr + x, + TILE_IRQ_HW_CLEAR); + + if (rc_config.plx_gen1) + controller->plx_gen1 = 1; + + return 0; +} + +/* + * First initialization entry point, called from setup_arch(). + * + * Find valid controllers and fill in pci_controller structs for each + * of them. + * + * Returns the number of controllers discovered. + */ +int __init tile_pci_init(void) +{ + int i; + + pr_info("PCI: Searching for controllers...\n"); + + /* Do any configuration we need before using the PCIe */ + + for (i = 0; i < TILE_NUM_PCIE; i++) { + int hv_cfg_fd0 = -1; + int hv_cfg_fd1 = -1; + int hv_mem_fd = -1; + char name[32]; + struct pci_controller *controller; + + /* + * Open the fd to the HV. If it fails then this + * device doesn't exist. + */ + hv_cfg_fd0 = tile_pcie_open(i, 0); + if (hv_cfg_fd0 < 0) + continue; + hv_cfg_fd1 = tile_pcie_open(i, 1); + if (hv_cfg_fd1 < 0) { + pr_err("PCI: Couldn't open config fd to HV " + "for controller %d\n", i); + goto err_cont; + } + + sprintf(name, "pcie/%d/mem", i); + hv_mem_fd = hv_dev_open((HV_VirtAddr)name, 0); + if (hv_mem_fd < 0) { + pr_err("PCI: Could not open mem fd to HV!\n"); + goto err_cont; + } + + pr_info("PCI: Found PCI controller #%d\n", i); + + controller = &controllers[num_controllers]; + + if (tile_init_irqs(i, controller)) { + pr_err("PCI: Could not initialize " + "IRQs, aborting.\n"); + goto err_cont; + } + + controller->index = num_controllers; + controller->hv_cfg_fd[0] = hv_cfg_fd0; + controller->hv_cfg_fd[1] = hv_cfg_fd1; + controller->hv_mem_fd = hv_mem_fd; + controller->first_busno = 0; + controller->last_busno = 0xff; + controller->ops = &tile_cfg_ops; + + num_controllers++; + continue; + +err_cont: + if (hv_cfg_fd0 >= 0) + hv_dev_close(hv_cfg_fd0); + if (hv_cfg_fd1 >= 0) + hv_dev_close(hv_cfg_fd1); + if (hv_mem_fd >= 0) + hv_dev_close(hv_mem_fd); + continue; + } + + /* + * Before using the PCIe, see if we need to do any platform-specific + * configuration, such as the PLX switch Gen 1 issue on TILEmpower. + */ + for (i = 0; i < num_controllers; i++) { + struct pci_controller *controller = &controllers[i]; + + if (controller->plx_gen1) + tile_plx_gen1 = 1; + } + + return num_controllers; +} + +/* + * (pin - 1) converts from the PCI standard's [1:4] convention to + * a normal [0:3] range. + */ +static int tile_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + struct pci_controller *controller = + (struct pci_controller *)dev->sysdata; + return (pin - 1) + controller->irq_base; +} + + +static void __init fixup_read_and_payload_sizes(void) +{ + struct pci_dev *dev = NULL; + int smallest_max_payload = 0x1; /* Tile maxes out at 256 bytes. */ + int max_read_size = 0x2; /* Limit to 512 byte reads. */ + u16 new_values; + + /* Scan for the smallest maximum payload size. */ + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + int pcie_caps_offset; + u32 devcap; + int max_payload; + + pcie_caps_offset = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (pcie_caps_offset == 0) + continue; + + pci_read_config_dword(dev, pcie_caps_offset + PCI_EXP_DEVCAP, + &devcap); + max_payload = devcap & PCI_EXP_DEVCAP_PAYLOAD; + if (max_payload < smallest_max_payload) + smallest_max_payload = max_payload; + } + + /* Now, set the max_payload_size for all devices to that value. */ + new_values = (max_read_size << 12) | (smallest_max_payload << 5); + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + int pcie_caps_offset; + u16 devctl; + + pcie_caps_offset = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (pcie_caps_offset == 0) + continue; + + pci_read_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL, + &devctl); + devctl &= ~(PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ); + devctl |= new_values; + pci_write_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL, + devctl); + } +} + + +/* + * Second PCI initialization entry point, called by subsys_initcall. + * + * The controllers have been set up by the time we get here, by a call to + * tile_pci_init. + */ +static int __init pcibios_init(void) +{ + int i; + + pr_info("PCI: Probing PCI hardware\n"); + + /* + * Delay a bit in case devices aren't ready. Some devices are + * known to require at least 20ms here, but we use a more + * conservative value. + */ + mdelay(250); + + /* Scan all of the recorded PCI controllers. */ + for (i = 0; i < num_controllers; i++) { + struct pci_controller *controller = &controllers[i]; + struct pci_bus *bus; + + pr_info("PCI: initializing controller #%d\n", i); + + /* + * This comes from the generic Linux PCI driver. + * + * It reads the PCI tree for this bus into the Linux + * data structures. + * + * This is inlined in linux/pci.h and calls into + * pci_scan_bus_parented() in probe.c. + */ + bus = pci_scan_bus(0, controller->ops, controller); + controller->root_bus = bus; + controller->last_busno = bus->subordinate; + + } + + /* Do machine dependent PCI interrupt routing */ + pci_fixup_irqs(pci_common_swizzle, tile_map_irq); + + /* + * This comes from the generic Linux PCI driver. + * + * It allocates all of the resources (I/O memory, etc) + * associated with the devices read in above. + */ + + pci_assign_unassigned_resources(); + + /* Configure the max_read_size and max_payload_size values. */ + fixup_read_and_payload_sizes(); + + /* Record the I/O resources in the PCI controller structure. */ + for (i = 0; i < num_controllers; i++) { + struct pci_bus *root_bus = controllers[i].root_bus; + struct pci_bus *next_bus; + struct pci_dev *dev; + + list_for_each_entry(dev, &root_bus->devices, bus_list) { + /* Find the PCI host controller, ie. the 1st bridge. */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && + (PCI_SLOT(dev->devfn) == 0)) { + next_bus = dev->subordinate; + controllers[i].mem_resources[0] = + *next_bus->resource[0]; + controllers[i].mem_resources[1] = + *next_bus->resource[1]; + controllers[i].mem_resources[2] = + *next_bus->resource[2]; + + break; + } + } + + } + + return 0; +} +subsys_initcall(pcibios_init); + +/* + * No bus fixups needed. + */ +void __devinit pcibios_fixup_bus(struct pci_bus *bus) +{ + /* Nothing needs to be done. */ +} + +/* + * This can be called from the generic PCI layer, but doesn't need to + * do anything. + */ +char __devinit *pcibios_setup(char *str) +{ + /* Nothing needs to be done. */ + return str; +} + +/* + * This is called from the generic Linux layer. + */ +void __init pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} + +/* + * Enable memory and/or address decoding, as appropriate, for the + * device described by the 'dev' struct. + * + * This is called from the generic PCI layer, and can be called + * for bridges or endpoints. + */ +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + u8 header_type; + int i; + struct resource *r; + + pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* + * For bridges, we enable both memory and I/O decoding + * in call cases. + */ + cmd |= PCI_COMMAND_IO; + cmd |= PCI_COMMAND_MEMORY; + } else { + /* + * For endpoints, we enable memory and/or I/O decoding + * only if they have a memory resource of that type. + */ + for (i = 0; i < 6; i++) { + r = &dev->resource[i]; + if (r->flags & IORESOURCE_UNSET) { + pr_err("PCI: Device %s not available " + "because of resource collisions\n", + pci_name(dev)); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + } + + /* + * We only write the command if it changed. + */ + if (cmd != old_cmd) + pci_write_config_word(dev, PCI_COMMAND, cmd); + return 0; +} + +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len) + return NULL; + if (max && len > max) + len = max; + + if (!(flags & IORESOURCE_MEM)) { + pr_info("PCI: Trying to map invalid resource %#lx\n", flags); + start = 0; + } + + return (void __iomem *)start; +} +EXPORT_SYMBOL(pci_iomap); + + +/**************************************************************** + * + * Tile PCI config space read/write routines + * + ****************************************************************/ + +/* + * These are the normal read and write ops + * These are expanded with macros from pci_bus_read_config_byte() etc. + * + * devfn is the combined PCI slot & function. + * + * offset is in bytes, from the start of config space for the + * specified bus & slot. + */ + +static int __devinit tile_cfg_read(struct pci_bus *bus, + unsigned int devfn, + int offset, + int size, + u32 *val) +{ + struct pci_controller *controller = bus->sysdata; + int busnum = bus->number & 0xff; + int slot = (devfn >> 3) & 0x1f; + int function = devfn & 0x7; + u32 addr; + int config_mode = 1; + + /* + * There is no bridge between the Tile and bus 0, so we + * use config0 to talk to bus 0. + * + * If we're talking to a bus other than zero then we + * must have found a bridge. + */ + if (busnum == 0) { + /* + * We fake an empty slot for (busnum == 0) && (slot > 0), + * since there is only one slot on bus 0. + */ + if (slot) { + *val = 0xFFFFFFFF; + return 0; + } + config_mode = 0; + } + + addr = busnum << 20; /* Bus in 27:20 */ + addr |= slot << 15; /* Slot (device) in 19:15 */ + addr |= function << 12; /* Function is in 14:12 */ + addr |= (offset & 0xFFF); /* byte address in 0:11 */ + + return hv_dev_pread(controller->hv_cfg_fd[config_mode], 0, + (HV_VirtAddr)(val), size, addr); +} + + +/* + * See tile_cfg_read() for relevent comments. + * Note that "val" is the value to write, not a pointer to that value. + */ +static int __devinit tile_cfg_write(struct pci_bus *bus, + unsigned int devfn, + int offset, + int size, + u32 val) +{ + struct pci_controller *controller = bus->sysdata; + int busnum = bus->number & 0xff; + int slot = (devfn >> 3) & 0x1f; + int function = devfn & 0x7; + u32 addr; + int config_mode = 1; + HV_VirtAddr valp = (HV_VirtAddr)&val; + + /* + * For bus 0 slot 0 we use config 0 accesses. + */ + if (busnum == 0) { + /* + * We fake an empty slot for (busnum == 0) && (slot > 0), + * since there is only one slot on bus 0. + */ + if (slot) + return 0; + config_mode = 0; + } + + addr = busnum << 20; /* Bus in 27:20 */ + addr |= slot << 15; /* Slot (device) in 19:15 */ + addr |= function << 12; /* Function is in 14:12 */ + addr |= (offset & 0xFFF); /* byte address in 0:11 */ + +#ifdef __BIG_ENDIAN + /* Point to the correct part of the 32-bit "val". */ + valp += 4 - size; +#endif + + return hv_dev_pwrite(controller->hv_cfg_fd[config_mode], 0, + valp, size, addr); +} + + +static struct pci_ops tile_cfg_ops = { + .read = tile_cfg_read, + .write = tile_cfg_write, +}; + + +/* + * In the following, each PCI controller's mem_resources[1] + * represents its (non-prefetchable) PCI memory resource. + * mem_resources[0] and mem_resources[2] refer to its PCI I/O and + * prefetchable PCI memory resources, respectively. + * For more details, see pci_setup_bridge() in setup-bus.c. + * By comparing the target PCI memory address against the + * end address of controller 0, we can determine the controller + * that should accept the PCI memory access. + */ +#define TILE_READ(size, type) \ +type _tile_read##size(unsigned long addr) \ +{ \ + type val; \ + int idx = 0; \ + if (addr > controllers[0].mem_resources[1].end && \ + addr > controllers[0].mem_resources[2].end) \ + idx = 1; \ + if (hv_dev_pread(controllers[idx].hv_mem_fd, 0, \ + (HV_VirtAddr)(&val), sizeof(type), addr)) \ + pr_err("PCI: read %zd bytes at 0x%lX failed\n", \ + sizeof(type), addr); \ + return val; \ +} \ +EXPORT_SYMBOL(_tile_read##size) + +TILE_READ(b, u8); +TILE_READ(w, u16); +TILE_READ(l, u32); +TILE_READ(q, u64); + +#define TILE_WRITE(size, type) \ +void _tile_write##size(type val, unsigned long addr) \ +{ \ + int idx = 0; \ + if (addr > controllers[0].mem_resources[1].end && \ + addr > controllers[0].mem_resources[2].end) \ + idx = 1; \ + if (hv_dev_pwrite(controllers[idx].hv_mem_fd, 0, \ + (HV_VirtAddr)(&val), sizeof(type), addr)) \ + pr_err("PCI: write %zd bytes at 0x%lX failed\n", \ + sizeof(type), addr); \ +} \ +EXPORT_SYMBOL(_tile_write##size) + +TILE_WRITE(b, u8); +TILE_WRITE(w, u16); +TILE_WRITE(l, u32); +TILE_WRITE(q, u64); diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 8430f45daea6..e90eb53173b0 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -212,6 +212,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, childregs->sp = sp; /* override with new user stack pointer */ /* + * If CLONE_SETTLS is set, set "tp" in the new task to "r4", + * which is passed in as arg #5 to sys_clone(). + */ + if (clone_flags & CLONE_SETTLS) + childregs->tp = regs->regs[4]; + + /* * Copy the callee-saved registers from the passed pt_regs struct * into the context-switch callee-saved registers area. * This way when we start the interrupt-return sequence, the @@ -539,6 +546,7 @@ struct task_struct *__sched _switch_to(struct task_struct *prev, return __switch_to(prev, next, next_current_ksp0(next)); } +/* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */ SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, void __user *, parent_tidptr, void __user *, child_tidptr, struct pt_regs *, regs) diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c index fb0b3cbeae14..f18573643ed1 100644 --- a/arch/tile/kernel/setup.c +++ b/arch/tile/kernel/setup.c @@ -840,7 +840,7 @@ static int __init topology_init(void) for_each_online_node(i) register_one_node(i); - for_each_present_cpu(i) + for (i = 0; i < smp_height * smp_width; ++i) register_cpu(&cpu_devices[i], i); return 0; diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c index 757407e36696..1260321155f1 100644 --- a/arch/tile/kernel/signal.c +++ b/arch/tile/kernel/signal.c @@ -52,7 +52,7 @@ SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss, */ int restore_sigcontext(struct pt_regs *regs, - struct sigcontext __user *sc, long *pr0) + struct sigcontext __user *sc) { int err = 0; int i; @@ -75,17 +75,15 @@ int restore_sigcontext(struct pt_regs *regs, regs->faultnum = INT_SWINT_1_SIGRETURN; - err |= __get_user(*pr0, &sc->gregs[0]); return err; } -/* sigreturn() returns long since it restores r0 in the interrupted code. */ +/* The assembly shim for this function arranges to ignore the return value. */ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs) { struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(regs->sp); sigset_t set; - long r0; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; @@ -98,13 +96,13 @@ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) + if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) goto badframe; - return r0; + return 0; badframe: force_sig(SIGSEGV, current); diff --git a/arch/tile/lib/memchr_32.c b/arch/tile/lib/memchr_32.c index 6235283b4859..cc3d9badf030 100644 --- a/arch/tile/lib/memchr_32.c +++ b/arch/tile/lib/memchr_32.c @@ -18,12 +18,24 @@ void *memchr(const void *s, int c, size_t n) { + const uint32_t *last_word_ptr; + const uint32_t *p; + const char *last_byte_ptr; + uintptr_t s_int; + uint32_t goal, before_mask, v, bits; + char *ret; + + if (__builtin_expect(n == 0, 0)) { + /* Don't dereference any memory if the array is empty. */ + return NULL; + } + /* Get an aligned pointer. */ - const uintptr_t s_int = (uintptr_t) s; - const uint32_t *p = (const uint32_t *)(s_int & -4); + s_int = (uintptr_t) s; + p = (const uint32_t *)(s_int & -4); /* Create four copies of the byte for which we are looking. */ - const uint32_t goal = 0x01010101 * (uint8_t) c; + goal = 0x01010101 * (uint8_t) c; /* Read the first word, but munge it so that bytes before the array * will not match goal. @@ -31,23 +43,14 @@ void *memchr(const void *s, int c, size_t n) * Note that this shift count expression works because we know * shift counts are taken mod 32. */ - const uint32_t before_mask = (1 << (s_int << 3)) - 1; - uint32_t v = (*p | before_mask) ^ (goal & before_mask); + before_mask = (1 << (s_int << 3)) - 1; + v = (*p | before_mask) ^ (goal & before_mask); /* Compute the address of the last byte. */ - const char *const last_byte_ptr = (const char *)s + n - 1; + last_byte_ptr = (const char *)s + n - 1; /* Compute the address of the word containing the last byte. */ - const uint32_t *const last_word_ptr = - (const uint32_t *)((uintptr_t) last_byte_ptr & -4); - - uint32_t bits; - char *ret; - - if (__builtin_expect(n == 0, 0)) { - /* Don't dereference any memory if the array is empty. */ - return NULL; - } + last_word_ptr = (const uint32_t *)((uintptr_t) last_byte_ptr & -4); while ((bits = __insn_seqb(v, goal)) == 0) { if (__builtin_expect(p == last_word_ptr, 0)) { diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c index 485e24d62c6b..5cd1c4004eca 100644 --- a/arch/tile/lib/spinlock_32.c +++ b/arch/tile/lib/spinlock_32.c @@ -167,23 +167,30 @@ void arch_write_lock_slow(arch_rwlock_t *rwlock, u32 val) * when we compare them. */ u32 my_ticket_; + u32 iterations = 0; - /* Take out the next ticket; this will also stop would-be readers. */ - if (val & 1) - val = get_rwlock(rwlock); - rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT); + /* + * Wait until there are no readers, then bump up the next + * field and capture the ticket value. + */ + for (;;) { + if (!(val & 1)) { + if ((val >> RD_COUNT_SHIFT) == 0) + break; + rwlock->lock = val; + } + delay_backoff(iterations++); + val = __insn_tns((int *)&rwlock->lock); + } - /* Extract my ticket value from the original word. */ + /* Take out the next ticket and extract my ticket value. */ + rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT); my_ticket_ = val >> WR_NEXT_SHIFT; - /* - * Wait until the "current" field matches our ticket, and - * there are no remaining readers. - */ + /* Wait until the "current" field matches our ticket. */ for (;;) { u32 curr_ = val >> WR_CURR_SHIFT; - u32 readers = val >> RD_COUNT_SHIFT; - u32 delta = ((my_ticket_ - curr_) & WR_MASK) + !!readers; + u32 delta = ((my_ticket_ - curr_) & WR_MASK); if (likely(delta == 0)) break; diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 7f7338c90784..1664cce7b0ac 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -727,6 +727,9 @@ struct winch { static void free_winch(struct winch *winch, int free_irq_ok) { + if (free_irq_ok) + free_irq(WINCH_IRQ, winch); + list_del(&winch->list); if (winch->pid != -1) @@ -735,8 +738,6 @@ static void free_winch(struct winch *winch, int free_irq_ok) os_close_file(winch->fd); if (winch->stack != 0) free_stack(winch->stack, 0); - if (free_irq_ok) - free_irq(WINCH_IRQ, winch); kfree(winch); } diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e8327686d3c5..e330da21b84f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -21,7 +21,7 @@ config X86 select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_IDE select HAVE_OPROFILE - select HAVE_PERF_EVENTS if (!M386 && !M486) + select HAVE_PERF_EVENTS select HAVE_IRQ_WORK select HAVE_IOREMAP_PROT select HAVE_KPROBES diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 23f315c9f215..325c05294fc4 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -355,7 +355,7 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, if (heap > 0x3fffffffffffUL) error("Destination address too large"); #else - if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff)) + if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff)) error("Destination address too large"); #endif #ifndef CONFIG_RELOCATABLE diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c index cbcc8d8ea93a..7a6e68e4f748 100644 --- a/arch/x86/crypto/ghash-clmulni-intel_glue.c +++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c @@ -10,6 +10,7 @@ * by the Free Software Foundation. */ +#include <linux/err.h> #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h index 5be1542fbfaf..e99d55d74df5 100644 --- a/arch/x86/include/asm/e820.h +++ b/arch/x86/include/asm/e820.h @@ -72,6 +72,9 @@ struct e820map { #define BIOS_BEGIN 0x000a0000 #define BIOS_END 0x00100000 +#define BIOS_ROM_BASE 0xffe00000 +#define BIOS_ROM_END 0xffffffff + #ifdef __KERNEL__ /* see comment in arch/x86/kernel/e820.c */ extern struct e820map e820; diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 4d293dced62f..9479a037419f 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -216,8 +216,8 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr) } /* Return an pointer with offset calculated */ -static inline unsigned long __set_fixmap_offset(enum fixed_addresses idx, - phys_addr_t phys, pgprot_t flags) +static __always_inline unsigned long +__set_fixmap_offset(enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags) { __set_fixmap(idx, phys, flags); return fix_to_virt(idx) + (phys & (PAGE_SIZE - 1)); diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 9e6fe391094e..f702f82aa1eb 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -79,7 +79,7 @@ #define KVM_NUM_MMU_PAGES (1 << KVM_MMU_HASH_SHIFT) #define KVM_MIN_FREE_MMU_PAGES 5 #define KVM_REFILL_PAGES 25 -#define KVM_MAX_CPUID_ENTRIES 40 +#define KVM_MAX_CPUID_ENTRIES 80 #define KVM_NR_FIXED_MTRR_REGION 88 #define KVM_NR_VAR_MTRR 8 diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 3ea3dc487047..6b89f5e86021 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -128,7 +128,7 @@ #define FAM10H_MMIO_CONF_ENABLE (1<<0) #define FAM10H_MMIO_CONF_BUSRANGE_MASK 0xf #define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2 -#define FAM10H_MMIO_CONF_BASE_MASK 0xfffffff +#define FAM10H_MMIO_CONF_BASE_MASK 0xfffffffULL #define FAM10H_MMIO_CONF_BASE_SHIFT 20 #define MSR_FAM10H_NODE_ID 0xc001100c diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 18e3b8a8709f..ef9975812c77 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -824,27 +824,27 @@ static __always_inline void arch_spin_unlock(struct arch_spinlock *lock) #define __PV_IS_CALLEE_SAVE(func) \ ((struct paravirt_callee_save) { func }) -static inline unsigned long arch_local_save_flags(void) +static inline notrace unsigned long arch_local_save_flags(void) { return PVOP_CALLEE0(unsigned long, pv_irq_ops.save_fl); } -static inline void arch_local_irq_restore(unsigned long f) +static inline notrace void arch_local_irq_restore(unsigned long f) { PVOP_VCALLEE1(pv_irq_ops.restore_fl, f); } -static inline void arch_local_irq_disable(void) +static inline notrace void arch_local_irq_disable(void) { PVOP_VCALLEE0(pv_irq_ops.irq_disable); } -static inline void arch_local_irq_enable(void) +static inline notrace void arch_local_irq_enable(void) { PVOP_VCALLEE0(pv_irq_ops.irq_enable); } -static inline unsigned long arch_local_irq_save(void) +static inline notrace unsigned long arch_local_irq_save(void) { unsigned long f; diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h index 7f7e577a0e39..31d84acc1512 100644 --- a/arch/x86/include/asm/pvclock.h +++ b/arch/x86/include/asm/pvclock.h @@ -11,6 +11,7 @@ unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src); void pvclock_read_wallclock(struct pvclock_wall_clock *wall, struct pvclock_vcpu_time_info *vcpu, struct timespec *ts); +void pvclock_resume(void); /* * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index e969f691cbfd..a501741c2335 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -199,6 +199,8 @@ union uvh_apicid { #define UVH_APICID 0x002D0E00L #define UV_APIC_PNODE_SHIFT 6 +#define UV_APICID_HIBIT_MASK 0xffff0000 + /* Local Bus from cpu's perspective */ #define LOCAL_BUS_BASE 0x1c00000 #define LOCAL_BUS_SIZE (4 * 1024 * 1024) @@ -491,8 +493,10 @@ static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value) } } +extern unsigned int uv_apicid_hibits; static unsigned long uv_hub_ipi_value(int apicid, int vector, int mode) { + apicid |= uv_apicid_hibits; return (1UL << UVH_IPI_INT_SEND_SHFT) | ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) | (mode << UVH_IPI_INT_DELIVERY_MODE_SHFT) | diff --git a/arch/x86/include/asm/uv/uv_mmrs.h b/arch/x86/include/asm/uv/uv_mmrs.h index 6d90adf4428a..20cafeac7455 100644 --- a/arch/x86/include/asm/uv/uv_mmrs.h +++ b/arch/x86/include/asm/uv/uv_mmrs.h @@ -5,7 +5,7 @@ * * SGI UV MMR definitions * - * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_X86_UV_UV_MMRS_H @@ -754,6 +754,23 @@ union uvh_lb_bau_sb_descriptor_base_u { }; /* ========================================================================= */ +/* UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK */ +/* ========================================================================= */ +#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK 0x320130UL +#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_32 0x009f0 + +#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_SHFT 0 +#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_MASK 0x00000000ffffffffUL + +union uvh_lb_target_physical_apic_id_mask_u { + unsigned long v; + struct uvh_lb_target_physical_apic_id_mask_s { + unsigned long bit_enables : 32; /* RW */ + unsigned long rsvd_32_63 : 32; /* */ + } s; +}; + +/* ========================================================================= */ /* UVH_NODE_ID */ /* ========================================================================= */ #define UVH_NODE_ID 0x0UL diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h index e8506c1f0c55..1c10c88ee4e1 100644 --- a/arch/x86/include/asm/xen/interface.h +++ b/arch/x86/include/asm/xen/interface.h @@ -61,9 +61,9 @@ DEFINE_GUEST_HANDLE(void); #define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) #endif -#ifndef machine_to_phys_mapping -#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) -#endif +#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START) +#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END) +#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>__MACH2PHYS_SHIFT) /* Maximum number of virtual CPUs in multi-processor guests. */ #define MAX_VIRT_CPUS 32 diff --git a/arch/x86/include/asm/xen/interface_32.h b/arch/x86/include/asm/xen/interface_32.h index 42a7e004ae5c..8413688b2571 100644 --- a/arch/x86/include/asm/xen/interface_32.h +++ b/arch/x86/include/asm/xen/interface_32.h @@ -32,6 +32,11 @@ /* And the trap vector is... */ #define TRAP_INSTR "int $0x82" +#define __MACH2PHYS_VIRT_START 0xF5800000 +#define __MACH2PHYS_VIRT_END 0xF6800000 + +#define __MACH2PHYS_SHIFT 2 + /* * Virtual addresses beyond this are not modifiable by guest OSes. The * machine->physical mapping table starts at this address, read-only. diff --git a/arch/x86/include/asm/xen/interface_64.h b/arch/x86/include/asm/xen/interface_64.h index 100d2662b97c..839a4811cf98 100644 --- a/arch/x86/include/asm/xen/interface_64.h +++ b/arch/x86/include/asm/xen/interface_64.h @@ -39,18 +39,7 @@ #define __HYPERVISOR_VIRT_END 0xFFFF880000000000 #define __MACH2PHYS_VIRT_START 0xFFFF800000000000 #define __MACH2PHYS_VIRT_END 0xFFFF804000000000 - -#ifndef HYPERVISOR_VIRT_START -#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) -#define HYPERVISOR_VIRT_END mk_unsigned_long(__HYPERVISOR_VIRT_END) -#endif - -#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START) -#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END) -#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3) -#ifndef machine_to_phys_mapping -#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) -#endif +#define __MACH2PHYS_SHIFT 3 /* * int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base) diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index dd8c1414b3d5..8760cc60a21c 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -5,6 +5,7 @@ #include <linux/types.h> #include <linux/spinlock.h> #include <linux/pfn.h> +#include <linux/mm.h> #include <asm/uaccess.h> #include <asm/page.h> @@ -35,6 +36,8 @@ typedef struct xpaddr { #define MAX_DOMAIN_PAGES \ ((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE)) +extern unsigned long *machine_to_phys_mapping; +extern unsigned int machine_to_phys_order; extern unsigned long get_phys_to_machine(unsigned long pfn); extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn); @@ -69,10 +72,8 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn) if (xen_feature(XENFEAT_auto_translated_physmap)) return mfn; -#if 0 if (unlikely((mfn >> machine_to_phys_order) != 0)) - return max_mapnr; -#endif + return ~0; pfn = 0; /* diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 9e13763b6092..1e994754d323 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -45,6 +45,7 @@ obj-y += pci-dma.o quirks.o i8237.o topology.o kdebugfs.o obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o obj-y += tsc.o io_delay.o rtc.o obj-y += pci-iommu_table.o +obj-y += resource.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-y += process.o diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 3f838d537392..78218135b48e 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1389,6 +1389,14 @@ void __cpuinit end_local_APIC_setup(void) setup_apic_nmi_watchdog(NULL); apic_pm_activate(); + + /* + * Now that local APIC setup is completed for BP, configure the fault + * handling for interrupt remapping. + */ + if (!smp_processor_id() && intr_remapping_enabled) + enable_drhd_fault_handling(); + } #ifdef CONFIG_X86_X2APIC diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index cefd6942f0e9..62f6e1e55b90 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -17,15 +17,16 @@ #include <linux/nmi.h> #include <linux/module.h> -/* For reliability, we're prepared to waste bits here. */ -static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; - u64 hw_nmi_get_sample_period(void) { return (u64)(cpu_khz) * 1000 * 60; } #ifdef ARCH_HAS_NMI_WATCHDOG + +/* For reliability, we're prepared to waste bits here. */ +static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; + void arch_trigger_all_cpu_backtrace(void) { int i; diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 7cc0a721f628..fadcd743a74f 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2430,13 +2430,12 @@ static void ack_apic_level(struct irq_data *data) { struct irq_cfg *cfg = data->chip_data; int i, do_unmask_irq = 0, irq = data->irq; - struct irq_desc *desc = irq_to_desc(irq); unsigned long v; irq_complete_move(cfg); #ifdef CONFIG_GENERIC_PENDING_IRQ /* If we are moving the irq we need to mask it */ - if (unlikely(desc->status & IRQ_MOVE_PENDING)) { + if (unlikely(irq_to_desc(irq)->status & IRQ_MOVE_PENDING)) { do_unmask_irq = 1; mask_ioapic(cfg); } @@ -3413,6 +3412,7 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask, msg.data |= MSI_DATA_VECTOR(cfg->vector); msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; msg.address_lo |= MSI_ADDR_DEST_ID(dest); + msg.address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(dest); dmar_msi_write(irq, &msg); diff --git a/arch/x86/kernel/apic/probe_64.c b/arch/x86/kernel/apic/probe_64.c index f9e4e6a54073..d8c4a6feb286 100644 --- a/arch/x86/kernel/apic/probe_64.c +++ b/arch/x86/kernel/apic/probe_64.c @@ -79,13 +79,6 @@ void __init default_setup_apic_routing(void) /* need to update phys_pkg_id */ apic->phys_pkg_id = apicid_phys_pkg_id; } - - /* - * Now that apic routing model is selected, configure the - * fault handling for intr remapping. - */ - if (intr_remapping_enabled) - enable_drhd_fault_handling(); } /* Same for both flat and physical. */ diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 194539aea175..c1c52c341f40 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -44,6 +44,8 @@ static u64 gru_start_paddr, gru_end_paddr; static union uvh_apicid uvh_apicid; int uv_min_hub_revision_id; EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); +unsigned int uv_apicid_hibits; +EXPORT_SYMBOL_GPL(uv_apicid_hibits); static DEFINE_SPINLOCK(uv_nmi_lock); static inline bool is_GRU_range(u64 start, u64 end) @@ -85,6 +87,23 @@ static void __init early_get_apic_pnode_shift(void) uvh_apicid.s.pnode_shift = UV_APIC_PNODE_SHIFT; } +/* + * Add an extra bit as dictated by bios to the destination apicid of + * interrupts potentially passing through the UV HUB. This prevents + * a deadlock between interrupts and IO port operations. + */ +static void __init uv_set_apicid_hibit(void) +{ + union uvh_lb_target_physical_apic_id_mask_u apicid_mask; + unsigned long *mmr; + + mmr = early_ioremap(UV_LOCAL_MMR_BASE | + UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK, sizeof(*mmr)); + apicid_mask.v = *mmr; + early_iounmap(mmr, sizeof(*mmr)); + uv_apicid_hibits = apicid_mask.s.bit_enables & UV_APICID_HIBIT_MASK; +} + static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id) { int nodeid; @@ -102,6 +121,7 @@ static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id) __get_cpu_var(x2apic_extra_bits) = nodeid << (uvh_apicid.s.pnode_shift - 1); uv_system_type = UV_NON_UNIQUE_APIC; + uv_set_apicid_hibit(); return 1; } } @@ -155,6 +175,7 @@ static int __cpuinit uv_wakeup_secondary(int phys_apicid, unsigned long start_ri int pnode; pnode = uv_apicid_to_pnode(phys_apicid); + phys_apicid |= uv_apicid_hibits; val = (1UL << UVH_IPI_INT_SEND_SHFT) | (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) | ((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) | @@ -236,7 +257,7 @@ static unsigned int uv_cpu_mask_to_apicid(const struct cpumask *cpumask) int cpu = cpumask_first(cpumask); if ((unsigned)cpu < nr_cpu_ids) - return per_cpu(x86_cpu_to_apicid, cpu); + return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits; else return BAD_APICID; } @@ -255,7 +276,7 @@ uv_cpu_mask_to_apicid_and(const struct cpumask *cpumask, if (cpumask_test_cpu(cpu, cpu_online_mask)) break; } - return per_cpu(x86_cpu_to_apicid, cpu); + return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits; } static unsigned int x2apic_get_apic_id(unsigned long x) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index ed6310183efb..6d75b9145b13 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -381,6 +381,20 @@ static void release_pmc_hardware(void) {} #endif +static bool check_hw_exists(void) +{ + u64 val, val_new = 0; + int ret = 0; + + val = 0xabcdUL; + ret |= checking_wrmsrl(x86_pmu.perfctr, val); + ret |= rdmsrl_safe(x86_pmu.perfctr, &val_new); + if (ret || val != val_new) + return false; + + return true; +} + static void reserve_ds_buffers(void); static void release_ds_buffers(void); @@ -1372,6 +1386,12 @@ void __init init_hw_perf_events(void) pmu_check_apic(); + /* sanity check that the hardware exists or is emulated */ + if (!check_hw_exists()) { + pr_cont("Broken PMU hardware detected, software events only.\n"); + return; + } + pr_cont("%s PMU driver.\n", x86_pmu.name); if (x86_pmu.quirks) diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 59e175e89599..591e60104278 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -395,7 +395,7 @@ sysenter_past_esp: * A tiny bit of offset fixup is necessary - 4*4 means the 4 words * pushed above; +8 corresponds to copy_thread's esp0 setting. */ - pushl_cfi (TI_sysenter_return-THREAD_SIZE_asm+8+4*4)(%esp) + pushl_cfi ((TI_sysenter_return)-THREAD_SIZE_asm+8+4*4)(%esp) CFI_REL_OFFSET eip, 0 pushl_cfi %eax diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index fe2690d71c0c..e3ba417e8697 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -295,6 +295,7 @@ ENDPROC(native_usergs_sysret64) .endm /* save partial stack frame */ + .pushsection .kprobes.text, "ax" ENTRY(save_args) XCPT_FRAME cld @@ -334,6 +335,7 @@ ENTRY(save_args) ret CFI_ENDPROC END(save_args) + .popsection ENTRY(save_rest) PARTIAL_FRAME 1 REST_SKIP+8 diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index bcece91dd311..c0dbd9ac24f0 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -60,16 +60,18 @@ #define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD) #endif +/* Number of possible pages in the lowmem region */ +LOWMEM_PAGES = (((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT) + /* Enough space to fit pagetables for the low memory linear map */ -MAPPING_BEYOND_END = \ - PAGE_TABLE_SIZE(((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT) << PAGE_SHIFT +MAPPING_BEYOND_END = PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT /* * Worst-case size of the kernel mapping we need to make: - * the worst-case size of the kernel itself, plus the extra we need - * to map for the linear map. + * a relocatable kernel can live anywhere in lowmem, so we need to be able + * to map all of lowmem. */ -KERNEL_PAGES = (KERNEL_IMAGE_SIZE + MAPPING_BEYOND_END)>>PAGE_SHIFT +KERNEL_PAGES = LOWMEM_PAGES INIT_MAP_SIZE = PAGE_TABLE_SIZE(KERNEL_PAGES) * PAGE_SIZE_asm RESERVE_BRK(pagetables, INIT_MAP_SIZE) @@ -620,13 +622,13 @@ ENTRY(initial_code) __PAGE_ALIGNED_BSS .align PAGE_SIZE_asm #ifdef CONFIG_X86_PAE -initial_pg_pmd: +ENTRY(initial_pg_pmd) .fill 1024*KPMDS,4,0 #else ENTRY(initial_page_table) .fill 1024,4,0 #endif -initial_pg_fixmap: +ENTRY(initial_pg_fixmap) .fill 1024,4,0 ENTRY(empty_zero_page) .fill 4096,1,0 diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index ae03cab4352e..4ff5968f12d2 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -27,6 +27,9 @@ #define HPET_DEV_FSB_CAP 0x1000 #define HPET_DEV_PERI_CAP 0x2000 +#define HPET_MIN_CYCLES 128 +#define HPET_MIN_PROG_DELTA (HPET_MIN_CYCLES + (HPET_MIN_CYCLES >> 1)) + #define EVT_TO_HPET_DEV(evt) container_of(evt, struct hpet_dev, evt) /* @@ -299,8 +302,9 @@ static void hpet_legacy_clockevent_register(void) /* Calculate the min / max delta */ hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, &hpet_clockevent); - /* 5 usec minimum reprogramming delta. */ - hpet_clockevent.min_delta_ns = 5000; + /* Setup minimum reprogramming delta. */ + hpet_clockevent.min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA, + &hpet_clockevent); /* * Start hpet with the boot cpu mask and make it @@ -393,22 +397,24 @@ static int hpet_next_event(unsigned long delta, * the wraparound into account) nor a simple count down event * mode. Further the write to the comparator register is * delayed internally up to two HPET clock cycles in certain - * chipsets (ATI, ICH9,10). We worked around that by reading - * back the compare register, but that required another - * workaround for ICH9,10 chips where the first readout after - * write can return the old stale value. We already have a - * minimum delta of 5us enforced, but a NMI or SMI hitting + * chipsets (ATI, ICH9,10). Some newer AMD chipsets have even + * longer delays. We worked around that by reading back the + * compare register, but that required another workaround for + * ICH9,10 chips where the first readout after write can + * return the old stale value. We already had a minimum + * programming delta of 5us enforced, but a NMI or SMI hitting * between the counter readout and the comparator write can * move us behind that point easily. Now instead of reading * the compare register back several times, we make the ETIME * decision based on the following: Return ETIME if the - * counter value after the write is less than 8 HPET cycles + * counter value after the write is less than HPET_MIN_CYCLES * away from the event or if the counter is already ahead of - * the event. + * the event. The minimum programming delta for the generic + * clockevents code is set to 1.5 * HPET_MIN_CYCLES. */ res = (s32)(cnt - hpet_readl(HPET_COUNTER)); - return res < 8 ? -ETIME : 0; + return res < HPET_MIN_CYCLES ? -ETIME : 0; } static void hpet_legacy_set_mode(enum clock_event_mode mode, diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index ff15c9dcc25d..42c594254507 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c @@ -433,6 +433,10 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) dr6_p = (unsigned long *)ERR_PTR(args->err); dr6 = *dr6_p; + /* If it's a single step, TRAP bits are random */ + if (dr6 & DR_STEP) + return NOTIFY_DONE; + /* Do an early return if no trap bits are set in DR6 */ if ((dr6 & DR_TRAP_BITS) == 0) return NOTIFY_DONE; diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index ec592caac4b4..cd21b654dec6 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -315,14 +315,18 @@ static void kgdb_remove_all_hw_break(void) if (!breakinfo[i].enabled) continue; bp = *per_cpu_ptr(breakinfo[i].pev, cpu); - if (bp->attr.disabled == 1) + if (!bp->attr.disabled) { + arch_uninstall_hw_breakpoint(bp); + bp->attr.disabled = 1; continue; + } if (dbg_is_early) early_dr7 &= ~encode_dr7(i, breakinfo[i].len, breakinfo[i].type); - else - arch_uninstall_hw_breakpoint(bp); - bp->attr.disabled = 1; + else if (hw_break_release_slot(i)) + printk(KERN_ERR "KGDB: hw bpt remove failed %lx\n", + breakinfo[i].addr); + breakinfo[i].enabled = 0; } } diff --git a/arch/x86/kernel/mmconf-fam10h_64.c b/arch/x86/kernel/mmconf-fam10h_64.c index 6da143c2a6b8..ac861b8348e2 100644 --- a/arch/x86/kernel/mmconf-fam10h_64.c +++ b/arch/x86/kernel/mmconf-fam10h_64.c @@ -25,7 +25,6 @@ struct pci_hostbridge_probe { }; static u64 __cpuinitdata fam10h_pci_mmconf_base; -static int __cpuinitdata fam10h_pci_mmconf_base_status; static struct pci_hostbridge_probe pci_probes[] __cpuinitdata = { { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 }, @@ -44,10 +43,12 @@ static int __cpuinit cmp_range(const void *x1, const void *x2) return start1 - start2; } -/*[47:0] */ -/* need to avoid (0xfd<<32) and (0xfe<<32), ht used space */ +#define MMCONF_UNIT (1ULL << FAM10H_MMIO_CONF_BASE_SHIFT) +#define MMCONF_MASK (~(MMCONF_UNIT - 1)) +#define MMCONF_SIZE (MMCONF_UNIT << 8) +/* need to avoid (0xfd<<32), (0xfe<<32), and (0xff<<32), ht used space */ #define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32) -#define BASE_VALID(b) ((b != (0xfdULL << 32)) && (b != (0xfeULL << 32))) +#define BASE_VALID(b) ((b) + MMCONF_SIZE <= (0xfdULL<<32) || (b) >= (1ULL<<40)) static void __cpuinit get_fam10h_pci_mmconf_base(void) { int i; @@ -64,12 +65,11 @@ static void __cpuinit get_fam10h_pci_mmconf_base(void) struct range range[8]; /* only try to get setting from BSP */ - /* -1 or 1 */ - if (fam10h_pci_mmconf_base_status) + if (fam10h_pci_mmconf_base) return; if (!early_pci_allowed()) - goto fail; + return; found = 0; for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { @@ -91,7 +91,7 @@ static void __cpuinit get_fam10h_pci_mmconf_base(void) } if (!found) - goto fail; + return; /* SYS_CFG */ address = MSR_K8_SYSCFG; @@ -99,16 +99,16 @@ static void __cpuinit get_fam10h_pci_mmconf_base(void) /* TOP_MEM2 is not enabled? */ if (!(val & (1<<21))) { - tom2 = 0; + tom2 = 1ULL << 32; } else { /* TOP_MEM2 */ address = MSR_K8_TOP_MEM2; rdmsrl(address, val); - tom2 = val & (0xffffULL<<32); + tom2 = max(val & 0xffffff800000ULL, 1ULL << 32); } if (base <= tom2) - base = tom2 + (1ULL<<32); + base = (tom2 + 2 * MMCONF_UNIT - 1) & MMCONF_MASK; /* * need to check if the range is in the high mmio range that is @@ -123,11 +123,11 @@ static void __cpuinit get_fam10h_pci_mmconf_base(void) if (!(reg & 3)) continue; - start = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/ + start = (u64)(reg & 0xffffff00) << 8; /* 39:16 on 31:8*/ reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3)); - end = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/ + end = ((u64)(reg & 0xffffff00) << 8) | 0xffff; /* 39:16 on 31:8*/ - if (!end) + if (end < tom2) continue; range[hi_mmio_num].start = start; @@ -143,32 +143,27 @@ static void __cpuinit get_fam10h_pci_mmconf_base(void) if (range[hi_mmio_num - 1].end < base) goto out; - if (range[0].start > base) + if (range[0].start > base + MMCONF_SIZE) goto out; /* need to find one window */ - base = range[0].start - (1ULL << 32); + base = (range[0].start & MMCONF_MASK) - MMCONF_UNIT; if ((base > tom2) && BASE_VALID(base)) goto out; - base = range[hi_mmio_num - 1].end + (1ULL << 32); - if ((base > tom2) && BASE_VALID(base)) + base = (range[hi_mmio_num - 1].end + MMCONF_UNIT) & MMCONF_MASK; + if (BASE_VALID(base)) goto out; /* need to find window between ranges */ - if (hi_mmio_num > 1) - for (i = 0; i < hi_mmio_num - 1; i++) { - if (range[i + 1].start > (range[i].end + (1ULL << 32))) { - base = range[i].end + (1ULL << 32); - if ((base > tom2) && BASE_VALID(base)) - goto out; - } + for (i = 1; i < hi_mmio_num; i++) { + base = (range[i - 1].end + MMCONF_UNIT) & MMCONF_MASK; + val = range[i].start & MMCONF_MASK; + if (val >= base + MMCONF_SIZE && BASE_VALID(base)) + goto out; } - -fail: - fam10h_pci_mmconf_base_status = -1; return; + out: fam10h_pci_mmconf_base = base; - fam10h_pci_mmconf_base_status = 1; } void __cpuinit fam10h_check_enable_mmcfg(void) @@ -190,11 +185,10 @@ void __cpuinit fam10h_check_enable_mmcfg(void) /* only trust the one handle 256 buses, if acpi=off */ if (!acpi_pci_disabled || busnbits >= 8) { - u64 base; - base = val & (0xffffULL << 32); - if (fam10h_pci_mmconf_base_status <= 0) { + u64 base = val & MMCONF_MASK; + + if (!fam10h_pci_mmconf_base) { fam10h_pci_mmconf_base = base; - fam10h_pci_mmconf_base_status = 1; return; } else if (fam10h_pci_mmconf_base == base) return; @@ -206,8 +200,10 @@ void __cpuinit fam10h_check_enable_mmcfg(void) * with 256 buses */ get_fam10h_pci_mmconf_base(); - if (fam10h_pci_mmconf_base_status <= 0) + if (!fam10h_pci_mmconf_base) { + pci_probe &= ~PCI_CHECK_ENABLE_AMD_MMCONF; return; + } printk(KERN_INFO "Enable MMCONFIG on AMD Family 10h\n"); val &= ~((FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT) | diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c index 008b91eefa18..42eb3300dfc6 100644 --- a/arch/x86/kernel/pvclock.c +++ b/arch/x86/kernel/pvclock.c @@ -83,6 +83,11 @@ unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src) static atomic64_t last_value = ATOMIC64_INIT(0); +void pvclock_resume(void) +{ + atomic64_set(&last_value, 0); +} + cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) { struct pvclock_shadow_time shadow; diff --git a/arch/x86/kernel/resource.c b/arch/x86/kernel/resource.c new file mode 100644 index 000000000000..2a26819bb6a8 --- /dev/null +++ b/arch/x86/kernel/resource.c @@ -0,0 +1,48 @@ +#include <linux/ioport.h> +#include <asm/e820.h> + +static void resource_clip(struct resource *res, resource_size_t start, + resource_size_t end) +{ + resource_size_t low = 0, high = 0; + + if (res->end < start || res->start > end) + return; /* no conflict */ + + if (res->start < start) + low = start - res->start; + + if (res->end > end) + high = res->end - end; + + /* Keep the area above or below the conflict, whichever is larger */ + if (low > high) + res->end = start - 1; + else + res->start = end + 1; +} + +static void remove_e820_regions(struct resource *avail) +{ + int i; + struct e820entry *entry; + + for (i = 0; i < e820.nr_map; i++) { + entry = &e820.map[i]; + + resource_clip(avail, entry->addr, + entry->addr + entry->size - 1); + } +} + +void arch_remove_reservations(struct resource *avail) +{ + /* Trim out BIOS areas (low 1MB and high 2MB) and E820 regions */ + if (avail->flags & IORESOURCE_MEM) { + if (avail->start < BIOS_END) + avail->start = BIOS_END; + resource_clip(avail, BIOS_ROM_BASE, BIOS_ROM_END); + + remove_e820_regions(avail); + } +} diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 21c6746338af..85268f8eadf6 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -769,7 +769,6 @@ void __init setup_arch(char **cmdline_p) x86_init.oem.arch_setup(); - resource_alloc_from_bottom = 0; iomem_resource.end = (1ULL << boot_cpu_data.x86_phys_bits) - 1; setup_memory_map(); parse_setup_data(); diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index 9c253bd65e24..547128546cc3 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c @@ -394,7 +394,8 @@ static void __init setup_xstate_init(void) * Setup init_xstate_buf to represent the init state of * all the features managed by the xsave */ - init_xstate_buf = alloc_bootmem(xstate_size); + init_xstate_buf = alloc_bootmem_align(xstate_size, + __alignof__(struct xsave_struct)); init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT; clts(); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 82e144a4e514..b81a9b7c2ca4 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -3395,6 +3395,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip; load_host_msrs(vcpu); + kvm_load_ldt(ldt_selector); loadsegment(fs, fs_selector); #ifdef CONFIG_X86_64 load_gs_index(gs_selector); @@ -3402,7 +3403,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) #else loadsegment(gs, gs_selector); #endif - kvm_load_ldt(ldt_selector); reload_tss(vcpu); @@ -3494,6 +3494,10 @@ static void svm_cpuid_update(struct kvm_vcpu *vcpu) static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry) { switch (func) { + case 0x00000001: + /* Mask out xsave bit as long as it is not supported by SVM */ + entry->ecx &= ~(bit(X86_FEATURE_XSAVE)); + break; case 0x80000001: if (nested) entry->ecx |= (1 << 2); /* Set SVM bit */ diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8da0e45ff7c9..81fcbe9515c5 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -821,10 +821,9 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu) #endif #ifdef CONFIG_X86_64 - if (is_long_mode(&vmx->vcpu)) { - rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); + rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); + if (is_long_mode(&vmx->vcpu)) wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); - } #endif for (i = 0; i < vmx->save_nmsrs; ++i) kvm_set_shared_msr(vmx->guest_msrs[i].index, @@ -839,23 +838,23 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) ++vmx->vcpu.stat.host_state_reload; vmx->host_state.loaded = 0; - if (vmx->host_state.fs_reload_needed) - loadsegment(fs, vmx->host_state.fs_sel); +#ifdef CONFIG_X86_64 + if (is_long_mode(&vmx->vcpu)) + rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); +#endif if (vmx->host_state.gs_ldt_reload_needed) { kvm_load_ldt(vmx->host_state.ldt_sel); #ifdef CONFIG_X86_64 load_gs_index(vmx->host_state.gs_sel); - wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs); #else loadsegment(gs, vmx->host_state.gs_sel); #endif } + if (vmx->host_state.fs_reload_needed) + loadsegment(fs, vmx->host_state.fs_sel); reload_tss(); #ifdef CONFIG_X86_64 - if (is_long_mode(&vmx->vcpu)) { - rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); - wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); - } + wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); #endif if (current_thread_info()->status & TS_USEDFPU) clts(); @@ -4228,11 +4227,6 @@ static int vmx_get_lpage_level(void) return PT_PDPE_LEVEL; } -static inline u32 bit(int bitno) -{ - return 1 << (bitno & 31); -} - static void vmx_cpuid_update(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index cdac9e592aa5..b989e1f1e5d3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -155,11 +155,6 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { u64 __read_mostly host_xcr0; -static inline u32 bit(int bitno) -{ - return 1 << (bitno & 31); -} - static void kvm_on_user_return(struct user_return_notifier *urn) { unsigned slot; @@ -4569,9 +4564,11 @@ static void kvm_timer_init(void) #ifdef CONFIG_CPU_FREQ struct cpufreq_policy policy; memset(&policy, 0, sizeof(policy)); - cpufreq_get_policy(&policy, get_cpu()); + cpu = get_cpu(); + cpufreq_get_policy(&policy, cpu); if (policy.cpuinfo.max_freq) max_tsc_khz = policy.cpuinfo.max_freq; + put_cpu(); #endif cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); @@ -5522,6 +5519,8 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4; kvm_x86_ops->set_cr4(vcpu, sregs->cr4); + if (sregs->cr4 & X86_CR4_OSXSAVE) + update_cpuid(vcpu); if (!is_long_mode(vcpu) && is_pae(vcpu)) { load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3); mmu_reset_needed = 1; diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 2cea414489f3..c600da830ce0 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -70,6 +70,11 @@ static inline int is_paging(struct kvm_vcpu *vcpu) return kvm_read_cr0_bits(vcpu, X86_CR0_PG); } +static inline u32 bit(int bitno) +{ + return 1 << (bitno & 31); +} + void kvm_before_handle_nmi(struct kvm_vcpu *vcpu); void kvm_after_handle_nmi(struct kvm_vcpu *vcpu); int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq); diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 73b1e1a1f489..4996cf5f73a0 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -531,7 +531,10 @@ static void lguest_write_cr3(unsigned long cr3) { lguest_data.pgdir = cr3; lazy_hcall1(LHCALL_NEW_PGTABLE, cr3); - cr3_changed = true; + + /* These two page tables are simple, linear, and used during boot */ + if (cr3 != __pa(swapper_pg_dir) && cr3 != __pa(initial_page_table)) + cr3_changed = true; } static unsigned long lguest_read_cr3(void) @@ -703,9 +706,9 @@ static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval) * to forget all of them. Fortunately, this is very rare. * * ... except in early boot when the kernel sets up the initial pagetables, - * which makes booting astonishingly slow: 1.83 seconds! So we don't even tell - * the Host anything changed until we've done the first page table switch, - * which brings boot back to 0.25 seconds. + * which makes booting astonishingly slow: 48 seconds! So we don't even tell + * the Host anything changed until we've done the first real page table switch, + * which brings boot back to 4.3 seconds. */ static void lguest_set_pte(pte_t *ptep, pte_t pteval) { @@ -1002,7 +1005,7 @@ static void lguest_time_init(void) clockevents_register_device(&lguest_clockevent); /* Finally, we unblock the timer interrupt. */ - enable_lguest_irq(0); + clear_bit(0, lguest_data.blocked_interrupts); } /* @@ -1349,9 +1352,6 @@ __init void lguest_init(void) */ switch_to_new_gdt(0); - /* We actually boot with all memory mapped, but let's say 128MB. */ - max_pfn_mapped = (128*1024*1024) >> PAGE_SHIFT; - /* * The Host<->Guest Switcher lives at the top of our address space, and * the Host told us how big it is when we made LGUEST_INIT hypercall: diff --git a/arch/x86/lguest/i386_head.S b/arch/x86/lguest/i386_head.S index 4f420c2f2d55..e7d5382ef263 100644 --- a/arch/x86/lguest/i386_head.S +++ b/arch/x86/lguest/i386_head.S @@ -4,6 +4,7 @@ #include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/processor-flags.h> +#include <asm/pgtable.h> /*G:020 * Our story starts with the kernel booting into startup_32 in @@ -37,9 +38,113 @@ ENTRY(lguest_entry) /* Set up the initial stack so we can run C code. */ movl $(init_thread_union+THREAD_SIZE),%esp + call init_pagetables + /* Jumps are relative: we're running __PAGE_OFFSET too low. */ jmp lguest_init+__PAGE_OFFSET +/* + * Initialize page tables. This creates a PDE and a set of page + * tables, which are located immediately beyond __brk_base. The variable + * _brk_end is set up to point to the first "safe" location. + * Mappings are created both at virtual address 0 (identity mapping) + * and PAGE_OFFSET for up to _end. + * + * FIXME: This code is taken verbatim from arch/x86/kernel/head_32.S: they + * don't have a stack at this point, so we can't just use call and ret. + */ +init_pagetables: +#if PTRS_PER_PMD > 1 +#define PAGE_TABLE_SIZE(pages) (((pages) / PTRS_PER_PMD) + PTRS_PER_PGD) +#else +#define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD) +#endif +#define pa(X) ((X) - __PAGE_OFFSET) + +/* Enough space to fit pagetables for the low memory linear map */ +MAPPING_BEYOND_END = \ + PAGE_TABLE_SIZE(((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT) << PAGE_SHIFT +#ifdef CONFIG_X86_PAE + + /* + * In PAE mode initial_page_table is statically defined to contain + * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3 + * entries). The identity mapping is handled by pointing two PGD entries + * to the first kernel PMD. + * + * Note the upper half of each PMD or PTE are always zero at this stage. + */ + +#define KPMDS (((-__PAGE_OFFSET) >> 30) & 3) /* Number of kernel PMDs */ + + xorl %ebx,%ebx /* %ebx is kept at zero */ + + movl $pa(__brk_base), %edi + movl $pa(initial_pg_pmd), %edx + movl $PTE_IDENT_ATTR, %eax +10: + leal PDE_IDENT_ATTR(%edi),%ecx /* Create PMD entry */ + movl %ecx,(%edx) /* Store PMD entry */ + /* Upper half already zero */ + addl $8,%edx + movl $512,%ecx +11: + stosl + xchgl %eax,%ebx + stosl + xchgl %eax,%ebx + addl $0x1000,%eax + loop 11b + + /* + * End condition: we must map up to the end + MAPPING_BEYOND_END. + */ + movl $pa(_end) + MAPPING_BEYOND_END + PTE_IDENT_ATTR, %ebp + cmpl %ebp,%eax + jb 10b +1: + addl $__PAGE_OFFSET, %edi + movl %edi, pa(_brk_end) + shrl $12, %eax + movl %eax, pa(max_pfn_mapped) + + /* Do early initialization of the fixmap area */ + movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax + movl %eax,pa(initial_pg_pmd+0x1000*KPMDS-8) +#else /* Not PAE */ + +page_pde_offset = (__PAGE_OFFSET >> 20); + + movl $pa(__brk_base), %edi + movl $pa(initial_page_table), %edx + movl $PTE_IDENT_ATTR, %eax +10: + leal PDE_IDENT_ATTR(%edi),%ecx /* Create PDE entry */ + movl %ecx,(%edx) /* Store identity PDE entry */ + movl %ecx,page_pde_offset(%edx) /* Store kernel PDE entry */ + addl $4,%edx + movl $1024, %ecx +11: + stosl + addl $0x1000,%eax + loop 11b + /* + * End condition: we must map up to the end + MAPPING_BEYOND_END. + */ + movl $pa(_end) + MAPPING_BEYOND_END + PTE_IDENT_ATTR, %ebp + cmpl %ebp,%eax + jb 10b + addl $__PAGE_OFFSET, %edi + movl %edi, pa(_brk_end) + shrl $12, %eax + movl %eax, pa(max_pfn_mapped) + + /* Do early initialization of the fixmap area */ + movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax + movl %eax,pa(initial_page_table+0xffc) +#endif + ret + /*G:055 * We create a macro which puts the assembler code between lgstart_ and lgend_ * markers. These templates are put in the .text section: they can't be diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 12cdbb17ad18..6acc724d5d8f 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -223,7 +223,7 @@ void native_flush_tlb_others(const struct cpumask *cpumask, static void __cpuinit calculate_tlb_offset(void) { - int cpu, node, nr_node_vecs; + int cpu, node, nr_node_vecs, idx = 0; /* * we are changing tlb_vector_offset for each CPU in runtime, but this * will not cause inconsistency, as the write is atomic under X86. we @@ -239,7 +239,7 @@ static void __cpuinit calculate_tlb_offset(void) nr_node_vecs = NUM_INVALIDATE_TLB_VECTORS/nr_online_nodes; for_each_online_node(node) { - int node_offset = (node % NUM_INVALIDATE_TLB_VECTORS) * + int node_offset = (idx % NUM_INVALIDATE_TLB_VECTORS) * nr_node_vecs; int cpu_offset = 0; for_each_cpu(cpu, cpumask_of_node(node)) { @@ -248,6 +248,7 @@ static void __cpuinit calculate_tlb_offset(void) cpu_offset++; cpu_offset = cpu_offset % nr_node_vecs; } + idx++; } } diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index c4bb261c106e..b1805b78842f 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -65,21 +65,13 @@ pcibios_align_resource(void *data, const struct resource *res, resource_size_t size, resource_size_t align) { struct pci_dev *dev = data; - resource_size_t start = round_down(res->end - size + 1, align); + resource_size_t start = res->start; if (res->flags & IORESOURCE_IO) { - - /* - * If we're avoiding ISA aliases, the largest contiguous I/O - * port space is 256 bytes. Clearing bits 9 and 10 preserves - * all 256-byte and smaller alignments, so the result will - * still be correctly aligned. - */ - if (!skip_isa_ioresource_align(dev)) - start &= ~0x300; - } else if (res->flags & IORESOURCE_MEM) { - if (start < BIOS_END) - start = res->end; /* fail; no space */ + if (skip_isa_ioresource_align(dev)) + return start; + if (start & 0x300) + start = (start + 0x3ff) & ~0x3ff; } return start; } diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index d7b5109f7a9c..25cd4a07d09f 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -70,6 +70,9 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, struct xen_pci_frontend_ops *xen_pci_frontend; EXPORT_SYMBOL_GPL(xen_pci_frontend); +#define XEN_PIRQ_MSI_DATA (MSI_DATA_TRIGGER_EDGE | \ + MSI_DATA_LEVEL_ASSERT | (3 << 8) | MSI_DATA_VECTOR(0)) + static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq, struct msi_msg *msg) { @@ -83,12 +86,7 @@ static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq, MSI_ADDR_REDIRECTION_CPU | MSI_ADDR_DEST_ID(pirq); - msg->data = - MSI_DATA_TRIGGER_EDGE | - MSI_DATA_LEVEL_ASSERT | - /* delivery mode reserved */ - (3 << 8) | - MSI_DATA_VECTOR(0); + msg->data = XEN_PIRQ_MSI_DATA; } static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) @@ -98,8 +96,23 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) struct msi_msg msg; list_for_each_entry(msidesc, &dev->msi_list, list) { + __read_msi_msg(msidesc, &msg); + pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) | + ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff); + if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) { + xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? + "msi-x" : "msi", &irq, &pirq, XEN_ALLOC_IRQ); + if (irq < 0) + goto error; + ret = set_irq_msi(irq, msidesc); + if (ret < 0) + goto error_while; + printk(KERN_DEBUG "xen: msi already setup: msi --> irq=%d" + " pirq=%d\n", irq, pirq); + return 0; + } xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? - "msi-x" : "msi", &irq, &pirq); + "msi-x" : "msi", &irq, &pirq, (XEN_ALLOC_IRQ | XEN_ALLOC_PIRQ)); if (irq < 0 || pirq < 0) goto error; printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq); diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index a318194002b5..ba9caa808a9c 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -1455,7 +1455,7 @@ static void __init uv_init_uvhub(int uvhub, int vector) * the below initialization can't be in firmware because the * messaging IRQ will be determined by the OS */ - apicid = uvhub_to_first_apicid(uvhub); + apicid = uvhub_to_first_apicid(uvhub) | uv_apicid_hibits; uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG, ((apicid << 32) | vector)); } diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c index 56e421bc379b..9daf5d1af9f1 100644 --- a/arch/x86/platform/uv/uv_time.c +++ b/arch/x86/platform/uv/uv_time.c @@ -89,6 +89,7 @@ static void uv_rtc_send_IPI(int cpu) apicid = cpu_physical_id(cpu); pnode = uv_apicid_to_pnode(apicid); + apicid |= uv_apicid_hibits; val = (1UL << UVH_IPI_INT_SEND_SHFT) | (apicid << UVH_IPI_INT_APIC_ID_SHFT) | (X86_PLATFORM_IPI_VECTOR << UVH_IPI_INT_VECTOR_SHFT); @@ -107,6 +108,7 @@ static int uv_intr_pending(int pnode) static int uv_setup_intr(int cpu, u64 expires) { u64 val; + unsigned long apicid = cpu_physical_id(cpu) | uv_apicid_hibits; int pnode = uv_cpu_to_pnode(cpu); uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, @@ -117,7 +119,7 @@ static int uv_setup_intr(int cpu, u64 expires) UVH_EVENT_OCCURRED0_RTC1_MASK); val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) | - ((u64)cpu_physical_id(cpu) << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT); + ((u64)apicid << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT); /* Set configuration */ uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, val); diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile index 4a2afa1bac51..b6552b189bcd 100644 --- a/arch/x86/vdso/Makefile +++ b/arch/x86/vdso/Makefile @@ -25,7 +25,7 @@ targets += vdso.so vdso.so.dbg vdso.lds $(vobjs-y) export CPPFLAGS_vdso.lds += -P -C -VDSO_LDFLAGS_vdso.lds = -m elf_x86_64 -Wl,-soname=linux-vdso.so.1 \ +VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \ -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 $(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so @@ -69,7 +69,7 @@ vdso32.so-$(VDSO32-y) += sysenter vdso32-images = $(vdso32.so-y:%=vdso32-%.so) CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds) -VDSO_LDFLAGS_vdso32.lds = -m elf_i386 -Wl,-soname=linux-gate.so.1 +VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-soname=linux-gate.so.1 # This makes sure the $(obj) subdirectory exists even though vdso32/ # is not a kbuild sub-make subdirectory. diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 235c0f4d3861..44dcad43989d 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -75,6 +75,11 @@ DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info); enum xen_domain_type xen_domain_type = XEN_NATIVE; EXPORT_SYMBOL_GPL(xen_domain_type); +unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START; +EXPORT_SYMBOL(machine_to_phys_mapping); +unsigned int machine_to_phys_order; +EXPORT_SYMBOL(machine_to_phys_order); + struct start_info *xen_start_info; EXPORT_SYMBOL_GPL(xen_start_info); @@ -1016,10 +1021,6 @@ static void xen_reboot(int reason) { struct sched_shutdown r = { .reason = reason }; -#ifdef CONFIG_SMP - stop_other_cpus(); -#endif - if (HYPERVISOR_sched_op(SCHEDOP_shutdown, &r)) BUG(); } @@ -1090,6 +1091,8 @@ static void __init xen_setup_stackprotector(void) /* First C function to be called on Xen boot */ asmlinkage void __init xen_start_kernel(void) { + struct physdev_set_iopl set_iopl; + int rc; pgd_t *pgd; if (!xen_start_info) @@ -1097,6 +1100,8 @@ asmlinkage void __init xen_start_kernel(void) xen_domain_type = XEN_PV_DOMAIN; + xen_setup_machphys_mapping(); + /* Install Xen paravirt ops */ pv_info = xen_info; pv_init_ops = xen_init_ops; @@ -1191,8 +1196,6 @@ asmlinkage void __init xen_start_kernel(void) /* Allocate and initialize top and mid mfn levels for p2m structure */ xen_build_mfn_list_list(); - init_mm.pgd = pgd; - /* keep using Xen gdt for now; no urgent need to change it */ #ifdef CONFIG_X86_32 @@ -1202,10 +1205,18 @@ asmlinkage void __init xen_start_kernel(void) #else pv_info.kernel_rpl = 0; #endif - /* set the limit of our address space */ xen_reserve_top(); + /* We used to do this in xen_arch_setup, but that is too late on AMD + * were early_cpu_init (run before ->arch_setup()) calls early_amd_init + * which pokes 0xcf8 port. + */ + set_iopl.iopl = 1; + rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); + if (rc != 0) + xen_raw_printk("physdev_op failed %d\n", rc); + #ifdef CONFIG_X86_32 /* set up basic CPUID stuff */ cpu_detect(&new_cpu_data); diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 21ed8d7f75a5..44924e551fde 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -2034,6 +2034,20 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) set_page_prot(pmd, PAGE_KERNEL_RO); } +void __init xen_setup_machphys_mapping(void) +{ + struct xen_machphys_mapping mapping; + unsigned long machine_to_phys_nr_ents; + + if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) { + machine_to_phys_mapping = (unsigned long *)mapping.v_start; + machine_to_phys_nr_ents = mapping.max_mfn + 1; + } else { + machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES; + } + machine_to_phys_order = fls(machine_to_phys_nr_ents - 1); +} + #ifdef CONFIG_X86_64 static void convert_pfn_mfn(void *v) { @@ -2119,44 +2133,83 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, return pgd; } #else /* !CONFIG_X86_64 */ -static RESERVE_BRK_ARRAY(pmd_t, level2_kernel_pgt, PTRS_PER_PMD); +static RESERVE_BRK_ARRAY(pmd_t, initial_kernel_pmd, PTRS_PER_PMD); +static RESERVE_BRK_ARRAY(pmd_t, swapper_kernel_pmd, PTRS_PER_PMD); + +static __init void xen_write_cr3_init(unsigned long cr3) +{ + unsigned long pfn = PFN_DOWN(__pa(swapper_pg_dir)); + + BUG_ON(read_cr3() != __pa(initial_page_table)); + BUG_ON(cr3 != __pa(swapper_pg_dir)); + + /* + * We are switching to swapper_pg_dir for the first time (from + * initial_page_table) and therefore need to mark that page + * read-only and then pin it. + * + * Xen disallows sharing of kernel PMDs for PAE + * guests. Therefore we must copy the kernel PMD from + * initial_page_table into a new kernel PMD to be used in + * swapper_pg_dir. + */ + swapper_kernel_pmd = + extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE); + memcpy(swapper_kernel_pmd, initial_kernel_pmd, + sizeof(pmd_t) * PTRS_PER_PMD); + swapper_pg_dir[KERNEL_PGD_BOUNDARY] = + __pgd(__pa(swapper_kernel_pmd) | _PAGE_PRESENT); + set_page_prot(swapper_kernel_pmd, PAGE_KERNEL_RO); + + set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO); + xen_write_cr3(cr3); + pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, pfn); + + pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, + PFN_DOWN(__pa(initial_page_table))); + set_page_prot(initial_page_table, PAGE_KERNEL); + set_page_prot(initial_kernel_pmd, PAGE_KERNEL); + + pv_mmu_ops.write_cr3 = &xen_write_cr3; +} __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) { pmd_t *kernel_pmd; - level2_kernel_pgt = extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE); + initial_kernel_pmd = + extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE); max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) + xen_start_info->nr_pt_frames * PAGE_SIZE + 512*1024); kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd); - memcpy(level2_kernel_pgt, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD); + memcpy(initial_kernel_pmd, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD); - xen_map_identity_early(level2_kernel_pgt, max_pfn); + xen_map_identity_early(initial_kernel_pmd, max_pfn); - memcpy(swapper_pg_dir, pgd, sizeof(pgd_t) * PTRS_PER_PGD); - set_pgd(&swapper_pg_dir[KERNEL_PGD_BOUNDARY], - __pgd(__pa(level2_kernel_pgt) | _PAGE_PRESENT)); + memcpy(initial_page_table, pgd, sizeof(pgd_t) * PTRS_PER_PGD); + initial_page_table[KERNEL_PGD_BOUNDARY] = + __pgd(__pa(initial_kernel_pmd) | _PAGE_PRESENT); - set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO); - set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO); + set_page_prot(initial_kernel_pmd, PAGE_KERNEL_RO); + set_page_prot(initial_page_table, PAGE_KERNEL_RO); set_page_prot(empty_zero_page, PAGE_KERNEL_RO); pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd))); - xen_write_cr3(__pa(swapper_pg_dir)); - - pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(swapper_pg_dir))); + pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, + PFN_DOWN(__pa(initial_page_table))); + xen_write_cr3(__pa(initial_page_table)); memblock_x86_reserve_range(__pa(xen_start_info->pt_base), __pa(xen_start_info->pt_base + xen_start_info->nr_pt_frames * PAGE_SIZE), "XEN PAGETABLES"); - return swapper_pg_dir; + return initial_page_table; } #endif /* CONFIG_X86_64 */ @@ -2290,7 +2343,11 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = { .write_cr2 = xen_write_cr2, .read_cr3 = xen_read_cr3, +#ifdef CONFIG_X86_32 + .write_cr3 = xen_write_cr3_init, +#else .write_cr3 = xen_write_cr3, +#endif .flush_tlb_user = xen_flush_tlb, .flush_tlb_kernel = xen_flush_tlb, @@ -2358,8 +2415,6 @@ void __init xen_init_mmu_ops(void) x86_init.paging.pagetable_setup_done = xen_pagetable_setup_done; pv_mmu_ops = xen_mmu_ops; - vmap_lazy_unmap = false; - memset(dummy_mapping, 0xff, PAGE_SIZE); } @@ -2627,7 +2682,8 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP); - vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP; + BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_RESERVED | VM_IO)) == + (VM_PFNMAP | VM_RESERVED | VM_IO))); rmd.mfn = mfn; rmd.prot = prot; diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c index 0f456386cce5..25c52f94a27c 100644 --- a/arch/x86/xen/platform-pci-unplug.c +++ b/arch/x86/xen/platform-pci-unplug.c @@ -68,7 +68,7 @@ static int __init check_platform_magic(void) return 0; } -void __init xen_unplug_emulated_devices(void) +void xen_unplug_emulated_devices(void) { int r; diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 769c4b01fa32..b5a7f928234b 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -23,7 +23,6 @@ #include <xen/interface/callback.h> #include <xen/interface/memory.h> #include <xen/interface/physdev.h> -#include <xen/interface/memory.h> #include <xen/features.h> #include "xen-ops.h" @@ -182,24 +181,21 @@ char * __init xen_memory_setup(void) for (i = 0; i < memmap.nr_entries; i++) { unsigned long long end = map[i].addr + map[i].size; - if (map[i].type == E820_RAM) { - if (map[i].addr < mem_end && end > mem_end) { - /* Truncate region to max_mem. */ - u64 delta = end - mem_end; + if (map[i].type == E820_RAM && end > mem_end) { + /* RAM off the end - may be partially included */ + u64 delta = min(map[i].size, end - mem_end); - map[i].size -= delta; - extra_pages += PFN_DOWN(delta); + map[i].size -= delta; + end -= delta; - end = mem_end; - } + extra_pages += PFN_DOWN(delta); } - if (end > xen_extra_mem_start) + if (map[i].size > 0 && end > xen_extra_mem_start) xen_extra_mem_start = end; - /* If region is non-RAM or below mem_end, add what remains */ - if ((map[i].type != E820_RAM || map[i].addr < mem_end) && - map[i].size > 0) + /* Add region if any remains */ + if (map[i].size > 0) e820_add_region(map[i].addr, map[i].size, map[i].type); } @@ -248,26 +244,11 @@ char * __init xen_memory_setup(void) else extra_pages = 0; - if (!xen_initial_domain()) - xen_add_extra_mem(extra_pages); + xen_add_extra_mem(extra_pages); return "Xen"; } -static void xen_idle(void) -{ - local_irq_disable(); - - if (need_resched()) - local_irq_enable(); - else { - current_thread_info()->status &= ~TS_POLLING; - smp_mb__after_clear_bit(); - safe_halt(); - current_thread_info()->status |= TS_POLLING; - } -} - /* * Set the bit indicating "nosegneg" library variants should be used. * We only need to bother in pure 32-bit mode; compat 32-bit processes @@ -337,9 +318,6 @@ void __cpuinit xen_enable_syscall(void) void __init xen_arch_setup(void) { - struct physdev_set_iopl set_iopl; - int rc; - xen_panic_handler_init(); HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments); @@ -356,11 +334,6 @@ void __init xen_arch_setup(void) xen_enable_sysenter(); xen_enable_syscall(); - set_iopl.iopl = 1; - rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); - if (rc != 0) - printk(KERN_INFO "physdev_op failed %d\n", rc); - #ifdef CONFIG_ACPI if (!(xen_start_info->flags & SIF_INITDOMAIN)) { printk(KERN_INFO "ACPI in unprivileged domain disabled\n"); @@ -372,7 +345,11 @@ void __init xen_arch_setup(void) MAX_GUEST_CMDLINE > COMMAND_LINE_SIZE ? COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE); - pm_idle = xen_idle; + /* Set up idle, making sure it calls safe_halt() pvop */ +#ifdef CONFIG_X86_32 + boot_cpu_data.hlt_works_ok = 1; +#endif + pm_idle = default_idle; fiddle_vdso(); } diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index 1d789d56877c..9bbd63a129b5 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c @@ -31,6 +31,7 @@ void xen_hvm_post_suspend(int suspend_cancelled) int cpu; xen_hvm_init_shared_info(); xen_callback_vector(); + xen_unplug_emulated_devices(); if (xen_feature(XENFEAT_hvm_safe_pvclock)) { for_each_online_cpu(cpu) { xen_setup_runstate_info(cpu); diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index b2bb5aa3b054..5da5e53fb94c 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -426,6 +426,8 @@ void xen_timer_resume(void) { int cpu; + pvclock_resume(); + if (xen_clockevent != &xen_vcpuop_clockevent) return; diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 64044747348e..9d41bf985757 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -43,7 +43,7 @@ void xen_vcpu_restore(void); void xen_callback_vector(void); void xen_hvm_init_shared_info(void); -void __init xen_unplug_emulated_devices(void); +void xen_unplug_emulated_devices(void); void __init xen_build_dynamic_phys_to_machine(void); diff --git a/block/blk-map.c b/block/blk-map.c index 5d5dbe47c228..e663ac2d8e68 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -201,12 +201,13 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, for (i = 0; i < iov_count; i++) { unsigned long uaddr = (unsigned long)iov[i].iov_base; + if (!iov[i].iov_len) + return -EINVAL; + if (uaddr & queue_dma_alignment(q)) { unaligned = 1; break; } - if (!iov[i].iov_len) - return -EINVAL; } if (unaligned || (q->dma_pad_mask & len) || map_data) diff --git a/block/blk-merge.c b/block/blk-merge.c index 77b7c26df6b5..74bc4a768f32 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -21,7 +21,7 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q, return 0; fbio = bio; - cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); + cluster = blk_queue_cluster(q); seg_size = 0; nr_phys_segs = 0; for_each_bio(bio) { @@ -87,7 +87,7 @@ EXPORT_SYMBOL(blk_recount_segments); static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, struct bio *nxt) { - if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags)) + if (!blk_queue_cluster(q)) return 0; if (bio->bi_seg_back_size + nxt->bi_seg_front_size > @@ -123,7 +123,7 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, int nsegs, cluster; nsegs = 0; - cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); + cluster = blk_queue_cluster(q); /* * for each bio in rq diff --git a/block/blk-settings.c b/block/blk-settings.c index 701859fb9647..36c8c1f2af18 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -126,7 +126,7 @@ void blk_set_default_limits(struct queue_limits *lim) lim->alignment_offset = 0; lim->io_opt = 0; lim->misaligned = 0; - lim->no_cluster = 0; + lim->cluster = 1; } EXPORT_SYMBOL(blk_set_default_limits); @@ -229,8 +229,8 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 dma_mask) EXPORT_SYMBOL(blk_queue_bounce_limit); /** - * blk_queue_max_hw_sectors - set max sectors for a request for this queue - * @q: the request queue for the device + * blk_limits_max_hw_sectors - set hard and soft limit of max sectors for request + * @limits: the queue limits * @max_hw_sectors: max hardware sectors in the usual 512b unit * * Description: @@ -244,7 +244,7 @@ EXPORT_SYMBOL(blk_queue_bounce_limit); * per-device basis in /sys/block/<device>/queue/max_sectors_kb. * The soft limit can not exceed max_hw_sectors. **/ -void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors) +void blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_sectors) { if ((max_hw_sectors << 9) < PAGE_CACHE_SIZE) { max_hw_sectors = 1 << (PAGE_CACHE_SHIFT - 9); @@ -252,9 +252,23 @@ void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_secto __func__, max_hw_sectors); } - q->limits.max_hw_sectors = max_hw_sectors; - q->limits.max_sectors = min_t(unsigned int, max_hw_sectors, - BLK_DEF_MAX_SECTORS); + limits->max_hw_sectors = max_hw_sectors; + limits->max_sectors = min_t(unsigned int, max_hw_sectors, + BLK_DEF_MAX_SECTORS); +} +EXPORT_SYMBOL(blk_limits_max_hw_sectors); + +/** + * blk_queue_max_hw_sectors - set max sectors for a request for this queue + * @q: the request queue for the device + * @max_hw_sectors: max hardware sectors in the usual 512b unit + * + * Description: + * See description for blk_limits_max_hw_sectors(). + **/ +void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors) +{ + blk_limits_max_hw_sectors(&q->limits, max_hw_sectors); } EXPORT_SYMBOL(blk_queue_max_hw_sectors); @@ -464,15 +478,6 @@ EXPORT_SYMBOL(blk_queue_io_opt); void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b) { blk_stack_limits(&t->limits, &b->limits, 0); - - if (!t->queue_lock) - WARN_ON_ONCE(1); - else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) { - unsigned long flags; - spin_lock_irqsave(t->queue_lock, flags); - queue_flag_clear(QUEUE_FLAG_CLUSTER, t); - spin_unlock_irqrestore(t->queue_lock, flags); - } } EXPORT_SYMBOL(blk_queue_stack_limits); @@ -545,7 +550,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, t->io_min = max(t->io_min, b->io_min); t->io_opt = lcm(t->io_opt, b->io_opt); - t->no_cluster |= b->no_cluster; + t->cluster &= b->cluster; t->discard_zeroes_data &= b->discard_zeroes_data; /* Physical block size a multiple of the logical block size? */ @@ -641,7 +646,6 @@ void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, sector_t offset) { struct request_queue *t = disk->queue; - struct request_queue *b = bdev_get_queue(bdev); if (bdev_stack_limits(&t->limits, bdev, offset >> 9) < 0) { char top[BDEVNAME_SIZE], bottom[BDEVNAME_SIZE]; @@ -652,17 +656,6 @@ void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, printk(KERN_NOTICE "%s: Warning: Device %s is misaligned\n", top, bottom); } - - if (!t->queue_lock) - WARN_ON_ONCE(1); - else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) { - unsigned long flags; - - spin_lock_irqsave(t->queue_lock, flags); - if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) - queue_flag_clear(QUEUE_FLAG_CLUSTER, t); - spin_unlock_irqrestore(t->queue_lock, flags); - } } EXPORT_SYMBOL(disk_stack_limits); diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 013457f47fdc..41fb69150b4d 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -119,7 +119,7 @@ static ssize_t queue_max_integrity_segments_show(struct request_queue *q, char * static ssize_t queue_max_segment_size_show(struct request_queue *q, char *page) { - if (test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags)) + if (blk_queue_cluster(q)) return queue_var_show(queue_max_segment_size(q), (page)); return queue_var_show(PAGE_CACHE_SIZE, (page)); diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 56ad4531b412..381b09bb562b 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -355,6 +355,12 @@ throtl_start_new_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw) tg->slice_end[rw], jiffies); } +static inline void throtl_set_slice_end(struct throtl_data *td, + struct throtl_grp *tg, bool rw, unsigned long jiffy_end) +{ + tg->slice_end[rw] = roundup(jiffy_end, throtl_slice); +} + static inline void throtl_extend_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw, unsigned long jiffy_end) { @@ -391,6 +397,16 @@ throtl_trim_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw) if (throtl_slice_used(td, tg, rw)) return; + /* + * A bio has been dispatched. Also adjust slice_end. It might happen + * that initially cgroup limit was very low resulting in high + * slice_end, but later limit was bumped up and bio was dispached + * sooner, then we need to reduce slice_end. A high bogus slice_end + * is bad because it does not allow new slice to start. + */ + + throtl_set_slice_end(td, tg, rw, jiffies + throtl_slice); + time_elapsed = jiffies - tg->slice_start[rw]; nr_slices = time_elapsed / throtl_slice; @@ -645,7 +661,7 @@ static int throtl_dispatch_tg(struct throtl_data *td, struct throtl_grp *tg, { unsigned int nr_reads = 0, nr_writes = 0; unsigned int max_nr_reads = throtl_grp_quantum*3/4; - unsigned int max_nr_writes = throtl_grp_quantum - nr_reads; + unsigned int max_nr_writes = throtl_grp_quantum - max_nr_reads; struct bio *bio; /* Try to dispatch 75% READS and 25% WRITES */ @@ -709,26 +725,21 @@ static void throtl_process_limit_change(struct throtl_data *td) struct throtl_grp *tg; struct hlist_node *pos, *n; - /* - * Make sure atomic_inc() effects from - * throtl_update_blkio_group_read_bps(), group of functions are - * visible. - * Is this required or smp_mb__after_atomic_inc() was suffcient - * after the atomic_inc(). - */ - smp_rmb(); if (!atomic_read(&td->limits_changed)) return; throtl_log(td, "limit changed =%d", atomic_read(&td->limits_changed)); - hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) { - /* - * Do I need an smp_rmb() here to make sure tg->limits_changed - * update is visible. I am relying on smp_rmb() at the - * beginning of function and not putting a new one here. - */ + /* + * Make sure updates from throtl_update_blkio_group_read_bps() group + * of functions to tg->limits_changed are visible. We do not + * want update td->limits_changed to be visible but update to + * tg->limits_changed not being visible yet on this cpu. Hence + * the read barrier. + */ + smp_rmb(); + hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) { if (throtl_tg_on_rr(tg) && tg->limits_changed) { throtl_log_tg(td, tg, "limit change rbps=%llu wbps=%llu" " riops=%u wiops=%u", tg->bps[READ], diff --git a/block/bsg.c b/block/bsg.c index f20d6a789d48..0c8b64a16484 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -250,6 +250,14 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm, int ret, rw; unsigned int dxfer_len; void *dxferp = NULL; + struct bsg_class_device *bcd = &q->bsg_dev; + + /* if the LLD has been removed then the bsg_unregister_queue will + * eventually be called and the class_dev was freed, so we can no + * longer use this request_queue. Return no such address. + */ + if (!bcd->class_dev) + return ERR_PTR(-ENXIO); dprintk("map hdr %llx/%u %llx/%u\n", (unsigned long long) hdr->dout_xferp, hdr->dout_xfer_len, (unsigned long long) hdr->din_xferp, diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index ba9afeaa23ac..25d3aaebc10d 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -100,24 +100,7 @@ static const struct file_operations acpi_ac_fops = { .release = single_release, }; #endif -static int get_ac_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct acpi_ac *ac = to_acpi_ac(psy); - switch (psp) { - case POWER_SUPPLY_PROP_ONLINE: - val->intval = ac->state; - break; - default: - return -EINVAL; - } - return 0; -} -static enum power_supply_property ac_props[] = { - POWER_SUPPLY_PROP_ONLINE, -}; /* -------------------------------------------------------------------------- AC Adapter Management -------------------------------------------------------------------------- */ @@ -140,6 +123,35 @@ static int acpi_ac_get_state(struct acpi_ac *ac) return 0; } +/* -------------------------------------------------------------------------- + sysfs I/F + -------------------------------------------------------------------------- */ +static int get_ac_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct acpi_ac *ac = to_acpi_ac(psy); + + if (!ac) + return -ENODEV; + + if (acpi_ac_get_state(ac)) + return -ENODEV; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = ac->state; + break; + default: + return -EINVAL; + } + return 0; +} + +static enum power_supply_property ac_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + #ifdef CONFIG_ACPI_PROCFS_POWER /* -------------------------------------------------------------------------- FS Interface (/proc) diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 1211c03149e8..5850d320404c 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -86,7 +86,7 @@ static struct erst_erange { * It is used to provide exclusive accessing for ERST Error Log * Address Range too. */ -static DEFINE_SPINLOCK(erst_lock); +static DEFINE_RAW_SPINLOCK(erst_lock); static inline int erst_errno(int command_status) { @@ -421,9 +421,9 @@ ssize_t erst_get_record_count(void) if (erst_disable) return -ENODEV; - spin_lock_irqsave(&erst_lock, flags); + raw_spin_lock_irqsave(&erst_lock, flags); count = __erst_get_record_count(); - spin_unlock_irqrestore(&erst_lock, flags); + raw_spin_unlock_irqrestore(&erst_lock, flags); return count; } @@ -456,9 +456,9 @@ int erst_get_next_record_id(u64 *record_id) if (erst_disable) return -ENODEV; - spin_lock_irqsave(&erst_lock, flags); + raw_spin_lock_irqsave(&erst_lock, flags); rc = __erst_get_next_record_id(record_id); - spin_unlock_irqrestore(&erst_lock, flags); + raw_spin_unlock_irqrestore(&erst_lock, flags); return rc; } @@ -624,17 +624,17 @@ int erst_write(const struct cper_record_header *record) return -EINVAL; if (erst_erange.attr & ERST_RANGE_NVRAM) { - if (!spin_trylock_irqsave(&erst_lock, flags)) + if (!raw_spin_trylock_irqsave(&erst_lock, flags)) return -EBUSY; rc = __erst_write_to_nvram(record); - spin_unlock_irqrestore(&erst_lock, flags); + raw_spin_unlock_irqrestore(&erst_lock, flags); return rc; } if (record->record_length > erst_erange.size) return -EINVAL; - if (!spin_trylock_irqsave(&erst_lock, flags)) + if (!raw_spin_trylock_irqsave(&erst_lock, flags)) return -EBUSY; memcpy(erst_erange.vaddr, record, record->record_length); rcd_erange = erst_erange.vaddr; @@ -642,7 +642,7 @@ int erst_write(const struct cper_record_header *record) memcpy(&rcd_erange->persistence_information, "ER", 2); rc = __erst_write_to_storage(0); - spin_unlock_irqrestore(&erst_lock, flags); + raw_spin_unlock_irqrestore(&erst_lock, flags); return rc; } @@ -696,9 +696,9 @@ ssize_t erst_read(u64 record_id, struct cper_record_header *record, if (erst_disable) return -ENODEV; - spin_lock_irqsave(&erst_lock, flags); + raw_spin_lock_irqsave(&erst_lock, flags); len = __erst_read(record_id, record, buflen); - spin_unlock_irqrestore(&erst_lock, flags); + raw_spin_unlock_irqrestore(&erst_lock, flags); return len; } EXPORT_SYMBOL_GPL(erst_read); @@ -719,20 +719,20 @@ ssize_t erst_read_next(struct cper_record_header *record, size_t buflen) if (erst_disable) return -ENODEV; - spin_lock_irqsave(&erst_lock, flags); + raw_spin_lock_irqsave(&erst_lock, flags); rc = __erst_get_next_record_id(&record_id); if (rc) { - spin_unlock_irqrestore(&erst_lock, flags); + raw_spin_unlock_irqrestore(&erst_lock, flags); return rc; } /* no more record */ if (record_id == APEI_ERST_INVALID_RECORD_ID) { - spin_unlock_irqrestore(&erst_lock, flags); + raw_spin_unlock_irqrestore(&erst_lock, flags); return 0; } len = __erst_read(record_id, record, buflen); - spin_unlock_irqrestore(&erst_lock, flags); + raw_spin_unlock_irqrestore(&erst_lock, flags); return len; } @@ -746,12 +746,12 @@ int erst_clear(u64 record_id) if (erst_disable) return -ENODEV; - spin_lock_irqsave(&erst_lock, flags); + raw_spin_lock_irqsave(&erst_lock, flags); if (erst_erange.attr & ERST_RANGE_NVRAM) rc = __erst_clear_from_nvram(record_id); else rc = __erst_clear_from_storage(record_id); - spin_unlock_irqrestore(&erst_lock, flags); + raw_spin_unlock_irqrestore(&erst_lock, flags); return rc; } diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 1a3508a7fe03..daa7bc63f1d4 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -46,9 +46,9 @@ EXPORT_SYMBOL_GPL(hest_disable); /* HEST table parsing */ -static struct acpi_table_hest *hest_tab; +static struct acpi_table_hest *__read_mostly hest_tab; -static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = { +static const int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = { [ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */ [ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1, [ACPI_HEST_TYPE_IA32_NMI] = sizeof(struct acpi_hest_ia_nmi), @@ -126,7 +126,7 @@ struct ghes_arr { unsigned int count; }; -static int hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data) +static int __init hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data) { int *count = data; @@ -135,7 +135,7 @@ static int hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data) return 0; } -static int hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data) +static int __init hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data) { struct platform_device *ghes_dev; struct ghes_arr *ghes_arr = data; @@ -165,7 +165,7 @@ err: return rc; } -static int hest_ghes_dev_register(unsigned int ghes_count) +static int __init hest_ghes_dev_register(unsigned int ghes_count) { int rc, i; struct ghes_arr ghes_arr; diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 95649d373071..9fb9d5ac939d 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -130,6 +130,8 @@ struct acpi_battery { unsigned long flags; }; +static int acpi_battery_update(struct acpi_battery *battery); + #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); inline int acpi_battery_present(struct acpi_battery *battery) @@ -184,6 +186,9 @@ static int acpi_battery_get_property(struct power_supply *psy, int ret = 0; struct acpi_battery *battery = to_acpi_battery(psy); + if (acpi_battery_update(battery)) + return -ENODEV; + if (acpi_battery_present(battery)) { /* run battery update only if it is present */ acpi_battery_get_state(battery); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 372ff80b7b0c..302b31ed31f1 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -934,6 +934,9 @@ static struct dmi_system_id __initdata ec_dmi_table[] = { ec_flag_msi, "MSI hardware", { DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star")}, NULL}, { + ec_flag_msi, "MSI hardware", { + DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR")}, NULL}, + { ec_validate_ecdt, "ASUS hardware", { DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL}, {}, diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 966feddf6b1b..055d7b701fff 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -110,9 +110,6 @@ struct acpi_ioremap { static LIST_HEAD(acpi_ioremaps); static DEFINE_SPINLOCK(acpi_ioremap_lock); -#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ -static char osi_setup_string[OSI_STRING_LENGTH_MAX]; - static void __init acpi_osi_setup_late(void); /* @@ -152,8 +149,7 @@ static struct osi_linux { unsigned int enable:1; unsigned int dmi:1; unsigned int cmdline:1; - unsigned int known:1; -} osi_linux = { 0, 0, 0, 0}; +} osi_linux = {0, 0, 0}; static u32 acpi_osi_handler(acpi_string interface, u32 supported) { @@ -1055,13 +1051,53 @@ static int __init acpi_os_name_setup(char *str) __setup("acpi_os_name=", acpi_os_name_setup); +#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ +#define OSI_STRING_ENTRIES_MAX 16 /* arbitrary */ + +struct osi_setup_entry { + char string[OSI_STRING_LENGTH_MAX]; + bool enable; +}; + +static struct osi_setup_entry __initdata osi_setup_entries[OSI_STRING_ENTRIES_MAX]; + +void __init acpi_osi_setup(char *str) +{ + struct osi_setup_entry *osi; + bool enable = true; + int i; + + if (!acpi_gbl_create_osi_method) + return; + + if (str == NULL || *str == '\0') { + printk(KERN_INFO PREFIX "_OSI method disabled\n"); + acpi_gbl_create_osi_method = FALSE; + return; + } + + if (*str == '!') { + str++; + enable = false; + } + + for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { + osi = &osi_setup_entries[i]; + if (!strcmp(osi->string, str)) { + osi->enable = enable; + break; + } else if (osi->string[0] == '\0') { + osi->enable = enable; + strncpy(osi->string, str, OSI_STRING_LENGTH_MAX); + break; + } + } +} + static void __init set_osi_linux(unsigned int enable) { - if (osi_linux.enable != enable) { + if (osi_linux.enable != enable) osi_linux.enable = enable; - printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n", - enable ? "Add": "Delet"); - } if (osi_linux.enable) acpi_osi_setup("Linux"); @@ -1073,7 +1109,8 @@ static void __init set_osi_linux(unsigned int enable) static void __init acpi_cmdline_osi_linux(unsigned int enable) { - osi_linux.cmdline = 1; /* cmdline set the default */ + osi_linux.cmdline = 1; /* cmdline set the default and override DMI */ + osi_linux.dmi = 0; set_osi_linux(enable); return; @@ -1081,15 +1118,12 @@ static void __init acpi_cmdline_osi_linux(unsigned int enable) void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d) { - osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */ - printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); if (enable == -1) return; - osi_linux.known = 1; /* DMI knows which OSI(Linux) default needed */ - + osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */ set_osi_linux(enable); return; @@ -1104,37 +1138,44 @@ void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d) */ static void __init acpi_osi_setup_late(void) { - char *str = osi_setup_string; + struct osi_setup_entry *osi; + char *str; + int i; + acpi_status status; - if (*str == '\0') - return; + for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { + osi = &osi_setup_entries[i]; + str = osi->string; - if (!strcmp("!Linux", str)) { - acpi_cmdline_osi_linux(0); /* !enable */ - } else if (*str == '!') { - if (acpi_remove_interface(++str) == AE_OK) - printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); - } else if (!strcmp("Linux", str)) { - acpi_cmdline_osi_linux(1); /* enable */ - } else { - if (acpi_install_interface(str) == AE_OK) - printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); + if (*str == '\0') + break; + if (osi->enable) { + status = acpi_install_interface(str); + + if (ACPI_SUCCESS(status)) + printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); + } else { + status = acpi_remove_interface(str); + + if (ACPI_SUCCESS(status)) + printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); + } } } -int __init acpi_osi_setup(char *str) +static int __init osi_setup(char *str) { - if (str == NULL || *str == '\0') { - printk(KERN_INFO PREFIX "_OSI method disabled\n"); - acpi_gbl_create_osi_method = FALSE; - } else { - strncpy(osi_setup_string, str, OSI_STRING_LENGTH_MAX); - } + if (str && !strcmp("Linux", str)) + acpi_cmdline_osi_linux(1); + else if (str && !strcmp("!Linux", str)) + acpi_cmdline_osi_linux(0); + else + acpi_osi_setup(str); return 1; } -__setup("acpi_osi=", acpi_osi_setup); +__setup("acpi_osi=", osi_setup); /* enable serialization to combat AE_ALREADY_EXISTS errors */ static int __init acpi_serialize_setup(char *str) @@ -1530,7 +1571,7 @@ acpi_status __init acpi_os_initialize(void) return AE_OK; } -acpi_status acpi_os_initialize1(void) +acpi_status __init acpi_os_initialize1(void) { kacpid_wq = create_workqueue("kacpid"); kacpi_notify_wq = create_workqueue("kacpi_notify"); diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 67dedeed144c..4c9c2fb5d98f 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -213,11 +213,13 @@ static int acpi_power_on(acpi_handle handle) resource->name)); } else { result = __acpi_power_on(resource); + if (result) + resource->ref_count--; } mutex_unlock(&resource->resource_lock); - return 0; + return result; } static int acpi_power_off_device(acpi_handle handle) @@ -465,10 +467,12 @@ int acpi_power_transition(struct acpi_device *device, int state) struct acpi_handle_list *tl = NULL; /* Target Resources */ int i = 0; - if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) return -EINVAL; + if (device->power.state == state) + return 0; + if ((device->power.state < ACPI_STATE_D0) || (device->power.state > ACPI_STATE_D3)) return -ENODEV; @@ -488,10 +492,6 @@ int acpi_power_transition(struct acpi_device *device, int state) goto end; } - if (device->power.state == state) { - goto end; - } - /* * Then we dereference all power resources used in the current list. */ diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index fde49b9b1d99..79cb65332894 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -156,15 +156,6 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) return 0; } -static int acpi_thermal_cpufreq_increase(unsigned int cpu) -{ - return -ENODEV; -} -static int acpi_thermal_cpufreq_decrease(unsigned int cpu) -{ - return -ENODEV; -} - #endif int acpi_processor_get_limit_info(struct acpi_processor *pr) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 721d93b3ceee..febb153b5a68 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -27,8 +27,6 @@ static u8 sleep_states[ACPI_S_STATE_COUNT]; -static u32 acpi_target_sleep_state = ACPI_STATE_S0; - static void acpi_sleep_tts_switch(u32 acpi_state) { union acpi_object in_arg = { ACPI_TYPE_INTEGER }; @@ -81,6 +79,8 @@ static int acpi_sleep_prepare(u32 acpi_state) } #ifdef CONFIG_ACPI_SLEEP +static u32 acpi_target_sleep_state = ACPI_STATE_S0; + /* * The ACPI specification wants us to save NVS memory regions during hibernation * and to restore them during the subsequent resume. Windows does that also for @@ -427,6 +427,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"), }, }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-NW130D", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"), + }, + }, {}, }; #endif /* CONFIG_SUSPEND */ diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 19835d39289d..66aa4bee80a6 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3166,8 +3166,8 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, /** * ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device + * @shost: SCSI host of command to be sent * @cmd: SCSI command to be sent - * @done: Completion function, called when command is complete * * In some cases, this function translates SCSI commands into * ATA taskfiles, and queues the taskfiles to be sent to @@ -3177,42 +3177,39 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, * ATA and ATAPI devices appearing as SCSI devices. * * LOCKING: - * Releases scsi-layer-held lock, and obtains host lock. + * ATA host lock * * RETURNS: * Return value from __ata_scsi_queuecmd() if @cmd can be queued, * 0 otherwise. */ -static int ata_scsi_queuecmd_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) +int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd) { struct ata_port *ap; struct ata_device *dev; struct scsi_device *scsidev = cmd->device; - struct Scsi_Host *shost = scsidev->host; int rc = 0; + unsigned long irq_flags; ap = ata_shost_to_port(shost); - spin_unlock(shost->host_lock); - spin_lock(ap->lock); + spin_lock_irqsave(ap->lock, irq_flags); ata_scsi_dump_cdb(ap, cmd); dev = ata_scsi_find_dev(ap, scsidev); if (likely(dev)) - rc = __ata_scsi_queuecmd(cmd, done, dev); + rc = __ata_scsi_queuecmd(cmd, cmd->scsi_done, dev); else { cmd->result = (DID_BAD_TARGET << 16); - done(cmd); + cmd->scsi_done(cmd); } - spin_unlock(ap->lock); - spin_lock(shost->host_lock); + spin_unlock_irqrestore(ap->lock, irq_flags); + return rc; } -DEF_SCSI_QCMD(ata_scsi_queuecmd) - /** * ata_scsi_simulate - simulate SCSI command on ATA device * @dev: the target device diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index c21589986c69..8b677bbf2d37 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -538,7 +538,7 @@ static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) return 0; } -static void svia_configure(struct pci_dev *pdev) +static void svia_configure(struct pci_dev *pdev, int board_id) { u8 tmp8; @@ -577,7 +577,7 @@ static void svia_configure(struct pci_dev *pdev) } /* - * vt6421 has problems talking to some drives. The following + * vt6420/1 has problems talking to some drives. The following * is the fix from Joseph Chan <JosephChan@via.com.tw>. * * When host issues HOLD, device may send up to 20DW of data @@ -596,8 +596,9 @@ static void svia_configure(struct pci_dev *pdev) * * https://bugzilla.kernel.org/show_bug.cgi?id=15173 * http://article.gmane.org/gmane.linux.ide/46352 + * http://thread.gmane.org/gmane.linux.kernel/1062139 */ - if (pdev->device == 0x3249) { + if (board_id == vt6420 || board_id == vt6421) { pci_read_config_byte(pdev, 0x52, &tmp8); tmp8 |= 1 << 2; pci_write_config_byte(pdev, 0x52, tmp8); @@ -652,7 +653,7 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - svia_configure(pdev); + svia_configure(pdev, board_id); pci_set_master(pdev); return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt, diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c index 46b94762125b..f9b983ae6877 100644 --- a/drivers/atm/adummy.c +++ b/drivers/atm/adummy.c @@ -154,7 +154,7 @@ static int __init adummy_init(void) err = -ENOMEM; goto out; } - atm_dev = atm_dev_register(DEV_LABEL, &adummy_ops, -1, NULL); + atm_dev = atm_dev_register(DEV_LABEL, NULL, &adummy_ops, -1, NULL); if (!atm_dev) { printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n"); err = -ENODEV; diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index a33896a482e6..ffe9b655292e 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -2244,7 +2244,8 @@ static int __devinit amb_probe(struct pci_dev *pci_dev, const struct pci_device_ goto out_reset; } - dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL); + dev->atm_dev = atm_dev_register (DEV_LABEL, &pci_dev->dev, &amb_ops, -1, + NULL); if (!dev->atm_dev) { PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); err = -EINVAL; diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c index b9101818b47b..2b464b631f22 100644 --- a/drivers/atm/atmtcp.c +++ b/drivers/atm/atmtcp.c @@ -366,7 +366,7 @@ static int atmtcp_create(int itf,int persist,struct atm_dev **result) if (!dev_data) return -ENOMEM; - dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL); + dev = atm_dev_register(DEV_LABEL,NULL,&atmtcp_v_dev_ops,itf,NULL); if (!dev) { kfree(dev_data); return itf == -1 ? -ENOMEM : -EBUSY; diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 97c5898cd76e..c495fae74200 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -2244,7 +2244,7 @@ static int __devinit eni_init_one(struct pci_dev *pci_dev, &zeroes); if (!cpu_zeroes) goto out1; } - dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL); + dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &ops, -1, NULL); if (!dev) goto out2; pci_set_drvdata(pci_dev, dev); eni_dev->pci_dev = pci_dev; diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 5d86bb803e94..7d912baf01d4 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -1911,7 +1911,7 @@ static int __devinit firestream_init_one (struct pci_dev *pci_dev, fs_dev, sizeof (struct fs_dev)); if (!fs_dev) goto err_out; - atm_dev = atm_dev_register("fs", &ops, -1, NULL); + atm_dev = atm_dev_register("fs", &pci_dev->dev, &ops, -1, NULL); if (!atm_dev) goto err_out_free_fs_dev; diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index c8fc69c85a06..962c309b40c0 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -2567,14 +2567,14 @@ release: static int __devinit -fore200e_register(struct fore200e* fore200e) +fore200e_register(struct fore200e* fore200e, struct device *parent) { struct atm_dev* atm_dev; DPRINTK(2, "device %s being registered\n", fore200e->name); - atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1, - NULL); + atm_dev = atm_dev_register(fore200e->bus->proc_name, parent, &fore200e_ops, + -1, NULL); if (atm_dev == NULL) { printk(FORE200E "unable to register device %s\n", fore200e->name); return -ENODEV; @@ -2594,9 +2594,9 @@ fore200e_register(struct fore200e* fore200e) static int __devinit -fore200e_init(struct fore200e* fore200e) +fore200e_init(struct fore200e* fore200e, struct device *parent) { - if (fore200e_register(fore200e) < 0) + if (fore200e_register(fore200e, parent) < 0) return -ENODEV; if (fore200e->bus->configure(fore200e) < 0) @@ -2662,7 +2662,7 @@ static int __devinit fore200e_sba_probe(struct platform_device *op, sprintf(fore200e->name, "%s-%d", bus->model_name, index); - err = fore200e_init(fore200e); + err = fore200e_init(fore200e, &op->dev); if (err < 0) { fore200e_shutdown(fore200e); kfree(fore200e); @@ -2740,7 +2740,7 @@ fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent sprintf(fore200e->name, "%s-%d", bus->model_name, index); - err = fore200e_init(fore200e); + err = fore200e_init(fore200e, &pci_dev->dev); if (err < 0) { fore200e_shutdown(fore200e); goto out_free; diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 801e8b6e9d1f..6cf59bf281dc 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -366,7 +366,7 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) goto init_one_failure; } - atm_dev = atm_dev_register(DEV_LABEL, &he_ops, -1, NULL); + atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &he_ops, -1, NULL); if (!atm_dev) { err = -ENODEV; goto init_one_failure; diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index a95790452a68..24761e1d6642 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -2733,7 +2733,8 @@ static int __devinit hrz_probe(struct pci_dev *pci_dev, const struct pci_device_ PRINTD(DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p", iobase, irq, membase); - dev->atm_dev = atm_dev_register(DEV_LABEL, &hrz_ops, -1, NULL); + dev->atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &hrz_ops, -1, + NULL); if (!(dev->atm_dev)) { PRINTD(DBG_ERR, "failed to register Madge ATM adapter"); err = -EINVAL; diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index bce57328ddde..bfb7feee0400 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -3698,7 +3698,8 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id) goto err_out_iounmap; } - dev = atm_dev_register("idt77252", &idt77252_ops, -1, NULL); + dev = atm_dev_register("idt77252", &pcidev->dev, &idt77252_ops, -1, + NULL); if (!dev) { printk("%s: can't register atm device\n", card->name); err = -EIO; diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 9309d4724e13..729254053758 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -3172,7 +3172,7 @@ static int __devinit ia_init_one(struct pci_dev *pdev, ret = -ENODEV; goto err_out_free_iadev; } - dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL); + dev = atm_dev_register(DEV_LABEL, &pdev->dev, &ops, -1, NULL); if (!dev) { ret = -ENOMEM; goto err_out_disable_dev; diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index cbe15a86c669..a395c9aab146 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -2591,7 +2591,7 @@ static int __devinit lanai_init_one(struct pci_dev *pci, return -ENOMEM; } - atmdev = atm_dev_register(DEV_LABEL, &ops, -1, NULL); + atmdev = atm_dev_register(DEV_LABEL, &pci->dev, &ops, -1, NULL); if (atmdev == NULL) { printk(KERN_ERR DEV_LABEL ": couldn't register atm device!\n"); diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index 2f3516b7f118..6b313ee9231b 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -771,7 +771,8 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev) } /* Register device */ - card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL); + card->atmdev = atm_dev_register("nicstar", &card->pcidev->dev, &atm_ops, + -1, NULL); if (card->atmdev == NULL) { printk("nicstar%d: can't register device.\n", i); error = 17; diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 2e08c996fd30..73fb1c4f4cd4 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -166,7 +166,7 @@ static irqreturn_t solos_irq(int irq, void *dev_id); static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); static int list_vccs(int vci); static void release_vccs(struct atm_dev *dev); -static int atm_init(struct solos_card *); +static int atm_init(struct solos_card *, struct device *); static void atm_remove(struct solos_card *); static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); static void solos_bh(unsigned long); @@ -1210,7 +1210,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) if (db_firmware_upgrade) flash_upgrade(card, 3); - err = atm_init(card); + err = atm_init(card, &dev->dev); if (err) goto out_free_irq; @@ -1233,7 +1233,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) return err; } -static int atm_init(struct solos_card *card) +static int atm_init(struct solos_card *card, struct device *parent) { int i; @@ -1244,7 +1244,7 @@ static int atm_init(struct solos_card *card) skb_queue_head_init(&card->tx_queue[i]); skb_queue_head_init(&card->cli_queue[i]); - card->atmdev[i] = atm_dev_register("solos-pci", &fpga_ops, -1, NULL); + card->atmdev[i] = atm_dev_register("solos-pci", parent, &fpga_ops, -1, NULL); if (!card->atmdev[i]) { dev_err(&card->dev->dev, "Could not register ATM device %d\n", i); atm_remove(card); diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 4e885d2da49c..624917902b65 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -1597,7 +1597,7 @@ static int __devinit zatm_init_one(struct pci_dev *pci_dev, goto out; } - dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL); + dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &ops, -1, NULL); if (!dev) goto out_free; diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index a1725e6488d3..7888501ad9ee 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1341,7 +1341,7 @@ static struct request *set_next_request(void) { struct request_queue *q; int cnt = FD_MAX_UNITS; - struct request *rq; + struct request *rq = NULL; /* Find next queue we can dispatch from */ fdc_queue = fdc_queue + 1; diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 4e4cc6c828cb..605a67e40bbf 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1399,7 +1399,7 @@ static struct request *set_next_request(void) { struct request_queue *q; int old_pos = fdc_queue; - struct request *rq; + struct request *rq = NULL; do { q = unit[fdc_queue].disk->queue; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index a67d0a611a8a..8e0f9256eb58 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -66,6 +66,7 @@ MODULE_VERSION("3.6.26"); MODULE_LICENSE("GPL"); static DEFINE_MUTEX(cciss_mutex); +static struct proc_dir_entry *proc_cciss; #include "cciss_cmd.h" #include "cciss.h" @@ -363,8 +364,6 @@ static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", #define ENG_GIG_FACTOR (ENG_GIG/512) #define ENGAGE_SCSI "engage scsi" -static struct proc_dir_entry *proc_cciss; - static void cciss_seq_show_header(struct seq_file *seq) { ctlr_info_t *h = seq->private; @@ -2835,6 +2834,8 @@ static int cciss_revalidate(struct gendisk *disk) InquiryData_struct *inq_buff = NULL; for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) { + if (!h->drv[logvol]) + continue; if (memcmp(h->drv[logvol]->LunID, drv->LunID, sizeof(drv->LunID)) == 0) { FOUND = 1; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 89d8a7cc4054..24487d4fb202 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3627,17 +3627,19 @@ static void drbdd(struct drbd_conf *mdev) } shs = drbd_cmd_handler[cmd].pkt_size - sizeof(union p_header); - rv = drbd_recv(mdev, &header->h80.payload, shs); - if (unlikely(rv != shs)) { - dev_err(DEV, "short read while reading sub header: rv=%d\n", rv); - goto err_out; - } - if (packet_size - shs > 0 && !drbd_cmd_handler[cmd].expect_payload) { dev_err(DEV, "No payload expected %s l:%d\n", cmdname(cmd), packet_size); goto err_out; } + if (shs) { + rv = drbd_recv(mdev, &header->h80.payload, shs); + if (unlikely(rv != shs)) { + dev_err(DEV, "short read while reading sub header: rv=%d\n", rv); + goto err_out; + } + } + rv = drbd_cmd_handler[cmd].function(mdev, cmd, packet_size - shs); if (unlikely(!rv)) { diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 181ea0364822..ab2bd09d54b4 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -339,7 +339,8 @@ static inline int _req_mod(struct drbd_request *req, enum drbd_req_event what) } /* completion of master bio is outside of spinlock. - * If you need it irqsave, do it your self! */ + * If you need it irqsave, do it your self! + * Which means: don't use from bio endio callback. */ static inline int req_mod(struct drbd_request *req, enum drbd_req_event what) { diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 47d223c2409c..34f224b018b3 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -193,8 +193,10 @@ void drbd_endio_sec(struct bio *bio, int error) */ void drbd_endio_pri(struct bio *bio, int error) { + unsigned long flags; struct drbd_request *req = bio->bi_private; struct drbd_conf *mdev = req->mdev; + struct bio_and_error m; enum drbd_req_event what; int uptodate = bio_flagged(bio, BIO_UPTODATE); @@ -220,7 +222,13 @@ void drbd_endio_pri(struct bio *bio, int error) bio_put(req->private_bio); req->private_bio = ERR_PTR(error); - req_mod(req, what); + /* not req_mod(), we need irqsave here! */ + spin_lock_irqsave(&mdev->req_lock, flags); + __req_mod(req, what, &m); + spin_unlock_irqrestore(&mdev->req_lock, flags); + + if (m.bio) + complete_master_bio(mdev, &m); } int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 6ec9d53806c5..008d4a00b50d 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -21,80 +21,9 @@ - Instructions for use - -------------------- + For usage instructions, please refer to: - 1) Map a Linux block device to an existing rbd image. - - Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name] - - $ echo "192.168.0.1 name=admin rbd foo" > /sys/class/rbd/add - - The snapshot name can be "-" or omitted to map the image read/write. - - 2) List all active blkdev<->object mappings. - - In this example, we have performed step #1 twice, creating two blkdevs, - mapped to two separate rados objects in the rados rbd pool - - $ cat /sys/class/rbd/list - #id major client_name pool name snap KB - 0 254 client4143 rbd foo - 1024000 - - The columns, in order, are: - - blkdev unique id - - blkdev assigned major - - rados client id - - rados pool name - - rados block device name - - mapped snapshot ("-" if none) - - device size in KB - - - 3) Create a snapshot. - - Usage: <blkdev id> <snapname> - - $ echo "0 mysnap" > /sys/class/rbd/snap_create - - - 4) Listing a snapshot. - - $ cat /sys/class/rbd/snaps_list - #id snap KB - 0 - 1024000 (*) - 0 foo 1024000 - - The columns, in order, are: - - blkdev unique id - - snapshot name, '-' means none (active read/write version) - - size of device at time of snapshot - - the (*) indicates this is the active version - - 5) Rollback to snapshot. - - Usage: <blkdev id> <snapname> - - $ echo "0 mysnap" > /sys/class/rbd/snap_rollback - - - 6) Mapping an image using snapshot. - - A snapshot mapping is read-only. This is being done by passing - snap=<snapname> to the options when adding a device. - - $ echo "192.168.0.1 name=admin,snap=mysnap rbd foo" > /sys/class/rbd/add - - - 7) Remove an active blkdev<->rbd image mapping. - - In this example, we remove the mapping with blkdev unique id 1. - - $ echo 1 > /sys/class/rbd/remove - - - NOTE: The actual creation and deletion of rados objects is outside the scope - of this driver. + Documentation/ABI/testing/sysfs-bus-rbd */ @@ -163,6 +92,14 @@ struct rbd_request { u64 len; }; +struct rbd_snap { + struct device dev; + const char *name; + size_t size; + struct list_head node; + u64 id; +}; + /* * a single device */ @@ -193,21 +130,60 @@ struct rbd_device { int read_only; struct list_head node; + + /* list of snapshots */ + struct list_head snaps; + + /* sysfs related */ + struct device dev; +}; + +static struct bus_type rbd_bus_type = { + .name = "rbd", }; static spinlock_t node_lock; /* protects client get/put */ -static struct class *class_rbd; /* /sys/class/rbd */ static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */ static LIST_HEAD(rbd_dev_list); /* devices */ static LIST_HEAD(rbd_client_list); /* clients */ +static int __rbd_init_snaps_header(struct rbd_device *rbd_dev); +static void rbd_dev_release(struct device *dev); +static ssize_t rbd_snap_rollback(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size); +static ssize_t rbd_snap_add(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count); +static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev, + struct rbd_snap *snap);; + + +static struct rbd_device *dev_to_rbd(struct device *dev) +{ + return container_of(dev, struct rbd_device, dev); +} + +static struct device *rbd_get_dev(struct rbd_device *rbd_dev) +{ + return get_device(&rbd_dev->dev); +} + +static void rbd_put_dev(struct rbd_device *rbd_dev) +{ + put_device(&rbd_dev->dev); +} static int rbd_open(struct block_device *bdev, fmode_t mode) { struct gendisk *disk = bdev->bd_disk; struct rbd_device *rbd_dev = disk->private_data; + rbd_get_dev(rbd_dev); + set_device_ro(bdev, rbd_dev->read_only); if ((mode & FMODE_WRITE) && rbd_dev->read_only) @@ -216,9 +192,19 @@ static int rbd_open(struct block_device *bdev, fmode_t mode) return 0; } +static int rbd_release(struct gendisk *disk, fmode_t mode) +{ + struct rbd_device *rbd_dev = disk->private_data; + + rbd_put_dev(rbd_dev); + + return 0; +} + static const struct block_device_operations rbd_bd_ops = { .owner = THIS_MODULE, .open = rbd_open, + .release = rbd_release, }; /* @@ -361,7 +347,6 @@ static int rbd_header_from_disk(struct rbd_image_header *header, int ret = -ENOMEM; init_rwsem(&header->snap_rwsem); - header->snap_names_len = le64_to_cpu(ondisk->snap_names_len); header->snapc = kmalloc(sizeof(struct ceph_snap_context) + snap_count * @@ -1256,10 +1241,20 @@ bad: return -ERANGE; } +static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev) +{ + struct rbd_snap *snap; + + while (!list_empty(&rbd_dev->snaps)) { + snap = list_first_entry(&rbd_dev->snaps, struct rbd_snap, node); + __rbd_remove_snap_dev(rbd_dev, snap); + } +} + /* * only read the first part of the ondisk header, without the snaps info */ -static int rbd_update_snaps(struct rbd_device *rbd_dev) +static int __rbd_update_snaps(struct rbd_device *rbd_dev) { int ret; struct rbd_image_header h; @@ -1280,12 +1275,15 @@ static int rbd_update_snaps(struct rbd_device *rbd_dev) rbd_dev->header.total_snaps = h.total_snaps; rbd_dev->header.snapc = h.snapc; rbd_dev->header.snap_names = h.snap_names; + rbd_dev->header.snap_names_len = h.snap_names_len; rbd_dev->header.snap_sizes = h.snap_sizes; rbd_dev->header.snapc->seq = snap_seq; + ret = __rbd_init_snaps_header(rbd_dev); + up_write(&rbd_dev->header.snap_rwsem); - return 0; + return ret; } static int rbd_init_disk(struct rbd_device *rbd_dev) @@ -1300,6 +1298,11 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) if (rc) return rc; + /* no need to lock here, as rbd_dev is not registered yet */ + rc = __rbd_init_snaps_header(rbd_dev); + if (rc) + return rc; + rc = rbd_header_set_snap(rbd_dev, rbd_dev->snap_name, &total_size); if (rc) return rc; @@ -1343,54 +1346,360 @@ out: return rc; } -/******************************************************************** - * /sys/class/rbd/ - * add map rados objects to blkdev - * remove unmap rados objects - * list show mappings - *******************************************************************/ +/* + sysfs +*/ + +static ssize_t rbd_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd(dev); + + return sprintf(buf, "%llu\n", (unsigned long long)rbd_dev->header.image_size); +} + +static ssize_t rbd_major_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd(dev); -static void class_rbd_release(struct class *cls) + return sprintf(buf, "%d\n", rbd_dev->major); +} + +static ssize_t rbd_client_id_show(struct device *dev, + struct device_attribute *attr, char *buf) { - kfree(cls); + struct rbd_device *rbd_dev = dev_to_rbd(dev); + + return sprintf(buf, "client%lld\n", ceph_client_id(rbd_dev->client)); } -static ssize_t class_rbd_list(struct class *c, - struct class_attribute *attr, - char *data) +static ssize_t rbd_pool_show(struct device *dev, + struct device_attribute *attr, char *buf) { - int n = 0; - struct list_head *tmp; - int max = PAGE_SIZE; + struct rbd_device *rbd_dev = dev_to_rbd(dev); + + return sprintf(buf, "%s\n", rbd_dev->pool_name); +} + +static ssize_t rbd_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd(dev); + + return sprintf(buf, "%s\n", rbd_dev->obj); +} + +static ssize_t rbd_snap_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd(dev); + + return sprintf(buf, "%s\n", rbd_dev->snap_name); +} + +static ssize_t rbd_image_refresh(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct rbd_device *rbd_dev = dev_to_rbd(dev); + int rc; + int ret = size; mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - n += snprintf(data, max, - "#id\tmajor\tclient_name\tpool\tname\tsnap\tKB\n"); + rc = __rbd_update_snaps(rbd_dev); + if (rc < 0) + ret = rc; - list_for_each(tmp, &rbd_dev_list) { - struct rbd_device *rbd_dev; + mutex_unlock(&ctl_mutex); + return ret; +} - rbd_dev = list_entry(tmp, struct rbd_device, node); - n += snprintf(data+n, max-n, - "%d\t%d\tclient%lld\t%s\t%s\t%s\t%lld\n", - rbd_dev->id, - rbd_dev->major, - ceph_client_id(rbd_dev->client), - rbd_dev->pool_name, - rbd_dev->obj, rbd_dev->snap_name, - rbd_dev->header.image_size >> 10); - if (n == max) +static DEVICE_ATTR(size, S_IRUGO, rbd_size_show, NULL); +static DEVICE_ATTR(major, S_IRUGO, rbd_major_show, NULL); +static DEVICE_ATTR(client_id, S_IRUGO, rbd_client_id_show, NULL); +static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL); +static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL); +static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh); +static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL); +static DEVICE_ATTR(create_snap, S_IWUSR, NULL, rbd_snap_add); +static DEVICE_ATTR(rollback_snap, S_IWUSR, NULL, rbd_snap_rollback); + +static struct attribute *rbd_attrs[] = { + &dev_attr_size.attr, + &dev_attr_major.attr, + &dev_attr_client_id.attr, + &dev_attr_pool.attr, + &dev_attr_name.attr, + &dev_attr_current_snap.attr, + &dev_attr_refresh.attr, + &dev_attr_create_snap.attr, + &dev_attr_rollback_snap.attr, + NULL +}; + +static struct attribute_group rbd_attr_group = { + .attrs = rbd_attrs, +}; + +static const struct attribute_group *rbd_attr_groups[] = { + &rbd_attr_group, + NULL +}; + +static void rbd_sysfs_dev_release(struct device *dev) +{ +} + +static struct device_type rbd_device_type = { + .name = "rbd", + .groups = rbd_attr_groups, + .release = rbd_sysfs_dev_release, +}; + + +/* + sysfs - snapshots +*/ + +static ssize_t rbd_snap_size_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev); + + return sprintf(buf, "%lld\n", (long long)snap->size); +} + +static ssize_t rbd_snap_id_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev); + + return sprintf(buf, "%lld\n", (long long)snap->id); +} + +static DEVICE_ATTR(snap_size, S_IRUGO, rbd_snap_size_show, NULL); +static DEVICE_ATTR(snap_id, S_IRUGO, rbd_snap_id_show, NULL); + +static struct attribute *rbd_snap_attrs[] = { + &dev_attr_snap_size.attr, + &dev_attr_snap_id.attr, + NULL, +}; + +static struct attribute_group rbd_snap_attr_group = { + .attrs = rbd_snap_attrs, +}; + +static void rbd_snap_dev_release(struct device *dev) +{ + struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev); + kfree(snap->name); + kfree(snap); +} + +static const struct attribute_group *rbd_snap_attr_groups[] = { + &rbd_snap_attr_group, + NULL +}; + +static struct device_type rbd_snap_device_type = { + .groups = rbd_snap_attr_groups, + .release = rbd_snap_dev_release, +}; + +static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev, + struct rbd_snap *snap) +{ + list_del(&snap->node); + device_unregister(&snap->dev); +} + +static int rbd_register_snap_dev(struct rbd_device *rbd_dev, + struct rbd_snap *snap, + struct device *parent) +{ + struct device *dev = &snap->dev; + int ret; + + dev->type = &rbd_snap_device_type; + dev->parent = parent; + dev->release = rbd_snap_dev_release; + dev_set_name(dev, "snap_%s", snap->name); + ret = device_register(dev); + + return ret; +} + +static int __rbd_add_snap_dev(struct rbd_device *rbd_dev, + int i, const char *name, + struct rbd_snap **snapp) +{ + int ret; + struct rbd_snap *snap = kzalloc(sizeof(*snap), GFP_KERNEL); + if (!snap) + return -ENOMEM; + snap->name = kstrdup(name, GFP_KERNEL); + snap->size = rbd_dev->header.snap_sizes[i]; + snap->id = rbd_dev->header.snapc->snaps[i]; + if (device_is_registered(&rbd_dev->dev)) { + ret = rbd_register_snap_dev(rbd_dev, snap, + &rbd_dev->dev); + if (ret < 0) + goto err; + } + *snapp = snap; + return 0; +err: + kfree(snap->name); + kfree(snap); + return ret; +} + +/* + * search for the previous snap in a null delimited string list + */ +const char *rbd_prev_snap_name(const char *name, const char *start) +{ + if (name < start + 2) + return NULL; + + name -= 2; + while (*name) { + if (name == start) + return start; + name--; + } + return name + 1; +} + +/* + * compare the old list of snapshots that we have to what's in the header + * and update it accordingly. Note that the header holds the snapshots + * in a reverse order (from newest to oldest) and we need to go from + * older to new so that we don't get a duplicate snap name when + * doing the process (e.g., removed snapshot and recreated a new + * one with the same name. + */ +static int __rbd_init_snaps_header(struct rbd_device *rbd_dev) +{ + const char *name, *first_name; + int i = rbd_dev->header.total_snaps; + struct rbd_snap *snap, *old_snap = NULL; + int ret; + struct list_head *p, *n; + + first_name = rbd_dev->header.snap_names; + name = first_name + rbd_dev->header.snap_names_len; + + list_for_each_prev_safe(p, n, &rbd_dev->snaps) { + u64 cur_id; + + old_snap = list_entry(p, struct rbd_snap, node); + + if (i) + cur_id = rbd_dev->header.snapc->snaps[i - 1]; + + if (!i || old_snap->id < cur_id) { + /* old_snap->id was skipped, thus was removed */ + __rbd_remove_snap_dev(rbd_dev, old_snap); + continue; + } + if (old_snap->id == cur_id) { + /* we have this snapshot already */ + i--; + name = rbd_prev_snap_name(name, first_name); + continue; + } + for (; i > 0; + i--, name = rbd_prev_snap_name(name, first_name)) { + if (!name) { + WARN_ON(1); + return -EINVAL; + } + cur_id = rbd_dev->header.snapc->snaps[i]; + /* snapshot removal? handle it above */ + if (cur_id >= old_snap->id) + break; + /* a new snapshot */ + ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap); + if (ret < 0) + return ret; + + /* note that we add it backward so using n and not p */ + list_add(&snap->node, n); + p = &snap->node; + } + } + /* we're done going over the old snap list, just add what's left */ + for (; i > 0; i--) { + name = rbd_prev_snap_name(name, first_name); + if (!name) { + WARN_ON(1); + return -EINVAL; + } + ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap); + if (ret < 0) + return ret; + list_add(&snap->node, &rbd_dev->snaps); + } + + return 0; +} + + +static void rbd_root_dev_release(struct device *dev) +{ +} + +static struct device rbd_root_dev = { + .init_name = "rbd", + .release = rbd_root_dev_release, +}; + +static int rbd_bus_add_dev(struct rbd_device *rbd_dev) +{ + int ret = -ENOMEM; + struct device *dev; + struct rbd_snap *snap; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + dev = &rbd_dev->dev; + + dev->bus = &rbd_bus_type; + dev->type = &rbd_device_type; + dev->parent = &rbd_root_dev; + dev->release = rbd_dev_release; + dev_set_name(dev, "%d", rbd_dev->id); + ret = device_register(dev); + if (ret < 0) + goto done_free; + + list_for_each_entry(snap, &rbd_dev->snaps, node) { + ret = rbd_register_snap_dev(rbd_dev, snap, + &rbd_dev->dev); + if (ret < 0) break; } mutex_unlock(&ctl_mutex); - return n; + return 0; +done_free: + mutex_unlock(&ctl_mutex); + return ret; } -static ssize_t class_rbd_add(struct class *c, - struct class_attribute *attr, - const char *buf, size_t count) +static void rbd_bus_del_dev(struct rbd_device *rbd_dev) +{ + device_unregister(&rbd_dev->dev); +} + +static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count) { struct ceph_osd_client *osdc; struct rbd_device *rbd_dev; @@ -1419,6 +1728,7 @@ static ssize_t class_rbd_add(struct class *c, /* static rbd_device initialization */ spin_lock_init(&rbd_dev->lock); INIT_LIST_HEAD(&rbd_dev->node); + INIT_LIST_HEAD(&rbd_dev->snaps); /* generate unique id: find highest unique id, add one */ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); @@ -1478,6 +1788,9 @@ static ssize_t class_rbd_add(struct class *c, } rbd_dev->major = irc; + rc = rbd_bus_add_dev(rbd_dev); + if (rc) + goto err_out_disk; /* set up and announce blkdev mapping */ rc = rbd_init_disk(rbd_dev); if (rc) @@ -1487,6 +1800,8 @@ static ssize_t class_rbd_add(struct class *c, err_out_blkdev: unregister_blkdev(rbd_dev->major, rbd_dev->name); +err_out_disk: + rbd_free_disk(rbd_dev); err_out_client: rbd_put_client(rbd_dev); mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); @@ -1518,35 +1833,10 @@ static struct rbd_device *__rbd_get_dev(unsigned long id) return NULL; } -static ssize_t class_rbd_remove(struct class *c, - struct class_attribute *attr, - const char *buf, - size_t count) +static void rbd_dev_release(struct device *dev) { - struct rbd_device *rbd_dev = NULL; - int target_id, rc; - unsigned long ul; - - rc = strict_strtoul(buf, 10, &ul); - if (rc) - return rc; - - /* convert to int; abort if we lost anything in the conversion */ - target_id = (int) ul; - if (target_id != ul) - return -EINVAL; - - /* remove object from list immediately */ - mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - - rbd_dev = __rbd_get_dev(target_id); - if (rbd_dev) - list_del_init(&rbd_dev->node); - - mutex_unlock(&ctl_mutex); - - if (!rbd_dev) - return -ENOENT; + struct rbd_device *rbd_dev = + container_of(dev, struct rbd_device, dev); rbd_put_client(rbd_dev); @@ -1557,67 +1847,11 @@ static ssize_t class_rbd_remove(struct class *c, /* release module ref */ module_put(THIS_MODULE); - - return count; } -static ssize_t class_rbd_snaps_list(struct class *c, - struct class_attribute *attr, - char *data) -{ - struct rbd_device *rbd_dev = NULL; - struct list_head *tmp; - struct rbd_image_header *header; - int i, n = 0, max = PAGE_SIZE; - int ret; - - mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - - n += snprintf(data, max, "#id\tsnap\tKB\n"); - - list_for_each(tmp, &rbd_dev_list) { - char *names, *p; - struct ceph_snap_context *snapc; - - rbd_dev = list_entry(tmp, struct rbd_device, node); - header = &rbd_dev->header; - - down_read(&header->snap_rwsem); - - names = header->snap_names; - snapc = header->snapc; - - n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n", - rbd_dev->id, RBD_SNAP_HEAD_NAME, - header->image_size >> 10, - (!rbd_dev->cur_snap ? " (*)" : "")); - if (n == max) - break; - - p = names; - for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) { - n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n", - rbd_dev->id, p, header->snap_sizes[i] >> 10, - (rbd_dev->cur_snap && - (snap_index(header, i) == rbd_dev->cur_snap) ? - " (*)" : "")); - if (n == max) - break; - } - - up_read(&header->snap_rwsem); - } - - - ret = n; - mutex_unlock(&ctl_mutex); - return ret; -} - -static ssize_t class_rbd_snaps_refresh(struct class *c, - struct class_attribute *attr, - const char *buf, - size_t count) +static ssize_t rbd_remove(struct bus_type *bus, + const char *buf, + size_t count) { struct rbd_device *rbd_dev = NULL; int target_id, rc; @@ -1641,95 +1875,70 @@ static ssize_t class_rbd_snaps_refresh(struct class *c, goto done; } - rc = rbd_update_snaps(rbd_dev); - if (rc < 0) - ret = rc; + list_del_init(&rbd_dev->node); + + __rbd_remove_all_snaps(rbd_dev); + rbd_bus_del_dev(rbd_dev); done: mutex_unlock(&ctl_mutex); return ret; } -static ssize_t class_rbd_snap_create(struct class *c, - struct class_attribute *attr, - const char *buf, - size_t count) +static ssize_t rbd_snap_add(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) { - struct rbd_device *rbd_dev = NULL; - int target_id, ret; - char *name; - - name = kmalloc(RBD_MAX_SNAP_NAME_LEN + 1, GFP_KERNEL); + struct rbd_device *rbd_dev = dev_to_rbd(dev); + int ret; + char *name = kmalloc(count + 1, GFP_KERNEL); if (!name) return -ENOMEM; - /* parse snaps add command */ - if (sscanf(buf, "%d " - "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s", - &target_id, - name) != 2) { - ret = -EINVAL; - goto done; - } + snprintf(name, count, "%s", buf); mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - rbd_dev = __rbd_get_dev(target_id); - if (!rbd_dev) { - ret = -ENOENT; - goto done_unlock; - } - ret = rbd_header_add_snap(rbd_dev, name, GFP_KERNEL); if (ret < 0) goto done_unlock; - ret = rbd_update_snaps(rbd_dev); + ret = __rbd_update_snaps(rbd_dev); if (ret < 0) goto done_unlock; ret = count; done_unlock: mutex_unlock(&ctl_mutex); -done: kfree(name); return ret; } -static ssize_t class_rbd_rollback(struct class *c, - struct class_attribute *attr, - const char *buf, - size_t count) +static ssize_t rbd_snap_rollback(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) { - struct rbd_device *rbd_dev = NULL; - int target_id, ret; + struct rbd_device *rbd_dev = dev_to_rbd(dev); + int ret; u64 snapid; - char snap_name[RBD_MAX_SNAP_NAME_LEN]; u64 cur_ofs; - char *seg_name; + char *seg_name = NULL; + char *snap_name = kmalloc(count + 1, GFP_KERNEL); + ret = -ENOMEM; + if (!snap_name) + return ret; /* parse snaps add command */ - if (sscanf(buf, "%d " - "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s", - &target_id, - snap_name) != 2) { - return -EINVAL; - } - - ret = -ENOMEM; + snprintf(snap_name, count, "%s", buf); seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO); if (!seg_name) - return ret; + goto done; mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - rbd_dev = __rbd_get_dev(target_id); - if (!rbd_dev) { - ret = -ENOENT; - goto done_unlock; - } - ret = snap_by_name(&rbd_dev->header, snap_name, &snapid, NULL); if (ret < 0) goto done_unlock; @@ -1750,7 +1959,7 @@ static ssize_t class_rbd_rollback(struct class *c, seg_name, ret); } - ret = rbd_update_snaps(rbd_dev); + ret = __rbd_update_snaps(rbd_dev); if (ret < 0) goto done_unlock; @@ -1758,57 +1967,42 @@ static ssize_t class_rbd_rollback(struct class *c, done_unlock: mutex_unlock(&ctl_mutex); +done: kfree(seg_name); + kfree(snap_name); return ret; } -static struct class_attribute class_rbd_attrs[] = { - __ATTR(add, 0200, NULL, class_rbd_add), - __ATTR(remove, 0200, NULL, class_rbd_remove), - __ATTR(list, 0444, class_rbd_list, NULL), - __ATTR(snaps_refresh, 0200, NULL, class_rbd_snaps_refresh), - __ATTR(snap_create, 0200, NULL, class_rbd_snap_create), - __ATTR(snaps_list, 0444, class_rbd_snaps_list, NULL), - __ATTR(snap_rollback, 0200, NULL, class_rbd_rollback), +static struct bus_attribute rbd_bus_attrs[] = { + __ATTR(add, S_IWUSR, NULL, rbd_add), + __ATTR(remove, S_IWUSR, NULL, rbd_remove), __ATTR_NULL }; /* * create control files in sysfs - * /sys/class/rbd/... + * /sys/bus/rbd/... */ static int rbd_sysfs_init(void) { - int ret = -ENOMEM; + int ret; - class_rbd = kzalloc(sizeof(*class_rbd), GFP_KERNEL); - if (!class_rbd) - goto out; + rbd_bus_type.bus_attrs = rbd_bus_attrs; - class_rbd->name = DRV_NAME; - class_rbd->owner = THIS_MODULE; - class_rbd->class_release = class_rbd_release; - class_rbd->class_attrs = class_rbd_attrs; + ret = bus_register(&rbd_bus_type); + if (ret < 0) + return ret; - ret = class_register(class_rbd); - if (ret) - goto out_class; - return 0; + ret = device_register(&rbd_root_dev); -out_class: - kfree(class_rbd); - class_rbd = NULL; - pr_err(DRV_NAME ": failed to create class rbd\n"); -out: return ret; } static void rbd_sysfs_cleanup(void) { - if (class_rbd) - class_destroy(class_rbd); - class_rbd = NULL; + device_unregister(&rbd_root_dev); + bus_unregister(&rbd_bus_type); } int __init rbd_init(void) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 255035cfc88a..657873e4328d 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -65,14 +65,14 @@ enum blkif_state { struct blk_shadow { struct blkif_request req; - unsigned long request; + struct request *request; unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST]; }; static DEFINE_MUTEX(blkfront_mutex); static const struct block_device_operations xlvbd_block_fops; -#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE) +#define BLK_RING_SIZE __CONST_RING_SIZE(blkif, PAGE_SIZE) /* * We have one of these per vbd, whether ide, scsi or 'other'. They @@ -136,7 +136,7 @@ static void add_id_to_freelist(struct blkfront_info *info, unsigned long id) { info->shadow[id].req.id = info->shadow_free; - info->shadow[id].request = 0; + info->shadow[id].request = NULL; info->shadow_free = id; } @@ -245,14 +245,11 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode, } /* - * blkif_queue_request + * Generate a Xen blkfront IO request from a blk layer request. Reads + * and writes are handled as expected. Since we lack a loose flush + * request, we map flushes into a full ordered barrier. * - * request block io - * - * id: for guest use only. - * operation: BLKIF_OP_{READ,WRITE,PROBE} - * buffer: buffer to read/write into. this should be a - * virtual address in the guest os. + * @req: a request struct */ static int blkif_queue_request(struct request *req) { @@ -281,7 +278,7 @@ static int blkif_queue_request(struct request *req) /* Fill out a communications ring structure. */ ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt); id = get_id_from_freelist(info); - info->shadow[id].request = (unsigned long)req; + info->shadow[id].request = req; ring_req->id = id; ring_req->sector_number = (blkif_sector_t)blk_rq_pos(req); @@ -290,6 +287,18 @@ static int blkif_queue_request(struct request *req) ring_req->operation = rq_data_dir(req) ? BLKIF_OP_WRITE : BLKIF_OP_READ; + if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) { + /* + * Ideally we could just do an unordered + * flush-to-disk, but all we have is a full write + * barrier at the moment. However, a barrier write is + * a superset of FUA, so we can implement it the same + * way. (It's also a FLUSH+FUA, since it is + * guaranteed ordered WRT previous writes.) + */ + ring_req->operation = BLKIF_OP_WRITE_BARRIER; + } + ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg); BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST); @@ -634,7 +643,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) bret = RING_GET_RESPONSE(&info->ring, i); id = bret->id; - req = (struct request *)info->shadow[id].request; + req = info->shadow[id].request; blkif_completion(&info->shadow[id]); @@ -647,6 +656,16 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) printk(KERN_WARNING "blkfront: %s: write barrier op failed\n", info->gd->disk_name); error = -EOPNOTSUPP; + } + if (unlikely(bret->status == BLKIF_RSP_ERROR && + info->shadow[id].req.nr_segments == 0)) { + printk(KERN_WARNING "blkfront: %s: empty write barrier op failed\n", + info->gd->disk_name); + error = -EOPNOTSUPP; + } + if (unlikely(error)) { + if (error == -EOPNOTSUPP) + error = 0; info->feature_flush = 0; xlvbd_flush(info); } @@ -899,7 +918,7 @@ static int blkif_recover(struct blkfront_info *info) /* Stage 3: Find pending requests and requeue them. */ for (i = 0; i < BLK_RING_SIZE; i++) { /* Not in use? */ - if (copy[i].request == 0) + if (!copy[i].request) continue; /* Grab a request slot and copy shadow state into it. */ @@ -916,9 +935,7 @@ static int blkif_recover(struct blkfront_info *info) req->seg[j].gref, info->xbdev->otherend_id, pfn_to_mfn(info->shadow[req->id].frame[j]), - rq_data_dir( - (struct request *) - info->shadow[req->id].request)); + rq_data_dir(info->shadow[req->id].request)); info->shadow[req->id].req = *req; info->ring.req_prod_pvt++; @@ -1067,14 +1084,8 @@ static void blkfront_connect(struct blkfront_info *info) */ info->feature_flush = 0; - /* - * The driver doesn't properly handled empty flushes, so - * lets disable barrier support for now. - */ -#if 0 if (!err && barrier) - info->feature_flush = REQ_FLUSH; -#endif + info->feature_flush = REQ_FLUSH | REQ_FUA; err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size); if (err) { diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 128cae4e8629..949ed09c6361 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -35,6 +35,10 @@ static struct usb_device_id ath3k_table[] = { /* Atheros AR3011 */ { USB_DEVICE(0x0CF3, 0x3000) }, + + /* Atheros AR3011 with sflash firmware*/ + { USB_DEVICE(0x0CF3, 0x3002) }, + { } /* Terminating entry */ }; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ab3894f742c3..1da773f899a2 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -99,6 +99,9 @@ static struct usb_device_id blacklist_table[] = { /* Broadcom BCM2033 without firmware */ { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE }, + /* Atheros 3011 with sflash firmware */ + { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, + /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, @@ -239,7 +242,8 @@ static void btusb_intr_complete(struct urb *urb) err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { - BT_ERR("%s urb %p failed to resubmit (%d)", + if (err != -EPERM) + BT_ERR("%s urb %p failed to resubmit (%d)", hdev->name, urb, -err); usb_unanchor_urb(urb); } @@ -323,7 +327,8 @@ static void btusb_bulk_complete(struct urb *urb) err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { - BT_ERR("%s urb %p failed to resubmit (%d)", + if (err != -EPERM) + BT_ERR("%s urb %p failed to resubmit (%d)", hdev->name, urb, -err); usb_unanchor_urb(urb); } @@ -412,7 +417,8 @@ static void btusb_isoc_complete(struct urb *urb) err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { - BT_ERR("%s urb %p failed to resubmit (%d)", + if (err != -EPERM) + BT_ERR("%s urb %p failed to resubmit (%d)", hdev->name, urb, -err); usb_unanchor_urb(urb); } diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 9272c38dd3c6..16a2847b7cdb 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -812,8 +812,10 @@ static int intel_fake_agp_fetch_size(void) static void i830_cleanup(void) { - kunmap(intel_private.i8xx_page); - intel_private.i8xx_flush_page = NULL; + if (intel_private.i8xx_flush_page) { + kunmap(intel_private.i8xx_flush_page); + intel_private.i8xx_flush_page = NULL; + } __free_page(intel_private.i8xx_page); intel_private.i8xx_page = NULL; diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 1030f8420137..c17a305ecb28 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -25,6 +25,7 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/wait.h> +#include <linux/acpi.h> #include "tpm.h" #define TPM_HEADER_SIZE 10 @@ -78,6 +79,26 @@ enum tis_defaults { static LIST_HEAD(tis_chips); static DEFINE_SPINLOCK(tis_lock); +#ifdef CONFIG_ACPI +static int is_itpm(struct pnp_dev *dev) +{ + struct acpi_device *acpi = pnp_acpi_device(dev); + struct acpi_hardware_id *id; + + list_for_each_entry(id, &acpi->pnp.ids, list) { + if (!strcmp("INTC0102", id->id)) + return 1; + } + + return 0; +} +#else +static int is_itpm(struct pnp_dev *dev) +{ + return 0; +} +#endif + static int check_locality(struct tpm_chip *chip, int l) { if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) & @@ -472,6 +493,9 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, "1.2 TPM (device-id 0x%X, rev-id %d)\n", vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); + if (is_itpm(to_pnp_dev(dev))) + itpm = 1; + if (itpm) dev_info(dev, "Intel iTPM workaround enabled\n"); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 6c1b676643a9..896a2ced1d27 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1547,31 +1547,16 @@ static int init_vqs(struct ports_device *portdev) nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2; vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL); - if (!vqs) { - err = -ENOMEM; - goto fail; - } io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL); - if (!io_callbacks) { - err = -ENOMEM; - goto free_vqs; - } io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL); - if (!io_names) { - err = -ENOMEM; - goto free_callbacks; - } portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), GFP_KERNEL); - if (!portdev->in_vqs) { - err = -ENOMEM; - goto free_names; - } portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), GFP_KERNEL); - if (!portdev->out_vqs) { + if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs || + !portdev->out_vqs) { err = -ENOMEM; - goto free_invqs; + goto free; } /* @@ -1605,7 +1590,7 @@ static int init_vqs(struct ports_device *portdev) io_callbacks, (const char **)io_names); if (err) - goto free_outvqs; + goto free; j = 0; portdev->in_vqs[0] = vqs[0]; @@ -1621,23 +1606,19 @@ static int init_vqs(struct ports_device *portdev) portdev->out_vqs[i] = vqs[j + 1]; } } - kfree(io_callbacks); kfree(io_names); + kfree(io_callbacks); kfree(vqs); return 0; -free_names: - kfree(io_names); -free_callbacks: - kfree(io_callbacks); -free_outvqs: +free: kfree(portdev->out_vqs); -free_invqs: kfree(portdev->in_vqs); -free_vqs: + kfree(io_names); + kfree(io_callbacks); kfree(vqs); -fail: + return err; } diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index d68d3aa1814b..f975d24890fa 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -283,16 +283,21 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p, } while (delay); } -static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) +static void __sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) { - unsigned long flags; - if (delta > p->max_match_value) dev_warn(&p->pdev->dev, "delta out of range\n"); - spin_lock_irqsave(&p->lock, flags); p->next_match_value = delta; sh_cmt_clock_event_program_verify(p, 0); +} + +static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) +{ + unsigned long flags; + + spin_lock_irqsave(&p->lock, flags); + __sh_cmt_set_next(p, delta); spin_unlock_irqrestore(&p->lock, flags); } @@ -359,7 +364,7 @@ static int sh_cmt_start(struct sh_cmt_priv *p, unsigned long flag) /* setup timeout if no clockevent */ if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT))) - sh_cmt_set_next(p, p->max_match_value); + __sh_cmt_set_next(p, p->max_match_value); out: spin_unlock_irqrestore(&p->lock, flags); @@ -381,7 +386,7 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag) /* adjust the timeout to maximum if only clocksource left */ if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE)) - sh_cmt_set_next(p, p->max_match_value); + __sh_cmt_set_next(p, p->max_match_value); spin_unlock_irqrestore(&p->lock, flags); } diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index e16c3fa8d2e3..05117f1ad867 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -36,6 +36,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector."); +MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_CONNECTOR); static struct cn_dev cdev; diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index a8a84f4587f2..64b21f5cd740 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -1,8 +1,8 @@ ifeq ($(CONFIG_DMADEVICES_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG + ccflags-y += -DDEBUG endif ifeq ($(CONFIG_DMADEVICES_VDEBUG),y) - EXTRA_CFLAGS += -DVERBOSE_DEBUG + ccflags-y += -DVERBOSE_DEBUG endif obj-$(CONFIG_DMA_ENGINE) += dmaengine.o diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index a0f3e6a06e06..ea0ee81cff53 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -722,7 +722,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, desc->lli.daddr = mem; desc->lli.ctrla = ctrla | ATC_DST_WIDTH(mem_width) - | len >> mem_width; + | len >> reg_width; desc->lli.ctrlb = ctrlb; if (!first) { diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 286c3ac6bdcc..e5e172d21692 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -50,9 +50,11 @@ static void dma_init(struct fsldma_chan *chan) * EIE - Error interrupt enable * EOSIE - End of segments interrupt enable (basic mode) * EOLNIE - End of links interrupt enable + * BWC - Bandwidth sharing among channels */ - DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EIE - | FSL_DMA_MR_EOLNIE | FSL_DMA_MR_EOSIE, 32); + DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC + | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE + | FSL_DMA_MR_EOSIE, 32); break; case FSL_DMA_IP_83XX: /* Set the channel to below modes: diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index cb4d6ff51597..ba9f403c0fbe 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. All rights reserved. * * Author: * Zhang Wei <wei.zhang@freescale.com>, Jul 2007 @@ -36,6 +36,13 @@ #define FSL_DMA_MR_DAHE 0x00002000 #define FSL_DMA_MR_SAHE 0x00001000 +/* + * Bandwidth/pause control determines how many bytes a given + * channel is allowed to transfer before the DMA engine pauses + * the current channel and switches to the next channel + */ +#define FSL_DMA_MR_BWC 0x08000000 + /* Special MR definition for MPC8349 */ #define FSL_DMA_MR_EOTIE 0x00000080 #define FSL_DMA_MR_PRC_RM 0x00000800 diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index f629e4961af5..e53d438142bb 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -379,7 +379,7 @@ static int __init imxdma_probe(struct platform_device *pdev) return 0; err_init: - while (i-- >= 0) { + while (--i >= 0) { struct imxdma_channel *imxdmac = &imxdma->channel[i]; imx_dma_free(imxdmac->imxdma_channel); } diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 0834323a0599..d0602dd5d1b2 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -951,7 +951,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg( struct sdma_buffer_descriptor *bd = &sdmac->bd[i]; int param; - bd->buffer_addr = sgl->dma_address; + bd->buffer_addr = sg->dma_address; count = sg->length; @@ -1385,7 +1385,7 @@ static int __init sdma_module_init(void) { return platform_driver_probe(&sdma_driver, sdma_probe); } -subsys_initcall(sdma_module_init); +module_init(sdma_module_init); MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>"); MODULE_DESCRIPTION("i.MX SDMA driver"); diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 338bc4eed1f3..3109bd94bc4f 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -1075,7 +1075,6 @@ static int mid_setup_dma(struct pci_dev *pdev) if (NULL == dma->dma_pool) { pr_err("ERR_MDMA:pci_pool_create failed\n"); err = -ENOMEM; - kfree(dma); goto err_dma_pool; } @@ -1186,7 +1185,6 @@ err_engine: free_irq(pdev->irq, dma); err_irq: pci_pool_destroy(dma->dma_pool); - kfree(dma); err_dma_pool: pr_err("ERR_MDMA:setup_dma failed: %d\n", err); return err; @@ -1413,7 +1411,7 @@ static const struct dev_pm_ops intel_mid_dma_pm = { .runtime_idle = dma_runtime_idle, }; -static struct pci_driver intel_mid_dma_pci = { +static struct pci_driver intel_mid_dma_pci_driver = { .name = "Intel MID DMA", .id_table = intel_mid_dma_ids, .probe = intel_mid_dma_probe, @@ -1431,13 +1429,13 @@ static int __init intel_mid_dma_init(void) { pr_debug("INFO_MDMA: LNW DMA Driver Version %s\n", INTEL_MID_DMA_DRIVER_VERSION); - return pci_register_driver(&intel_mid_dma_pci); + return pci_register_driver(&intel_mid_dma_pci_driver); } fs_initcall(intel_mid_dma_init); static void __exit intel_mid_dma_exit(void) { - pci_unregister_driver(&intel_mid_dma_pci); + pci_unregister_driver(&intel_mid_dma_pci_driver); } module_exit(intel_mid_dma_exit); diff --git a/drivers/dma/ioat/Makefile b/drivers/dma/ioat/Makefile index 8997d3fb9051..0ff7270af25b 100644 --- a/drivers/dma/ioat/Makefile +++ b/drivers/dma/ioat/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o -ioatdma-objs := pci.o dma.o dma_v2.o dma_v3.o dca.o +ioatdma-y := pci.o dma.o dma_v2.o dma_v3.o dca.o diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index 92b679024fed..c064c89420d0 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -259,11 +259,6 @@ static void pdc_dostart(struct pch_dma_chan *pd_chan, struct pch_dma_desc* desc) return; } - channel_writel(pd_chan, DEV_ADDR, desc->regs.dev_addr); - channel_writel(pd_chan, MEM_ADDR, desc->regs.mem_addr); - channel_writel(pd_chan, SIZE, desc->regs.size); - channel_writel(pd_chan, NEXT, desc->regs.next); - dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> dev_addr: %x\n", pd_chan->chan.chan_id, desc->regs.dev_addr); dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> mem_addr: %x\n", @@ -273,10 +268,16 @@ static void pdc_dostart(struct pch_dma_chan *pd_chan, struct pch_dma_desc* desc) dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> next: %x\n", pd_chan->chan.chan_id, desc->regs.next); - if (list_empty(&desc->tx_list)) + if (list_empty(&desc->tx_list)) { + channel_writel(pd_chan, DEV_ADDR, desc->regs.dev_addr); + channel_writel(pd_chan, MEM_ADDR, desc->regs.mem_addr); + channel_writel(pd_chan, SIZE, desc->regs.size); + channel_writel(pd_chan, NEXT, desc->regs.next); pdc_set_mode(&pd_chan->chan, DMA_CTL0_ONESHOT); - else + } else { + channel_writel(pd_chan, NEXT, desc->txd.phys); pdc_set_mode(&pd_chan->chan, DMA_CTL0_SG); + } val = dma_readl(pd, CTL2); val |= 1 << (DMA_CTL2_START_SHIFT_BITS + pd_chan->chan.chan_id); diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index 0d58a4a4487f..cef584533ee8 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -4449,9 +4449,8 @@ static int __devinit ppc440spe_adma_probe(struct platform_device *ofdev, if (!request_mem_region(res.start, resource_size(&res), dev_driver_string(&ofdev->dev))) { - dev_err(&ofdev->dev, "failed to request memory region " - "(0x%016llx-0x%016llx)\n", - (u64)res.start, (u64)res.end); + dev_err(&ofdev->dev, "failed to request memory region %pR\n", + &res); initcode = PPC_ADMA_INIT_MEMREG; ret = -EBUSY; goto out; diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index eb6b54dbb806..85ffd5e38c50 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -1213,3 +1213,4 @@ module_exit(sh_dmae_exit); MODULE_AUTHOR("Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>"); MODULE_DESCRIPTION("Renesas SH DMA Engine driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sh-dma-engine"); diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index b3781399b38a..ba2898b3639b 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -10,16 +10,16 @@ obj-$(CONFIG_EDAC) := edac_stub.o obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o obj-$(CONFIG_EDAC_MCE) += edac_mce.o -edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o -edac_core-objs += edac_module.o edac_device_sysfs.o +edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o +edac_core-y += edac_module.o edac_device_sysfs.o ifdef CONFIG_PCI -edac_core-objs += edac_pci.o edac_pci_sysfs.o +edac_core-y += edac_pci.o edac_pci_sysfs.o endif obj-$(CONFIG_EDAC_MCE_INJ) += mce_amd_inj.o -edac_mce_amd-objs := mce_amd.o +edac_mce_amd-y := mce_amd.o obj-$(CONFIG_EDAC_DECODE_MCE) += edac_mce_amd.o obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 8521401bbd75..eca9ba193e94 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -1572,7 +1572,7 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int dram_range, debugf1(" HoleOffset=0x%x HoleValid=0x%x IntlvSel=0x%x\n", hole_off, hole_valid, intlv_sel); - if (intlv_en || + if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en))) return -EINVAL; diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index d7ca43a828bd..251440cd50a3 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -41,10 +41,10 @@ #define MC_PROC_NAME_MAX_LEN 7 #if PAGE_SHIFT < 20 -#define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) ) -#define MiB_TO_PAGES(mb) ((mb) >> (20 - PAGE_SHIFT)) +#define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT)) +#define MiB_TO_PAGES(mb) ((mb) << (20 - PAGE_SHIFT)) #else /* PAGE_SHIFT > 20 */ -#define PAGES_TO_MiB( pages ) ( ( pages ) << ( PAGE_SHIFT - 20 ) ) +#define PAGES_TO_MiB(pages) ((pages) << (PAGE_SHIFT - 20)) #define MiB_TO_PAGES(mb) ((mb) >> (PAGE_SHIFT - 20)) #endif diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index ba6586a69ccc..795ea69c4d8f 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -586,14 +586,16 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev) return NULL; } - /* marking MCI offline */ - mci->op_state = OP_OFFLINE; - del_mc_from_global_list(mci); mutex_unlock(&mem_ctls_mutex); - /* flush workq processes and remove sysfs */ + /* flush workq processes */ edac_mc_workq_teardown(mci); + + /* marking MCI offline */ + mci->op_state = OP_OFFLINE; + + /* remove from sysfs */ edac_remove_sysfs_mci_device(mci); edac_printk(KERN_INFO, EDAC_MC, diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c index 8d0688f36d4c..39faded3cadd 100644 --- a/drivers/edac/mce_amd_inj.c +++ b/drivers/edac/mce_amd_inj.c @@ -139,7 +139,7 @@ static int __init edac_init_mce_inject(void) return 0; err_sysfs_create: - while (i-- >= 0) + while (--i >= 0) sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr); kobject_del(mce_kobj); diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 18fdd9703b48..1a467a91fb0b 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -7,6 +7,7 @@ */ #include <linux/bug.h> +#include <linux/delay.h> #include <linux/device.h> #include <linux/firewire.h> #include <linux/firewire-constants.h> @@ -26,8 +27,14 @@ #include <asm/unaligned.h> #include <net/arp.h> -#define FWNET_MAX_FRAGMENTS 25 /* arbitrary limit */ -#define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16 * 1024 ? 4 : 2) +/* rx limits */ +#define FWNET_MAX_FRAGMENTS 30 /* arbitrary, > TX queue depth */ +#define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16*1024 ? 4 : 2) + +/* tx limits */ +#define FWNET_MAX_QUEUED_DATAGRAMS 20 /* < 64 = number of tlabels */ +#define FWNET_MIN_QUEUED_DATAGRAMS 10 /* should keep AT DMA busy enough */ +#define FWNET_TX_QUEUE_LEN FWNET_MAX_QUEUED_DATAGRAMS /* ? */ #define IEEE1394_BROADCAST_CHANNEL 31 #define IEEE1394_ALL_NODES (0xffc0 | 0x003f) @@ -169,15 +176,8 @@ struct fwnet_device { struct fw_address_handler handler; u64 local_fifo; - /* List of packets to be sent */ - struct list_head packet_list; - /* - * List of packets that were broadcasted. When we get an ISO interrupt - * one of them has been sent - */ - struct list_head broadcasted_list; - /* List of packets that have been sent but not yet acked */ - struct list_head sent_list; + /* Number of tx datagrams that have been queued but not yet acked */ + int queued_datagrams; struct list_head peer_list; struct fw_card *card; @@ -195,7 +195,7 @@ struct fwnet_peer { unsigned pdg_size; /* pd_list size */ u16 datagram_label; /* outgoing datagram label */ - unsigned max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */ + u16 max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */ int node_id; int generation; unsigned speed; @@ -203,22 +203,18 @@ struct fwnet_peer { /* This is our task struct. It's used for the packet complete callback. */ struct fwnet_packet_task { - /* - * ptask can actually be on dev->packet_list, dev->broadcasted_list, - * or dev->sent_list depending on its current state. - */ - struct list_head pt_link; struct fw_transaction transaction; struct rfc2734_header hdr; struct sk_buff *skb; struct fwnet_device *dev; int outstanding_pkts; - unsigned max_payload; u64 fifo_addr; u16 dest_node; + u16 max_payload; u8 generation; u8 speed; + u8 enqueued; }; /* @@ -650,8 +646,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, net->stats.rx_packets++; net->stats.rx_bytes += skb->len; } - if (netif_queue_stopped(net)) - netif_wake_queue(net); return 0; @@ -660,8 +654,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, net->stats.rx_dropped++; dev_kfree_skb_any(skb); - if (netif_queue_stopped(net)) - netif_wake_queue(net); return -ENOENT; } @@ -793,15 +785,10 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, * Datagram is not complete, we're done for the * moment. */ - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; + retval = 0; fail: spin_unlock_irqrestore(&dev->lock, flags); - if (netif_queue_stopped(net)) - netif_wake_queue(net); - return retval; } @@ -901,11 +888,19 @@ static void fwnet_free_ptask(struct fwnet_packet_task *ptask) kmem_cache_free(fwnet_packet_task_cache, ptask); } +/* Caller must hold dev->lock. */ +static void dec_queued_datagrams(struct fwnet_device *dev) +{ + if (--dev->queued_datagrams == FWNET_MIN_QUEUED_DATAGRAMS) + netif_wake_queue(dev->netdev); +} + static int fwnet_send_packet(struct fwnet_packet_task *ptask); static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) { struct fwnet_device *dev = ptask->dev; + struct sk_buff *skb = ptask->skb; unsigned long flags; bool free; @@ -914,10 +909,14 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) ptask->outstanding_pkts--; /* Check whether we or the networking TX soft-IRQ is last user. */ - free = (ptask->outstanding_pkts == 0 && !list_empty(&ptask->pt_link)); + free = (ptask->outstanding_pkts == 0 && ptask->enqueued); + if (free) + dec_queued_datagrams(dev); - if (ptask->outstanding_pkts == 0) - list_del(&ptask->pt_link); + if (ptask->outstanding_pkts == 0) { + dev->netdev->stats.tx_packets++; + dev->netdev->stats.tx_bytes += skb->len; + } spin_unlock_irqrestore(&dev->lock, flags); @@ -926,7 +925,6 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) u16 fg_off; u16 datagram_label; u16 lf; - struct sk_buff *skb; /* Update the ptask to point to the next fragment and send it */ lf = fwnet_get_hdr_lf(&ptask->hdr); @@ -953,7 +951,7 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) datagram_label = fwnet_get_hdr_dgl(&ptask->hdr); break; } - skb = ptask->skb; + skb_pull(skb, ptask->max_payload); if (ptask->outstanding_pkts > 1) { fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG, @@ -970,6 +968,31 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) fwnet_free_ptask(ptask); } +static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask) +{ + struct fwnet_device *dev = ptask->dev; + unsigned long flags; + bool free; + + spin_lock_irqsave(&dev->lock, flags); + + /* One fragment failed; don't try to send remaining fragments. */ + ptask->outstanding_pkts = 0; + + /* Check whether we or the networking TX soft-IRQ is last user. */ + free = ptask->enqueued; + if (free) + dec_queued_datagrams(dev); + + dev->netdev->stats.tx_dropped++; + dev->netdev->stats.tx_errors++; + + spin_unlock_irqrestore(&dev->lock, flags); + + if (free) + fwnet_free_ptask(ptask); +} + static void fwnet_write_complete(struct fw_card *card, int rcode, void *payload, size_t length, void *data) { @@ -977,11 +1000,12 @@ static void fwnet_write_complete(struct fw_card *card, int rcode, ptask = data; - if (rcode == RCODE_COMPLETE) + if (rcode == RCODE_COMPLETE) { fwnet_transmit_packet_done(ptask); - else + } else { fw_error("fwnet_write_complete: failed: %x\n", rcode); - /* ??? error recovery */ + fwnet_transmit_packet_failed(ptask); + } } static int fwnet_send_packet(struct fwnet_packet_task *ptask) @@ -1039,9 +1063,11 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) spin_lock_irqsave(&dev->lock, flags); /* If the AT tasklet already ran, we may be last user. */ - free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link)); + free = (ptask->outstanding_pkts == 0 && !ptask->enqueued); if (!free) - list_add_tail(&ptask->pt_link, &dev->broadcasted_list); + ptask->enqueued = true; + else + dec_queued_datagrams(dev); spin_unlock_irqrestore(&dev->lock, flags); @@ -1056,9 +1082,11 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) spin_lock_irqsave(&dev->lock, flags); /* If the AT tasklet already ran, we may be last user. */ - free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link)); + free = (ptask->outstanding_pkts == 0 && !ptask->enqueued); if (!free) - list_add_tail(&ptask->pt_link, &dev->sent_list); + ptask->enqueued = true; + else + dec_queued_datagrams(dev); spin_unlock_irqrestore(&dev->lock, flags); @@ -1224,6 +1252,15 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) struct fwnet_peer *peer; unsigned long flags; + spin_lock_irqsave(&dev->lock, flags); + + /* Can this happen? */ + if (netif_queue_stopped(dev->netdev)) { + spin_unlock_irqrestore(&dev->lock, flags); + + return NETDEV_TX_BUSY; + } + ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC); if (ptask == NULL) goto fail; @@ -1242,9 +1279,6 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) proto = hdr_buf.h_proto; dg_size = skb->len; - /* serialize access to peer, including peer->datagram_label */ - spin_lock_irqsave(&dev->lock, flags); - /* * Set the transmission type for the packet. ARP packets and IP * broadcast packets are sent via GASP. @@ -1266,7 +1300,7 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid)); if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR) - goto fail_unlock; + goto fail; generation = peer->generation; dest_node = peer->node_id; @@ -1320,18 +1354,21 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) max_payload += RFC2374_FRAG_HDR_SIZE; } + if (++dev->queued_datagrams == FWNET_MAX_QUEUED_DATAGRAMS) + netif_stop_queue(dev->netdev); + spin_unlock_irqrestore(&dev->lock, flags); ptask->max_payload = max_payload; - INIT_LIST_HEAD(&ptask->pt_link); + ptask->enqueued = 0; fwnet_send_packet(ptask); return NETDEV_TX_OK; - fail_unlock: - spin_unlock_irqrestore(&dev->lock, flags); fail: + spin_unlock_irqrestore(&dev->lock, flags); + if (ptask) kmem_cache_free(fwnet_packet_task_cache, ptask); @@ -1377,7 +1414,7 @@ static void fwnet_init_dev(struct net_device *net) net->addr_len = FWNET_ALEN; net->hard_header_len = FWNET_HLEN; net->type = ARPHRD_IEEE1394; - net->tx_queue_len = 10; + net->tx_queue_len = FWNET_TX_QUEUE_LEN; } /* caller must hold fwnet_device_mutex */ @@ -1457,14 +1494,9 @@ static int fwnet_probe(struct device *_dev) dev->broadcast_rcv_context = NULL; dev->broadcast_xmt_max_payload = 0; dev->broadcast_xmt_datagramlabel = 0; - dev->local_fifo = FWNET_NO_FIFO_ADDR; - - INIT_LIST_HEAD(&dev->packet_list); - INIT_LIST_HEAD(&dev->broadcasted_list); - INIT_LIST_HEAD(&dev->sent_list); + dev->queued_datagrams = 0; INIT_LIST_HEAD(&dev->peer_list); - dev->card = card; dev->netdev = net; @@ -1522,7 +1554,7 @@ static int fwnet_remove(struct device *_dev) struct fwnet_peer *peer = dev_get_drvdata(_dev); struct fwnet_device *dev = peer->dev; struct net_device *net; - struct fwnet_packet_task *ptask, *pt_next; + int i; mutex_lock(&fwnet_device_mutex); @@ -1540,21 +1572,9 @@ static int fwnet_remove(struct device *_dev) dev->card); fw_iso_context_destroy(dev->broadcast_rcv_context); } - list_for_each_entry_safe(ptask, pt_next, - &dev->packet_list, pt_link) { - dev_kfree_skb_any(ptask->skb); - kmem_cache_free(fwnet_packet_task_cache, ptask); - } - list_for_each_entry_safe(ptask, pt_next, - &dev->broadcasted_list, pt_link) { - dev_kfree_skb_any(ptask->skb); - kmem_cache_free(fwnet_packet_task_cache, ptask); - } - list_for_each_entry_safe(ptask, pt_next, - &dev->sent_list, pt_link) { - dev_kfree_skb_any(ptask->skb); - kmem_cache_free(fwnet_packet_task_cache, ptask); - } + for (i = 0; dev->queued_datagrams && i < 5; i++) + ssleep(1); + WARN_ON(dev->queued_datagrams); list_del(&dev->dev_link); free_netdev(net); diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 84eb607d6c03..e3c8b60bd86b 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -242,6 +242,7 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) static char ohci_driver_name[] = KBUILD_MODNAME; +#define PCI_DEVICE_ID_AGERE_FW643 0x5901 #define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380 #define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 @@ -253,18 +254,34 @@ static char ohci_driver_name[] = KBUILD_MODNAME; /* In case of multiple matches in ohci_quirks[], only the first one is used. */ static const struct { - unsigned short vendor, device, flags; + unsigned short vendor, device, revision, flags; } ohci_quirks[] = { - {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, QUIRK_CYCLE_TIMER | - QUIRK_RESET_PACKET | - QUIRK_NO_1394A}, - {PCI_VENDOR_ID_TI, PCI_ANY_ID, QUIRK_RESET_PACKET}, - {PCI_VENDOR_ID_AL, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, - {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, QUIRK_NO_MSI}, - {PCI_VENDOR_ID_NEC, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, - {PCI_VENDOR_ID_VIA, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, - {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, - {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS}, + {PCI_VENDOR_ID_AL, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_CYCLE_TIMER}, + + {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, PCI_ANY_ID, + QUIRK_BE_HEADERS}, + + {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6, + QUIRK_NO_MSI}, + + {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, PCI_ANY_ID, + QUIRK_NO_MSI}, + + {PCI_VENDOR_ID_NEC, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_CYCLE_TIMER}, + + {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_CYCLE_TIMER}, + + {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID, + QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A}, + + {PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_RESET_PACKET}, + + {PCI_VENDOR_ID_VIA, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_CYCLE_TIMER | QUIRK_NO_MSI}, }; /* This overrides anything that was found in ohci_quirks[]. */ @@ -2927,9 +2944,11 @@ static int __devinit pci_probe(struct pci_dev *dev, } for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++) - if (ohci_quirks[i].vendor == dev->vendor && - (ohci_quirks[i].device == dev->device || - ohci_quirks[i].device == (unsigned short)PCI_ANY_ID)) { + if ((ohci_quirks[i].vendor == dev->vendor) && + (ohci_quirks[i].device == (unsigned short)PCI_ANY_ID || + ohci_quirks[i].device == dev->device) && + (ohci_quirks[i].revision == (unsigned short)PCI_ANY_ID || + ohci_quirks[i].revision >= dev->revision)) { ohci->quirks = ohci_quirks[i].flags; break; } diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index e23c06893d19..599f6c9e0fbf 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -56,6 +56,18 @@ static struct cs5535_gpio_chip { * registers, see include/linux/cs5535.h. */ +static void errata_outl(u32 val, unsigned long addr) +{ + /* + * According to the CS5536 errata (#36), after suspend + * a write to the high bank GPIO register will clear all + * non-selected bits; the recommended workaround is a + * read-modify-write operation. + */ + val |= inl(addr); + outl(val, addr); +} + static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset, unsigned int reg) { @@ -64,7 +76,7 @@ static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset, outl(1 << offset, chip->base + reg); else /* high bank register */ - outl(1 << (offset - 16), chip->base + 0x80 + reg); + errata_outl(1 << (offset - 16), chip->base + 0x80 + reg); } void cs5535_gpio_set(unsigned offset, unsigned int reg) @@ -86,7 +98,7 @@ static void __cs5535_gpio_clear(struct cs5535_gpio_chip *chip, unsigned offset, outl(1 << (offset + 16), chip->base + reg); else /* high bank register */ - outl(1 << offset, chip->base + 0x80 + reg); + errata_outl(1 << offset, chip->base + 0x80 + reg); } void cs5535_gpio_clear(unsigned offset, unsigned int reg) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 6985cb1da72c..2baa6708e44c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -156,12 +156,12 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 }, { DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 }, { DRM_MODE_CONNECTOR_Component, "Component", 0 }, - { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN", 0 }, - { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort", 0 }, - { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A", 0 }, - { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B", 0 }, + { DRM_MODE_CONNECTOR_9PinDIN, "DIN", 0 }, + { DRM_MODE_CONNECTOR_DisplayPort, "DP", 0 }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A", 0 }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 }, { DRM_MODE_CONNECTOR_TV, "TV", 0 }, - { DRM_MODE_CONNECTOR_eDP, "Embedded DisplayPort", 0 }, + { DRM_MODE_CONNECTOR_eDP, "eDP", 0 }, }; static struct drm_prop_enum_list drm_encoder_enum_list[] = diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index f7af91cb273d..bede10a03407 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -241,7 +241,7 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) } list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (!drm_helper_encoder_in_use(encoder)) { + if (encoder->crtc && !drm_helper_encoder_in_use(encoder)) { drm_encoder_disable(encoder); /* disconnector encoder from any connector */ encoder->crtc = NULL; @@ -471,6 +471,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) int count = 0, ro, fail = 0; struct drm_crtc_helper_funcs *crtc_funcs; int ret = 0; + int i; DRM_DEBUG_KMS("\n"); @@ -666,6 +667,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) if (ret != 0) goto fail; } + DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); + for (i = 0; i < set->num_connectors; i++) { + DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, + drm_get_connector_name(set->connectors[i])); + set->connectors[i]->dpms = DRM_MODE_DPMS_ON; + } kfree(save_connectors); kfree(save_encoders); @@ -841,7 +848,7 @@ static void output_poll_execute(struct work_struct *work) struct delayed_work *delayed_work = to_delayed_work(work); struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); struct drm_connector *connector; - enum drm_connector_status old_status, status; + enum drm_connector_status old_status; bool repoll = false, changed = false; if (!drm_kms_helper_poll) @@ -866,8 +873,9 @@ static void output_poll_execute(struct work_struct *work) !(connector->polled & DRM_CONNECTOR_POLL_HPD)) continue; - status = connector->funcs->detect(connector, false); - if (old_status != status) + connector->status = connector->funcs->detect(connector, false); + DRM_DEBUG_KMS("connector status updated to %d\n", connector->status); + if (old_status != connector->status) changed = true; } diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 9d3a5030b6e1..16d5155edad1 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -585,10 +585,13 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, struct timeval now; unsigned long flags; unsigned int seq; + int ret; e = kzalloc(sizeof *e, GFP_KERNEL); - if (e == NULL) - return -ENOMEM; + if (e == NULL) { + ret = -ENOMEM; + goto err_put; + } e->pipe = pipe; e->base.pid = current->pid; @@ -603,9 +606,8 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, spin_lock_irqsave(&dev->event_lock, flags); if (file_priv->event_space < sizeof e->event) { - spin_unlock_irqrestore(&dev->event_lock, flags); - kfree(e); - return -ENOMEM; + ret = -EBUSY; + goto err_unlock; } file_priv->event_space -= sizeof e->event; @@ -626,7 +628,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, if ((seq - vblwait->request.sequence) <= (1 << 23)) { e->event.tv_sec = now.tv_sec; e->event.tv_usec = now.tv_usec; - drm_vblank_put(dev, e->pipe); + drm_vblank_put(dev, pipe); list_add_tail(&e->base.link, &e->base.file_priv->event_list); wake_up_interruptible(&e->base.file_priv->event_wait); trace_drm_vblank_event_delivered(current->pid, pipe, @@ -638,6 +640,13 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, spin_unlock_irqrestore(&dev->event_lock, flags); return 0; + +err_unlock: + spin_unlock_irqrestore(&dev->event_lock, flags); + kfree(e); +err_put: + drm_vblank_put(dev, pipe); + return ret; } /** diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7a26f4dd21ae..e6800819bca8 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -767,6 +767,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_BLT: value = HAS_BLT(dev); break; + case I915_PARAM_HAS_COHERENT_RINGS: + value = 1; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 80745f85902c..f737960712e6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -150,7 +150,8 @@ static const struct intel_device_info intel_ironlake_d_info = { static const struct intel_device_info intel_ironlake_m_info = { .gen = 5, .is_mobile = 1, - .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, + .need_gfx_hws = 1, .has_rc6 = 1, .has_hotplug = 1, + .has_fbc = 0, /* disabled due to buggy hardware */ .has_bsd_ring = 1, }; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 90414ae86afc..409826da3099 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1045,6 +1045,8 @@ void i915_gem_clflush_object(struct drm_gem_object *obj); int i915_gem_object_set_domain(struct drm_gem_object *obj, uint32_t read_domains, uint32_t write_domain); +int i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, + bool interruptible); int i915_gem_init_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int i915_gem_do_init(struct drm_device *dev, unsigned long start, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ef188e391406..275ec6ed43ae 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -38,8 +38,7 @@ static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj); -static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, - bool pipelined); +static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, @@ -547,6 +546,19 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_object *obj_priv; int ret = 0; + if (args->size == 0) + return 0; + + if (!access_ok(VERIFY_WRITE, + (char __user *)(uintptr_t)args->data_ptr, + args->size)) + return -EFAULT; + + ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr, + args->size); + if (ret) + return -EFAULT; + ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; @@ -564,23 +576,6 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, goto out; } - if (args->size == 0) - goto out; - - if (!access_ok(VERIFY_WRITE, - (char __user *)(uintptr_t)args->data_ptr, - args->size)) { - ret = -EFAULT; - goto out; - } - - ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr, - args->size); - if (ret) { - ret = -EFAULT; - goto out; - } - ret = i915_gem_object_get_pages_or_evict(obj); if (ret) goto out; @@ -981,7 +976,20 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_pwrite *args = data; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - int ret = 0; + int ret; + + if (args->size == 0) + return 0; + + if (!access_ok(VERIFY_READ, + (char __user *)(uintptr_t)args->data_ptr, + args->size)) + return -EFAULT; + + ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr, + args->size); + if (ret) + return -EFAULT; ret = i915_mutex_lock_interruptible(dev); if (ret) @@ -994,30 +1002,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, } obj_priv = to_intel_bo(obj); - /* Bounds check destination. */ if (args->offset > obj->size || args->size > obj->size - args->offset) { ret = -EINVAL; goto out; } - if (args->size == 0) - goto out; - - if (!access_ok(VERIFY_READ, - (char __user *)(uintptr_t)args->data_ptr, - args->size)) { - ret = -EFAULT; - goto out; - } - - ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr, - args->size); - if (ret) { - ret = -EFAULT; - goto out; - } - /* We can only do the GTT pwrite on untiled buffers, as otherwise * it would end up going through the fenced access, and we'll get * different detiling behavior between reading and writing. @@ -2603,7 +2593,7 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj, if (reg->gpu) { int ret; - ret = i915_gem_object_flush_gpu_write_domain(obj, true); + ret = i915_gem_object_flush_gpu_write_domain(obj); if (ret) return ret; @@ -2751,8 +2741,7 @@ i915_gem_clflush_object(struct drm_gem_object *obj) /** Flushes any GPU write domain for the object if it's dirty. */ static int -i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, - bool pipelined) +i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; uint32_t old_write_domain; @@ -2771,10 +2760,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, obj->read_domains, old_write_domain); - if (pipelined) - return 0; - - return i915_gem_object_wait_rendering(obj, true); + return 0; } /** Flushes the GTT write domain for the object if it's dirty. */ @@ -2835,18 +2821,15 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) if (obj_priv->gtt_space == NULL) return -EINVAL; - ret = i915_gem_object_flush_gpu_write_domain(obj, false); + ret = i915_gem_object_flush_gpu_write_domain(obj); if (ret != 0) return ret; + ret = i915_gem_object_wait_rendering(obj, true); + if (ret) + return ret; i915_gem_object_flush_cpu_write_domain(obj); - if (write) { - ret = i915_gem_object_wait_rendering(obj, true); - if (ret) - return ret; - } - old_write_domain = obj->write_domain; old_read_domains = obj->read_domains; @@ -2884,7 +2867,7 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj, if (obj_priv->gtt_space == NULL) return -EINVAL; - ret = i915_gem_object_flush_gpu_write_domain(obj, true); + ret = i915_gem_object_flush_gpu_write_domain(obj); if (ret) return ret; @@ -2907,6 +2890,20 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj, return 0; } +int +i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, + bool interruptible) +{ + if (!obj->active) + return 0; + + if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) + i915_gem_flush_ring(obj->base.dev, NULL, obj->ring, + 0, obj->base.write_domain); + + return i915_gem_object_wait_rendering(&obj->base, interruptible); +} + /** * Moves a single object to the CPU read, and possibly write domain. * @@ -2919,9 +2916,12 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) uint32_t old_write_domain, old_read_domains; int ret; - ret = i915_gem_object_flush_gpu_write_domain(obj, false); + ret = i915_gem_object_flush_gpu_write_domain(obj); if (ret != 0) return ret; + ret = i915_gem_object_wait_rendering(obj, true); + if (ret) + return ret; i915_gem_object_flush_gtt_write_domain(obj); @@ -2930,12 +2930,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) */ i915_gem_object_set_to_full_cpu_read_domain(obj); - if (write) { - ret = i915_gem_object_wait_rendering(obj, true); - if (ret) - return ret; - } - old_write_domain = obj->write_domain; old_read_domains = obj->read_domains; @@ -3200,9 +3194,13 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, if (offset == 0 && size == obj->size) return i915_gem_object_set_to_cpu_domain(obj, 0); - ret = i915_gem_object_flush_gpu_write_domain(obj, false); + ret = i915_gem_object_flush_gpu_write_domain(obj); if (ret != 0) return ret; + ret = i915_gem_object_wait_rendering(obj, true); + if (ret) + return ret; + i915_gem_object_flush_gtt_write_domain(obj); /* If we're already fully in the CPU read domain, we're done. */ @@ -3249,192 +3247,230 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, return 0; } -/** - * Pin an object to the GTT and evaluate the relocations landing in it. - */ static int -i915_gem_execbuffer_relocate(struct drm_i915_gem_object *obj, - struct drm_file *file_priv, - struct drm_i915_gem_exec_object2 *entry) +i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, + struct drm_file *file_priv, + struct drm_i915_gem_exec_object2 *entry, + struct drm_i915_gem_relocation_entry *reloc) { struct drm_device *dev = obj->base.dev; - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_relocation_entry __user *user_relocs; - struct drm_gem_object *target_obj = NULL; - uint32_t target_handle = 0; - int i, ret = 0; + struct drm_gem_object *target_obj; + uint32_t target_offset; + int ret = -EINVAL; - user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr; - for (i = 0; i < entry->relocation_count; i++) { - struct drm_i915_gem_relocation_entry reloc; - uint32_t target_offset; + target_obj = drm_gem_object_lookup(dev, file_priv, + reloc->target_handle); + if (target_obj == NULL) + return -ENOENT; - if (__copy_from_user_inatomic(&reloc, - user_relocs+i, - sizeof(reloc))) { - ret = -EFAULT; - break; - } + target_offset = to_intel_bo(target_obj)->gtt_offset; - if (reloc.target_handle != target_handle) { - drm_gem_object_unreference(target_obj); +#if WATCH_RELOC + DRM_INFO("%s: obj %p offset %08x target %d " + "read %08x write %08x gtt %08x " + "presumed %08x delta %08x\n", + __func__, + obj, + (int) reloc->offset, + (int) reloc->target_handle, + (int) reloc->read_domains, + (int) reloc->write_domain, + (int) target_offset, + (int) reloc->presumed_offset, + reloc->delta); +#endif - target_obj = drm_gem_object_lookup(dev, file_priv, - reloc.target_handle); - if (target_obj == NULL) { - ret = -ENOENT; - break; - } + /* The target buffer should have appeared before us in the + * exec_object list, so it should have a GTT space bound by now. + */ + if (target_offset == 0) { + DRM_ERROR("No GTT space found for object %d\n", + reloc->target_handle); + goto err; + } - target_handle = reloc.target_handle; - } - target_offset = to_intel_bo(target_obj)->gtt_offset; + /* Validate that the target is in a valid r/w GPU domain */ + if (reloc->write_domain & (reloc->write_domain - 1)) { + DRM_ERROR("reloc with multiple write domains: " + "obj %p target %d offset %d " + "read %08x write %08x", + obj, reloc->target_handle, + (int) reloc->offset, + reloc->read_domains, + reloc->write_domain); + goto err; + } + if (reloc->write_domain & I915_GEM_DOMAIN_CPU || + reloc->read_domains & I915_GEM_DOMAIN_CPU) { + DRM_ERROR("reloc with read/write CPU domains: " + "obj %p target %d offset %d " + "read %08x write %08x", + obj, reloc->target_handle, + (int) reloc->offset, + reloc->read_domains, + reloc->write_domain); + goto err; + } + if (reloc->write_domain && target_obj->pending_write_domain && + reloc->write_domain != target_obj->pending_write_domain) { + DRM_ERROR("Write domain conflict: " + "obj %p target %d offset %d " + "new %08x old %08x\n", + obj, reloc->target_handle, + (int) reloc->offset, + reloc->write_domain, + target_obj->pending_write_domain); + goto err; + } -#if WATCH_RELOC - DRM_INFO("%s: obj %p offset %08x target %d " - "read %08x write %08x gtt %08x " - "presumed %08x delta %08x\n", - __func__, - obj, - (int) reloc.offset, - (int) reloc.target_handle, - (int) reloc.read_domains, - (int) reloc.write_domain, - (int) target_offset, - (int) reloc.presumed_offset, - reloc.delta); -#endif + target_obj->pending_read_domains |= reloc->read_domains; + target_obj->pending_write_domain |= reloc->write_domain; - /* The target buffer should have appeared before us in the - * exec_object list, so it should have a GTT space bound by now. - */ - if (target_offset == 0) { - DRM_ERROR("No GTT space found for object %d\n", - reloc.target_handle); - ret = -EINVAL; - break; - } + /* If the relocation already has the right value in it, no + * more work needs to be done. + */ + if (target_offset == reloc->presumed_offset) + goto out; - /* Validate that the target is in a valid r/w GPU domain */ - if (reloc.write_domain & (reloc.write_domain - 1)) { - DRM_ERROR("reloc with multiple write domains: " - "obj %p target %d offset %d " - "read %08x write %08x", - obj, reloc.target_handle, - (int) reloc.offset, - reloc.read_domains, - reloc.write_domain); - ret = -EINVAL; - break; - } - if (reloc.write_domain & I915_GEM_DOMAIN_CPU || - reloc.read_domains & I915_GEM_DOMAIN_CPU) { - DRM_ERROR("reloc with read/write CPU domains: " - "obj %p target %d offset %d " - "read %08x write %08x", - obj, reloc.target_handle, - (int) reloc.offset, - reloc.read_domains, - reloc.write_domain); - ret = -EINVAL; - break; - } - if (reloc.write_domain && target_obj->pending_write_domain && - reloc.write_domain != target_obj->pending_write_domain) { - DRM_ERROR("Write domain conflict: " - "obj %p target %d offset %d " - "new %08x old %08x\n", - obj, reloc.target_handle, - (int) reloc.offset, - reloc.write_domain, - target_obj->pending_write_domain); - ret = -EINVAL; - break; - } + /* Check that the relocation address is valid... */ + if (reloc->offset > obj->base.size - 4) { + DRM_ERROR("Relocation beyond object bounds: " + "obj %p target %d offset %d size %d.\n", + obj, reloc->target_handle, + (int) reloc->offset, + (int) obj->base.size); + goto err; + } + if (reloc->offset & 3) { + DRM_ERROR("Relocation not 4-byte aligned: " + "obj %p target %d offset %d.\n", + obj, reloc->target_handle, + (int) reloc->offset); + goto err; + } - target_obj->pending_read_domains |= reloc.read_domains; - target_obj->pending_write_domain |= reloc.write_domain; + /* and points to somewhere within the target object. */ + if (reloc->delta >= target_obj->size) { + DRM_ERROR("Relocation beyond target object bounds: " + "obj %p target %d delta %d size %d.\n", + obj, reloc->target_handle, + (int) reloc->delta, + (int) target_obj->size); + goto err; + } - /* If the relocation already has the right value in it, no - * more work needs to be done. - */ - if (target_offset == reloc.presumed_offset) - continue; + reloc->delta += target_offset; + if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) { + uint32_t page_offset = reloc->offset & ~PAGE_MASK; + char *vaddr; - /* Check that the relocation address is valid... */ - if (reloc.offset > obj->base.size - 4) { - DRM_ERROR("Relocation beyond object bounds: " - "obj %p target %d offset %d size %d.\n", - obj, reloc.target_handle, - (int) reloc.offset, (int) obj->base.size); - ret = -EINVAL; - break; - } - if (reloc.offset & 3) { - DRM_ERROR("Relocation not 4-byte aligned: " - "obj %p target %d offset %d.\n", - obj, reloc.target_handle, - (int) reloc.offset); - ret = -EINVAL; - break; - } + vaddr = kmap_atomic(obj->pages[reloc->offset >> PAGE_SHIFT]); + *(uint32_t *)(vaddr + page_offset) = reloc->delta; + kunmap_atomic(vaddr); + } else { + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t __iomem *reloc_entry; + void __iomem *reloc_page; - /* and points to somewhere within the target object. */ - if (reloc.delta >= target_obj->size) { - DRM_ERROR("Relocation beyond target object bounds: " - "obj %p target %d delta %d size %d.\n", - obj, reloc.target_handle, - (int) reloc.delta, (int) target_obj->size); - ret = -EINVAL; - break; - } + ret = i915_gem_object_set_to_gtt_domain(&obj->base, 1); + if (ret) + goto err; - reloc.delta += target_offset; - if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) { - uint32_t page_offset = reloc.offset & ~PAGE_MASK; - char *vaddr; + /* Map the page containing the relocation we're going to perform. */ + reloc->offset += obj->gtt_offset; + reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + reloc->offset & PAGE_MASK); + reloc_entry = (uint32_t __iomem *) + (reloc_page + (reloc->offset & ~PAGE_MASK)); + iowrite32(reloc->delta, reloc_entry); + io_mapping_unmap_atomic(reloc_page); + } - vaddr = kmap_atomic(obj->pages[reloc.offset >> PAGE_SHIFT]); - *(uint32_t *)(vaddr + page_offset) = reloc.delta; - kunmap_atomic(vaddr); - } else { - uint32_t __iomem *reloc_entry; - void __iomem *reloc_page; + /* and update the user's relocation entry */ + reloc->presumed_offset = target_offset; - ret = i915_gem_object_set_to_gtt_domain(&obj->base, 1); - if (ret) - break; +out: + ret = 0; +err: + drm_gem_object_unreference(target_obj); + return ret; +} - /* Map the page containing the relocation we're going to perform. */ - reloc.offset += obj->gtt_offset; - reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, - reloc.offset & PAGE_MASK); - reloc_entry = (uint32_t __iomem *) - (reloc_page + (reloc.offset & ~PAGE_MASK)); - iowrite32(reloc.delta, reloc_entry); - io_mapping_unmap_atomic(reloc_page); - } +static int +i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, + struct drm_file *file_priv, + struct drm_i915_gem_exec_object2 *entry) +{ + struct drm_i915_gem_relocation_entry __user *user_relocs; + int i, ret; + + user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr; + for (i = 0; i < entry->relocation_count; i++) { + struct drm_i915_gem_relocation_entry reloc; + + if (__copy_from_user_inatomic(&reloc, + user_relocs+i, + sizeof(reloc))) + return -EFAULT; + + ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &reloc); + if (ret) + return ret; - /* and update the user's relocation entry */ - reloc.presumed_offset = target_offset; if (__copy_to_user_inatomic(&user_relocs[i].presumed_offset, - &reloc.presumed_offset, - sizeof(reloc.presumed_offset))) { - ret = -EFAULT; - break; - } + &reloc.presumed_offset, + sizeof(reloc.presumed_offset))) + return -EFAULT; } - drm_gem_object_unreference(target_obj); - return ret; + return 0; } static int -i915_gem_execbuffer_pin(struct drm_device *dev, - struct drm_file *file, - struct drm_gem_object **object_list, - struct drm_i915_gem_exec_object2 *exec_list, - int count) +i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, + struct drm_file *file_priv, + struct drm_i915_gem_exec_object2 *entry, + struct drm_i915_gem_relocation_entry *relocs) +{ + int i, ret; + + for (i = 0; i < entry->relocation_count; i++) { + ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &relocs[i]); + if (ret) + return ret; + } + + return 0; +} + +static int +i915_gem_execbuffer_relocate(struct drm_device *dev, + struct drm_file *file, + struct drm_gem_object **object_list, + struct drm_i915_gem_exec_object2 *exec_list, + int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]); + obj->base.pending_read_domains = 0; + obj->base.pending_write_domain = 0; + ret = i915_gem_execbuffer_relocate_object(obj, file, + &exec_list[i]); + if (ret) + return ret; + } + + return 0; +} + +static int +i915_gem_execbuffer_reserve(struct drm_device *dev, + struct drm_file *file, + struct drm_gem_object **object_list, + struct drm_i915_gem_exec_object2 *exec_list, + int count) { struct drm_i915_private *dev_priv = dev->dev_private; int ret, i, retry; @@ -3497,6 +3533,87 @@ i915_gem_execbuffer_pin(struct drm_device *dev, } static int +i915_gem_execbuffer_relocate_slow(struct drm_device *dev, + struct drm_file *file, + struct drm_gem_object **object_list, + struct drm_i915_gem_exec_object2 *exec_list, + int count) +{ + struct drm_i915_gem_relocation_entry *reloc; + int i, total, ret; + + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]); + obj->in_execbuffer = false; + } + + mutex_unlock(&dev->struct_mutex); + + total = 0; + for (i = 0; i < count; i++) + total += exec_list[i].relocation_count; + + reloc = drm_malloc_ab(total, sizeof(*reloc)); + if (reloc == NULL) { + mutex_lock(&dev->struct_mutex); + return -ENOMEM; + } + + total = 0; + for (i = 0; i < count; i++) { + struct drm_i915_gem_relocation_entry __user *user_relocs; + + user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr; + + if (copy_from_user(reloc+total, user_relocs, + exec_list[i].relocation_count * + sizeof(*reloc))) { + ret = -EFAULT; + mutex_lock(&dev->struct_mutex); + goto err; + } + + total += exec_list[i].relocation_count; + } + + ret = i915_mutex_lock_interruptible(dev); + if (ret) { + mutex_lock(&dev->struct_mutex); + goto err; + } + + ret = i915_gem_execbuffer_reserve(dev, file, + object_list, exec_list, + count); + if (ret) + goto err; + + total = 0; + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]); + obj->base.pending_read_domains = 0; + obj->base.pending_write_domain = 0; + ret = i915_gem_execbuffer_relocate_object_slow(obj, file, + &exec_list[i], + reloc + total); + if (ret) + goto err; + + total += exec_list[i].relocation_count; + } + + /* Leave the user relocations as are, this is the painfully slow path, + * and we want to avoid the complication of dropping the lock whilst + * having buffers reserved in the aperture and so causing spurious + * ENOSPC for random operations. + */ + +err: + drm_free_large(reloc); + return ret; +} + +static int i915_gem_execbuffer_move_to_gpu(struct drm_device *dev, struct drm_file *file, struct intel_ring_buffer *ring, @@ -3625,8 +3742,15 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, for (i = 0; i < count; i++) { char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; - size_t length = exec[i].relocation_count * sizeof(struct drm_i915_gem_relocation_entry); + int length; /* limited by fault_in_pages_readable() */ + + /* First check for malicious input causing overflow */ + if (exec[i].relocation_count > + INT_MAX / sizeof(struct drm_i915_gem_relocation_entry)) + return -EINVAL; + length = exec[i].relocation_count * + sizeof(struct drm_i915_gem_relocation_entry); if (!access_ok(VERIFY_READ, ptr, length)) return -EFAULT; @@ -3769,18 +3893,24 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } /* Move the objects en-masse into the GTT, evicting if necessary. */ - ret = i915_gem_execbuffer_pin(dev, file, - object_list, exec_list, - args->buffer_count); + ret = i915_gem_execbuffer_reserve(dev, file, + object_list, exec_list, + args->buffer_count); if (ret) goto err; /* The objects are in their final locations, apply the relocations. */ - for (i = 0; i < args->buffer_count; i++) { - struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]); - obj->base.pending_read_domains = 0; - obj->base.pending_write_domain = 0; - ret = i915_gem_execbuffer_relocate(obj, file, &exec_list[i]); + ret = i915_gem_execbuffer_relocate(dev, file, + object_list, exec_list, + args->buffer_count); + if (ret) { + if (ret == -EFAULT) { + ret = i915_gem_execbuffer_relocate_slow(dev, file, + object_list, + exec_list, + args->buffer_count); + BUG_ON(!mutex_is_locked(&dev->struct_mutex)); + } if (ret) goto err; } @@ -4244,10 +4374,20 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, * use this buffer rather sooner than later, so issuing the required * flush earlier is beneficial. */ - if (obj->write_domain & I915_GEM_GPU_DOMAINS) + if (obj->write_domain & I915_GEM_GPU_DOMAINS) { i915_gem_flush_ring(dev, file_priv, obj_priv->ring, 0, obj->write_domain); + } else if (obj_priv->ring->outstanding_lazy_request) { + /* This ring is not being cleared by active usage, + * so emit a request to do so. + */ + u32 seqno = i915_add_request(dev, + NULL, NULL, + obj_priv->ring); + if (seqno == 0) + ret = -ENOMEM; + } /* Update the active list for the hardware's current position. * Otherwise this only updates on a delayed timer or when irqs diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 25ed911a3112..878fc766a12c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3033,6 +3033,7 @@ #define TRANS_DP_10BPC (1<<9) #define TRANS_DP_6BPC (2<<9) #define TRANS_DP_12BPC (3<<9) +#define TRANS_DP_BPC_MASK (3<<9) #define TRANS_DP_VSYNC_ACTIVE_HIGH (1<<4) #define TRANS_DP_VSYNC_ACTIVE_LOW 0 #define TRANS_DP_HSYNC_ACTIVE_HIGH (1<<3) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 454c064f8ef7..42729d25da58 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -239,6 +239,16 @@ static void i915_save_modeset_reg(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) return; + /* Cursor state */ + dev_priv->saveCURACNTR = I915_READ(CURACNTR); + dev_priv->saveCURAPOS = I915_READ(CURAPOS); + dev_priv->saveCURABASE = I915_READ(CURABASE); + dev_priv->saveCURBCNTR = I915_READ(CURBCNTR); + dev_priv->saveCURBPOS = I915_READ(CURBPOS); + dev_priv->saveCURBBASE = I915_READ(CURBBASE); + if (IS_GEN2(dev)) + dev_priv->saveCURSIZE = I915_READ(CURSIZE); + if (HAS_PCH_SPLIT(dev)) { dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL); dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL); @@ -529,6 +539,16 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); I915_WRITE(DSPBADDR, I915_READ(DSPBADDR)); + /* Cursor state */ + I915_WRITE(CURAPOS, dev_priv->saveCURAPOS); + I915_WRITE(CURACNTR, dev_priv->saveCURACNTR); + I915_WRITE(CURABASE, dev_priv->saveCURABASE); + I915_WRITE(CURBPOS, dev_priv->saveCURBPOS); + I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR); + I915_WRITE(CURBBASE, dev_priv->saveCURBBASE); + if (IS_GEN2(dev)) + I915_WRITE(CURSIZE, dev_priv->saveCURSIZE); + return; } @@ -543,16 +563,6 @@ void i915_save_display(struct drm_device *dev) /* Don't save them in KMS mode */ i915_save_modeset_reg(dev); - /* Cursor state */ - dev_priv->saveCURACNTR = I915_READ(CURACNTR); - dev_priv->saveCURAPOS = I915_READ(CURAPOS); - dev_priv->saveCURABASE = I915_READ(CURABASE); - dev_priv->saveCURBCNTR = I915_READ(CURBCNTR); - dev_priv->saveCURBPOS = I915_READ(CURBPOS); - dev_priv->saveCURBBASE = I915_READ(CURBBASE); - if (IS_GEN2(dev)) - dev_priv->saveCURSIZE = I915_READ(CURSIZE); - /* CRT state */ if (HAS_PCH_SPLIT(dev)) { dev_priv->saveADPA = I915_READ(PCH_ADPA); @@ -657,16 +667,6 @@ void i915_restore_display(struct drm_device *dev) /* Don't restore them in KMS mode */ i915_restore_modeset_reg(dev); - /* Cursor state */ - I915_WRITE(CURAPOS, dev_priv->saveCURAPOS); - I915_WRITE(CURACNTR, dev_priv->saveCURACNTR); - I915_WRITE(CURABASE, dev_priv->saveCURABASE); - I915_WRITE(CURBPOS, dev_priv->saveCURBPOS); - I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR); - I915_WRITE(CURBBASE, dev_priv->saveCURBBASE); - if (IS_GEN2(dev)) - I915_WRITE(CURSIZE, dev_priv->saveCURSIZE); - /* CRT state */ if (HAS_PCH_SPLIT(dev)) I915_WRITE(PCH_ADPA, dev_priv->saveADPA); diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c index 65c88f9ba12c..2cb8e0b9f1ee 100644 --- a/drivers/gpu/drm/i915/intel_acpi.c +++ b/drivers/gpu/drm/i915/intel_acpi.c @@ -190,37 +190,6 @@ out: kfree(output.pointer); } -static int intel_dsm_switchto(enum vga_switcheroo_client_id id) -{ - return 0; -} - -static int intel_dsm_power_state(enum vga_switcheroo_client_id id, - enum vga_switcheroo_state state) -{ - return 0; -} - -static int intel_dsm_init(void) -{ - return 0; -} - -static int intel_dsm_get_client_id(struct pci_dev *pdev) -{ - if (intel_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev)) - return VGA_SWITCHEROO_IGD; - else - return VGA_SWITCHEROO_DIS; -} - -static struct vga_switcheroo_handler intel_dsm_handler = { - .switchto = intel_dsm_switchto, - .power_state = intel_dsm_power_state, - .init = intel_dsm_init, - .get_client_id = intel_dsm_get_client_id, -}; - static bool intel_dsm_pci_probe(struct pci_dev *pdev) { acpi_handle dhandle, intel_handle; @@ -276,11 +245,8 @@ void intel_register_dsm_handler(void) { if (!intel_dsm_detect()) return; - - vga_switcheroo_register_handler(&intel_dsm_handler); } void intel_unregister_dsm_handler(void) { - vga_switcheroo_unregister_handler(); } diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index c55c77043357..8df574316063 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -34,6 +34,25 @@ #include "i915_drm.h" #include "i915_drv.h" +/* Here's the desired hotplug mode */ +#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 | \ + ADPA_CRT_HOTPLUG_WARMUP_10MS | \ + ADPA_CRT_HOTPLUG_SAMPLE_4S | \ + ADPA_CRT_HOTPLUG_VOLTAGE_50 | \ + ADPA_CRT_HOTPLUG_VOLREF_325MV | \ + ADPA_CRT_HOTPLUG_ENABLE) + +struct intel_crt { + struct intel_encoder base; + bool force_hotplug_required; +}; + +static struct intel_crt *intel_attached_crt(struct drm_connector *connector) +{ + return container_of(intel_attached_encoder(connector), + struct intel_crt, base); +} + static void intel_crt_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; @@ -129,7 +148,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); } - adpa = 0; + adpa = ADPA_HOTPLUG_BITS; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) adpa |= ADPA_HSYNC_ACTIVE_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) @@ -157,53 +176,44 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; + struct intel_crt *crt = intel_attached_crt(connector); struct drm_i915_private *dev_priv = dev->dev_private; - u32 adpa, temp; + u32 adpa; bool ret; - bool turn_off_dac = false; - temp = adpa = I915_READ(PCH_ADPA); + /* The first time through, trigger an explicit detection cycle */ + if (crt->force_hotplug_required) { + bool turn_off_dac = HAS_PCH_SPLIT(dev); + u32 save_adpa; - if (HAS_PCH_SPLIT(dev)) - turn_off_dac = true; - - adpa &= ~ADPA_CRT_HOTPLUG_MASK; - if (turn_off_dac) - adpa &= ~ADPA_DAC_ENABLE; - - /* disable HPD first */ - I915_WRITE(PCH_ADPA, adpa); - (void)I915_READ(PCH_ADPA); - - adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 | - ADPA_CRT_HOTPLUG_WARMUP_10MS | - ADPA_CRT_HOTPLUG_SAMPLE_4S | - ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */ - ADPA_CRT_HOTPLUG_VOLREF_325MV | - ADPA_CRT_HOTPLUG_ENABLE | - ADPA_CRT_HOTPLUG_FORCE_TRIGGER); - - DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa); - I915_WRITE(PCH_ADPA, adpa); - - if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, - 1000)) - DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); - - if (turn_off_dac) { - /* Make sure hotplug is enabled */ - I915_WRITE(PCH_ADPA, temp | ADPA_CRT_HOTPLUG_ENABLE); - (void)I915_READ(PCH_ADPA); + crt->force_hotplug_required = 0; + + save_adpa = adpa = I915_READ(PCH_ADPA); + DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); + + adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; + if (turn_off_dac) + adpa &= ~ADPA_DAC_ENABLE; + + I915_WRITE(PCH_ADPA, adpa); + + if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, + 1000)) + DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); + + if (turn_off_dac) { + I915_WRITE(PCH_ADPA, save_adpa); + POSTING_READ(PCH_ADPA); + } } /* Check the status to see if both blue and green are on now */ adpa = I915_READ(PCH_ADPA); - adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK; - if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) || - (adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO)) + if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) ret = true; else ret = false; + DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret); return ret; } @@ -277,13 +287,12 @@ static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus) return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1; } -static bool intel_crt_detect_ddc(struct drm_encoder *encoder) +static bool intel_crt_detect_ddc(struct intel_crt *crt) { - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct drm_i915_private *dev_priv = encoder->dev->dev_private; + struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private; /* CRT should always be at 0, but check anyway */ - if (intel_encoder->type != INTEL_OUTPUT_ANALOG) + if (crt->base.type != INTEL_OUTPUT_ANALOG) return false; if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) { @@ -291,7 +300,7 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder) return true; } - if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) { + if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) { DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); return true; } @@ -300,9 +309,9 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder) } static enum drm_connector_status -intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder) +intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt) { - struct drm_encoder *encoder = &intel_encoder->base; + struct drm_encoder *encoder = &crt->base.base; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -434,7 +443,7 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; - struct intel_encoder *encoder = intel_attached_encoder(connector); + struct intel_crt *crt = intel_attached_crt(connector); struct drm_crtc *crtc; int dpms_mode; enum drm_connector_status status; @@ -443,28 +452,31 @@ intel_crt_detect(struct drm_connector *connector, bool force) if (intel_crt_detect_hotplug(connector)) { DRM_DEBUG_KMS("CRT detected via hotplug\n"); return connector_status_connected; - } else + } else { + DRM_DEBUG_KMS("CRT not detected via hotplug\n"); return connector_status_disconnected; + } } - if (intel_crt_detect_ddc(&encoder->base)) + if (intel_crt_detect_ddc(crt)) return connector_status_connected; if (!force) return connector->status; /* for pre-945g platforms use load detect */ - if (encoder->base.crtc && encoder->base.crtc->enabled) { - status = intel_crt_load_detect(encoder->base.crtc, encoder); + crtc = crt->base.base.crtc; + if (crtc && crtc->enabled) { + status = intel_crt_load_detect(crtc, crt); } else { - crtc = intel_get_load_detect_pipe(encoder, connector, + crtc = intel_get_load_detect_pipe(&crt->base, connector, NULL, &dpms_mode); if (crtc) { - if (intel_crt_detect_ddc(&encoder->base)) + if (intel_crt_detect_ddc(crt)) status = connector_status_connected; else - status = intel_crt_load_detect(crtc, encoder); - intel_release_load_detect_pipe(encoder, + status = intel_crt_load_detect(crtc, crt); + intel_release_load_detect_pipe(&crt->base, connector, dpms_mode); } else status = connector_status_unknown; @@ -536,17 +548,17 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = { void intel_crt_init(struct drm_device *dev) { struct drm_connector *connector; - struct intel_encoder *intel_encoder; + struct intel_crt *crt; struct intel_connector *intel_connector; struct drm_i915_private *dev_priv = dev->dev_private; - intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL); - if (!intel_encoder) + crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL); + if (!crt) return; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(crt); return; } @@ -554,20 +566,20 @@ void intel_crt_init(struct drm_device *dev) drm_connector_init(dev, &intel_connector->base, &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); - drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs, + drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); - intel_connector_attach_encoder(intel_connector, intel_encoder); + intel_connector_attach_encoder(intel_connector, &crt->base); - intel_encoder->type = INTEL_OUTPUT_ANALOG; - intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT) | - (1 << INTEL_SDVO_LVDS_CLONE_BIT); - intel_encoder->crtc_mask = (1 << 0) | (1 << 1); + crt->base.type = INTEL_OUTPUT_ANALOG; + crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT | + 1 << INTEL_ANALOG_CLONE_BIT | + 1 << INTEL_SDVO_LVDS_CLONE_BIT); + crt->base.crtc_mask = (1 << 0) | (1 << 1); connector->interlace_allowed = 1; connector->doublescan_allowed = 0; - drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs); + drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); drm_sysfs_connector_add(connector); @@ -577,5 +589,22 @@ void intel_crt_init(struct drm_device *dev) else connector->polled = DRM_CONNECTOR_POLL_CONNECT; + /* + * Configure the automatic hotplug detection stuff + */ + crt->force_hotplug_required = 0; + if (HAS_PCH_SPLIT(dev)) { + u32 adpa; + + adpa = I915_READ(PCH_ADPA); + adpa &= ~ADPA_CRT_HOTPLUG_MASK; + adpa |= ADPA_HOTPLUG_BITS; + I915_WRITE(PCH_ADPA, adpa); + POSTING_READ(PCH_ADPA); + + DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa); + crt->force_hotplug_required = 1; + } + dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 48d8fd686ea9..d9b7092439ef 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1611,6 +1611,18 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, wait_event(dev_priv->pending_flip_queue, atomic_read(&obj_priv->pending_flip) == 0); + + /* Big Hammer, we also need to ensure that any pending + * MI_WAIT_FOR_EVENT inside a user batch buffer on the + * current scanout is retired before unpinning the old + * framebuffer. + */ + ret = i915_gem_object_flush_gpu(obj_priv, false); + if (ret) { + i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); + mutex_unlock(&dev->struct_mutex); + return ret; + } } ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y, @@ -2108,9 +2120,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) reg = TRANS_DP_CTL(pipe); temp = I915_READ(reg); temp &= ~(TRANS_DP_PORT_SEL_MASK | - TRANS_DP_SYNC_MASK); + TRANS_DP_SYNC_MASK | + TRANS_DP_BPC_MASK); temp |= (TRANS_DP_OUTPUT_ENABLE | TRANS_DP_ENH_FRAMING); + temp |= TRANS_DP_8BPC; if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) temp |= TRANS_DP_HSYNC_ACTIVE_HIGH; @@ -2700,27 +2714,19 @@ fdi_reduce_ratio(u32 *num, u32 *den) } } -#define DATA_N 0x800000 -#define LINK_N 0x80000 - static void ironlake_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock, int link_clock, struct fdi_m_n *m_n) { - u64 temp; - m_n->tu = 64; /* default size */ - temp = (u64) DATA_N * pixel_clock; - temp = div_u64(temp, link_clock); - m_n->gmch_m = div_u64(temp * bits_per_pixel, nlanes); - m_n->gmch_m >>= 3; /* convert to bytes_per_pixel */ - m_n->gmch_n = DATA_N; + /* BUG_ON(pixel_clock > INT_MAX / 36); */ + m_n->gmch_m = bits_per_pixel * pixel_clock; + m_n->gmch_n = link_clock * nlanes * 8; fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); - temp = (u64) LINK_N * pixel_clock; - m_n->link_m = div_u64(temp, link_clock); - m_n->link_n = LINK_N; + m_n->link_m = pixel_clock; + m_n->link_n = link_clock; fdi_reduce_ratio(&m_n->link_m, &m_n->link_n); } @@ -3704,6 +3710,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* FDI link */ if (HAS_PCH_SPLIT(dev)) { + int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode); int lane = 0, link_bw, bpp; /* CPU eDP doesn't require FDI link, so just set DP M/N according to current link config */ @@ -3787,6 +3794,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, intel_crtc->fdi_lanes = lane; + if (pixel_multiplier > 1) + link_bw *= pixel_multiplier; ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n); } @@ -5224,6 +5233,55 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { .page_flip = intel_crtc_page_flip, }; +static void intel_sanitize_modesetting(struct drm_device *dev, + int pipe, int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg, val; + + if (HAS_PCH_SPLIT(dev)) + return; + + /* Who knows what state these registers were left in by the BIOS or + * grub? + * + * If we leave the registers in a conflicting state (e.g. with the + * display plane reading from the other pipe than the one we intend + * to use) then when we attempt to teardown the active mode, we will + * not disable the pipes and planes in the correct order -- leaving + * a plane reading from a disabled pipe and possibly leading to + * undefined behaviour. + */ + + reg = DSPCNTR(plane); + val = I915_READ(reg); + + if ((val & DISPLAY_PLANE_ENABLE) == 0) + return; + if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe) + return; + + /* This display plane is active and attached to the other CPU pipe. */ + pipe = !pipe; + + /* Disable the plane and wait for it to stop reading from the pipe. */ + I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE); + intel_flush_display_plane(dev, plane); + + if (IS_GEN2(dev)) + intel_wait_for_vblank(dev, pipe); + + if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) + return; + + /* Switch off the pipe. */ + reg = PIPECONF(pipe); + val = I915_READ(reg); + if (val & PIPECONF_ENABLE) { + I915_WRITE(reg, val & ~PIPECONF_ENABLE); + intel_wait_for_pipe_off(dev, pipe); + } +} static void intel_crtc_init(struct drm_device *dev, int pipe) { @@ -5275,6 +5333,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer, (unsigned long)intel_crtc); + + intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane); } int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, @@ -5324,9 +5384,14 @@ static void intel_setup_outputs(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *encoder; bool dpd_is_edp = false; + bool has_lvds = false; if (IS_MOBILE(dev) && !IS_I830(dev)) - intel_lvds_init(dev); + has_lvds = intel_lvds_init(dev); + if (!has_lvds && !HAS_PCH_SPLIT(dev)) { + /* disable the panel fitter on everything but LVDS */ + I915_WRITE(PFIT_CONTROL, 0); + } if (HAS_PCH_SPLIT(dev)) { dpd_is_edp = intel_dpd_is_edp(dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c8e005553310..df648cb4c296 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -584,17 +584,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, mode->clock = dev_priv->panel_fixed_mode->clock; } - /* Just use VBT values for eDP */ - if (is_edp(intel_dp)) { - intel_dp->lane_count = dev_priv->edp.lanes; - intel_dp->link_bw = dev_priv->edp.rate; - adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw); - DRM_DEBUG_KMS("eDP link bw %02x lane count %d clock %d\n", - intel_dp->link_bw, intel_dp->lane_count, - adjusted_mode->clock); - return true; - } - for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { for (clock = 0; clock <= max_clock; clock++) { int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); @@ -613,6 +602,19 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, } } + if (is_edp(intel_dp)) { + /* okay we failed just pick the highest */ + intel_dp->lane_count = max_lane_count; + intel_dp->link_bw = bws[max_clock]; + adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw); + DRM_DEBUG_KMS("Force picking display port link bw %02x lane " + "count %d clock %d\n", + intel_dp->link_bw, intel_dp->lane_count, + adjusted_mode->clock); + + return true; + } + return false; } @@ -1087,21 +1089,11 @@ intel_get_adjust_train(struct intel_dp *intel_dp) } static uint32_t -intel_dp_signal_levels(struct intel_dp *intel_dp) +intel_dp_signal_levels(uint8_t train_set, int lane_count) { - struct drm_device *dev = intel_dp->base.base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t signal_levels = 0; - u8 train_set = intel_dp->train_set[0]; - u32 vswing = train_set & DP_TRAIN_VOLTAGE_SWING_MASK; - u32 preemphasis = train_set & DP_TRAIN_PRE_EMPHASIS_MASK; + uint32_t signal_levels = 0; - if (is_edp(intel_dp)) { - vswing = dev_priv->edp.vswing; - preemphasis = dev_priv->edp.preemphasis; - } - - switch (vswing) { + switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) { case DP_TRAIN_VOLTAGE_SWING_400: default: signal_levels |= DP_VOLTAGE_0_4; @@ -1116,7 +1108,7 @@ intel_dp_signal_levels(struct intel_dp *intel_dp) signal_levels |= DP_VOLTAGE_1_2; break; } - switch (preemphasis) { + switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) { case DP_TRAIN_PRE_EMPHASIS_0: default: signal_levels |= DP_PRE_EMPHASIS_0; @@ -1203,18 +1195,6 @@ intel_channel_eq_ok(struct intel_dp *intel_dp) } static bool -intel_dp_aux_handshake_required(struct intel_dp *intel_dp) -{ - struct drm_device *dev = intel_dp->base.base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - if (is_edp(intel_dp) && dev_priv->no_aux_handshake) - return false; - - return true; -} - -static bool intel_dp_set_link_train(struct intel_dp *intel_dp, uint32_t dp_reg_value, uint8_t dp_train_pat) @@ -1226,9 +1206,6 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, I915_WRITE(intel_dp->output_reg, dp_reg_value); POSTING_READ(intel_dp->output_reg); - if (!intel_dp_aux_handshake_required(intel_dp)) - return true; - intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET, dp_train_pat); @@ -1261,11 +1238,10 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) POSTING_READ(intel_dp->output_reg); intel_wait_for_vblank(dev, intel_crtc->pipe); - if (intel_dp_aux_handshake_required(intel_dp)) - /* Write the link configuration data */ - intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, - intel_dp->link_configuration, - DP_LINK_CONFIGURATION_SIZE); + /* Write the link configuration data */ + intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, + intel_dp->link_configuration, + DP_LINK_CONFIGURATION_SIZE); DP |= DP_PORT_EN; if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) @@ -1283,7 +1259,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(intel_dp); + signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } @@ -1297,37 +1273,33 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) break; /* Set training pattern 1 */ - udelay(500); - if (intel_dp_aux_handshake_required(intel_dp)) { + udelay(100); + if (!intel_dp_get_link_status(intel_dp)) + break; + + if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) { + clock_recovery = true; break; - } else { - if (!intel_dp_get_link_status(intel_dp)) - break; + } - if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) { - clock_recovery = true; + /* Check to see if we've tried the max voltage */ + for (i = 0; i < intel_dp->lane_count; i++) + if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) break; - } + if (i == intel_dp->lane_count) + break; - /* Check to see if we've tried the max voltage */ - for (i = 0; i < intel_dp->lane_count; i++) - if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) - break; - if (i == intel_dp->lane_count) + /* Check to see if we've tried the same voltage 5 times */ + if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { + ++tries; + if (tries == 5) break; + } else + tries = 0; + voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; - /* Check to see if we've tried the same voltage 5 times */ - if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { - ++tries; - if (tries == 5) - break; - } else - tries = 0; - voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; - - /* Compute new intel_dp->train_set as requested by target */ - intel_get_adjust_train(intel_dp); - } + /* Compute new intel_dp->train_set as requested by target */ + intel_get_adjust_train(intel_dp); } intel_dp->DP = DP; @@ -1354,7 +1326,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(intel_dp); + signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } @@ -1368,28 +1340,24 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) DP_TRAINING_PATTERN_2)) break; - udelay(500); - - if (!intel_dp_aux_handshake_required(intel_dp)) { + udelay(400); + if (!intel_dp_get_link_status(intel_dp)) break; - } else { - if (!intel_dp_get_link_status(intel_dp)) - break; - if (intel_channel_eq_ok(intel_dp)) { - channel_eq = true; - break; - } + if (intel_channel_eq_ok(intel_dp)) { + channel_eq = true; + break; + } - /* Try 5 times */ - if (tries > 5) - break; + /* Try 5 times */ + if (tries > 5) + break; - /* Compute new intel_dp->train_set as requested by target */ - intel_get_adjust_train(intel_dp); - ++tries; - } + /* Compute new intel_dp->train_set as requested by target */ + intel_get_adjust_train(intel_dp); + ++tries; } + if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) reg = DP | DP_LINK_TRAIN_OFF_CPT; else @@ -1408,6 +1376,9 @@ intel_dp_link_down(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t DP = intel_dp->DP; + if ((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0) + return; + DRM_DEBUG_KMS("\n"); if (is_edp(intel_dp)) { @@ -1430,6 +1401,28 @@ intel_dp_link_down(struct intel_dp *intel_dp) if (is_edp(intel_dp)) DP |= DP_LINK_TRAIN_OFF; + + if (!HAS_PCH_CPT(dev) && + I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) { + struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc); + /* Hardware workaround: leaving our transcoder select + * set to transcoder B while it's off will prevent the + * corresponding HDMI output on transcoder A. + * + * Combine this with another hardware workaround: + * transcoder select bit can only be cleared while the + * port is enabled. + */ + DP &= ~DP_PIPEB_SELECT; + I915_WRITE(intel_dp->output_reg, DP); + + /* Changes to enable or select take place the vblank + * after being written. + */ + intel_wait_for_vblank(intel_dp->base.base.dev, + intel_crtc->pipe); + } + I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); POSTING_READ(intel_dp->output_reg); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 21551fe74541..e52c6125bb1f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -237,7 +237,7 @@ extern bool intel_sdvo_init(struct drm_device *dev, int output_device); extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); extern void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj); -extern void intel_lvds_init(struct drm_device *dev); +extern bool intel_lvds_init(struct drm_device *dev); extern void intel_dp_init(struct drm_device *dev, int dp_reg); void intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 2be4f728ed0c..3dba086e7eea 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -160,7 +160,7 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin) }; struct intel_gpio *gpio; - if (pin < 1 || pin > 7) + if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin]) return NULL; gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL); @@ -172,7 +172,8 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin) gpio->reg += PCH_GPIOA - GPIOA; gpio->dev_priv = dev_priv; - snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO%c", "?BACDEF?"[pin]); + snprintf(gpio->adapter.name, sizeof(gpio->adapter.name), + "i915 GPIO%c", "?BACDE?F"[pin]); gpio->adapter.owner = THIS_MODULE; gpio->adapter.algo_data = &gpio->algo; gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev; @@ -349,7 +350,7 @@ int intel_setup_gmbus(struct drm_device *dev) "panel", "dpc", "dpb", - "reserved" + "reserved", "dpd", }; struct drm_i915_private *dev_priv = dev->dev_private; @@ -366,8 +367,8 @@ int intel_setup_gmbus(struct drm_device *dev) bus->adapter.owner = THIS_MODULE; bus->adapter.class = I2C_CLASS_DDC; snprintf(bus->adapter.name, - I2C_NAME_SIZE, - "gmbus %s", + sizeof(bus->adapter.name), + "i915 gmbus %s", names[i]); bus->adapter.dev.parent = &dev->pdev->dev; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 4324a326f98e..25bcedf386fd 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -68,7 +68,7 @@ static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector) /** * Sets the power state for the panel. */ -static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on) +static void intel_lvds_enable(struct intel_lvds *intel_lvds) { struct drm_device *dev = intel_lvds->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -82,26 +82,61 @@ static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on) lvds_reg = LVDS; } - if (on) { - I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); - I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); - intel_panel_set_backlight(dev, dev_priv->backlight_level); - } else { - dev_priv->backlight_level = intel_panel_get_backlight(dev); - - intel_panel_set_backlight(dev, 0); - I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); + I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); - if (intel_lvds->pfit_control) { - if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) - DRM_ERROR("timed out waiting for panel to power off\n"); - I915_WRITE(PFIT_CONTROL, 0); - intel_lvds->pfit_control = 0; + if (intel_lvds->pfit_dirty) { + /* + * Enable automatic panel scaling so that non-native modes + * fill the screen. The panel fitter should only be + * adjusted whilst the pipe is disabled, according to + * register description and PRM. + */ + DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", + intel_lvds->pfit_control, + intel_lvds->pfit_pgm_ratios); + if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) { + DRM_ERROR("timed out waiting for panel to power off\n"); + } else { + I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); + I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); intel_lvds->pfit_dirty = false; } + } + + I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); + POSTING_READ(lvds_reg); + + intel_panel_set_backlight(dev, dev_priv->backlight_level); +} + +static void intel_lvds_disable(struct intel_lvds *intel_lvds) +{ + struct drm_device *dev = intel_lvds->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 ctl_reg, lvds_reg; + + if (HAS_PCH_SPLIT(dev)) { + ctl_reg = PCH_PP_CONTROL; + lvds_reg = PCH_LVDS; + } else { + ctl_reg = PP_CONTROL; + lvds_reg = LVDS; + } + + dev_priv->backlight_level = intel_panel_get_backlight(dev); + intel_panel_set_backlight(dev, 0); + + I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); + + if (intel_lvds->pfit_control) { + if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) + DRM_ERROR("timed out waiting for panel to power off\n"); - I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); + I915_WRITE(PFIT_CONTROL, 0); + intel_lvds->pfit_dirty = true; } + + I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); POSTING_READ(lvds_reg); } @@ -110,9 +145,9 @@ static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) struct intel_lvds *intel_lvds = to_intel_lvds(encoder); if (mode == DRM_MODE_DPMS_ON) - intel_lvds_set_power(intel_lvds, true); + intel_lvds_enable(intel_lvds); else - intel_lvds_set_power(intel_lvds, false); + intel_lvds_disable(intel_lvds); /* XXX: We never power down the LVDS pairs. */ } @@ -411,43 +446,18 @@ static void intel_lvds_commit(struct drm_encoder *encoder) /* Always do a full power on as we do not know what state * we were left in. */ - intel_lvds_set_power(intel_lvds, true); + intel_lvds_enable(intel_lvds); } static void intel_lvds_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = encoder->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_lvds *intel_lvds = to_intel_lvds(encoder); - /* * The LVDS pin pair will already have been turned on in the * intel_crtc_mode_set since it has a large impact on the DPLL * settings. */ - - if (HAS_PCH_SPLIT(dev)) - return; - - if (!intel_lvds->pfit_dirty) - return; - - /* - * Enable automatic panel scaling so that non-native modes fill the - * screen. Should be enabled before the pipe is enabled, according to - * register description and PRM. - */ - DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", - intel_lvds->pfit_control, - intel_lvds->pfit_pgm_ratios); - if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) - DRM_ERROR("timed out waiting for panel to power off\n"); - - I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); - I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); - intel_lvds->pfit_dirty = false; } /** @@ -837,7 +847,7 @@ static bool intel_lvds_ddc_probe(struct drm_device *dev, u8 pin) * Create the connector, register the LVDS DDC bus, and try to figure out what * modes we can display on the LVDS panel (if present). */ -void intel_lvds_init(struct drm_device *dev) +bool intel_lvds_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_lvds *intel_lvds; @@ -853,37 +863,37 @@ void intel_lvds_init(struct drm_device *dev) /* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) - return; + return false; pin = GMBUS_PORT_PANEL; if (!lvds_is_present_in_vbt(dev, &pin)) { DRM_DEBUG_KMS("LVDS is not present in VBT\n"); - return; + return false; } if (HAS_PCH_SPLIT(dev)) { if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) - return; + return false; if (dev_priv->edp.support) { DRM_DEBUG_KMS("disable LVDS for eDP support\n"); - return; + return false; } } if (!intel_lvds_ddc_probe(dev, pin)) { DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n"); - return; + return false; } intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL); if (!intel_lvds) { - return; + return false; } intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { kfree(intel_lvds); - return; + return false; } if (!HAS_PCH_SPLIT(dev)) { @@ -1026,7 +1036,7 @@ out: /* keep the LVDS connector */ dev_priv->int_lvds_connector = connector; drm_sysfs_connector_add(connector); - return; + return true; failed: DRM_DEBUG_KMS("No LVDS modes found, disabling.\n"); @@ -1034,4 +1044,5 @@ failed: drm_encoder_cleanup(encoder); kfree(intel_lvds); kfree(intel_connector); + return false; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b83306f9244b..89a65be8a3f3 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -156,23 +156,25 @@ static int init_ring_common(struct drm_device *dev, /* G45 ring initialization fails to reset head to zero */ if (head != 0) { - DRM_ERROR("%s head not reset to zero " - "ctl %08x head %08x tail %08x start %08x\n", - ring->name, - I915_READ_CTL(ring), - I915_READ_HEAD(ring), - I915_READ_TAIL(ring), - I915_READ_START(ring)); + DRM_DEBUG_KMS("%s head not reset to zero " + "ctl %08x head %08x tail %08x start %08x\n", + ring->name, + I915_READ_CTL(ring), + I915_READ_HEAD(ring), + I915_READ_TAIL(ring), + I915_READ_START(ring)); I915_WRITE_HEAD(ring, 0); - DRM_ERROR("%s head forced to zero " - "ctl %08x head %08x tail %08x start %08x\n", - ring->name, - I915_READ_CTL(ring), - I915_READ_HEAD(ring), - I915_READ_TAIL(ring), - I915_READ_START(ring)); + if (I915_READ_HEAD(ring) & HEAD_ADDR) { + DRM_ERROR("failed to set %s head to zero " + "ctl %08x head %08x tail %08x start %08x\n", + ring->name, + I915_READ_CTL(ring), + I915_READ_HEAD(ring), + I915_READ_TAIL(ring), + I915_READ_START(ring)); + } } I915_WRITE_CTL(ring, diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index de158b76bcd5..d97e6cb52d34 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -107,7 +107,8 @@ struct intel_sdvo { * This is set if we treat the device as HDMI, instead of DVI. */ bool is_hdmi; - bool has_audio; + bool has_hdmi_monitor; + bool has_hdmi_audio; /** * This is set if we detect output of sdvo device as LVDS and @@ -1023,7 +1024,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, if (!intel_sdvo_set_target_input(intel_sdvo)) return; - if (intel_sdvo->is_hdmi && + if (intel_sdvo->has_hdmi_monitor && !intel_sdvo_set_avi_infoframe(intel_sdvo)) return; @@ -1063,7 +1064,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, } if (intel_crtc->pipe == 1) sdvox |= SDVO_PIPE_B_SELECT; - if (intel_sdvo->has_audio) + if (intel_sdvo->has_hdmi_audio) sdvox |= SDVO_AUDIO_ENABLE; if (INTEL_INFO(dev)->gen >= 4) { @@ -1295,55 +1296,14 @@ intel_sdvo_get_edid(struct drm_connector *connector) return drm_get_edid(connector, &sdvo->ddc); } -static struct drm_connector * -intel_find_analog_connector(struct drm_device *dev) -{ - struct drm_connector *connector; - struct intel_sdvo *encoder; - - list_for_each_entry(encoder, - &dev->mode_config.encoder_list, - base.base.head) { - if (encoder->base.type == INTEL_OUTPUT_ANALOG) { - list_for_each_entry(connector, - &dev->mode_config.connector_list, - head) { - if (&encoder->base == - intel_attached_encoder(connector)) - return connector; - } - } - } - - return NULL; -} - -static int -intel_analog_is_connected(struct drm_device *dev) -{ - struct drm_connector *analog_connector; - - analog_connector = intel_find_analog_connector(dev); - if (!analog_connector) - return false; - - if (analog_connector->funcs->detect(analog_connector, false) == - connector_status_disconnected) - return false; - - return true; -} - /* Mac mini hack -- use the same DDC as the analog connector */ static struct edid * intel_sdvo_get_analog_edid(struct drm_connector *connector) { struct drm_i915_private *dev_priv = connector->dev->dev_private; - if (!intel_analog_is_connected(connector->dev)) - return NULL; - - return drm_get_edid(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter); + return drm_get_edid(connector, + &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter); } enum drm_connector_status @@ -1388,8 +1348,10 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) /* DDC bus is shared, match EDID to connector type */ if (edid->input & DRM_EDID_INPUT_DIGITAL) { status = connector_status_connected; - intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid); - intel_sdvo->has_audio = drm_detect_monitor_audio(edid); + if (intel_sdvo->is_hdmi) { + intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); + intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); + } } connector->display_info.raw_edid = NULL; kfree(edid); @@ -1398,7 +1360,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) if (status == connector_status_connected) { struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); if (intel_sdvo_connector->force_audio) - intel_sdvo->has_audio = intel_sdvo_connector->force_audio > 0; + intel_sdvo->has_hdmi_audio = intel_sdvo_connector->force_audio > 0; } return status; @@ -1415,10 +1377,12 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0)) return connector_status_unknown; - if (intel_sdvo->is_tv) { - /* add 30ms delay when the output type is SDVO-TV */ + + /* add 30ms delay when the output type might be TV */ + if (intel_sdvo->caps.output_flags & + (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_CVBS0)) mdelay(30); - } + if (!intel_sdvo_read_response(intel_sdvo, &response, 2)) return connector_status_unknown; @@ -1472,8 +1436,10 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) edid = intel_sdvo_get_analog_edid(connector); if (edid != NULL) { - drm_mode_connector_update_edid_property(connector, edid); - drm_add_edid_modes(connector, edid); + if (edid->input & DRM_EDID_INPUT_DIGITAL) { + drm_mode_connector_update_edid_property(connector, edid); + drm_add_edid_modes(connector, edid); + } connector->display_info.raw_edid = NULL; kfree(edid); } @@ -1713,12 +1679,12 @@ intel_sdvo_set_property(struct drm_connector *connector, intel_sdvo_connector->force_audio = val; - if (val > 0 && intel_sdvo->has_audio) + if (val > 0 && intel_sdvo->has_hdmi_audio) return 0; - if (val < 0 && !intel_sdvo->has_audio) + if (val < 0 && !intel_sdvo->has_hdmi_audio) return 0; - intel_sdvo->has_audio = val > 0; + intel_sdvo->has_hdmi_audio = val > 0; goto done; } @@ -2070,6 +2036,8 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_set_colorimetry(intel_sdvo, SDVO_COLORIMETRY_RGB256); connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; + + intel_sdvo_add_hdmi_properties(intel_sdvo_connector); intel_sdvo->is_hdmi = true; } intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | @@ -2077,8 +2045,6 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); - intel_sdvo_add_hdmi_properties(intel_sdvo_connector); - return true; } diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 406228f4a2a0..b14c81110575 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -31,6 +31,7 @@ */ #include <linux/backlight.h> +#include <linux/acpi.h> #include "drmP.h" #include "nouveau_drv.h" @@ -136,6 +137,14 @@ int nouveau_backlight_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; +#ifdef CONFIG_ACPI + if (acpi_video_backlight_support()) { + NV_INFO(dev, "ACPI backlight interface available, " + "not registering our own\n"); + return 0; + } +#endif + switch (dev_priv->card_type) { case NV_40: return nouveau_nv40_backlight_init(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 5f21030a293b..b2293576f278 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6829,7 +6829,7 @@ nouveau_bios_posted(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; unsigned htotal; - if (dev_priv->chipset >= NV_50) { + if (dev_priv->card_type >= NV_50) { if (NVReadVgaCrtc(dev, 0, 0x00) == 0 && NVReadVgaCrtc(dev, 0, 0x1a) == 0) return false; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 80353e2b8409..c41e1c200ef5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -143,8 +143,10 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, nvbo->no_vm = no_vm; nvbo->tile_mode = tile_mode; nvbo->tile_flags = tile_flags; + nvbo->bo.bdev = &dev_priv->ttm.bdev; - nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size); + nouveau_bo_fixup_align(dev, tile_mode, nouveau_bo_tile_layout(nvbo), + &align, &size); align >>= PAGE_SHIFT; nouveau_bo_placement_set(nvbo, flags, 0); @@ -176,6 +178,31 @@ set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags) pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags; } +static void +set_placement_range(struct nouveau_bo *nvbo, uint32_t type) +{ + struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); + + if (dev_priv->card_type == NV_10 && + nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) { + /* + * Make sure that the color and depth buffers are handled + * by independent memory controller units. Up to a 9x + * speed up when alpha-blending and depth-test are enabled + * at the same time. + */ + int vram_pages = dev_priv->vram_size >> PAGE_SHIFT; + + if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) { + nvbo->placement.fpfn = vram_pages / 2; + nvbo->placement.lpfn = ~0; + } else { + nvbo->placement.fpfn = 0; + nvbo->placement.lpfn = vram_pages / 2; + } + } +} + void nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy) { @@ -190,6 +217,8 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy) pl->busy_placement = nvbo->busy_placements; set_placement_list(nvbo->busy_placements, &pl->num_busy_placement, type | busy, flags); + + set_placement_range(nvbo, type); } int @@ -525,7 +554,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, stride = 16 * 4; height = amount / stride; - if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) { + if (new_mem->mem_type == TTM_PL_VRAM && + nouveau_bo_tile_layout(nvbo)) { ret = RING_SPACE(chan, 8); if (ret) return ret; @@ -546,7 +576,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, BEGIN_RING(chan, NvSubM2MF, 0x0200, 1); OUT_RING (chan, 1); } - if (old_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) { + if (old_mem->mem_type == TTM_PL_VRAM && + nouveau_bo_tile_layout(nvbo)) { ret = RING_SPACE(chan, 8); if (ret) return ret; @@ -753,7 +784,8 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem, if (dev_priv->card_type == NV_50) { ret = nv50_mem_vm_bind_linear(dev, offset + dev_priv->vm_vram_base, - new_mem->size, nvbo->tile_flags, + new_mem->size, + nouveau_bo_tile_layout(nvbo), offset); if (ret) return ret; @@ -894,7 +926,8 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) * nothing to do here. */ if (bo->mem.mem_type != TTM_PL_VRAM) { - if (dev_priv->card_type < NV_50 || !nvbo->tile_flags) + if (dev_priv->card_type < NV_50 || + !nouveau_bo_tile_layout(nvbo)) return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 0871495096fa..52c356e9a3d1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -281,7 +281,7 @@ detect_analog: nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); if (!nv_encoder && !nouveau_tv_disable) nv_encoder = find_encoder_by_type(connector, OUTPUT_TV); - if (nv_encoder) { + if (nv_encoder && force) { struct drm_encoder *encoder = to_drm_encoder(nv_encoder); struct drm_encoder_helper_funcs *helper = encoder->helper_private; @@ -641,11 +641,28 @@ nouveau_connector_get_modes(struct drm_connector *connector) return ret; } +static unsigned +get_tmds_link_bandwidth(struct drm_connector *connector) +{ + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct drm_nouveau_private *dev_priv = connector->dev->dev_private; + struct dcb_entry *dcb = nv_connector->detected_encoder->dcb; + + if (dcb->location != DCB_LOC_ON_CHIP || + dev_priv->chipset >= 0x46) + return 165000; + else if (dev_priv->chipset >= 0x40) + return 155000; + else if (dev_priv->chipset >= 0x18) + return 135000; + else + return 112000; +} + static int nouveau_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct drm_nouveau_private *dev_priv = connector->dev->dev_private; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct drm_encoder *encoder = to_drm_encoder(nv_encoder); @@ -663,11 +680,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector, max_clock = 400000; break; case OUTPUT_TMDS: - if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) || - !nv_encoder->dcb->duallink_possible) - max_clock = 165000; - else - max_clock = 330000; + max_clock = get_tmds_link_bandwidth(connector); + if (nouveau_duallink && nv_encoder->dcb->duallink_possible) + max_clock *= 2; break; case OUTPUT_ANALOG: max_clock = nv_encoder->dcb->crtconf.maxfreq; @@ -709,44 +724,6 @@ nouveau_connector_best_encoder(struct drm_connector *connector) return NULL; } -void -nouveau_connector_set_polling(struct drm_connector *connector) -{ - struct drm_device *dev = connector->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - bool spare_crtc = false; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - spare_crtc |= !crtc->enabled; - - connector->polled = 0; - - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_VGA: - case DRM_MODE_CONNECTOR_TV: - if (dev_priv->card_type >= NV_50 || - (nv_gf4_disp_arch(dev) && spare_crtc)) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - break; - - case DRM_MODE_CONNECTOR_DVII: - case DRM_MODE_CONNECTOR_DVID: - case DRM_MODE_CONNECTOR_HDMIA: - case DRM_MODE_CONNECTOR_DisplayPort: - case DRM_MODE_CONNECTOR_eDP: - if (dev_priv->card_type >= NV_50) - connector->polled = DRM_CONNECTOR_POLL_HPD; - else if (connector->connector_type == DRM_MODE_CONNECTOR_DVID || - spare_crtc) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - break; - - default: - break; - } -} - static const struct drm_connector_helper_funcs nouveau_connector_helper_funcs = { .get_modes = nouveau_connector_get_modes, @@ -872,6 +849,7 @@ nouveau_connector_create(struct drm_device *dev, int index) dev->mode_config.scaling_mode_property, nv_connector->scaling_mode); } + connector->polled = DRM_CONNECTOR_POLL_CONNECT; /* fall-through */ case DCB_CONNECTOR_TV_0: case DCB_CONNECTOR_TV_1: @@ -888,11 +866,16 @@ nouveau_connector_create(struct drm_device *dev, int index) dev->mode_config.dithering_mode_property, nv_connector->use_dithering ? DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); + + if (dcb->type != DCB_CONNECTOR_LVDS) { + if (dev_priv->card_type >= NV_50) + connector->polled = DRM_CONNECTOR_POLL_HPD; + else + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + } break; } - nouveau_connector_set_polling(connector); - drm_sysfs_connector_add(connector); dcb->drm = connector; return dcb->drm; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index c21ed6b16f88..711b1e9203af 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -52,9 +52,6 @@ static inline struct nouveau_connector *nouveau_connector( struct drm_connector * nouveau_connector_create(struct drm_device *, int index); -void -nouveau_connector_set_polling(struct drm_connector *); - int nouveau_connector_bpp(struct drm_connector *); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 3a07e580d27a..1c7db64c03bf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -100,6 +100,9 @@ struct nouveau_bo { int pin_refcnt; }; +#define nouveau_bo_tile_layout(nvbo) \ + ((nvbo)->tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) + static inline struct nouveau_bo * nouveau_bo(struct ttm_buffer_object *bo) { @@ -304,6 +307,7 @@ struct nouveau_fifo_engine { void (*destroy_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *); int (*unload_context)(struct drm_device *); + void (*tlb_flush)(struct drm_device *dev); }; struct nouveau_pgraph_object_method { @@ -336,6 +340,7 @@ struct nouveau_pgraph_engine { void (*destroy_context)(struct nouveau_channel *); int (*load_context)(struct nouveau_channel *); int (*unload_context)(struct drm_device *); + void (*tlb_flush)(struct drm_device *dev); void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, uint32_t size, uint32_t pitch); @@ -485,13 +490,13 @@ enum nv04_fp_display_regs { }; struct nv04_crtc_reg { - unsigned char MiscOutReg; /* */ + unsigned char MiscOutReg; uint8_t CRTC[0xa0]; uint8_t CR58[0x10]; uint8_t Sequencer[5]; uint8_t Graphics[9]; uint8_t Attribute[21]; - unsigned char DAC[768]; /* Internal Colorlookuptable */ + unsigned char DAC[768]; /* PCRTC regs */ uint32_t fb_start; @@ -539,43 +544,9 @@ struct nv04_output_reg { }; struct nv04_mode_state { - uint32_t bpp; - uint32_t width; - uint32_t height; - uint32_t interlace; - uint32_t repaint0; - uint32_t repaint1; - uint32_t screen; - uint32_t scale; - uint32_t dither; - uint32_t extra; - uint32_t fifo; - uint32_t pixel; - uint32_t horiz; - int arbitration0; - int arbitration1; - uint32_t pll; - uint32_t pllB; - uint32_t vpll; - uint32_t vpll2; - uint32_t vpllB; - uint32_t vpll2B; + struct nv04_crtc_reg crtc_reg[2]; uint32_t pllsel; uint32_t sel_clk; - uint32_t general; - uint32_t crtcOwner; - uint32_t head; - uint32_t head2; - uint32_t cursorConfig; - uint32_t cursor0; - uint32_t cursor1; - uint32_t cursor2; - uint32_t timingH; - uint32_t timingV; - uint32_t displayV; - uint32_t crtcSync; - - struct nv04_crtc_reg crtc_reg[2]; }; enum nouveau_card_type { @@ -613,6 +584,12 @@ struct drm_nouveau_private { struct work_struct irq_work; struct work_struct hpd_work; + struct { + spinlock_t lock; + uint32_t hpd0_bits; + uint32_t hpd1_bits; + } hpd_state; + struct list_head vbl_waiting; struct { @@ -1045,6 +1022,7 @@ extern int nv50_fifo_create_context(struct nouveau_channel *); extern void nv50_fifo_destroy_context(struct nouveau_channel *); extern int nv50_fifo_load_context(struct nouveau_channel *); extern int nv50_fifo_unload_context(struct drm_device *); +extern void nv50_fifo_tlb_flush(struct drm_device *dev); /* nvc0_fifo.c */ extern int nvc0_fifo_init(struct drm_device *); @@ -1122,6 +1100,8 @@ extern int nv50_graph_load_context(struct nouveau_channel *); extern int nv50_graph_unload_context(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); +extern void nv50_graph_tlb_flush(struct drm_device *dev); +extern void nv86_graph_tlb_flush(struct drm_device *dev); /* nvc0_graph.c */ extern int nvc0_graph_init(struct drm_device *); @@ -1239,7 +1219,6 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val); extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val); -extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *); /* nouveau_fence.c */ struct nouveau_fence; diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 441b12420bb1..ab1bbfbf266e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -249,6 +249,7 @@ alloc_semaphore(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_semaphore *sema; + int ret; if (!USE_SEMA(dev)) return NULL; @@ -257,10 +258,14 @@ alloc_semaphore(struct drm_device *dev) if (!sema) goto fail; + ret = drm_mm_pre_get(&dev_priv->fence.heap); + if (ret) + goto fail; + spin_lock(&dev_priv->fence.lock); sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0); if (sema->mem) - sema->mem = drm_mm_get_block(sema->mem, 4, 0); + sema->mem = drm_mm_get_block_atomic(sema->mem, 4, 0); spin_unlock(&dev_priv->fence.lock); if (!sema->mem) diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 5c4c929d7f74..9a1fdcf400c2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -107,23 +107,29 @@ nouveau_gem_info(struct drm_gem_object *gem, struct drm_nouveau_gem_info *rep) } static bool -nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) { - switch (tile_flags) { - case 0x0000: - case 0x1800: - case 0x2800: - case 0x4800: - case 0x7000: - case 0x7400: - case 0x7a00: - case 0xe000: - break; - default: - NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags); - return false; +nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->card_type >= NV_50) { + switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) { + case 0x0000: + case 0x1800: + case 0x2800: + case 0x4800: + case 0x7000: + case 0x7400: + case 0x7a00: + case 0xe000: + return true; + } + } else { + if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)) + return true; } - return true; + NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags); + return false; } int diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c index bed669a54a2d..b9672a05c411 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.c +++ b/drivers/gpu/drm/nouveau/nouveau_hw.c @@ -519,11 +519,11 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head) struct pll_lims pll_lim; struct nouveau_pll_vals pv; - uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF; + enum pll_types pll = head ? PLL_VPLL1 : PLL_VPLL0; - if (get_pll_limits(dev, pllreg, &pll_lim)) + if (get_pll_limits(dev, pll, &pll_lim)) return; - nouveau_hw_get_pllvals(dev, pllreg, &pv); + nouveau_hw_get_pllvals(dev, pll, &pv); if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m && pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n && @@ -536,7 +536,7 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head) pv.M1 = pll_lim.vco1.max_m; pv.N1 = pll_lim.vco1.min_n; pv.log2P = pll_lim.max_usable_log2p; - nouveau_hw_setpll(dev, pllreg, &pv); + nouveau_hw_setpll(dev, pll_lim.reg, &pv); } /* diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.h b/drivers/gpu/drm/nouveau/nouveau_hw.h index 869130f83602..2989090b9434 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.h +++ b/drivers/gpu/drm/nouveau/nouveau_hw.h @@ -416,6 +416,25 @@ nv_fix_nv40_hw_cursor(struct drm_device *dev, int head) } static inline void +nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + NVWriteCRTC(dev, head, NV_PCRTC_START, offset); + + if (dev_priv->card_type == NV_04) { + /* + * Hilarious, the 24th bit doesn't want to stick to + * PCRTC_START... + */ + int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX); + + NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX, + (cre_heb & ~0x40) | ((offset >> 18) & 0x40)); + } +} + +static inline void nv_show_cursor(struct drm_device *dev, int head, bool show) { struct drm_nouveau_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index fdd7e3de79c8..cb389d014326 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -256,7 +256,7 @@ nouveau_i2c_find(struct drm_device *dev, int index) if (index >= DCB_MAX_NUM_I2C_ENTRIES) return NULL; - if (dev_priv->chipset >= NV_50 && (i2c->entry & 0x00000100)) { + if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) { uint32_t reg = 0xe500, val; if (i2c->port_type == 6) { diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 6fd51a51c608..7bfd9e6c9d67 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -42,6 +42,13 @@ #include "nouveau_connector.h" #include "nv50_display.h" +static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20); + +static int nouveau_ratelimit(void) +{ + return __ratelimit(&nouveau_ratelimit_state); +} + void nouveau_irq_preinstall(struct drm_device *dev) { @@ -53,6 +60,7 @@ nouveau_irq_preinstall(struct drm_device *dev) if (dev_priv->card_type >= NV_50) { INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); + spin_lock_init(&dev_priv->hpd_state.lock); INIT_LIST_HEAD(&dev_priv->vbl_waiting); } } @@ -202,8 +210,8 @@ nouveau_fifo_irq_handler(struct drm_device *dev) } if (status & NV_PFIFO_INTR_DMA_PUSHER) { - u32 get = nv_rd32(dev, 0x003244); - u32 put = nv_rd32(dev, 0x003240); + u32 dma_get = nv_rd32(dev, 0x003244); + u32 dma_put = nv_rd32(dev, 0x003240); u32 push = nv_rd32(dev, 0x003220); u32 state = nv_rd32(dev, 0x003228); @@ -213,16 +221,18 @@ nouveau_fifo_irq_handler(struct drm_device *dev) u32 ib_get = nv_rd32(dev, 0x003334); u32 ib_put = nv_rd32(dev, 0x003330); - NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " + if (nouveau_ratelimit()) + NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " "State 0x%08x Push 0x%08x\n", - chid, ho_get, get, ho_put, put, ib_get, ib_put, - state, push); + chid, ho_get, dma_get, ho_put, + dma_put, ib_get, ib_put, state, + push); /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ nv_wr32(dev, 0x003364, 0x00000000); - if (get != put || ho_get != ho_put) { - nv_wr32(dev, 0x003244, put); + if (dma_get != dma_put || ho_get != ho_put) { + nv_wr32(dev, 0x003244, dma_put); nv_wr32(dev, 0x003328, ho_put); } else if (ib_get != ib_put) { @@ -231,10 +241,10 @@ nouveau_fifo_irq_handler(struct drm_device *dev) } else { NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " "Put 0x%08x State 0x%08x Push 0x%08x\n", - chid, get, put, state, push); + chid, dma_get, dma_put, state, push); - if (get != put) - nv_wr32(dev, 0x003244, put); + if (dma_get != dma_put) + nv_wr32(dev, 0x003244, dma_put); } nv_wr32(dev, 0x003228, 0x00000000); @@ -266,8 +276,9 @@ nouveau_fifo_irq_handler(struct drm_device *dev) } if (status) { - NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", - status, chid); + if (nouveau_ratelimit()) + NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", + status, chid); nv_wr32(dev, NV03_PFIFO_INTR_0, status); status = 0; } @@ -544,13 +555,6 @@ nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource) nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap); } -static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20); - -static int nouveau_ratelimit(void) -{ - return __ratelimit(&nouveau_ratelimit_state); -} - static inline void nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource) diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index a163c7c612e7..fe4a30dc4b42 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -33,9 +33,9 @@ #include "drmP.h" #include "drm.h" #include "drm_sarea.h" -#include "nouveau_drv.h" -#define MIN(a,b) a < b ? a : b +#include "nouveau_drv.h" +#include "nouveau_pm.h" /* * NV10-NV40 tiling helpers @@ -175,11 +175,10 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, } } } - dev_priv->engine.instmem.flush(dev); - nv50_vm_flush(dev, 5); - nv50_vm_flush(dev, 0); - nv50_vm_flush(dev, 4); + dev_priv->engine.instmem.flush(dev); + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); nv50_vm_flush(dev, 6); return 0; } @@ -209,11 +208,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) pte++; } } - dev_priv->engine.instmem.flush(dev); - nv50_vm_flush(dev, 5); - nv50_vm_flush(dev, 0); - nv50_vm_flush(dev, 4); + dev_priv->engine.instmem.flush(dev); + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); nv50_vm_flush(dev, 6); } @@ -653,6 +651,7 @@ nouveau_mem_gart_init(struct drm_device *dev) void nouveau_mem_timing_init(struct drm_device *dev) { + /* cards < NVC0 only */ struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct nouveau_pm_memtimings *memtimings = &pm->memtimings; @@ -719,14 +718,14 @@ nouveau_mem_timing_init(struct drm_device *dev) tUNK_19 = 1; tUNK_20 = 0; tUNK_21 = 0; - switch (MIN(recordlen,21)) { - case 21: + switch (min(recordlen, 22)) { + case 22: tUNK_21 = entry[21]; - case 20: + case 21: tUNK_20 = entry[20]; - case 19: + case 20: tUNK_19 = entry[19]; - case 18: + case 19: tUNK_18 = entry[18]; default: tUNK_0 = entry[0]; @@ -756,24 +755,30 @@ nouveau_mem_timing_init(struct drm_device *dev) timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); if(recordlen > 19) { timing->reg_100228 += (tUNK_19 - 1) << 24; - } else { + }/* I cannot back-up this else-statement right now + else { timing->reg_100228 += tUNK_12 << 24; - } + }*/ /* XXX: reg_10022c */ + timing->reg_10022c = tUNK_2 - 1; timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | tUNK_13 << 8 | tUNK_13); /* XXX: +6? */ timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC); - if(tUNK_10 > tUNK_11) { - timing->reg_100234 += tUNK_10 << 16; - } else { - timing->reg_100234 += tUNK_11 << 16; + timing->reg_100234 += max(tUNK_10,tUNK_11) << 16; + + /* XXX; reg_100238, reg_10023c + * reg: 0x00?????? + * reg_10023c: + * 0 for pre-NV50 cards + * 0x????0202 for NV50+ cards (empirical evidence) */ + if(dev_priv->card_type >= NV_50) { + timing->reg_10023c = 0x202; } - /* XXX; reg_100238, reg_10023c */ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, timing->reg_100220, timing->reg_100224, timing->reg_100228, timing->reg_10022c); diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 896cf8634144..dd572adca02a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -129,7 +129,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, if (ramin == NULL) { spin_unlock(&dev_priv->ramin_lock); nouveau_gpuobj_ref(NULL, &gpuobj); - return ret; + return -ENOMEM; } ramin = drm_mm_get_block_atomic(ramin, size, align); diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 1c99c55d6d46..9f7b158f5825 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -284,6 +284,7 @@ nouveau_sysfs_fini(struct drm_device *dev) } } +#ifdef CONFIG_HWMON static ssize_t nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) { @@ -395,10 +396,12 @@ static struct attribute *hwmon_attributes[] = { static const struct attribute_group hwmon_attrgroup = { .attrs = hwmon_attributes, }; +#endif static int nouveau_hwmon_init(struct drm_device *dev) { +#ifdef CONFIG_HWMON struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct device *hwmon_dev; @@ -425,13 +428,14 @@ nouveau_hwmon_init(struct drm_device *dev) } pm->hwmon = hwmon_dev; - +#endif return 0; } static void nouveau_hwmon_fini(struct drm_device *dev) { +#ifdef CONFIG_HWMON struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pm_engine *pm = &dev_priv->engine.pm; @@ -439,6 +443,7 @@ nouveau_hwmon_fini(struct drm_device *dev) sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup); hwmon_device_unregister(pm->hwmon); } +#endif } int diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c index 7f16697cc96c..2d8580927ca4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ramht.c +++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c @@ -153,26 +153,42 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle, return -ENOMEM; } +static struct nouveau_ramht_entry * +nouveau_ramht_remove_entry(struct nouveau_channel *chan, u32 handle) +{ + struct nouveau_ramht *ramht = chan ? chan->ramht : NULL; + struct nouveau_ramht_entry *entry; + unsigned long flags; + + if (!ramht) + return NULL; + + spin_lock_irqsave(&ramht->lock, flags); + list_for_each_entry(entry, &ramht->entries, head) { + if (entry->channel == chan && + (!handle || entry->handle == handle)) { + list_del(&entry->head); + spin_unlock_irqrestore(&ramht->lock, flags); + + return entry; + } + } + spin_unlock_irqrestore(&ramht->lock, flags); + + return NULL; +} + static void -nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle) +nouveau_ramht_remove_hash(struct nouveau_channel *chan, u32 handle) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; struct nouveau_gpuobj *ramht = chan->ramht->gpuobj; - struct nouveau_ramht_entry *entry, *tmp; + unsigned long flags; u32 co, ho; - list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) { - if (entry->channel != chan || entry->handle != handle) - continue; - - nouveau_gpuobj_ref(NULL, &entry->gpuobj); - list_del(&entry->head); - kfree(entry); - break; - } - + spin_lock_irqsave(&chan->ramht->lock, flags); co = ho = nouveau_ramht_hash_handle(chan, handle); do { if (nouveau_ramht_entry_valid(dev, ramht, co) && @@ -184,7 +200,7 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle) nv_wo32(ramht, co + 0, 0x00000000); nv_wo32(ramht, co + 4, 0x00000000); instmem->flush(dev); - return; + goto out; } co += 8; @@ -194,17 +210,22 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle) NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n", chan->id, handle); +out: + spin_unlock_irqrestore(&chan->ramht->lock, flags); } void nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle) { - struct nouveau_ramht *ramht = chan->ramht; - unsigned long flags; + struct nouveau_ramht_entry *entry; - spin_lock_irqsave(&ramht->lock, flags); - nouveau_ramht_remove_locked(chan, handle); - spin_unlock_irqrestore(&ramht->lock, flags); + entry = nouveau_ramht_remove_entry(chan, handle); + if (!entry) + return; + + nouveau_ramht_remove_hash(chan, entry->handle); + nouveau_gpuobj_ref(NULL, &entry->gpuobj); + kfree(entry); } struct nouveau_gpuobj * @@ -265,23 +286,19 @@ void nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr, struct nouveau_channel *chan) { - struct nouveau_ramht_entry *entry, *tmp; + struct nouveau_ramht_entry *entry; struct nouveau_ramht *ramht; - unsigned long flags; if (ref) kref_get(&ref->refcount); ramht = *ptr; if (ramht) { - spin_lock_irqsave(&ramht->lock, flags); - list_for_each_entry_safe(entry, tmp, &ramht->entries, head) { - if (entry->channel != chan) - continue; - - nouveau_ramht_remove_locked(chan, entry->handle); + while ((entry = nouveau_ramht_remove_entry(chan, 0))) { + nouveau_ramht_remove_hash(chan, entry->handle); + nouveau_gpuobj_ref(NULL, &entry->gpuobj); + kfree(entry); } - spin_unlock_irqrestore(&ramht->lock, flags); kref_put(&ramht->refcount, nouveau_ramht_del); } diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 288bacac7e5a..d4ac97007038 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -120,8 +120,8 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) dev_priv->engine.instmem.flush(nvbe->dev); if (dev_priv->card_type == NV_50) { - nv50_vm_flush(dev, 5); /* PGRAPH */ - nv50_vm_flush(dev, 0); /* PFIFO */ + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); } nvbe->bound = true; @@ -162,8 +162,8 @@ nouveau_sgdma_unbind(struct ttm_backend *be) dev_priv->engine.instmem.flush(nvbe->dev); if (dev_priv->card_type == NV_50) { - nv50_vm_flush(dev, 5); - nv50_vm_flush(dev, 0); + dev_priv->engine.fifo.tlb_flush(dev); + dev_priv->engine.graph.tlb_flush(dev); } nvbe->bound = false; @@ -224,7 +224,11 @@ nouveau_sgdma_init(struct drm_device *dev) int i, ret; if (dev_priv->card_type < NV_50) { - aper_size = (64 * 1024 * 1024); + if(dev_priv->ramin_rsvd_vram < 2 * 1024 * 1024) + aper_size = 64 * 1024 * 1024; + else + aper_size = 512 * 1024 * 1024; + obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4; obj_size += 8; /* ctxdma header */ } else { diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index ed7757f14083..049f755567e5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -354,6 +354,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.destroy_context = nv50_graph_destroy_context; engine->graph.load_context = nv50_graph_load_context; engine->graph.unload_context = nv50_graph_unload_context; + if (dev_priv->chipset != 0x86) + engine->graph.tlb_flush = nv50_graph_tlb_flush; + else { + /* from what i can see nvidia do this on every + * pre-NVA3 board except NVAC, but, we've only + * ever seen problems on NV86 + */ + engine->graph.tlb_flush = nv86_graph_tlb_flush; + } engine->fifo.channels = 128; engine->fifo.init = nv50_fifo_init; engine->fifo.takedown = nv50_fifo_takedown; @@ -365,6 +374,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.destroy_context = nv50_fifo_destroy_context; engine->fifo.load_context = nv50_fifo_load_context; engine->fifo.unload_context = nv50_fifo_unload_context; + engine->fifo.tlb_flush = nv50_fifo_tlb_flush; engine->display.early_init = nv50_display_early_init; engine->display.late_takedown = nv50_display_late_takedown; engine->display.create = nv50_display_create; @@ -1041,6 +1051,9 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, case NOUVEAU_GETPARAM_PTIMER_TIME: getparam->value = dev_priv->engine.timer.read(dev); break; + case NOUVEAU_GETPARAM_HAS_BO_USAGE: + getparam->value = 1; + break; case NOUVEAU_GETPARAM_GRAPH_UNITS: /* NV40 and NV50 versions are quite different, but register * address is the same. User is supposed to know the card @@ -1051,7 +1064,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, } /* FALLTHRU */ default: - NV_ERROR(dev, "unknown parameter %lld\n", getparam->param); + NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param); return -EINVAL; } @@ -1066,7 +1079,7 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data, switch (setparam->param) { default: - NV_ERROR(dev, "unknown parameter %lld\n", setparam->param); + NV_DEBUG(dev, "unknown parameter %lld\n", setparam->param); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c index 16bbbf1eff63..7ecc4adc1e45 100644 --- a/drivers/gpu/drm/nouveau/nouveau_temp.c +++ b/drivers/gpu/drm/nouveau/nouveau_temp.c @@ -191,7 +191,7 @@ nv40_temp_get(struct drm_device *dev) int offset = sensor->offset_mult / sensor->offset_div; int core_temp; - if (dev_priv->chipset >= 0x50) { + if (dev_priv->card_type >= NV_50) { core_temp = nv_rd32(dev, 0x20008); } else { core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff; diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index c71abc2a34d5..40e180741629 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -158,7 +158,6 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct drm_device *dev = crtc->dev; - struct drm_connector *connector; unsigned char seq1 = 0, crtc17 = 0; unsigned char crtc1A; @@ -213,10 +212,6 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) NVVgaSeqReset(dev, nv_crtc->index, false); NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A); - - /* Update connector polling modes */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) - nouveau_connector_set_polling(connector); } static bool @@ -831,7 +826,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, /* Update the framebuffer location. */ regp->fb_start = nv_crtc->fb.offset & ~3; regp->fb_start += (y * drm_fb->pitch) + (x * drm_fb->bits_per_pixel / 8); - NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_START, regp->fb_start); + nv_set_crtc_base(dev, nv_crtc->index, regp->fb_start); /* Update the arbitration parameters. */ nouveau_calc_arb(dev, crtc->mode.clock, drm_fb->bits_per_pixel, diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index c936403b26e2..ef23550407b5 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -185,14 +185,15 @@ static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder, struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder); - /* For internal panels and gpu scaling on DVI we need the native mode */ - if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { - if (!nv_connector->native_mode) - return false; + if (!nv_connector->native_mode || + nv_connector->scaling_mode == DRM_MODE_SCALE_NONE || + mode->hdisplay > nv_connector->native_mode->hdisplay || + mode->vdisplay > nv_connector->native_mode->vdisplay) { + nv_encoder->mode = *adjusted_mode; + + } else { nv_encoder->mode = *nv_connector->native_mode; adjusted_mode->clock = nv_connector->native_mode->clock; - } else { - nv_encoder->mode = *adjusted_mode; } return true; diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c index 6a6eb697d38e..eb1c70dd82ed 100644 --- a/drivers/gpu/drm/nouveau/nv04_pm.c +++ b/drivers/gpu/drm/nouveau/nv04_pm.c @@ -76,6 +76,15 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state) reg += 4; nouveau_hw_setpll(dev, reg, &state->calc); + + if (dev_priv->card_type < NV_30 && reg == NV_PRAMDAC_MPLL_COEFF) { + if (dev_priv->card_type == NV_20) + nv_mask(dev, 0x1002c4, 0, 1 << 20); + + /* Reset the DLLs */ + nv_mask(dev, 0x1002c0, 0, 1 << 8); + } + kfree(state); } diff --git a/drivers/gpu/drm/nouveau/nv50_calc.c b/drivers/gpu/drm/nouveau/nv50_calc.c index 2cdc2bfe7179..de81151648f8 100644 --- a/drivers/gpu/drm/nouveau/nv50_calc.c +++ b/drivers/gpu/drm/nouveau/nv50_calc.c @@ -51,24 +51,28 @@ nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk, int *N, int *fN, int *M, int *P) { fixed20_12 fb_div, a, b; + u32 refclk = pll->refclk / 10; + u32 max_vco_freq = pll->vco1.maxfreq / 10; + u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10; + clk /= 10; - *P = pll->vco1.maxfreq / clk; + *P = max_vco_freq / clk; if (*P > pll->max_p) *P = pll->max_p; if (*P < pll->min_p) *P = pll->min_p; - /* *M = ceil(refclk / pll->vco.max_inputfreq); */ - a.full = dfixed_const(pll->refclk); - b.full = dfixed_const(pll->vco1.max_inputfreq); + /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */ + a.full = dfixed_const(refclk + max_vco_inputfreq); + b.full = dfixed_const(max_vco_inputfreq); a.full = dfixed_div(a, b); - a.full = dfixed_ceil(a); + a.full = dfixed_floor(a); *M = dfixed_trunc(a); /* fb_div = (vco * *M) / refclk; */ fb_div.full = dfixed_const(clk * *P); fb_div.full = dfixed_mul(fb_div, a); - a.full = dfixed_const(pll->refclk); + a.full = dfixed_const(refclk); fb_div.full = dfixed_div(fb_div, a); /* *N = floor(fb_div); */ diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 16380d52cd88..56476d0c6de8 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -546,7 +546,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, } nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base; - nv_crtc->fb.tile_flags = fb->nvbo->tile_flags; + nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo); nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8; if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) { ret = RING_SPACE(evo, 2); @@ -578,7 +578,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, fb->nvbo->tile_mode); } if (dev_priv->chipset == 0x50) - OUT_RING(evo, (fb->nvbo->tile_flags << 8) | format); + OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format); else OUT_RING(evo, format); diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 55c9663ef2bf..f624c611ddea 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1032,11 +1032,18 @@ nv50_display_irq_hotplug_bh(struct work_struct *work) struct drm_connector *connector; const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; uint32_t unplug_mask, plug_mask, change_mask; - uint32_t hpd0, hpd1 = 0; + uint32_t hpd0, hpd1; - hpd0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050); + spin_lock_irq(&dev_priv->hpd_state.lock); + hpd0 = dev_priv->hpd_state.hpd0_bits; + dev_priv->hpd_state.hpd0_bits = 0; + hpd1 = dev_priv->hpd_state.hpd1_bits; + dev_priv->hpd_state.hpd1_bits = 0; + spin_unlock_irq(&dev_priv->hpd_state.lock); + + hpd0 &= nv_rd32(dev, 0xe050); if (dev_priv->chipset >= 0x90) - hpd1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070); + hpd1 &= nv_rd32(dev, 0xe070); plug_mask = (hpd0 & 0x0000ffff) | (hpd1 << 16); unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000); @@ -1078,10 +1085,6 @@ nv50_display_irq_hotplug_bh(struct work_struct *work) helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); } - nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054)); - if (dev_priv->chipset >= 0x90) - nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074)); - drm_helper_hpd_irq_event(dev); } @@ -1092,8 +1095,22 @@ nv50_display_irq_handler(struct drm_device *dev) uint32_t delayed = 0; if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) { - if (!work_pending(&dev_priv->hpd_work)) - queue_work(dev_priv->wq, &dev_priv->hpd_work); + uint32_t hpd0_bits, hpd1_bits = 0; + + hpd0_bits = nv_rd32(dev, 0xe054); + nv_wr32(dev, 0xe054, hpd0_bits); + + if (dev_priv->chipset >= 0x90) { + hpd1_bits = nv_rd32(dev, 0xe074); + nv_wr32(dev, 0xe074, hpd1_bits); + } + + spin_lock(&dev_priv->hpd_state.lock); + dev_priv->hpd_state.hpd0_bits |= hpd0_bits; + dev_priv->hpd_state.hpd1_bits |= hpd1_bits; + spin_unlock(&dev_priv->hpd_state.lock); + + queue_work(dev_priv->wq, &dev_priv->hpd_work); } while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) { diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index a46a961102f3..1da65bd60c10 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -464,3 +464,8 @@ nv50_fifo_unload_context(struct drm_device *dev) return 0; } +void +nv50_fifo_tlb_flush(struct drm_device *dev) +{ + nv50_vm_flush(dev, 5); +} diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index cbf5ae2f67d4..8b669d0af610 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -402,3 +402,55 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = { { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */ {} }; + +void +nv50_graph_tlb_flush(struct drm_device *dev) +{ + nv50_vm_flush(dev, 0); +} + +void +nv86_graph_tlb_flush(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; + bool idle, timeout = false; + unsigned long flags; + u64 start; + u32 tmp; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + nv_mask(dev, 0x400500, 0x00000001, 0x00000000); + + start = ptimer->read(dev); + do { + idle = true; + + for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + } while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000)); + + if (timeout) { + NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: " + "0x%08x 0x%08x 0x%08x 0x%08x\n", + nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380), + nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388)); + } + + nv50_vm_flush(dev, 0); + + nv_mask(dev, 0x400500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +} diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index a53fc974332b..b773229b7647 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -402,7 +402,6 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) } dev_priv->engine.instmem.flush(dev); - nv50_vm_flush(dev, 4); nv50_vm_flush(dev, 6); gpuobj->im_bound = 1; diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 8e421f644a54..05efb5b9f13e 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -112,6 +112,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, base += 3; break; case ATOM_IIO_WRITE: + (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1)); ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp); base += 3; break; diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 488c36c8f5e6..4dc5b4714c5a 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1650,7 +1650,36 @@ static void evergreen_gpu_init(struct radeon_device *rdev) } } - rdev->config.evergreen.tile_config = gb_addr_config; + /* setup tiling info dword. gb_addr_config is not adequate since it does + * not have bank info, so create a custom tiling dword. + * bits 3:0 num_pipes + * bits 7:4 num_banks + * bits 11:8 group_size + * bits 15:12 row_size + */ + rdev->config.evergreen.tile_config = 0; + switch (rdev->config.evergreen.max_tile_pipes) { + case 1: + default: + rdev->config.evergreen.tile_config |= (0 << 0); + break; + case 2: + rdev->config.evergreen.tile_config |= (1 << 0); + break; + case 4: + rdev->config.evergreen.tile_config |= (2 << 0); + break; + case 8: + rdev->config.evergreen.tile_config |= (3 << 0); + break; + } + rdev->config.evergreen.tile_config |= + ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; + rdev->config.evergreen.tile_config |= + ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8; + rdev->config.evergreen.tile_config |= + ((gb_addr_config & 0x30000000) >> 28) << 12; + WREG32(GB_BACKEND_MAP, gb_backend_map); WREG32(GB_ADDR_CONFIG, gb_addr_config); WREG32(DMIF_ADDR_CONFIG, gb_addr_config); diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c index ac3b6dde23db..e0e590110dd4 100644 --- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c +++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c @@ -459,7 +459,7 @@ int evergreen_blit_init(struct radeon_device *rdev) obj_size += evergreen_ps_size * 4; obj_size = ALIGN(obj_size, 256); - r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM, + r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &rdev->r600_blit.shader_obj); if (r) { DRM_ERROR("evergreen failed to allocate shader\n"); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 0f806cc7dc75..4d7a2e1bdb90 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -878,12 +878,15 @@ void r600_pcie_gart_tlb_flush(struct radeon_device *rdev) u32 tmp; /* flush hdp cache so updates hit vram */ - if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) { + if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) && + !(rdev->flags & RADEON_IS_AGP)) { void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; u32 tmp; /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL + * This seems to cause problems on some AGP cards. Just use the old + * method for them. */ WREG32(HDP_DEBUG1, 0); tmp = readl((void __iomem *)ptr); @@ -1195,8 +1198,10 @@ void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) mc->vram_end, mc->real_vram_size >> 20); } else { u64 base = 0; - if (rdev->flags & RADEON_IS_IGP) - base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24; + if (rdev->flags & RADEON_IS_IGP) { + base = RREG32(MC_VM_FB_LOCATION) & 0xFFFF; + base <<= 24; + } radeon_vram_location(rdev, &rdev->mc, base); rdev->mc.gtt_base_align = 0; radeon_gtt_location(rdev, mc); @@ -2718,7 +2723,7 @@ static int r600_ih_ring_alloc(struct radeon_device *rdev) /* Allocate ring buffer */ if (rdev->ih.ring_obj == NULL) { r = radeon_bo_create(rdev, NULL, rdev->ih.ring_size, - true, + PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, &rdev->ih.ring_obj); if (r) { @@ -3483,10 +3488,12 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev) void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo) { /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read - * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL + * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL. + * This seems to cause problems on some AGP cards. Just use the old + * method for them. */ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) && - rdev->vram_scratch.ptr) { + rdev->vram_scratch.ptr && !(rdev->flags & RADEON_IS_AGP)) { void __iomem *ptr = (void *)rdev->vram_scratch.ptr; u32 tmp; diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index 8362974ef41a..86e5aa07f0db 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -501,7 +501,7 @@ int r600_blit_init(struct radeon_device *rdev) obj_size += r6xx_ps_size * 4; obj_size = ALIGN(obj_size, 256); - r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM, + r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &rdev->r600_blit.shader_obj); if (r) { DRM_ERROR("r600 failed to allocate shader\n"); diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 37cc2aa9f923..0f90fc3482ce 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -50,6 +50,7 @@ struct r600_cs_track { u32 nsamples; u32 cb_color_base_last[8]; struct radeon_bo *cb_color_bo[8]; + u64 cb_color_bo_mc[8]; u32 cb_color_bo_offset[8]; struct radeon_bo *cb_color_frag_bo[8]; struct radeon_bo *cb_color_tile_bo[8]; @@ -67,6 +68,7 @@ struct r600_cs_track { u32 db_depth_size; u32 db_offset; struct radeon_bo *db_bo; + u64 db_bo_mc; }; static inline int r600_bpe_from_format(u32 *bpe, u32 format) @@ -140,6 +142,68 @@ static inline int r600_bpe_from_format(u32 *bpe, u32 format) return 0; } +struct array_mode_checker { + int array_mode; + u32 group_size; + u32 nbanks; + u32 npipes; + u32 nsamples; + u32 bpe; +}; + +/* returns alignment in pixels for pitch/height/depth and bytes for base */ +static inline int r600_get_array_mode_alignment(struct array_mode_checker *values, + u32 *pitch_align, + u32 *height_align, + u32 *depth_align, + u64 *base_align) +{ + u32 tile_width = 8; + u32 tile_height = 8; + u32 macro_tile_width = values->nbanks; + u32 macro_tile_height = values->npipes; + u32 tile_bytes = tile_width * tile_height * values->bpe * values->nsamples; + u32 macro_tile_bytes = macro_tile_width * macro_tile_height * tile_bytes; + + switch (values->array_mode) { + case ARRAY_LINEAR_GENERAL: + /* technically tile_width/_height for pitch/height */ + *pitch_align = 1; /* tile_width */ + *height_align = 1; /* tile_height */ + *depth_align = 1; + *base_align = 1; + break; + case ARRAY_LINEAR_ALIGNED: + *pitch_align = max((u32)64, (u32)(values->group_size / values->bpe)); + *height_align = tile_height; + *depth_align = 1; + *base_align = values->group_size; + break; + case ARRAY_1D_TILED_THIN1: + *pitch_align = max((u32)tile_width, + (u32)(values->group_size / + (tile_height * values->bpe * values->nsamples))); + *height_align = tile_height; + *depth_align = 1; + *base_align = values->group_size; + break; + case ARRAY_2D_TILED_THIN1: + *pitch_align = max((u32)macro_tile_width, + (u32)(((values->group_size / tile_height) / + (values->bpe * values->nsamples)) * + values->nbanks)) * tile_width; + *height_align = macro_tile_height * tile_height; + *depth_align = 1; + *base_align = max(macro_tile_bytes, + (*pitch_align) * values->bpe * (*height_align) * values->nsamples); + break; + default: + return -EINVAL; + } + + return 0; +} + static void r600_cs_track_init(struct r600_cs_track *track) { int i; @@ -153,10 +217,12 @@ static void r600_cs_track_init(struct r600_cs_track *track) track->cb_color_info[i] = 0; track->cb_color_bo[i] = NULL; track->cb_color_bo_offset[i] = 0xFFFFFFFF; + track->cb_color_bo_mc[i] = 0xFFFFFFFF; } track->cb_target_mask = 0xFFFFFFFF; track->cb_shader_mask = 0xFFFFFFFF; track->db_bo = NULL; + track->db_bo_mc = 0xFFFFFFFF; /* assume the biggest format and that htile is enabled */ track->db_depth_info = 7 | (1 << 25); track->db_depth_view = 0xFFFFC000; @@ -168,7 +234,10 @@ static void r600_cs_track_init(struct r600_cs_track *track) static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) { struct r600_cs_track *track = p->track; - u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align; + u32 bpe = 0, slice_tile_max, size, tmp; + u32 height, height_align, pitch, pitch_align, depth_align; + u64 base_offset, base_align; + struct array_mode_checker array_check; volatile u32 *ib = p->ib->ptr; unsigned array_mode; @@ -183,60 +252,40 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) i, track->cb_color_info[i]); return -EINVAL; } - /* pitch is the number of 8x8 tiles per row */ - pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1; + /* pitch in pixels */ + pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) * 8; slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1; slice_tile_max *= 64; - height = slice_tile_max / (pitch * 8); + height = slice_tile_max / pitch; if (height > 8192) height = 8192; array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]); + + base_offset = track->cb_color_bo_mc[i] + track->cb_color_bo_offset[i]; + array_check.array_mode = array_mode; + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = track->nsamples; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__, + G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i, + track->cb_color_info[i]); + return -EINVAL; + } switch (array_mode) { case V_0280A0_ARRAY_LINEAR_GENERAL: - /* technically height & 0x7 */ break; case V_0280A0_ARRAY_LINEAR_ALIGNED: - pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_0280A0_ARRAY_1D_TILED_THIN1: - pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe * track->nsamples))) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } /* avoid breaking userspace */ if (height > 7) height &= ~0x7; - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_0280A0_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED((height / 8), track->npipes)) { - dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; default: dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__, @@ -244,8 +293,24 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) track->cb_color_info[i]); return -EINVAL; } + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(height, height_align)) { + dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", + __func__, __LINE__, height); + return -EINVAL; + } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset); + return -EINVAL; + } + /* check offset */ - tmp = height * pitch * 8 * bpe; + tmp = height * pitch * bpe; if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) { if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) { /* the initial DDX does bad things with the CB size occasionally */ @@ -260,15 +325,11 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) return -EINVAL; } } - if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) { - dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]); - return -EINVAL; - } /* limit max tile */ - tmp = (height * pitch * 8) >> 6; + tmp = (height * pitch) >> 6; if (tmp < slice_tile_max) slice_tile_max = tmp; - tmp = S_028060_PITCH_TILE_MAX(pitch - 1) | + tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) | S_028060_SLICE_TILE_MAX(slice_tile_max - 1); ib[track->cb_color_size_idx[i]] = tmp; return 0; @@ -310,7 +371,12 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) /* Check depth buffer */ if (G_028800_STENCIL_ENABLE(track->db_depth_control) || G_028800_Z_ENABLE(track->db_depth_control)) { - u32 nviews, bpe, ntiles, pitch, pitch_align, height, size, slice_tile_max; + u32 nviews, bpe, ntiles, size, slice_tile_max; + u32 height, height_align, pitch, pitch_align, depth_align; + u64 base_offset, base_align; + struct array_mode_checker array_check; + int array_mode; + if (track->db_bo == NULL) { dev_warn(p->dev, "z/stencil with no depth buffer\n"); return -EINVAL; @@ -353,41 +419,34 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF); } else { size = radeon_bo_size(track->db_bo); - pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1; + /* pitch in pixels */ + pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8; slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1; slice_tile_max *= 64; - height = slice_tile_max / (pitch * 8); + height = slice_tile_max / pitch; if (height > 8192) height = 8192; - switch (G_028010_ARRAY_MODE(track->db_depth_info)) { + base_offset = track->db_bo_mc + track->db_offset; + array_mode = G_028010_ARRAY_MODE(track->db_depth_info); + array_check.array_mode = array_mode; + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = track->nsamples; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, + G_028010_ARRAY_MODE(track->db_depth_info), + track->db_depth_info); + return -EINVAL; + } + switch (array_mode) { case V_028010_ARRAY_1D_TILED_THIN1: - pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8); - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } /* don't break userspace */ height &= ~0x7; - if (!IS_ALIGNED(height, 8)) { - dev_warn(p->dev, "%s:%d db height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; case V_028010_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - if (!IS_ALIGNED((height / 8), track->npipes)) { - dev_warn(p->dev, "%s:%d db height (%d) invalid\n", - __func__, __LINE__, height); - return -EINVAL; - } break; default: dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, @@ -395,15 +454,27 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) track->db_depth_info); return -EINVAL; } - if (!IS_ALIGNED(track->db_offset, track->group_size)) { - dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->db_offset); + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(height, height_align)) { + dev_warn(p->dev, "%s:%d db height (%d) invalid\n", + __func__, __LINE__, height); return -EINVAL; } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset); + return -EINVAL; + } + ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1; nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1; tmp = ntiles * bpe * 64 * nviews; if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) { - dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %d have %ld)\n", + dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n", track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset, radeon_bo_size(track->db_bo)); return -EINVAL; @@ -954,6 +1025,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); track->cb_color_base_last[tmp] = ib[idx]; track->cb_color_bo[tmp] = reloc->robj; + track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset; break; case DB_DEPTH_BASE: r = r600_cs_packet_next_reloc(p, &reloc); @@ -965,6 +1037,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx track->db_offset = radeon_get_ib_value(p, idx) << 8; ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); track->db_bo = reloc->robj; + track->db_bo_mc = reloc->lobj.gpu_offset; break; case DB_HTILE_DATA_BASE: case SQ_PGM_START_FS: @@ -1086,16 +1159,25 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx, struct radeon_bo *texture, struct radeon_bo *mipmap, + u64 base_offset, + u64 mip_offset, u32 tiling_flags) { struct r600_cs_track *track = p->track; u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0; - u32 word0, word1, l0_size, mipmap_size, pitch, pitch_align; + u32 word0, word1, l0_size, mipmap_size; + u32 height_align, pitch, pitch_align, depth_align; + u64 base_align; + struct array_mode_checker array_check; /* on legacy kernel we don't perform advanced check */ if (p->rdev == NULL) return 0; + /* convert to bytes */ + base_offset <<= 8; + mip_offset <<= 8; + word0 = radeon_get_ib_value(p, idx + 0); if (tiling_flags & RADEON_TILING_MACRO) word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); @@ -1128,46 +1210,38 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i return -EINVAL; } - pitch = G_038000_PITCH(word0) + 1; - switch (G_038000_TILE_MODE(word0)) { - case V_038000_ARRAY_LINEAR_GENERAL: - pitch_align = 1; - /* XXX check height align */ - break; - case V_038000_ARRAY_LINEAR_ALIGNED: - pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - case V_038000_ARRAY_1D_TILED_THIN1: - pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - case V_038000_ARRAY_2D_TILED_THIN1: - pitch_align = max((u32)track->nbanks, - (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8; - if (!IS_ALIGNED(pitch, pitch_align)) { - dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", - __func__, __LINE__, pitch); - return -EINVAL; - } - /* XXX check height align */ - break; - default: - dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, - G_038000_TILE_MODE(word0), word0); + /* pitch in texels */ + pitch = (G_038000_PITCH(word0) + 1) * 8; + array_check.array_mode = G_038000_TILE_MODE(word0); + array_check.group_size = track->group_size; + array_check.nbanks = track->nbanks; + array_check.npipes = track->npipes; + array_check.nsamples = 1; + array_check.bpe = bpe; + if (r600_get_array_mode_alignment(&array_check, + &pitch_align, &height_align, &depth_align, &base_align)) { + dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n", + __func__, __LINE__, G_038000_TILE_MODE(word0)); + return -EINVAL; + } + + /* XXX check height as well... */ + + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(base_offset, base_align)) { + dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n", + __func__, __LINE__, base_offset); + return -EINVAL; + } + if (!IS_ALIGNED(mip_offset, base_align)) { + dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n", + __func__, __LINE__, mip_offset); return -EINVAL; } - /* XXX check offset align */ word0 = radeon_get_ib_value(p, idx + 4); word1 = radeon_get_ib_value(p, idx + 5); @@ -1402,7 +1476,10 @@ static int r600_packet3_check(struct radeon_cs_parser *p, mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); mipmap = reloc->robj; r = r600_check_texture_resource(p, idx+(i*7)+1, - texture, mipmap, reloc->lobj.tiling_flags); + texture, mipmap, + base_offset + radeon_get_ib_value(p, idx+1+(i*7)+2), + mip_offset + radeon_get_ib_value(p, idx+1+(i*7)+3), + reloc->lobj.tiling_flags); if (r) return r; ib[idx+1+(i*7)+2] += base_offset; diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h index d84612ae47e0..33cda016b083 100644 --- a/drivers/gpu/drm/radeon/r600_reg.h +++ b/drivers/gpu/drm/radeon/r600_reg.h @@ -86,6 +86,7 @@ #define R600_HDP_NONSURFACE_BASE 0x2c04 #define R600_BUS_CNTL 0x5420 +# define R600_BIOS_ROM_DIS (1 << 1) #define R600_CONFIG_CNTL 0x5424 #define R600_CONFIG_MEMSIZE 0x5428 #define R600_CONFIG_F0_BASE 0x542C diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 966a793e225b..bff4dc4f410f 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -51,6 +51,12 @@ #define PTE_READABLE (1 << 5) #define PTE_WRITEABLE (1 << 6) +/* tiling bits */ +#define ARRAY_LINEAR_GENERAL 0x00000000 +#define ARRAY_LINEAR_ALIGNED 0x00000001 +#define ARRAY_1D_TILED_THIN1 0x00000002 +#define ARRAY_2D_TILED_THIN1 0x00000004 + /* Registers */ #define ARB_POP 0x2418 #define ENABLE_TC128 (1 << 30) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 73f600d39ad4..3a7095743d44 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1262,6 +1262,10 @@ void r100_pll_errata_after_index(struct radeon_device *rdev); (rdev->family == CHIP_RS400) || \ (rdev->family == CHIP_RS480)) #define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600)) +#define ASIC_IS_DCE2(rdev) ((rdev->family == CHIP_RS600) || \ + (rdev->family == CHIP_RS690) || \ + (rdev->family == CHIP_RS740) || \ + (rdev->family >= CHIP_R600)) #define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620)) #define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730)) #define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR)) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 87ead090c7d5..bc5a2c3382d9 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -98,6 +98,14 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev } } + /* some DCE3 boards have bad data for this entry */ + if (ASIC_IS_DCE3(rdev)) { + if ((i == 4) && + (gpio->usClkMaskRegisterIndex == 0x1fda) && + (gpio->sucI2cId.ucAccess == 0x94)) + gpio->sucI2cId.ucAccess = 0x14; + } + if (gpio->sucI2cId.ucAccess == id) { i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; @@ -174,6 +182,14 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev) } } + /* some DCE3 boards have bad data for this entry */ + if (ASIC_IS_DCE3(rdev)) { + if ((i == 4) && + (gpio->usClkMaskRegisterIndex == 0x1fda) && + (gpio->sucI2cId.ucAccess == 0x94)) + gpio->sucI2cId.ucAccess = 0x14; + } + i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4; diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index 7932dc4d6b90..c558685cc637 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -41,7 +41,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize, size = bsize; n = 1024; - r = radeon_bo_create(rdev, NULL, size, true, sdomain, &sobj); + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, sdomain, &sobj); if (r) { goto out_cleanup; } @@ -53,7 +53,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize, if (r) { goto out_cleanup; } - r = radeon_bo_create(rdev, NULL, size, true, ddomain, &dobj); + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, ddomain, &dobj); if (r) { goto out_cleanup; } diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 654787ec43f4..8f2c7b50dcf5 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -130,6 +130,7 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) } return true; } + static bool r700_read_disabled_bios(struct radeon_device *rdev) { uint32_t viph_control; @@ -143,7 +144,7 @@ static bool r700_read_disabled_bios(struct radeon_device *rdev) bool r; viph_control = RREG32(RADEON_VIPH_CONTROL); - bus_cntl = RREG32(RADEON_BUS_CNTL); + bus_cntl = RREG32(R600_BUS_CNTL); d1vga_control = RREG32(AVIVO_D1VGA_CONTROL); d2vga_control = RREG32(AVIVO_D2VGA_CONTROL); vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL); @@ -152,7 +153,7 @@ static bool r700_read_disabled_bios(struct radeon_device *rdev) /* disable VIP */ WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); /* enable the rom */ - WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS)); /* Disable VGA mode */ WREG32(AVIVO_D1VGA_CONTROL, (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | @@ -191,7 +192,7 @@ static bool r700_read_disabled_bios(struct radeon_device *rdev) cg_spll_status = RREG32(R600_CG_SPLL_STATUS); } WREG32(RADEON_VIPH_CONTROL, viph_control); - WREG32(RADEON_BUS_CNTL, bus_cntl); + WREG32(R600_BUS_CNTL, bus_cntl); WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); @@ -216,7 +217,7 @@ static bool r600_read_disabled_bios(struct radeon_device *rdev) bool r; viph_control = RREG32(RADEON_VIPH_CONTROL); - bus_cntl = RREG32(RADEON_BUS_CNTL); + bus_cntl = RREG32(R600_BUS_CNTL); d1vga_control = RREG32(AVIVO_D1VGA_CONTROL); d2vga_control = RREG32(AVIVO_D2VGA_CONTROL); vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL); @@ -231,7 +232,7 @@ static bool r600_read_disabled_bios(struct radeon_device *rdev) /* disable VIP */ WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); /* enable the rom */ - WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS)); /* Disable VGA mode */ WREG32(AVIVO_D1VGA_CONTROL, (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | @@ -262,7 +263,7 @@ static bool r600_read_disabled_bios(struct radeon_device *rdev) /* restore regs */ WREG32(RADEON_VIPH_CONTROL, viph_control); - WREG32(RADEON_BUS_CNTL, bus_cntl); + WREG32(R600_BUS_CNTL, bus_cntl); WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 7b7ea269549c..137b8075f6e7 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -571,6 +571,7 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde } if (clk_mask && data_mask) { + /* system specific masks */ i2c.mask_clk_mask = clk_mask; i2c.mask_data_mask = data_mask; i2c.a_clk_mask = clk_mask; @@ -579,7 +580,19 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde i2c.en_data_mask = data_mask; i2c.y_clk_mask = clk_mask; i2c.y_data_mask = data_mask; + } else if ((ddc_line == RADEON_GPIOPAD_MASK) || + (ddc_line == RADEON_MDGPIO_MASK)) { + /* default gpiopad masks */ + i2c.mask_clk_mask = (0x20 << 8); + i2c.mask_data_mask = 0x80; + i2c.a_clk_mask = (0x20 << 8); + i2c.a_data_mask = 0x80; + i2c.en_clk_mask = (0x20 << 8); + i2c.en_data_mask = 0x80; + i2c.y_clk_mask = (0x20 << 8); + i2c.y_data_mask = 0x80; } else { + /* default masks for ddc pads */ i2c.mask_clk_mask = RADEON_GPIO_EN_1; i2c.mask_data_mask = RADEON_GPIO_EN_0; i2c.a_clk_mask = RADEON_GPIO_A_1; @@ -716,7 +729,7 @@ void radeon_combios_i2c_init(struct radeon_device *rdev) clk = RBIOS8(offset + 3 + (i * 5) + 3); data = RBIOS8(offset + 3 + (i * 5) + 4); i2c = combios_setup_i2c_bus(rdev, DDC_MONID, - clk, data); + (1 << clk), (1 << data)); rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK"); break; } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index fe6c74780f18..8afaf7a7459e 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1008,9 +1008,21 @@ static void radeon_dp_connector_destroy(struct drm_connector *connector) static int radeon_dp_get_modes(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; int ret; + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); + } ret = radeon_ddc_get_modes(radeon_connector); + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_OFF); + } + return ret; } @@ -1029,8 +1041,14 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { /* eDP is always DP */ radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); if (radeon_dp_getdpcd(radeon_connector)) ret = connector_status_connected; + if (!radeon_dig_connector->edp_on) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_OFF); } else { radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { @@ -1157,6 +1175,8 @@ radeon_add_atom_connector(struct drm_device *dev, /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; connector->polled = DRM_CONNECTOR_POLL_CONNECT; + connector->interlace_allowed = true; + connector->doublescan_allowed = true; break; case DRM_MODE_CONNECTOR_DVIA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); @@ -1172,6 +1192,8 @@ radeon_add_atom_connector(struct drm_device *dev, 1); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; + connector->interlace_allowed = true; + connector->doublescan_allowed = true; break; case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: @@ -1208,6 +1230,11 @@ radeon_add_atom_connector(struct drm_device *dev, rdev->mode_info.load_detect_property, 1); } + connector->interlace_allowed = true; + if (connector_type == DRM_MODE_CONNECTOR_DVII) + connector->doublescan_allowed = true; + else + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_HDMIA: case DRM_MODE_CONNECTOR_HDMIB: @@ -1238,6 +1265,11 @@ radeon_add_atom_connector(struct drm_device *dev, 0); } subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = true; + if (connector_type == DRM_MODE_CONNECTOR_HDMIB) + connector->doublescan_allowed = true; + else + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_DisplayPort: case DRM_MODE_CONNECTOR_eDP: @@ -1275,6 +1307,9 @@ radeon_add_atom_connector(struct drm_device *dev, rdev->mode_info.underscan_vborder_property, 0); } + connector->interlace_allowed = true; + /* in theory with a DP to VGA converter... */ + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_Composite: @@ -1290,6 +1325,8 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_atombios_get_tv_info(rdev)); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_LVDS: radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); @@ -1308,6 +1345,8 @@ radeon_add_atom_connector(struct drm_device *dev, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; break; } @@ -1385,6 +1424,8 @@ radeon_add_legacy_connector(struct drm_device *dev, /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; connector->polled = DRM_CONNECTOR_POLL_CONNECT; + connector->interlace_allowed = true; + connector->doublescan_allowed = true; break; case DRM_MODE_CONNECTOR_DVIA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); @@ -1400,6 +1441,8 @@ radeon_add_legacy_connector(struct drm_device *dev, 1); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; + connector->interlace_allowed = true; + connector->doublescan_allowed = true; break; case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: @@ -1417,6 +1460,11 @@ radeon_add_legacy_connector(struct drm_device *dev, 1); } subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = true; + if (connector_type == DRM_MODE_CONNECTOR_DVII) + connector->doublescan_allowed = true; + else + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_Composite: @@ -1439,6 +1487,8 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_combios_get_tv_info(rdev)); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; break; case DRM_MODE_CONNECTOR_LVDS: drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); @@ -1452,6 +1502,8 @@ radeon_add_legacy_connector(struct drm_device *dev, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; break; } diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 8adfedfe547f..e12e79326cb1 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -180,7 +180,7 @@ int radeon_wb_init(struct radeon_device *rdev) int r; if (rdev->wb.wb_obj == NULL) { - r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true, + r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj); if (r) { dev_warn(rdev->dev, "(%d) create WB bo failed\n", r); @@ -286,7 +286,7 @@ void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 mc->mc_vram_size = mc->aper_size; } mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; - dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n", + dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n", mc->mc_vram_size >> 20, mc->vram_start, mc->vram_end, mc->real_vram_size >> 20); } @@ -323,7 +323,7 @@ void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align; } mc->gtt_end = mc->gtt_start + mc->gtt_size - 1; - dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n", + dev_info(rdev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n", mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end); } diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index f678257c42e6..041943df966b 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -176,6 +176,7 @@ static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) return false; } } + void radeon_link_encoder_connector(struct drm_device *dev) { @@ -228,6 +229,27 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder) return NULL; } +struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *other_encoder; + struct radeon_encoder *other_radeon_encoder; + + if (radeon_encoder->is_ext_encoder) + return NULL; + + list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { + if (other_encoder == encoder) + continue; + other_radeon_encoder = to_radeon_encoder(other_encoder); + if (other_radeon_encoder->is_ext_encoder && + (radeon_encoder->devices & other_radeon_encoder->devices)) + return other_encoder; + } + return NULL; +} + void radeon_panel_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { @@ -426,52 +448,49 @@ atombios_tv_setup(struct drm_encoder *encoder, int action) } -void -atombios_external_tmds_setup(struct drm_encoder *encoder, int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args; - int index = 0; - - memset(&args, 0, sizeof(args)); - - index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); - - args.sXTmdsEncoder.ucEnable = action; - - if (radeon_encoder->pixel_clock > 165000) - args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL; - - /*if (pScrn->rgbBits == 8)*/ - args.sXTmdsEncoder.ucMisc |= (1 << 1); - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - -} +union dvo_encoder_control { + ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; + DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; + DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3; +}; -static void -atombios_ddia_setup(struct drm_encoder *encoder, int action) +void +atombios_dvo_setup(struct drm_encoder *encoder, int action) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - DVO_ENCODER_CONTROL_PS_ALLOCATION args; - int index = 0; + union dvo_encoder_control args; + int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); memset(&args, 0, sizeof(args)); - index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + if (ASIC_IS_DCE3(rdev)) { + /* DCE3+ */ + args.dvo_v3.ucAction = action; + args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.dvo_v3.ucDVOConfig = 0; /* XXX */ + } else if (ASIC_IS_DCE2(rdev)) { + /* DCE2 (pre-DCE3 R6xx, RS600/690/740 */ + args.dvo.sDVOEncoder.ucAction = action; + args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + /* DFP1, CRT1, TV1 depending on the type of port */ + args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX; + + if (radeon_encoder->pixel_clock > 165000) + args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL; + } else { + /* R4xx, R5xx */ + args.ext_tmds.sXTmdsEncoder.ucEnable = action; - args.sDVOEncoder.ucAction = action; - args.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (radeon_encoder->pixel_clock > 165000) + args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL; - if (radeon_encoder->pixel_clock > 165000) - args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL; + /*if (pScrn->rgbBits == 8)*/ + args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB; + } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - } union lvds_encoder_control { @@ -532,14 +551,14 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) - args.v1.ucMisc |= (1 << 1); + args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; } else { if (dig->linkb) args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; if (radeon_encoder->pixel_clock > 165000) args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; /*if (pScrn->rgbBits == 8) */ - args.v1.ucMisc |= (1 << 1); + args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; } break; case 2: @@ -595,6 +614,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) int atombios_get_encoder_mode(struct drm_encoder *encoder) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; @@ -602,9 +622,20 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) struct radeon_connector_atom_dig *dig_connector; connector = radeon_get_connector_for_encoder(encoder); - if (!connector) - return 0; - + if (!connector) { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + return ATOM_ENCODER_MODE_DVI; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + default: + return ATOM_ENCODER_MODE_CRT; + } + } radeon_connector = to_radeon_connector(connector); switch (connector->connector_type) { @@ -834,6 +865,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t memset(&args, 0, sizeof(args)); switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: @@ -978,6 +1012,105 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +void +atombios_set_edp_panel_power(struct drm_connector *connector, int action) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_device *dev = radeon_connector->base.dev; + struct radeon_device *rdev = dev->dev_private; + union dig_transmitter_control args; + int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + uint8_t frev, crev; + + if (connector->connector_type != DRM_MODE_CONNECTOR_eDP) + return; + + if (!ASIC_IS_DCE4(rdev)) + return; + + if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) || + (action != ATOM_TRANSMITTER_ACTION_POWER_OFF)) + return; + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + memset(&args, 0, sizeof(args)); + + args.v1.ucAction = action; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +union external_encoder_control { + EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; +}; + +static void +atombios_external_encoder_setup(struct drm_encoder *encoder, + struct drm_encoder *ext_encoder, + int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + union external_encoder_control args; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); + u8 frev, crev; + int dp_clock = 0; + int dp_lane_count = 0; + int connector_object_id = 0; + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + connector_object_id = + (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + } + + memset(&args, 0, sizeof(args)); + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + /* no params on frev 1 */ + break; + case 2: + switch (crev) { + case 1: + case 2: + args.v1.sDigEncoder.ucAction = action; + args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (args.v1.sDigEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) { + if (dp_clock == 270000) + args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + args.v1.sDigEncoder.ucLaneNum = dp_lane_count; + } else if (radeon_encoder->pixel_clock > 165000) + args.v1.sDigEncoder.ucLaneNum = 8; + else + args.v1.sDigEncoder.ucLaneNum = 4; + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + static void atombios_yuv_setup(struct drm_encoder *encoder, bool enable) { @@ -1021,6 +1154,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; int index = 0; bool is_dig = false; @@ -1043,9 +1177,14 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) break; case ENCODER_OBJECT_ID_INTERNAL_DVO1: case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + if (ASIC_IS_DCE3(rdev)) + is_dig = true; + else + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; case ENCODER_OBJECT_ID_INTERNAL_LVDS: index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); break; @@ -1082,34 +1221,85 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + if (connector && + (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *radeon_dig_connector = + radeon_connector->con_priv; + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); + radeon_dig_connector->edp_on = true; + } dp_link_train(encoder, connector); if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON); } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF); + if (connector && + (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *radeon_dig_connector = + radeon_connector->con_priv; + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_OFF); + radeon_dig_connector->edp_on = false; + } } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); break; } } else { switch (mode) { case DRM_MODE_DPMS_ON: args.ucAction = ATOM_ENABLE; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + args.ucAction = ATOM_LCD_BLON; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: args.ucAction = ATOM_DISABLE; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + args.ucAction = ATOM_LCD_BLOFF; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } break; } - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } + + if (ext_encoder) { + int action; + + switch (mode) { + case DRM_MODE_DPMS_ON: + default: + action = ATOM_ENABLE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + action = ATOM_DISABLE; + break; + } + atombios_external_encoder_setup(encoder, ext_encoder, action); + } + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); } @@ -1242,7 +1432,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) break; default: DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); - break; + return; } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); @@ -1357,6 +1547,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); radeon_encoder->pixel_clock = adjusted_mode->clock; @@ -1400,11 +1591,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, } break; case ENCODER_OBJECT_ID_INTERNAL_DDI: - atombios_ddia_setup(encoder, ATOM_ENABLE); - break; case ENCODER_OBJECT_ID_INTERNAL_DVO1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - atombios_external_tmds_setup(encoder, ATOM_ENABLE); + atombios_dvo_setup(encoder, ATOM_ENABLE); break; case ENCODER_OBJECT_ID_INTERNAL_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: @@ -1419,6 +1608,11 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, } break; } + + if (ext_encoder) { + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); + } + atombios_apply_encoder_quirks(encoder, adjusted_mode); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { @@ -1595,11 +1789,9 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) } break; case ENCODER_OBJECT_ID_INTERNAL_DDI: - atombios_ddia_setup(encoder, ATOM_DISABLE); - break; case ENCODER_OBJECT_ID_INTERNAL_DVO1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - atombios_external_tmds_setup(encoder, ATOM_DISABLE); + atombios_dvo_setup(encoder, ATOM_DISABLE); break; case ENCODER_OBJECT_ID_INTERNAL_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: @@ -1621,6 +1813,53 @@ disable_done: radeon_encoder->active_device = 0; } +/* these are handled by the primary encoders */ +static void radeon_atom_ext_prepare(struct drm_encoder *encoder) +{ + +} + +static void radeon_atom_ext_commit(struct drm_encoder *encoder) +{ + +} + +static void +radeon_atom_ext_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + +} + +static void radeon_atom_ext_disable(struct drm_encoder *encoder) +{ + +} + +static void +radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) +{ + +} + +static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { + .dpms = radeon_atom_ext_dpms, + .mode_fixup = radeon_atom_ext_mode_fixup, + .prepare = radeon_atom_ext_prepare, + .mode_set = radeon_atom_ext_mode_set, + .commit = radeon_atom_ext_commit, + .disable = radeon_atom_ext_disable, + /* no detect for TMDS/LVDS yet */ +}; + static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { .dpms = radeon_atom_encoder_dpms, .mode_fixup = radeon_atom_mode_fixup, @@ -1730,6 +1969,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t radeon_encoder->devices = supported_device; radeon_encoder->rmx_type = RMX_OFF; radeon_encoder->underscan_type = UNDERSCAN_OFF; + radeon_encoder->is_ext_encoder = false; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_LVDS: @@ -1771,6 +2011,9 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t radeon_encoder->rmx_type = RMX_FULL; drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); + } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); } else { drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); @@ -1779,5 +2022,22 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t } drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); break; + case ENCODER_OBJECT_ID_SI170B: + case ENCODER_OBJECT_ID_CH7303: + case ENCODER_OBJECT_ID_EXTERNAL_SDVOA: + case ENCODER_OBJECT_ID_EXTERNAL_SDVOB: + case ENCODER_OBJECT_ID_TITFP513: + case ENCODER_OBJECT_ID_VT1623: + case ENCODER_OBJECT_ID_HDMI_SI1930: + /* these are handled by the primary encoders */ + radeon_encoder->is_ext_encoder = true; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); + else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + else + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs); + break; } } diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index e65b90317fab..65016117d95f 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -79,8 +79,8 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev) if (rdev->gart.table.vram.robj == NULL) { r = radeon_bo_create(rdev, NULL, rdev->gart.table_size, - true, RADEON_GEM_DOMAIN_VRAM, - &rdev->gart.table.vram.robj); + PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, + &rdev->gart.table.vram.robj); if (r) { return r; } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index d1e595d91723..df95eb83dac6 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -67,7 +67,7 @@ int radeon_gem_object_create(struct radeon_device *rdev, int size, if (alignment < PAGE_SIZE) { alignment = PAGE_SIZE; } - r = radeon_bo_create(rdev, gobj, size, kernel, initial_domain, &robj); + r = radeon_bo_create(rdev, gobj, size, alignment, kernel, initial_domain, &robj); if (r) { if (r != -ERESTARTSYS) DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n", diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 0cfbba02c4d0..ded2a45bc95c 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -896,7 +896,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, ((rdev->family <= CHIP_RS480) || ((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580))))) { /* set the radeon hw i2c adapter */ - sprintf(i2c->adapter.name, "Radeon i2c hw bus %s", name); + snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), + "Radeon i2c hw bus %s", name); i2c->adapter.algo = &radeon_i2c_algo; ret = i2c_add_adapter(&i2c->adapter); if (ret) { @@ -905,7 +906,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, } } else { /* set the radeon bit adapter */ - sprintf(i2c->adapter.name, "Radeon i2c bit bus %s", name); + snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), + "Radeon i2c bit bus %s", name); i2c->adapter.algo_data = &i2c->algo.bit; i2c->algo.bit.pre_xfer = pre_xfer; i2c->algo.bit.post_xfer = post_xfer; @@ -946,6 +948,8 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, i2c->rec = *rec; i2c->adapter.owner = THIS_MODULE; i2c->dev = dev; + snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), + "Radeon aux bus %s", name); i2c_set_adapdata(&i2c->adapter, i2c); i2c->adapter.algo_data = &i2c->algo.dp; i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch; diff --git a/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c index 2f349a300195..465746bd51b7 100644 --- a/drivers/gpu/drm/radeon/radeon_irq.c +++ b/drivers/gpu/drm/radeon/radeon_irq.c @@ -76,7 +76,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc) default: DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc); - return EINVAL; + return -EINVAL; } } else { switch (crtc) { @@ -89,7 +89,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc) default: DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc); - return EINVAL; + return -EINVAL; } } diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 0b8397000f4c..59f834ba283d 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -670,7 +670,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, if (rdev->is_atom_bios) { radeon_encoder->pixel_clock = adjusted_mode->clock; - atombios_external_tmds_setup(encoder, ATOM_ENABLE); + atombios_dvo_setup(encoder, ATOM_ENABLE); fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); } else { fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 680f57644e86..e301c6f9e059 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -375,6 +375,7 @@ struct radeon_encoder { int hdmi_config_offset; int hdmi_audio_workaround; int hdmi_buffer_status; + bool is_ext_encoder; }; struct radeon_connector_atom_dig { @@ -385,6 +386,7 @@ struct radeon_connector_atom_dig { u8 dp_sink_type; int dp_clock; int dp_lane_count; + bool edp_on; }; struct radeon_gpio_rec { @@ -523,9 +525,10 @@ struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv); struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index); struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index); -extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action); +extern void atombios_dvo_setup(struct drm_encoder *encoder, int action); extern void atombios_digital_setup(struct drm_encoder *encoder, int action); extern int atombios_get_encoder_mode(struct drm_encoder *encoder); +extern void atombios_set_edp_panel_power(struct drm_connector *connector, int action); extern void radeon_encoder_set_active_device(struct drm_encoder *encoder); extern void radeon_crtc_load_lut(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 8eb183466015..a598d0049aa5 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -69,7 +69,7 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) u32 c = 0; rbo->placement.fpfn = 0; - rbo->placement.lpfn = rbo->rdev->mc.active_vram_size >> PAGE_SHIFT; + rbo->placement.lpfn = 0; rbo->placement.placement = rbo->placements; rbo->placement.busy_placement = rbo->placements; if (domain & RADEON_GEM_DOMAIN_VRAM) @@ -86,11 +86,13 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) } int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj, - unsigned long size, bool kernel, u32 domain, - struct radeon_bo **bo_ptr) + unsigned long size, int byte_align, bool kernel, u32 domain, + struct radeon_bo **bo_ptr) { struct radeon_bo *bo; enum ttm_bo_type type; + unsigned long page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT; + unsigned long max_size = 0; int r; if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) { @@ -103,6 +105,14 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj, } *bo_ptr = NULL; + /* maximun bo size is the minimun btw visible vram and gtt size */ + max_size = min(rdev->mc.visible_vram_size, rdev->mc.gtt_size); + if ((page_align << PAGE_SHIFT) >= max_size) { + printk(KERN_WARNING "%s:%d alloc size %ldM bigger than %ldMb limit\n", + __func__, __LINE__, page_align >> (20 - PAGE_SHIFT), max_size >> 20); + return -ENOMEM; + } + retry: bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL); if (bo == NULL) @@ -115,7 +125,7 @@ retry: /* Kernel allocation are uninterruptible */ mutex_lock(&rdev->vram_mutex); r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type, - &bo->placement, 0, 0, !kernel, NULL, size, + &bo->placement, page_align, 0, !kernel, NULL, size, &radeon_ttm_bo_destroy); mutex_unlock(&rdev->vram_mutex); if (unlikely(r != 0)) { diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 3481bc7f6f58..d143702b244a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -137,9 +137,10 @@ static inline int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, } extern int radeon_bo_create(struct radeon_device *rdev, - struct drm_gem_object *gobj, unsigned long size, - bool kernel, u32 domain, - struct radeon_bo **bo_ptr); + struct drm_gem_object *gobj, unsigned long size, + int byte_align, + bool kernel, u32 domain, + struct radeon_bo **bo_ptr); extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr); extern void radeon_bo_kunmap(struct radeon_bo *bo); extern void radeon_bo_unref(struct radeon_bo **bo); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 6ea798ce8218..06e79822a2bf 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -176,8 +176,8 @@ int radeon_ib_pool_init(struct radeon_device *rdev) INIT_LIST_HEAD(&rdev->ib_pool.bogus_ib); /* Allocate 1M object buffer */ r = radeon_bo_create(rdev, NULL, RADEON_IB_POOL_SIZE*64*1024, - true, RADEON_GEM_DOMAIN_GTT, - &rdev->ib_pool.robj); + PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, + &rdev->ib_pool.robj); if (r) { DRM_ERROR("radeon: failed to ib pool (%d).\n", r); return r; @@ -332,7 +332,7 @@ int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size) rdev->cp.ring_size = ring_size; /* Allocate ring buffer */ if (rdev->cp.ring_obj == NULL) { - r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, true, + r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, &rdev->cp.ring_obj); if (r) { diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 313c96bc09da..5b44f652145c 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -52,7 +52,7 @@ void radeon_test_moves(struct radeon_device *rdev) goto out_cleanup; } - r = radeon_bo_create(rdev, NULL, size, true, RADEON_GEM_DOMAIN_VRAM, + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &vram_obj); if (r) { DRM_ERROR("Failed to create VRAM object\n"); @@ -71,7 +71,7 @@ void radeon_test_moves(struct radeon_device *rdev) void **gtt_start, **gtt_end; void **vram_start, **vram_end; - r = radeon_bo_create(rdev, NULL, size, true, + r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT, gtt_obj + i); if (r) { DRM_ERROR("Failed to create GTT object %d\n", i); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 01c2c736a1da..1272e4b6a1d4 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -529,7 +529,7 @@ int radeon_ttm_init(struct radeon_device *rdev) DRM_ERROR("Failed initializing VRAM heap.\n"); return r; } - r = radeon_bo_create(rdev, NULL, 256 * 1024, true, + r = radeon_bo_create(rdev, NULL, 256 * 1024, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, &rdev->stollen_vga_memory); if (r) { diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 245374e2b778..4dfead8cee33 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -915,8 +915,8 @@ static int rv770_vram_scratch_init(struct radeon_device *rdev) if (rdev->vram_scratch.robj == NULL) { r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, - true, RADEON_GEM_DOMAIN_VRAM, - &rdev->vram_scratch.robj); + PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, + &rdev->vram_scratch.robj); if (r) { return r; } diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 3ca77dc03915..148a322d8f5d 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -224,6 +224,9 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, int ret; while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) { + /** + * Deadlock avoidance for multi-bo reserving. + */ if (use_sequence && bo->seq_valid && (sequence - bo->val_seq < (1 << 31))) { return -EAGAIN; @@ -241,6 +244,14 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, } if (use_sequence) { + /** + * Wake up waiters that may need to recheck for deadlock, + * if we decreased the sequence number. + */ + if (unlikely((bo->val_seq - sequence < (1 << 31)) + || !bo->seq_valid)) + wake_up_all(&bo->event_queue); + bo->val_seq = sequence; bo->seq_valid = true; } else { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 36e129f0023f..5408b1b7996f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -862,7 +862,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, &vmw_vram_sys_placement, true, &vmw_user_dmabuf_destroy); if (unlikely(ret != 0)) - return ret; + goto out_no_dmabuf; tmp = ttm_bo_reference(&vmw_user_bo->dma.base); ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile, @@ -870,19 +870,21 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, false, ttm_buffer_type, &vmw_user_dmabuf_release, NULL); - if (unlikely(ret != 0)) { - ttm_bo_unref(&tmp); - } else { + if (unlikely(ret != 0)) + goto out_no_base_object; + else { rep->handle = vmw_user_bo->base.hash.key; rep->map_handle = vmw_user_bo->dma.base.addr_space_offset; rep->cur_gmr_id = vmw_user_bo->base.hash.key; rep->cur_gmr_offset = 0; } - ttm_bo_unref(&tmp); +out_no_base_object: + ttm_bo_unref(&tmp); +out_no_dmabuf: ttm_read_unlock(&vmaster->lock); - return 0; + return ret; } int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 515345b11ac9..88cb04e7962b 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1386,6 +1386,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c index 54b017ad258d..5a1b52e0eb85 100644 --- a/drivers/hid/hid-egalax.c +++ b/drivers/hid/hid-egalax.c @@ -221,7 +221,7 @@ static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id) struct egalax_data *td; struct hid_report *report; - td = kmalloc(sizeof(struct egalax_data), GFP_KERNEL); + td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL); if (!td) { dev_err(&hdev->dev, "cannot allocate eGalax data\n"); return -ENOMEM; diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index bb0b3659437b..d8d372bae3cc 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -174,7 +174,7 @@ static int hidinput_setkeycode(struct input_dev *dev, clear_bit(*old_keycode, dev->keybit); set_bit(usage->code, dev->keybit); - dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", + dbg_hid("Assigned keycode %d to HID usage code %x\n", usage->code, usage->hid); /* @@ -203,8 +203,8 @@ static int hidinput_setkeycode(struct input_dev *dev, * * as seen in the HID specification v1.11 6.2.2.7 Global Items. * - * Only exponent 1 length units are processed. Centimeters are converted to - * inches. Degrees are converted to radians. + * Only exponent 1 length units are processed. Centimeters and inches are + * converted to millimeters. Degrees are converted to radians. */ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) { @@ -225,13 +225,16 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) */ if (code == ABS_X || code == ABS_Y || code == ABS_Z) { if (field->unit == 0x11) { /* If centimeters */ - /* Convert to inches */ - prev = logical_extents; - logical_extents *= 254; - if (logical_extents < prev) + /* Convert to millimeters */ + unit_exponent += 1; + } else if (field->unit == 0x13) { /* If inches */ + /* Convert to millimeters */ + prev = physical_extents; + physical_extents *= 254; + if (physical_extents < prev) return 0; - unit_exponent += 2; - } else if (field->unit != 0x13) { /* If not inches */ + unit_exponent -= 1; + } else { return 0; } } else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) { diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c index 15434c814793..25be4e1461bd 100644 --- a/drivers/hid/hid-tmff.c +++ b/drivers/hid/hid-tmff.c @@ -256,6 +256,8 @@ static const struct hid_device_id tm_devices[] = { .driver_data = (unsigned long)ff_joystick }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654), /* FGT Force Feedback Wheel */ .driver_data = (unsigned long)ff_joystick }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a), /* F430 Force Feedback Wheel */ + .driver_data = (unsigned long)ff_joystick }, { } }; MODULE_DEVICE_TABLE(hid, tm_devices); diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 4bf969c0a32b..be0fdd58aa29 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -916,27 +916,27 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val, orig_div, new_div, shift; + int val, orig_div, new_div; val = simple_strtol(buf, NULL, 10); new_div = DIV_TO_REG(val); - if (new_div == 0) { - return -EINVAL; - } + mutex_lock(&data->update_lock); orig_div = data->fan_div[nr]; data->fan_div[nr] = DIV_FROM_REG(new_div); if (nr < 4) { /* 0 <= nr < 4 */ - shift = 2 * nr; adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3, - ((DIV_TO_REG(orig_div) & (~(0x03 << shift))) | - (new_div << shift))); + (DIV_TO_REG(data->fan_div[0]) << 0) | + (DIV_TO_REG(data->fan_div[1]) << 2) | + (DIV_TO_REG(data->fan_div[2]) << 4) | + (DIV_TO_REG(data->fan_div[3]) << 6)); } else { /* 3 < nr < 8 */ - shift = 2 * (nr - 4); adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7, - ((DIV_TO_REG(orig_div) & (~(0x03 << (2 * shift)))) | - (new_div << shift))); + (DIV_TO_REG(data->fan_div[4]) << 0) | + (DIV_TO_REG(data->fan_div[5]) << 2) | + (DIV_TO_REG(data->fan_div[6]) << 4) | + (DIV_TO_REG(data->fan_div[7]) << 6)); } if (data->fan_div[nr] != orig_div) { diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index 937983407e2a..c4c40be0edbf 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -497,12 +497,14 @@ static unsigned long chipset_ids[] = { 0 }; +#ifdef MODULE static struct pci_device_id i5k_amb_ids[] __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR) }, { 0, } }; MODULE_DEVICE_TABLE(pci, i5k_amb_ids); +#endif static int __devinit i5k_amb_probe(struct platform_device *pdev) { diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 14a5d981be7d..a428a9264195 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -187,6 +187,7 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; #define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_FAN_CTL 0x14 #define IT87_REG_PWM(nr) (0x15 + (nr)) +#define IT87_REG_PWM_DUTY(nr) (0x63 + (nr) * 8) #define IT87_REG_VIN(nr) (0x20 + (nr)) #define IT87_REG_TEMP(nr) (0x29 + (nr)) @@ -251,12 +252,16 @@ struct it87_data { u8 fan_main_ctrl; /* Register value */ u8 fan_ctl; /* Register value */ - /* The following 3 arrays correspond to the same registers. The - * meaning of bits 6-0 depends on the value of bit 7, and we want - * to preserve settings on mode changes, so we have to track all - * values separately. */ + /* The following 3 arrays correspond to the same registers up to + * the IT8720F. The meaning of bits 6-0 depends on the value of bit + * 7, and we want to preserve settings on mode changes, so we have + * to track all values separately. + * Starting with the IT8721F, the manual PWM duty cycles are stored + * in separate registers (8-bit values), so the separate tracking + * is no longer needed, but it is still done to keep the driver + * simple. */ u8 pwm_ctrl[3]; /* Register value */ - u8 pwm_duty[3]; /* Manual PWM value set by user (bit 6-0) */ + u8 pwm_duty[3]; /* Manual PWM value set by user */ u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */ /* Automatic fan speed control registers */ @@ -832,7 +837,9 @@ static ssize_t set_pwm_enable(struct device *dev, data->fan_main_ctrl); } else { if (val == 1) /* Manual mode */ - data->pwm_ctrl[nr] = data->pwm_duty[nr]; + data->pwm_ctrl[nr] = data->type == it8721 ? + data->pwm_temp_map[nr] : + data->pwm_duty[nr]; else /* Automatic mode */ data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr]; it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]); @@ -858,12 +865,25 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - data->pwm_duty[nr] = pwm_to_reg(data, val); - /* If we are in manual mode, write the duty cycle immediately; - * otherwise, just store it for later use. */ - if (!(data->pwm_ctrl[nr] & 0x80)) { - data->pwm_ctrl[nr] = data->pwm_duty[nr]; - it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]); + if (data->type == it8721) { + /* If we are in automatic mode, the PWM duty cycle register + * is read-only so we can't write the value */ + if (data->pwm_ctrl[nr] & 0x80) { + mutex_unlock(&data->update_lock); + return -EBUSY; + } + data->pwm_duty[nr] = pwm_to_reg(data, val); + it87_write_value(data, IT87_REG_PWM_DUTY(nr), + data->pwm_duty[nr]); + } else { + data->pwm_duty[nr] = pwm_to_reg(data, val); + /* If we are in manual mode, write the duty cycle immediately; + * otherwise, just store it for later use. */ + if (!(data->pwm_ctrl[nr] & 0x80)) { + data->pwm_ctrl[nr] = data->pwm_duty[nr]; + it87_write_value(data, IT87_REG_PWM(nr), + data->pwm_ctrl[nr]); + } } mutex_unlock(&data->update_lock); return count; @@ -1958,7 +1978,10 @@ static void __devinit it87_init_device(struct platform_device *pdev) * channels to use when later setting to automatic mode later. * Use a 1:1 mapping by default (we are clueless.) * In both cases, the value can (and should) be changed by the user - * prior to switching to a different mode. */ + * prior to switching to a different mode. + * Note that this is no longer needed for the IT8721F and later, as + * these have separate registers for the temperature mapping and the + * manual duty cycle. */ for (i = 0; i < 3; i++) { data->pwm_temp_map[i] = i; data->pwm_duty[i] = 0x7f; /* Full speed */ @@ -2034,10 +2057,16 @@ static void __devinit it87_init_device(struct platform_device *pdev) static void it87_update_pwm_ctrl(struct it87_data *data, int nr) { data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr)); - if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */ + if (data->type == it8721) { data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; - else /* Manual mode */ - data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f; + data->pwm_duty[nr] = it87_read_value(data, + IT87_REG_PWM_DUTY(nr)); + } else { + if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */ + data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; + else /* Manual mode */ + data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f; + } if (has_old_autopwm(data)) { int i; diff --git a/drivers/hwmon/lis3lv02d_i2c.c b/drivers/hwmon/lis3lv02d_i2c.c index 9f4bae07f719..8853afce85ce 100644 --- a/drivers/hwmon/lis3lv02d_i2c.c +++ b/drivers/hwmon/lis3lv02d_i2c.c @@ -186,7 +186,7 @@ static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int lis3lv02d_i2c_suspend(struct device *dev) { struct i2c_client *client = container_of(dev, struct i2c_client, dev); @@ -213,12 +213,9 @@ static int lis3lv02d_i2c_resume(struct device *dev) return 0; } -#else -#define lis3lv02d_i2c_suspend NULL -#define lis3lv02d_i2c_resume NULL -#define lis3lv02d_i2c_shutdown NULL -#endif +#endif /* CONFIG_PM_SLEEP */ +#ifdef CONFIG_PM_RUNTIME static int lis3_i2c_runtime_suspend(struct device *dev) { struct i2c_client *client = container_of(dev, struct i2c_client, dev); @@ -236,6 +233,7 @@ static int lis3_i2c_runtime_resume(struct device *dev) lis3lv02d_poweron(lis3); return 0; } +#endif /* CONFIG_PM_RUNTIME */ static const struct i2c_device_id lis3lv02d_id[] = { {"lis3lv02d", 0 }, diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c index 00d975eb5b83..c7e6d8e81656 100644 --- a/drivers/hwmon/ltc4215.c +++ b/drivers/hwmon/ltc4215.c @@ -205,7 +205,6 @@ LTC4215_ALARM(curr1_max_alarm, (1 << 2), LTC4215_STATUS); /* Power (virtual) */ LTC4215_POWER(power1_input); -LTC4215_ALARM(power1_alarm, (1 << 3), LTC4215_STATUS); /* Input Voltage */ LTC4215_VOLTAGE(in1_input, LTC4215_ADIN); @@ -214,6 +213,7 @@ LTC4215_ALARM(in1_min_alarm, (1 << 1), LTC4215_STATUS); /* Output Voltage */ LTC4215_VOLTAGE(in2_input, LTC4215_SOURCE); +LTC4215_ALARM(in2_min_alarm, (1 << 3), LTC4215_STATUS); /* Finally, construct an array of pointers to members of the above objects, * as required for sysfs_create_group() @@ -223,13 +223,13 @@ static struct attribute *ltc4215_attributes[] = { &sensor_dev_attr_curr1_max_alarm.dev_attr.attr, &sensor_dev_attr_power1_input.dev_attr.attr, - &sensor_dev_attr_power1_alarm.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in1_max_alarm.dev_attr.attr, &sensor_dev_attr_in1_min_alarm.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_min_alarm.dev_attr.attr, NULL, }; diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index b923074b2cbe..30f06e956bfb 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -75,8 +75,7 @@ config I2C_HELPER_AUTO In doubt, say Y. config I2C_SMBUS - tristate - prompt "SMBus-specific protocols" if !I2C_HELPER_AUTO + tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO help Say Y here if you want support for SMBus extensions to the I2C specification. At the moment, the only supported extension is diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig index 3998dd620a03..f1cfe7e5508b 100644 --- a/drivers/i2c/algos/Kconfig +++ b/drivers/i2c/algos/Kconfig @@ -3,7 +3,7 @@ # menu "I2C Algorithms" - depends on !I2C_HELPER_AUTO + visible if !I2C_HELPER_AUTO config I2C_ALGOBIT tristate "I2C bit-banging interfaces" @@ -15,15 +15,3 @@ config I2C_ALGOPCA tristate "I2C PCA 9564 interfaces" endmenu - -# In automatic configuration mode, we still have to define the -# symbols to avoid unmet dependencies. - -if I2C_HELPER_AUTO -config I2C_ALGOBIT - tristate -config I2C_ALGOPCF - tristate -config I2C_ALGOPCA - tristate -endif diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c index 80f70d3a744d..c71492782bbd 100644 --- a/drivers/i2c/busses/i2c-intel-mid.c +++ b/drivers/i2c/busses/i2c-intel-mid.c @@ -999,7 +999,7 @@ static int __devinit intel_mid_i2c_probe(struct pci_dev *dev, /* Initialize struct members */ snprintf(mrst->adap.name, sizeof(mrst->adap.name), - "MRST/Medfield I2C at %lx", start); + "Intel MID I2C at %lx", start); mrst->adap.owner = THIS_MODULE; mrst->adap.algo = &intel_mid_i2c_algorithm; mrst->adap.dev.parent = &dev->dev; diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 41665d2f9f93..c131d58bcb50 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -273,8 +273,6 @@ static int intel_idle_probe(void) pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates); - if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ - lapic_timer_reliable_states = 0xFFFFFFFF; if (boot_cpu_data.x86 != 6) /* family 6 */ return -ENODEV; @@ -286,8 +284,6 @@ static int intel_idle_probe(void) case 0x1F: /* Core i7 and i5 Processor - Nehalem */ case 0x2E: /* Nehalem-EX Xeon */ case 0x2F: /* Westmere-EX Xeon */ - lapic_timer_reliable_states = (1 << 1); /* C1 */ - case 0x25: /* Westmere */ case 0x2C: /* Westmere */ cpuidle_state_table = nehalem_cstates; @@ -295,7 +291,6 @@ static int intel_idle_probe(void) case 0x1C: /* 28 - Atom Processor */ case 0x26: /* 38 - Lincroft Atom Processor */ - lapic_timer_reliable_states = (1 << 1); /* C1 */ cpuidle_state_table = atom_cstates; break; @@ -303,10 +298,6 @@ static int intel_idle_probe(void) case 0x2D: /* SNB Xeon */ cpuidle_state_table = snb_cstates; break; -#ifdef FUTURE_USE - case 0x17: /* 23 - Core 2 Duo */ - lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */ -#endif default: pr_debug(PREFIX "does not run on family %d model %d\n", @@ -314,6 +305,9 @@ static int intel_idle_probe(void) return -ENODEV; } + if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ + lapic_timer_reliable_states = 0xFFFFFFFF; + pr_debug(PREFIX "v" INTEL_IDLE_VERSION " model 0x%X\n", boot_cpu_data.x86_model); diff --git a/drivers/infiniband/core/ud_header.c b/drivers/infiniband/core/ud_header.c index bb7e19280821..9b737ff133e2 100644 --- a/drivers/infiniband/core/ud_header.c +++ b/drivers/infiniband/core/ud_header.c @@ -278,36 +278,6 @@ void ib_ud_header_init(int payload_bytes, EXPORT_SYMBOL(ib_ud_header_init); /** - * ib_lrh_header_pack - Pack LRH header struct into wire format - * @lrh:unpacked LRH header struct - * @buf:Buffer to pack into - * - * ib_lrh_header_pack() packs the LRH header structure @lrh into - * wire format in the buffer @buf. - */ -int ib_lrh_header_pack(struct ib_unpacked_lrh *lrh, void *buf) -{ - ib_pack(lrh_table, ARRAY_SIZE(lrh_table), lrh, buf); - return 0; -} -EXPORT_SYMBOL(ib_lrh_header_pack); - -/** - * ib_lrh_header_unpack - Unpack LRH structure from wire format - * @lrh:unpacked LRH header struct - * @buf:Buffer to pack into - * - * ib_lrh_header_unpack() unpacks the LRH header structure from - * wire format (in buf) into @lrh. - */ -int ib_lrh_header_unpack(void *buf, struct ib_unpacked_lrh *lrh) -{ - ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), buf, lrh); - return 0; -} -EXPORT_SYMBOL(ib_lrh_header_unpack); - -/** * ib_ud_header_pack - Pack UD header struct into wire format * @header:UD header struct * @buf:Buffer to pack into diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index b342248aec05..c42699285f8e 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -893,68 +893,81 @@ out: return ret ? ret : in_len; } +static int copy_wc_to_user(void __user *dest, struct ib_wc *wc) +{ + struct ib_uverbs_wc tmp; + + tmp.wr_id = wc->wr_id; + tmp.status = wc->status; + tmp.opcode = wc->opcode; + tmp.vendor_err = wc->vendor_err; + tmp.byte_len = wc->byte_len; + tmp.ex.imm_data = (__u32 __force) wc->ex.imm_data; + tmp.qp_num = wc->qp->qp_num; + tmp.src_qp = wc->src_qp; + tmp.wc_flags = wc->wc_flags; + tmp.pkey_index = wc->pkey_index; + tmp.slid = wc->slid; + tmp.sl = wc->sl; + tmp.dlid_path_bits = wc->dlid_path_bits; + tmp.port_num = wc->port_num; + tmp.reserved = 0; + + if (copy_to_user(dest, &tmp, sizeof tmp)) + return -EFAULT; + + return 0; +} + ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) { struct ib_uverbs_poll_cq cmd; - struct ib_uverbs_poll_cq_resp *resp; + struct ib_uverbs_poll_cq_resp resp; + u8 __user *header_ptr; + u8 __user *data_ptr; struct ib_cq *cq; - struct ib_wc *wc; - int ret = 0; - int i; - int rsize; + struct ib_wc wc; + int ret; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL); - if (!wc) - return -ENOMEM; - - rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc); - resp = kmalloc(rsize, GFP_KERNEL); - if (!resp) { - ret = -ENOMEM; - goto out_wc; - } - cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0); - if (!cq) { - ret = -EINVAL; - goto out; - } + if (!cq) + return -EINVAL; - resp->count = ib_poll_cq(cq, cmd.ne, wc); + /* we copy a struct ib_uverbs_poll_cq_resp to user space */ + header_ptr = (void __user *)(unsigned long) cmd.response; + data_ptr = header_ptr + sizeof resp; - put_cq_read(cq); + memset(&resp, 0, sizeof resp); + while (resp.count < cmd.ne) { + ret = ib_poll_cq(cq, 1, &wc); + if (ret < 0) + goto out_put; + if (!ret) + break; + + ret = copy_wc_to_user(data_ptr, &wc); + if (ret) + goto out_put; - for (i = 0; i < resp->count; i++) { - resp->wc[i].wr_id = wc[i].wr_id; - resp->wc[i].status = wc[i].status; - resp->wc[i].opcode = wc[i].opcode; - resp->wc[i].vendor_err = wc[i].vendor_err; - resp->wc[i].byte_len = wc[i].byte_len; - resp->wc[i].ex.imm_data = (__u32 __force) wc[i].ex.imm_data; - resp->wc[i].qp_num = wc[i].qp->qp_num; - resp->wc[i].src_qp = wc[i].src_qp; - resp->wc[i].wc_flags = wc[i].wc_flags; - resp->wc[i].pkey_index = wc[i].pkey_index; - resp->wc[i].slid = wc[i].slid; - resp->wc[i].sl = wc[i].sl; - resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits; - resp->wc[i].port_num = wc[i].port_num; + data_ptr += sizeof(struct ib_uverbs_wc); + ++resp.count; } - if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize)) + if (copy_to_user(header_ptr, &resp, sizeof resp)) { ret = -EFAULT; + goto out_put; + } -out: - kfree(resp); + ret = in_len; -out_wc: - kfree(wc); - return ret ? ret : in_len; +out_put: + put_cq_read(cq); + return ret; } ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file, diff --git a/drivers/infiniband/core/uverbs_marshall.c b/drivers/infiniband/core/uverbs_marshall.c index 5440da0e59b4..1b1146f87124 100644 --- a/drivers/infiniband/core/uverbs_marshall.c +++ b/drivers/infiniband/core/uverbs_marshall.c @@ -40,18 +40,21 @@ void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst, dst->grh.sgid_index = src->grh.sgid_index; dst->grh.hop_limit = src->grh.hop_limit; dst->grh.traffic_class = src->grh.traffic_class; + memset(&dst->grh.reserved, 0, sizeof(dst->grh.reserved)); dst->dlid = src->dlid; dst->sl = src->sl; dst->src_path_bits = src->src_path_bits; dst->static_rate = src->static_rate; dst->is_global = src->ah_flags & IB_AH_GRH ? 1 : 0; dst->port_num = src->port_num; + dst->reserved = 0; } EXPORT_SYMBOL(ib_copy_ah_attr_to_user); void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst, struct ib_qp_attr *src) { + dst->qp_state = src->qp_state; dst->cur_qp_state = src->cur_qp_state; dst->path_mtu = src->path_mtu; dst->path_mig_state = src->path_mig_state; @@ -83,6 +86,7 @@ void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst, dst->rnr_retry = src->rnr_retry; dst->alt_port_num = src->alt_port_num; dst->alt_timeout = src->alt_timeout; + memset(dst->reserved, 0, sizeof(dst->reserved)); } EXPORT_SYMBOL(ib_copy_qp_attr_to_user); diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index bf3e20cd0298..30e09caf0da9 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -219,7 +219,7 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port, struct net_device *ndev; enum ib_mtu tmp; - props->active_width = IB_WIDTH_4X; + props->active_width = IB_WIDTH_1X; props->active_speed = 4; props->port_cap_flags = IB_PORT_CM_SUP; props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port]; @@ -242,7 +242,7 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port, tmp = iboe_get_mtu(ndev->mtu); props->active_mtu = tmp ? min(props->max_mtu, tmp) : IB_MTU_256; - props->state = netif_running(ndev) && netif_oper_up(ndev) ? + props->state = (netif_running(ndev) && netif_carrier_ok(ndev)) ? IB_PORT_ACTIVE : IB_PORT_DOWN; props->phys_state = state_to_phys_state(props->state); diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 9a7794ac34c1..2001f20a4361 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1816,6 +1816,11 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ? MLX4_WQE_CTRL_FENCE : 0) | size; + if (be16_to_cpu(vlan) < 0x1000) { + ctrl->ins_vlan = 1 << 6; + ctrl->vlan_tag = vlan; + } + /* * Make sure descriptor is fully written before * setting ownership bit (because HW can start @@ -1831,11 +1836,6 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, ctrl->owner_opcode = mlx4_ib_opcode[wr->opcode] | (ind & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0) | blh; - if (be16_to_cpu(vlan) < 0x1000) { - ctrl->ins_vlan = 1 << 6; - ctrl->vlan_tag = vlan; - } - stamp = ind + qp->sq_spare_wqes; ind += DIV_ROUND_UP(size * 16, 1U << qp->sq.wqe_shift); diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index e3f7fc6f9565..68f09a868434 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -534,76 +534,73 @@ static int handle_eviocgbit(struct input_dev *dev, } #undef OLD_KEY_MAX -static int evdev_handle_get_keycode(struct input_dev *dev, - void __user *p, size_t size) +static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p) { - struct input_keymap_entry ke; + struct input_keymap_entry ke = { + .len = sizeof(unsigned int), + .flags = 0, + }; + int __user *ip = (int __user *)p; int error; - memset(&ke, 0, sizeof(ke)); - - if (size == sizeof(unsigned int[2])) { - /* legacy case */ - int __user *ip = (int __user *)p; + /* legacy case */ + if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) + return -EFAULT; - if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) - return -EFAULT; + error = input_get_keycode(dev, &ke); + if (error) + return error; - ke.len = sizeof(unsigned int); - ke.flags = 0; + if (put_user(ke.keycode, ip + 1)) + return -EFAULT; - error = input_get_keycode(dev, &ke); - if (error) - return error; + return 0; +} - if (put_user(ke.keycode, ip + 1)) - return -EFAULT; +static int evdev_handle_get_keycode_v2(struct input_dev *dev, void __user *p) +{ + struct input_keymap_entry ke; + int error; - } else { - size = min(size, sizeof(ke)); + if (copy_from_user(&ke, p, sizeof(ke))) + return -EFAULT; - if (copy_from_user(&ke, p, size)) - return -EFAULT; + error = input_get_keycode(dev, &ke); + if (error) + return error; - error = input_get_keycode(dev, &ke); - if (error) - return error; + if (copy_to_user(p, &ke, sizeof(ke))) + return -EFAULT; - if (copy_to_user(p, &ke, size)) - return -EFAULT; - } return 0; } -static int evdev_handle_set_keycode(struct input_dev *dev, - void __user *p, size_t size) +static int evdev_handle_set_keycode(struct input_dev *dev, void __user *p) { - struct input_keymap_entry ke; - - memset(&ke, 0, sizeof(ke)); + struct input_keymap_entry ke = { + .len = sizeof(unsigned int), + .flags = 0, + }; + int __user *ip = (int __user *)p; - if (size == sizeof(unsigned int[2])) { - /* legacy case */ - int __user *ip = (int __user *)p; + if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) + return -EFAULT; - if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) - return -EFAULT; + if (get_user(ke.keycode, ip + 1)) + return -EFAULT; - if (get_user(ke.keycode, ip + 1)) - return -EFAULT; + return input_set_keycode(dev, &ke); +} - ke.len = sizeof(unsigned int); - ke.flags = 0; +static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p) +{ + struct input_keymap_entry ke; - } else { - size = min(size, sizeof(ke)); + if (copy_from_user(&ke, p, sizeof(ke))) + return -EFAULT; - if (copy_from_user(&ke, p, size)) - return -EFAULT; - - if (ke.len > sizeof(ke.scancode)) - return -EINVAL; - } + if (ke.len > sizeof(ke.scancode)) + return -EINVAL; return input_set_keycode(dev, &ke); } @@ -669,6 +666,18 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, return evdev_grab(evdev, client); else return evdev_ungrab(evdev, client); + + case EVIOCGKEYCODE: + return evdev_handle_get_keycode(dev, p); + + case EVIOCSKEYCODE: + return evdev_handle_set_keycode(dev, p); + + case EVIOCGKEYCODE_V2: + return evdev_handle_get_keycode_v2(dev, p); + + case EVIOCSKEYCODE_V2: + return evdev_handle_set_keycode_v2(dev, p); } size = _IOC_SIZE(cmd); @@ -708,12 +717,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, return -EFAULT; return error; - - case EVIOC_MASK_SIZE(EVIOCGKEYCODE): - return evdev_handle_get_keycode(dev, p, size); - - case EVIOC_MASK_SIZE(EVIOCSKEYCODE): - return evdev_handle_set_keycode(dev, p, size); } /* Multi-number variable-length handlers */ diff --git a/drivers/input/input.c b/drivers/input/input.c index 90b7ecfb6257..db409d6bd5d2 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -752,7 +752,7 @@ static int input_default_setkeycode(struct input_dev *dev, if (index >= dev->keycodemax) return -EINVAL; - if (dev->keycodesize < sizeof(dev->keycode) && + if (dev->keycodesize < sizeof(ke->keycode) && (ke->keycode >> (dev->keycodesize * 8))) return -EINVAL; diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index d53b9e900234..27b6a3ce18ca 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -245,6 +245,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) goto err_free_tgfx; } + parport_put_port(pp); return tgfx; err_free_dev: diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index b8c51b9781db..3a87f3ba5f75 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -179,6 +179,22 @@ config KEYBOARD_GPIO To compile this driver as a module, choose M here: the module will be called gpio_keys. +config KEYBOARD_GPIO_POLLED + tristate "Polled GPIO buttons" + depends on GENERIC_GPIO + select INPUT_POLLDEV + help + This driver implements support for buttons connected + to GPIO pins that are not capable of generating interrupts. + + Say Y here if your device has buttons connected + directly to such GPIO pins. Your board-specific + setup logic must also provide a platform device, + with configuration data saying which GPIOs are used. + + To compile this driver as a module, choose M here: the + module will be called gpio_keys_polled. + config KEYBOARD_TCA6416 tristate "TCA6416 Keypad Support" depends on I2C diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index a34452e8ebe2..622de73a445d 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o +obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c new file mode 100644 index 000000000000..4c17aff20657 --- /dev/null +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -0,0 +1,261 @@ +/* + * Driver for buttons on GPIO lines not capable of generating interrupts + * + * Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com> + * + * This file was based on: /drivers/input/misc/cobalt_btns.c + * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * + * also was based on: /drivers/input/keyboard/gpio_keys.c + * Copyright 2005 Phil Blundell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/input-polldev.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/gpio_keys.h> + +#define DRV_NAME "gpio-keys-polled" + +struct gpio_keys_button_data { + int last_state; + int count; + int threshold; + int can_sleep; +}; + +struct gpio_keys_polled_dev { + struct input_polled_dev *poll_dev; + struct device *dev; + struct gpio_keys_platform_data *pdata; + struct gpio_keys_button_data data[0]; +}; + +static void gpio_keys_polled_check_state(struct input_dev *input, + struct gpio_keys_button *button, + struct gpio_keys_button_data *bdata) +{ + int state; + + if (bdata->can_sleep) + state = !!gpio_get_value_cansleep(button->gpio); + else + state = !!gpio_get_value(button->gpio); + + if (state != bdata->last_state) { + unsigned int type = button->type ?: EV_KEY; + + input_event(input, type, button->code, + !!(state ^ button->active_low)); + input_sync(input); + bdata->count = 0; + bdata->last_state = state; + } +} + +static void gpio_keys_polled_poll(struct input_polled_dev *dev) +{ + struct gpio_keys_polled_dev *bdev = dev->private; + struct gpio_keys_platform_data *pdata = bdev->pdata; + struct input_dev *input = dev->input; + int i; + + for (i = 0; i < bdev->pdata->nbuttons; i++) { + struct gpio_keys_button_data *bdata = &bdev->data[i]; + + if (bdata->count < bdata->threshold) + bdata->count++; + else + gpio_keys_polled_check_state(input, &pdata->buttons[i], + bdata); + } +} + +static void gpio_keys_polled_open(struct input_polled_dev *dev) +{ + struct gpio_keys_polled_dev *bdev = dev->private; + struct gpio_keys_platform_data *pdata = bdev->pdata; + + if (pdata->enable) + pdata->enable(bdev->dev); +} + +static void gpio_keys_polled_close(struct input_polled_dev *dev) +{ + struct gpio_keys_polled_dev *bdev = dev->private; + struct gpio_keys_platform_data *pdata = bdev->pdata; + + if (pdata->disable) + pdata->disable(bdev->dev); +} + +static int __devinit gpio_keys_polled_probe(struct platform_device *pdev) +{ + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct gpio_keys_polled_dev *bdev; + struct input_polled_dev *poll_dev; + struct input_dev *input; + int error; + int i; + + if (!pdata || !pdata->poll_interval) + return -EINVAL; + + bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) + + pdata->nbuttons * sizeof(struct gpio_keys_button_data), + GFP_KERNEL); + if (!bdev) { + dev_err(dev, "no memory for private data\n"); + return -ENOMEM; + } + + poll_dev = input_allocate_polled_device(); + if (!poll_dev) { + dev_err(dev, "no memory for polled device\n"); + error = -ENOMEM; + goto err_free_bdev; + } + + poll_dev->private = bdev; + poll_dev->poll = gpio_keys_polled_poll; + poll_dev->poll_interval = pdata->poll_interval; + poll_dev->open = gpio_keys_polled_open; + poll_dev->close = gpio_keys_polled_close; + + input = poll_dev->input; + + input->evbit[0] = BIT(EV_KEY); + input->name = pdev->name; + input->phys = DRV_NAME"/input0"; + input->dev.parent = &pdev->dev; + + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + struct gpio_keys_button_data *bdata = &bdev->data[i]; + unsigned int gpio = button->gpio; + unsigned int type = button->type ?: EV_KEY; + + if (button->wakeup) { + dev_err(dev, DRV_NAME " does not support wakeup\n"); + error = -EINVAL; + goto err_free_gpio; + } + + error = gpio_request(gpio, + button->desc ? button->desc : DRV_NAME); + if (error) { + dev_err(dev, "unable to claim gpio %u, err=%d\n", + gpio, error); + goto err_free_gpio; + } + + error = gpio_direction_input(gpio); + if (error) { + dev_err(dev, + "unable to set direction on gpio %u, err=%d\n", + gpio, error); + goto err_free_gpio; + } + + bdata->can_sleep = gpio_cansleep(gpio); + bdata->last_state = -1; + bdata->threshold = DIV_ROUND_UP(button->debounce_interval, + pdata->poll_interval); + + input_set_capability(input, type, button->code); + } + + bdev->poll_dev = poll_dev; + bdev->dev = dev; + bdev->pdata = pdata; + platform_set_drvdata(pdev, bdev); + + error = input_register_polled_device(poll_dev); + if (error) { + dev_err(dev, "unable to register polled device, err=%d\n", + error); + goto err_free_gpio; + } + + /* report initial state of the buttons */ + for (i = 0; i < pdata->nbuttons; i++) + gpio_keys_polled_check_state(input, &pdata->buttons[i], + &bdev->data[i]); + + return 0; + +err_free_gpio: + while (--i >= 0) + gpio_free(pdata->buttons[i].gpio); + + input_free_polled_device(poll_dev); + +err_free_bdev: + kfree(bdev); + + platform_set_drvdata(pdev, NULL); + return error; +} + +static int __devexit gpio_keys_polled_remove(struct platform_device *pdev) +{ + struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev); + struct gpio_keys_platform_data *pdata = bdev->pdata; + int i; + + input_unregister_polled_device(bdev->poll_dev); + + for (i = 0; i < pdata->nbuttons; i++) + gpio_free(pdata->buttons[i].gpio); + + input_free_polled_device(bdev->poll_dev); + + kfree(bdev); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver gpio_keys_polled_driver = { + .probe = gpio_keys_polled_probe, + .remove = __devexit_p(gpio_keys_polled_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init gpio_keys_polled_init(void) +{ + return platform_driver_register(&gpio_keys_polled_driver); +} + +static void __exit gpio_keys_polled_exit(void) +{ + platform_driver_unregister(&gpio_keys_polled_driver); +} + +module_init(gpio_keys_polled_init); +module_exit(gpio_keys_polled_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_DESCRIPTION("Polled GPIO Buttons driver"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 613a3652f98f..0aefaa885871 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -51,7 +51,8 @@ #define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) #define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) -#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100) +#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ +#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ #define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) /* synaptics modes query bits */ diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 3c287dd879d3..4225f5d6b15f 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -358,7 +358,7 @@ static int __devinit gscps2_probe(struct parisc_device *dev) gscps2_reset(ps2port); ps2port->id = readb(ps2port->addr + GSC_ID) & 0x0f; - snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s", + snprintf(serio->name, sizeof(serio->name), "gsc-ps2-%s", (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse"); strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys)); serio->id.type = SERIO_8042; diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 57b25b84d1fc..0a619c558bfb 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -1097,7 +1097,7 @@ store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(pointer_mode, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletPointerMode, store_tabletPointerMode); /*********************************************************************** @@ -1134,7 +1134,7 @@ store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, co } static DEVICE_ATTR(coordinate_mode, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletCoordinateMode, store_tabletCoordinateMode); /*********************************************************************** @@ -1176,7 +1176,7 @@ store_tabletToolMode(struct device *dev, struct device_attribute *attr, const ch } static DEVICE_ATTR(tool_mode, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletToolMode, store_tabletToolMode); /*********************************************************************** @@ -1219,7 +1219,7 @@ store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char } static DEVICE_ATTR(xtilt, - S_IRUGO | S_IWUGO, show_tabletXtilt, store_tabletXtilt); + S_IRUGO | S_IWUSR, show_tabletXtilt, store_tabletXtilt); /*********************************************************************** * support routines for the 'ytilt' file. Note that this file @@ -1261,7 +1261,7 @@ store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char } static DEVICE_ATTR(ytilt, - S_IRUGO | S_IWUGO, show_tabletYtilt, store_tabletYtilt); + S_IRUGO | S_IWUSR, show_tabletYtilt, store_tabletYtilt); /*********************************************************************** * support routines for the 'jitter' file. Note that this file @@ -1288,7 +1288,7 @@ store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(jitter, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletJitterDelay, store_tabletJitterDelay); /*********************************************************************** @@ -1317,7 +1317,7 @@ store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(delay, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletProgrammableDelay, store_tabletProgrammableDelay); /*********************************************************************** @@ -1406,7 +1406,7 @@ store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(stylus_upper, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletStylusUpper, store_tabletStylusUpper); /*********************************************************************** @@ -1437,7 +1437,7 @@ store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(stylus_lower, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletStylusLower, store_tabletStylusLower); /*********************************************************************** @@ -1475,7 +1475,7 @@ store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const c } static DEVICE_ATTR(mouse_left, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletMouseLeft, store_tabletMouseLeft); /*********************************************************************** @@ -1505,7 +1505,7 @@ store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(mouse_middle, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletMouseMiddle, store_tabletMouseMiddle); /*********************************************************************** @@ -1535,7 +1535,7 @@ store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(mouse_right, - S_IRUGO | S_IWUGO, + S_IRUGO | S_IWUSR, show_tabletMouseRight, store_tabletMouseRight); /*********************************************************************** @@ -1567,7 +1567,7 @@ store_tabletWheel(struct device *dev, struct device_attribute *attr, const char } static DEVICE_ATTR(wheel, - S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel); + S_IRUGO | S_IWUSR, show_tabletWheel, store_tabletWheel); /*********************************************************************** * support routines for the 'execute' file. Note that this file @@ -1600,7 +1600,7 @@ store_tabletExecute(struct device *dev, struct device_attribute *attr, const cha } static DEVICE_ATTR(execute, - S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute); + S_IRUGO | S_IWUSR, show_tabletExecute, store_tabletExecute); /*********************************************************************** * support routines for the 'odm_code' file. Note that this file diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index b3252ef1e279..435b0af401e4 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1436,6 +1436,14 @@ static struct wacom_features wacom_features_0xD2 = { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; static struct wacom_features wacom_features_0xD3 = { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; +static const struct wacom_features wacom_features_0xD4 = + { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, 63, BAMBOO_PT }; +static struct wacom_features wacom_features_0xD8 = + { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; +static struct wacom_features wacom_features_0xDA = + { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; +static struct wacom_features wacom_features_0xDB = + { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; #define USB_DEVICE_WACOM(prod) \ USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \ @@ -1504,6 +1512,10 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xD1) }, { USB_DEVICE_WACOM(0xD2) }, { USB_DEVICE_WACOM(0xD3) }, + { USB_DEVICE_WACOM(0xD4) }, + { USB_DEVICE_WACOM(0xD8) }, + { USB_DEVICE_WACOM(0xDA) }, + { USB_DEVICE_WACOM(0xDB) }, { USB_DEVICE_WACOM(0xF0) }, { USB_DEVICE_WACOM(0xCC) }, { USB_DEVICE_WACOM(0x90) }, diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index f45f80f6d336..73fd6642b681 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -178,6 +178,7 @@ static const struct usb_device_id usbtouch_devices[] = { #ifdef CONFIG_TOUCHSCREEN_USB_ITM {USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM}, + {USB_DEVICE(0x16e3, 0xf9e9), .driver_info = DEVTYPE_ITM}, #endif #ifdef CONFIG_TOUCHSCREEN_USB_ETURBO diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 2e847a90bad0..f2b5bab5e6a1 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1627,7 +1627,7 @@ __setup("icn=", icn_setup); static int __init icn_init(void) { char *p; - char rev[10]; + char rev[20]; memset(&dev, 0, sizeof(icn_dev)); dev.memaddr = (membase & 0x0ffc000); @@ -1637,9 +1637,10 @@ static int __init icn_init(void) spin_lock_init(&dev.devlock); if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 1); + strncpy(rev, p + 1, 20); p = strchr(rev, '$'); - *p = 0; + if (p) + *p = 0; } else strcpy(rev, " ??? "); printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev, diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 77b8fd20cd90..6f190f4cdbc0 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -7,20 +7,20 @@ menuconfig NEW_LEDS This is not related to standard keyboard LEDs which are controlled via the input system. -if NEW_LEDS - config LEDS_CLASS bool "LED Class Support" + depends on NEW_LEDS help This option enables the led sysfs class in /sys/class/leds. You'll need this to do anything useful with LEDs. If unsure, say N. -if LEDS_CLASS +if NEW_LEDS comment "LED drivers" config LEDS_88PM860X tristate "LED Support for Marvell 88PM860x PMIC" + depends on LEDS_CLASS depends on MFD_88PM860X help This option enables support for on-chip LED drivers found on Marvell @@ -28,6 +28,7 @@ config LEDS_88PM860X config LEDS_ATMEL_PWM tristate "LED Support using Atmel PWM outputs" + depends on LEDS_CLASS depends on ATMEL_PWM help This option enables support for LEDs driven using outputs @@ -35,6 +36,7 @@ config LEDS_ATMEL_PWM config LEDS_LOCOMO tristate "LED Support for Locomo device" + depends on LEDS_CLASS depends on SHARP_LOCOMO help This option enables support for the LEDs on Sharp Locomo. @@ -42,6 +44,7 @@ config LEDS_LOCOMO config LEDS_MIKROTIK_RB532 tristate "LED Support for Mikrotik Routerboard 532" + depends on LEDS_CLASS depends on MIKROTIK_RB532 help This option enables support for the so called "User LED" of @@ -49,6 +52,7 @@ config LEDS_MIKROTIK_RB532 config LEDS_S3C24XX tristate "LED Support for Samsung S3C24XX GPIO LEDs" + depends on LEDS_CLASS depends on ARCH_S3C2410 help This option enables support for LEDs connected to GPIO lines @@ -56,12 +60,14 @@ config LEDS_S3C24XX config LEDS_AMS_DELTA tristate "LED Support for the Amstrad Delta (E3)" + depends on LEDS_CLASS depends on MACH_AMS_DELTA help This option enables support for the LEDs on Amstrad Delta (E3). config LEDS_NET48XX tristate "LED Support for Soekris net48xx series Error LED" + depends on LEDS_CLASS depends on SCx200_GPIO help This option enables support for the Soekris net4801 and net4826 error @@ -79,18 +85,21 @@ config LEDS_NET5501 config LEDS_FSG tristate "LED Support for the Freecom FSG-3" + depends on LEDS_CLASS depends on MACH_FSG help This option enables support for the LEDs on the Freecom FSG-3. config LEDS_WRAP tristate "LED Support for the WRAP series LEDs" + depends on LEDS_CLASS depends on SCx200_GPIO help This option enables support for the PCEngines WRAP programmable LEDs. config LEDS_ALIX2 tristate "LED Support for ALIX.2 and ALIX.3 series" + depends on LEDS_CLASS depends on X86 && !GPIO_CS5535 && !CS5535_GPIO help This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs. @@ -98,12 +107,14 @@ config LEDS_ALIX2 config LEDS_H1940 tristate "LED Support for iPAQ H1940 device" + depends on LEDS_CLASS depends on ARCH_H1940 help This option enables support for the LEDs on the h1940. config LEDS_COBALT_QUBE tristate "LED Support for the Cobalt Qube series front LED" + depends on LEDS_CLASS depends on MIPS_COBALT help This option enables support for the front LED on Cobalt Qube series @@ -117,6 +128,7 @@ config LEDS_COBALT_RAQ config LEDS_SUNFIRE tristate "LED support for SunFire servers." + depends on LEDS_CLASS depends on SPARC64 select LEDS_TRIGGERS help @@ -125,6 +137,7 @@ config LEDS_SUNFIRE config LEDS_HP6XX tristate "LED Support for the HP Jornada 6xx" + depends on LEDS_CLASS depends on SH_HP6XX help This option enables LED support for the handheld @@ -132,6 +145,7 @@ config LEDS_HP6XX config LEDS_PCA9532 tristate "LED driver for PCA9532 dimmer" + depends on LEDS_CLASS depends on I2C && INPUT && EXPERIMENTAL help This option enables support for NXP pca9532 @@ -140,6 +154,7 @@ config LEDS_PCA9532 config LEDS_GPIO tristate "LED Support for GPIO connected LEDs" + depends on LEDS_CLASS depends on GENERIC_GPIO help This option enables support for the LEDs connected to GPIO @@ -167,6 +182,7 @@ config LEDS_GPIO_OF config LEDS_LP3944 tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip" + depends on LEDS_CLASS depends on I2C help This option enables support for LEDs connected to the National @@ -196,6 +212,7 @@ config LEDS_LP5523 config LEDS_CLEVO_MAIL tristate "Mail LED on Clevo notebook" + depends on LEDS_CLASS depends on X86 && SERIO_I8042 && DMI help This driver makes the mail LED accessible from userspace @@ -226,6 +243,7 @@ config LEDS_CLEVO_MAIL config LEDS_PCA955X tristate "LED Support for PCA955x I2C chips" + depends on LEDS_CLASS depends on I2C help This option enables support for LEDs connected to PCA955x @@ -234,6 +252,7 @@ config LEDS_PCA955X config LEDS_WM831X_STATUS tristate "LED support for status LEDs on WM831x PMICs" + depends on LEDS_CLASS depends on MFD_WM831X help This option enables support for the status LEDs of the WM831x @@ -241,6 +260,7 @@ config LEDS_WM831X_STATUS config LEDS_WM8350 tristate "LED Support for WM8350 AudioPlus PMIC" + depends on LEDS_CLASS depends on MFD_WM8350 help This option enables support for LEDs driven by the Wolfson @@ -248,6 +268,7 @@ config LEDS_WM8350 config LEDS_DA903X tristate "LED Support for DA9030/DA9034 PMIC" + depends on LEDS_CLASS depends on PMIC_DA903X help This option enables support for on-chip LED drivers found @@ -255,6 +276,7 @@ config LEDS_DA903X config LEDS_DAC124S085 tristate "LED Support for DAC124S085 SPI DAC" + depends on LEDS_CLASS depends on SPI help This option enables support for DAC124S085 SPI DAC from NatSemi, @@ -262,18 +284,21 @@ config LEDS_DAC124S085 config LEDS_PWM tristate "PWM driven LED Support" + depends on LEDS_CLASS depends on HAVE_PWM help This option enables support for pwm driven LEDs config LEDS_REGULATOR tristate "REGULATOR driven LED support" + depends on LEDS_CLASS depends on REGULATOR help This option enables support for regulator driven LEDs. config LEDS_BD2802 tristate "LED driver for BD2802 RGB LED" + depends on LEDS_CLASS depends on I2C help This option enables support for BD2802GU RGB LED driver chips @@ -281,6 +306,7 @@ config LEDS_BD2802 config LEDS_INTEL_SS4200 tristate "LED driver for Intel NAS SS4200 series" + depends on LEDS_CLASS depends on PCI && DMI help This option enables support for the Intel SS4200 series of @@ -290,6 +316,7 @@ config LEDS_INTEL_SS4200 config LEDS_LT3593 tristate "LED driver for LT3593 controllers" + depends on LEDS_CLASS depends on GENERIC_GPIO help This option enables support for LEDs driven by a Linear Technology @@ -298,6 +325,7 @@ config LEDS_LT3593 config LEDS_ADP5520 tristate "LED Support for ADP5520/ADP5501 PMIC" + depends on LEDS_CLASS depends on PMIC_ADP5520 help This option enables support for on-chip LED drivers found @@ -308,6 +336,7 @@ config LEDS_ADP5520 config LEDS_DELL_NETBOOKS tristate "External LED on Dell Business Netbooks" + depends on LEDS_CLASS depends on X86 && ACPI_WMI help This adds support for the Latitude 2100 and similar @@ -315,6 +344,7 @@ config LEDS_DELL_NETBOOKS config LEDS_MC13783 tristate "LED Support for MC13783 PMIC" + depends on LEDS_CLASS depends on MFD_MC13783 help This option enable support for on-chip LED drivers found @@ -322,6 +352,7 @@ config LEDS_MC13783 config LEDS_NS2 tristate "LED support for Network Space v2 GPIO LEDs" + depends on LEDS_CLASS depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || MACH_NETSPACE_MAX_V2 || D2NET_V2 default y help @@ -340,17 +371,17 @@ config LEDS_NETXBIG config LEDS_TRIGGERS bool "LED Trigger support" + depends on LEDS_CLASS help This option enables trigger support for the leds class. These triggers allow kernel events to drive the LEDs and can be configured via sysfs. If unsure, say Y. -if LEDS_TRIGGERS - comment "LED Triggers" config LEDS_TRIGGER_TIMER tristate "LED Timer Trigger" + depends on LEDS_TRIGGERS help This allows LEDs to be controlled by a programmable timer via sysfs. Some LED hardware can be programmed to start @@ -362,12 +393,14 @@ config LEDS_TRIGGER_TIMER config LEDS_TRIGGER_IDE_DISK bool "LED IDE Disk Trigger" depends on IDE_GD_ATA + depends on LEDS_TRIGGERS help This allows LEDs to be controlled by IDE disk activity. If unsure, say Y. config LEDS_TRIGGER_HEARTBEAT tristate "LED Heartbeat Trigger" + depends on LEDS_TRIGGERS help This allows LEDs to be controlled by a CPU load average. The flash frequency is a hyperbolic function of the 1-minute @@ -376,6 +409,7 @@ config LEDS_TRIGGER_HEARTBEAT config LEDS_TRIGGER_BACKLIGHT tristate "LED backlight Trigger" + depends on LEDS_TRIGGERS help This allows LEDs to be controlled as a backlight device: they turn off and on when the display is blanked and unblanked. @@ -384,6 +418,7 @@ config LEDS_TRIGGER_BACKLIGHT config LEDS_TRIGGER_GPIO tristate "LED GPIO Trigger" + depends on LEDS_TRIGGERS depends on GPIOLIB help This allows LEDs to be controlled by gpio events. It's good @@ -396,6 +431,7 @@ config LEDS_TRIGGER_GPIO config LEDS_TRIGGER_DEFAULT_ON tristate "LED Default ON Trigger" + depends on LEDS_TRIGGERS help This allows LEDs to be initialised in the ON state. If unsure, say Y. @@ -403,8 +439,4 @@ config LEDS_TRIGGER_DEFAULT_ON comment "iptables trigger is under Netfilter config (LED target)" depends on LEDS_TRIGGERS -endif # LEDS_TRIGGERS - -endif # LEDS_CLASS - endif # NEW_LEDS diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 3782f31f06d2..33facd0c45d1 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -125,11 +125,22 @@ struct lp5521_chip { u8 num_leds; }; -#define cdev_to_led(c) container_of(c, struct lp5521_led, cdev) -#define engine_to_lp5521(eng) container_of((eng), struct lp5521_chip, \ - engines[(eng)->id - 1]) -#define led_to_lp5521(led) container_of((led), struct lp5521_chip, \ - leds[(led)->id]) +static inline struct lp5521_led *cdev_to_led(struct led_classdev *cdev) +{ + return container_of(cdev, struct lp5521_led, cdev); +} + +static inline struct lp5521_chip *engine_to_lp5521(struct lp5521_engine *engine) +{ + return container_of(engine, struct lp5521_chip, + engines[engine->id - 1]); +} + +static inline struct lp5521_chip *led_to_lp5521(struct lp5521_led *led) +{ + return container_of(led, struct lp5521_chip, + leds[led->id]); +} static void lp5521_led_brightness_work(struct work_struct *work); @@ -185,14 +196,17 @@ static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern) /* move current engine to direct mode and remember the state */ ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT); - usleep_range(1000, 10000); + /* Mode change requires min 500 us delay. 1 - 2 ms with margin */ + usleep_range(1000, 2000); ret |= lp5521_read(client, LP5521_REG_OP_MODE, &mode); /* For loading, all the engines to load mode */ lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT); - usleep_range(1000, 10000); + /* Mode change requires min 500 us delay. 1 - 2 ms with margin */ + usleep_range(1000, 2000); lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_LOAD); - usleep_range(1000, 10000); + /* Mode change requires min 500 us delay. 1 - 2 ms with margin */ + usleep_range(1000, 2000); addr = LP5521_PROG_MEM_BASE + eng->prog_page * LP5521_PROG_MEM_SIZE; i2c_smbus_write_i2c_block_data(client, @@ -231,10 +245,6 @@ static int lp5521_configure(struct i2c_client *client, lp5521_init_engine(chip, attr_group); - lp5521_write(client, LP5521_REG_RESET, 0xff); - - usleep_range(10000, 20000); - /* Set all PWMs to direct control mode */ ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); @@ -251,8 +261,8 @@ static int lp5521_configure(struct i2c_client *client, ret |= lp5521_write(client, LP5521_REG_ENABLE, LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM | LP5521_EXEC_RUN); - /* enable takes 500us */ - usleep_range(500, 20000); + /* enable takes 500us. 1 - 2 ms leaves some margin */ + usleep_range(1000, 2000); return ret; } @@ -305,7 +315,8 @@ static int lp5521_detect(struct i2c_client *client) LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM); if (ret) return ret; - usleep_range(1000, 10000); + /* enable takes 500us. 1 - 2 ms leaves some margin */ + usleep_range(1000, 2000); ret = lp5521_read(client, LP5521_REG_ENABLE, &buf); if (ret) return ret; @@ -693,11 +704,16 @@ static int lp5521_probe(struct i2c_client *client, if (pdata->enable) { pdata->enable(0); - usleep_range(1000, 10000); + usleep_range(1000, 2000); /* Keep enable down at least 1ms */ pdata->enable(1); - usleep_range(1000, 10000); /* Spec says min 500us */ + usleep_range(1000, 2000); /* 500us abs min. */ } + lp5521_write(client, LP5521_REG_RESET, 0xff); + usleep_range(10000, 20000); /* + * Exact value is not available. 10 - 20ms + * appears to be enough for reset. + */ ret = lp5521_detect(client); if (ret) { diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 1e11fcc08b28..0cc4ead2fd8b 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -134,15 +134,18 @@ struct lp5523_chip { u8 num_leds; }; -#define cdev_to_led(c) container_of(c, struct lp5523_led, cdev) +static inline struct lp5523_led *cdev_to_led(struct led_classdev *cdev) +{ + return container_of(cdev, struct lp5523_led, cdev); +} -static struct lp5523_chip *engine_to_lp5523(struct lp5523_engine *engine) +static inline struct lp5523_chip *engine_to_lp5523(struct lp5523_engine *engine) { return container_of(engine, struct lp5523_chip, engines[engine->id - 1]); } -static struct lp5523_chip *led_to_lp5523(struct lp5523_led *led) +static inline struct lp5523_chip *led_to_lp5523(struct lp5523_led *led) { return container_of(led, struct lp5523_chip, leds[led->id]); @@ -200,13 +203,9 @@ static int lp5523_configure(struct i2c_client *client) { 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0}, }; - lp5523_write(client, LP5523_REG_RESET, 0xff); - - usleep_range(10000, 100000); - ret |= lp5523_write(client, LP5523_REG_ENABLE, LP5523_ENABLE); - /* Chip startup time after reset is 500 us */ - usleep_range(1000, 10000); + /* Chip startup time is 500 us, 1 - 2 ms gives some margin */ + usleep_range(1000, 2000); ret |= lp5523_write(client, LP5523_REG_CONFIG, LP5523_AUTO_INC | LP5523_PWR_SAVE | @@ -243,8 +242,8 @@ static int lp5523_configure(struct i2c_client *client) return -1; } - /* Wait 3ms and check the engine status */ - usleep_range(3000, 20000); + /* Let the programs run for couple of ms and check the engine status */ + usleep_range(3000, 6000); lp5523_read(client, LP5523_REG_STATUS, &status); status &= LP5523_ENG_STATUS_MASK; @@ -449,10 +448,10 @@ static ssize_t lp5523_selftest(struct device *dev, /* Measure VDD (i.e. VBAT) first (channel 16 corresponds to VDD) */ lp5523_write(chip->client, LP5523_REG_LED_TEST_CTRL, LP5523_EN_LEDTEST | 16); - usleep_range(3000, 10000); + usleep_range(3000, 6000); /* ADC conversion time is typically 2.7 ms */ ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status); if (!(status & LP5523_LEDTEST_DONE)) - usleep_range(3000, 10000); + usleep_range(3000, 6000); /* Was not ready. Wait little bit */ ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &vdd); vdd--; /* There may be some fluctuation in measurement */ @@ -468,16 +467,16 @@ static ssize_t lp5523_selftest(struct device *dev, chip->pdata->led_config[i].led_current); lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0xff); - /* let current stabilize 2ms before measurements start */ - usleep_range(2000, 10000); + /* let current stabilize 2 - 4ms before measurements start */ + usleep_range(2000, 4000); lp5523_write(chip->client, LP5523_REG_LED_TEST_CTRL, LP5523_EN_LEDTEST | i); - /* ledtest takes 2.7ms */ - usleep_range(3000, 10000); + /* ADC conversion time is 2.7 ms typically */ + usleep_range(3000, 6000); ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status); if (!(status & LP5523_LEDTEST_DONE)) - usleep_range(3000, 10000); + usleep_range(3000, 6000);/* Was not ready. Wait. */ ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &adc); if (adc >= vdd || adc < LP5523_ADC_SHORTCIRC_LIM) @@ -930,11 +929,16 @@ static int lp5523_probe(struct i2c_client *client, if (pdata->enable) { pdata->enable(0); - usleep_range(1000, 10000); + usleep_range(1000, 2000); /* Keep enable down at least 1ms */ pdata->enable(1); - usleep_range(1000, 10000); /* Spec says min 500us */ + usleep_range(1000, 2000); /* 500us abs min. */ } + lp5523_write(client, LP5523_REG_RESET, 0xff); + usleep_range(10000, 20000); /* + * Exact value is not available. 10 - 20ms + * appears to be enough for reset. + */ ret = lp5523_detect(client); if (ret) goto fail2; diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c index a688293abd0b..614ebebaaa28 100644 --- a/drivers/leds/leds-ss4200.c +++ b/drivers/leds/leds-ss4200.c @@ -102,6 +102,7 @@ static struct dmi_system_id __initdata nas_led_whitelist[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00") } }, + {} }; /* diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 3d7355ff7308..fa51af11c6f1 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -102,6 +102,7 @@ config ADB_PMU_LED config ADB_PMU_LED_IDE bool "Use front LED as IDE LED by default" depends on ADB_PMU_LED + depends on LEDS_CLASS select LEDS_TRIGGERS select LEDS_TRIGGER_IDE_DISK help diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 90267f8d64ee..4d705cea0f8c 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -517,9 +517,8 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, */ if (q->merge_bvec_fn && !ti->type->merge) - limits->max_sectors = - min_not_zero(limits->max_sectors, - (unsigned int) (PAGE_SIZE >> 9)); + blk_limits_max_hw_sectors(limits, + (unsigned int) (PAGE_SIZE >> 9)); return 0; } EXPORT_SYMBOL_GPL(dm_set_device_limits); @@ -1131,11 +1130,6 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, */ q->limits = *limits; - if (limits->no_cluster) - queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); - else - queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q); - if (!dm_table_supports_discards(t)) queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); else diff --git a/drivers/md/md.c b/drivers/md/md.c index 324a3663fcda..175c424f201f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -371,10 +371,15 @@ static void md_end_flush(struct bio *bio, int err) bio_put(bio); } -static void submit_flushes(mddev_t *mddev) +static void md_submit_flush_data(struct work_struct *ws); + +static void submit_flushes(struct work_struct *ws) { + mddev_t *mddev = container_of(ws, mddev_t, flush_work); mdk_rdev_t *rdev; + INIT_WORK(&mddev->flush_work, md_submit_flush_data); + atomic_set(&mddev->flush_pending, 1); rcu_read_lock(); list_for_each_entry_rcu(rdev, &mddev->disks, same_set) if (rdev->raid_disk >= 0 && @@ -397,6 +402,8 @@ static void submit_flushes(mddev_t *mddev) rdev_dec_pending(rdev, mddev); } rcu_read_unlock(); + if (atomic_dec_and_test(&mddev->flush_pending)) + queue_work(md_wq, &mddev->flush_work); } static void md_submit_flush_data(struct work_struct *ws) @@ -404,8 +411,6 @@ static void md_submit_flush_data(struct work_struct *ws) mddev_t *mddev = container_of(ws, mddev_t, flush_work); struct bio *bio = mddev->flush_bio; - atomic_set(&mddev->flush_pending, 1); - if (bio->bi_size == 0) /* an empty barrier - all done */ bio_endio(bio, 0); @@ -414,10 +419,9 @@ static void md_submit_flush_data(struct work_struct *ws) if (mddev->pers->make_request(mddev, bio)) generic_make_request(bio); } - if (atomic_dec_and_test(&mddev->flush_pending)) { - mddev->flush_bio = NULL; - wake_up(&mddev->sb_wait); - } + + mddev->flush_bio = NULL; + wake_up(&mddev->sb_wait); } void md_flush_request(mddev_t *mddev, struct bio *bio) @@ -429,13 +433,8 @@ void md_flush_request(mddev_t *mddev, struct bio *bio) mddev->flush_bio = bio; spin_unlock_irq(&mddev->write_lock); - atomic_set(&mddev->flush_pending, 1); - INIT_WORK(&mddev->flush_work, md_submit_flush_data); - - submit_flushes(mddev); - - if (atomic_dec_and_test(&mddev->flush_pending)) - queue_work(md_wq, &mddev->flush_work); + INIT_WORK(&mddev->flush_work, submit_flushes); + queue_work(md_wq, &mddev->flush_work); } EXPORT_SYMBOL(md_flush_request); @@ -1337,7 +1336,7 @@ super_90_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors) md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size, rdev->sb_page); md_super_wait(rdev->mddev); - return num_sectors / 2; /* kB for sysfs */ + return num_sectors; } @@ -1704,7 +1703,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors) md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size, rdev->sb_page); md_super_wait(rdev->mddev); - return num_sectors / 2; /* kB for sysfs */ + return num_sectors; } static struct super_type super_types[] = { @@ -4296,9 +4295,6 @@ static int md_alloc(dev_t dev, char *name) goto abort; mddev->queue->queuedata = mddev; - /* Can be unlocked because the queue is new: no concurrency */ - queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, mddev->queue); - blk_queue_make_request(mddev->queue, md_make_request); disk = alloc_disk(1 << shift); @@ -4338,6 +4334,8 @@ static int md_alloc(dev_t dev, char *name) if (mddev->kobj.sd && sysfs_create_group(&mddev->kobj, &md_bitmap_group)) printk(KERN_DEBUG "pointless warning\n"); + + blk_queue_flush(mddev->queue, REQ_FLUSH | REQ_FUA); abort: mutex_unlock(&disks_mutex); if (!error && mddev->kobj.sd) { @@ -5158,7 +5156,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) PTR_ERR(rdev)); return PTR_ERR(rdev); } - /* set save_raid_disk if appropriate */ + /* set saved_raid_disk if appropriate */ if (!mddev->persistent) { if (info->state & (1<<MD_DISK_SYNC) && info->raid_disk < mddev->raid_disks) @@ -5168,7 +5166,10 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) } else super_types[mddev->major_version]. validate_super(mddev, rdev); - rdev->saved_raid_disk = rdev->raid_disk; + if (test_bit(In_sync, &rdev->flags)) + rdev->saved_raid_disk = rdev->raid_disk; + else + rdev->saved_raid_disk = -1; clear_bit(In_sync, &rdev->flags); /* just to be sure */ if (info->state & (1<<MD_DISK_WRITEMOSTLY)) @@ -6040,9 +6041,8 @@ static int md_thread(void * arg) || kthread_should_stop(), thread->timeout); - clear_bit(THREAD_WAKEUP, &thread->flags); - - thread->run(thread->mddev); + if (test_and_clear_bit(THREAD_WAKEUP, &thread->flags)) + thread->run(thread->mddev); } return 0; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 45f8324196ec..845cf95b612c 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1161,6 +1161,7 @@ static int raid1_remove_disk(mddev_t *mddev, int number) * is not possible. */ if (!test_bit(Faulty, &rdev->flags) && + !mddev->recovery_disabled && mddev->degraded < conf->raid_disks) { err = -EBUSY; goto abort; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index c67aa54694ae..0641674827f0 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2397,13 +2397,13 @@ static int run(mddev_t *mddev) return 0; out_free_conf: + md_unregister_thread(mddev->thread); if (conf->r10bio_pool) mempool_destroy(conf->r10bio_pool); safe_put_page(conf->tmppage); kfree(conf->mirrors); kfree(conf); mddev->private = NULL; - md_unregister_thread(mddev->thread); out: return -EIO; } diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c index 05bde9ccb770..1d1d8d200755 100644 --- a/drivers/media/common/saa7146_hlp.c +++ b/drivers/media/common/saa7146_hlp.c @@ -558,7 +558,7 @@ static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, e static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat) { struct saa7146_vv *vv = dev->vv_data; - struct saa7146_format *sfmt = format_by_fourcc(dev, pixelformat); + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat); int b_depth = vv->ov_fmt->depth; int b_bpl = vv->ov_fb.fmt.bytesperline; @@ -702,7 +702,7 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71 struct saa7146_vv *vv = dev->vv_data; struct saa7146_video_dma vdma1; - struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); int width = buf->fmt->width; int height = buf->fmt->height; @@ -827,7 +827,7 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71 struct saa7146_video_dma vdma2; struct saa7146_video_dma vdma3; - struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); int width = buf->fmt->width; int height = buf->fmt->height; @@ -994,7 +994,7 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar) void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) { - struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); struct saa7146_vv *vv = dev->vv_data; u32 vdma1_prot_addr; diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 741c5732b430..d246910129e8 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -84,7 +84,7 @@ static struct saa7146_format formats[] = { static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format); -struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc) +struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc) { int i, j = NUM_FORMATS; @@ -266,7 +266,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); struct scatterlist *list = dma->sglist; int length = dma->sglen; - struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); @@ -408,7 +408,7 @@ static int video_begin(struct saa7146_fh *fh) } } - fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); + fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); /* we need to have a valid format set here */ BUG_ON(NULL == fmt); @@ -460,7 +460,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file) return -EBUSY; } - fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); + fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); /* we need to have a valid format set here */ BUG_ON(NULL == fmt); @@ -536,7 +536,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f return -EPERM; /* check args */ - fmt = format_by_fourcc(dev, fb->fmt.pixelformat); + fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat); if (NULL == fmt) return -EINVAL; @@ -760,7 +760,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); - fmt = format_by_fourcc(dev, f->fmt.pix.pixelformat); + fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL; @@ -1264,7 +1264,7 @@ static int buffer_prepare(struct videobuf_queue *q, buf->fmt = &fh->video_fmt; buf->vb.field = fh->video_fmt.field; - sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); release_all_pagetables(dev, buf); if( 0 != IS_PLANAR(sfmt->trans)) { @@ -1378,7 +1378,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file) fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24; fh->video_fmt.bytesperline = 0; fh->video_fmt.field = V4L2_FIELD_ANY; - sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); + sfmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8; videobuf_queue_sg_init(&fh->video_q, &video_qops, diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig index 2385e6cca635..78b089526e02 100644 --- a/drivers/media/common/tuners/Kconfig +++ b/drivers/media/common/tuners/Kconfig @@ -31,7 +31,7 @@ config MEDIA_TUNER select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE -menuconfig MEDIA_TUNER_CUSTOMISE +config MEDIA_TUNER_CUSTOMISE bool "Customize analog and hybrid tuner modules to build" depends on MEDIA_TUNER default y if EMBEDDED @@ -44,7 +44,8 @@ menuconfig MEDIA_TUNER_CUSTOMISE If unsure say N. -if MEDIA_TUNER_CUSTOMISE +menu "Customize TV tuners" + visible if MEDIA_TUNER_CUSTOMISE config MEDIA_TUNER_SIMPLE tristate "Simple tuner support" @@ -185,5 +186,4 @@ config MEDIA_TUNER_TDA18218 default m if MEDIA_TUNER_CUSTOMISE help NXP TDA18218 silicon tuner driver. - -endif # MEDIA_TUNER_CUSTOMISE +endmenu diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index e9062b08a485..96b27016670e 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -12,9 +12,8 @@ config DVB_FE_CUSTOMISE If unsure say N. -if DVB_FE_CUSTOMISE - menu "Customise DVB Frontends" + visible if DVB_FE_CUSTOMISE comment "Multistandard (satellite) frontends" depends on DVB_CORE @@ -619,5 +618,3 @@ config DVB_DUMMY_FE tristate "Dummy frontend driver" default n endmenu - -endif diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 5bf4985daede..05e832f61c3e 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -361,7 +361,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations rtrack_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { @@ -412,13 +412,6 @@ static int __init rtrack_init(void) rt->vdev.release = video_device_release_empty; video_set_drvdata(&rt->vdev, rt); - if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(&rt->v4l2_dev); - release_region(rt->io, 2); - return -EINVAL; - } - v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n"); - /* Set up the I/O locking */ mutex_init(&rt->lock); @@ -430,6 +423,13 @@ static int __init rtrack_init(void) sleep_delay(2000000); /* make sure it's totally down */ outb(0xc0, rt->io); /* steady volume, mute card */ + if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(&rt->v4l2_dev); + release_region(rt->io, 2); + return -EINVAL; + } + v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n"); + return 0; } diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index c22311393624..dd8a6ab0d437 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -324,7 +324,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, static const struct v4l2_file_operations aztech_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops aztech_ioctl_ops = { @@ -375,6 +375,8 @@ static int __init aztech_init(void) az->vdev.ioctl_ops = &aztech_ioctl_ops; az->vdev.release = video_device_release_empty; video_set_drvdata(&az->vdev, az); + /* mute card - prevents noisy bootups */ + outb(0, az->io); if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(v4l2_dev); @@ -383,8 +385,6 @@ static int __init aztech_init(void) } v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); - /* mute card - prevents noisy bootups */ - outb(0, az->io); return 0; } diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index b701ea6e7c73..bc9ad0897c55 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -328,11 +328,10 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo unsigned char readbuf[RDS_BUFFER]; int i = 0; + mutex_lock(&dev->lock); if (dev->rdsstat == 0) { - mutex_lock(&dev->lock); dev->rdsstat = 1; outb(0x80, dev->io); /* Select RDS fifo */ - mutex_unlock(&dev->lock); init_timer(&dev->readtimer); dev->readtimer.function = cadet_handler; dev->readtimer.data = (unsigned long)dev; @@ -340,12 +339,15 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo add_timer(&dev->readtimer); } if (dev->rdsin == dev->rdsout) { + mutex_unlock(&dev->lock); if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; interruptible_sleep_on(&dev->read_queue); + mutex_lock(&dev->lock); } while (i < count && dev->rdsin != dev->rdsout) readbuf[i++] = dev->rdsbuf[dev->rdsout++]; + mutex_unlock(&dev->lock); if (copy_to_user(data, readbuf, i)) return -EFAULT; @@ -525,9 +527,11 @@ static int cadet_open(struct file *file) { struct cadet *dev = video_drvdata(file); + mutex_lock(&dev->lock); dev->users++; if (1 == dev->users) init_waitqueue_head(&dev->read_queue); + mutex_unlock(&dev->lock); return 0; } @@ -535,11 +539,13 @@ static int cadet_release(struct file *file) { struct cadet *dev = video_drvdata(file); + mutex_lock(&dev->lock); dev->users--; if (0 == dev->users) { del_timer_sync(&dev->readtimer); dev->rdsstat = 0; } + mutex_unlock(&dev->lock); return 0; } @@ -559,7 +565,7 @@ static const struct v4l2_file_operations cadet_fops = { .open = cadet_open, .release = cadet_release, .read = cadet_read, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .poll = cadet_poll, }; diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index 79039674a0e0..28fa85ba2087 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -361,7 +361,7 @@ MODULE_DEVICE_TABLE(pci, gemtek_pci_id); static const struct v4l2_file_operations gemtek_pci_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = { @@ -422,11 +422,11 @@ static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_dev card->vdev.release = video_device_release_empty; video_set_drvdata(&card->vdev, card); + gemtek_pci_mute(card); + if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0) goto err_video; - gemtek_pci_mute(card); - v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", pdev->revision, card->iobase, card->iobase + card->length - 1); diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 73985f641f07..259936422e49 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -378,7 +378,7 @@ static int gemtek_probe(struct gemtek *gt) static const struct v4l2_file_operations gemtek_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static int vidioc_querycap(struct file *file, void *priv, @@ -577,12 +577,6 @@ static int __init gemtek_init(void) gt->vdev.release = video_device_release_empty; video_set_drvdata(>->vdev, gt); - if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(gt->io, 1); - return -EBUSY; - } - /* Set defaults */ gt->lastfreq = GEMTEK_LOWFREQ; gt->bu2614data = 0; @@ -590,6 +584,12 @@ static int __init gemtek_init(void) if (initmute) gemtek_mute(gt); + if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(gt->io, 1); + return -EBUSY; + } + return 0; } diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index 08f1051979ca..6af61bfeb178 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -299,7 +299,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations maestro_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops maestro_ioctl_ops = { @@ -383,22 +383,20 @@ static int __devinit maestro_probe(struct pci_dev *pdev, dev->vdev.release = video_device_release_empty; video_set_drvdata(&dev->vdev, dev); + if (!radio_power_on(dev)) { + retval = -EIO; + goto errfr1; + } + retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr); if (retval) { v4l2_err(v4l2_dev, "can't register video device!\n"); goto errfr1; } - if (!radio_power_on(dev)) { - retval = -EIO; - goto errunr; - } - v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n"); return 0; -errunr: - video_unregister_device(&dev->vdev); errfr1: v4l2_device_unregister(v4l2_dev); errfr: diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 255d40df4b46..6459a220b0dd 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -346,7 +346,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, static const struct v4l2_file_operations maxiradio_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 4ff885445fd4..3fb76e3834c9 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -33,6 +33,7 @@ struct pcm20 { unsigned long freq; int muted; struct snd_miro_aci *aci; + struct mutex lock; }; static struct pcm20 pcm20_card = { @@ -72,7 +73,7 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq) static const struct v4l2_file_operations pcm20_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static int vidioc_querycap(struct file *file, void *priv, @@ -229,7 +230,7 @@ static int __init pcm20_init(void) return -ENODEV; } strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name)); - + mutex_init(&dev->lock); res = v4l2_device_register(NULL, v4l2_dev); if (res < 0) { @@ -242,6 +243,7 @@ static int __init pcm20_init(void) dev->vdev.fops = &pcm20_fops; dev->vdev.ioctl_ops = &pcm20_ioctl_ops; dev->vdev.release = video_device_release_empty; + dev->vdev.lock = &dev->lock; video_set_drvdata(&dev->vdev, dev); if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index a79296aac9a9..8d6ea591bd18 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -266,7 +266,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations rtrack2_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { @@ -315,6 +315,10 @@ static int __init rtrack2_init(void) dev->vdev.release = video_device_release_empty; video_set_drvdata(&dev->vdev, dev); + /* mute card - prevents noisy bootups */ + outb(1, dev->io); + dev->muted = 1; + mutex_init(&dev->lock); if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(v4l2_dev); @@ -324,10 +328,6 @@ static int __init rtrack2_init(void) v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n"); - /* mute card - prevents noisy bootups */ - outb(1, dev->io); - dev->muted = 1; - return 0; } diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 985359d18aa5..b5a5f89e238a 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -260,7 +260,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations fmi_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops fmi_ioctl_ops = { @@ -382,6 +382,9 @@ static int __init fmi_init(void) mutex_init(&fmi->lock); + /* mute card - prevents noisy bootups */ + fmi_mute(fmi); + if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(v4l2_dev); release_region(fmi->io, 2); @@ -391,8 +394,6 @@ static int __init fmi_init(void) } v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io); - /* mute card - prevents noisy bootups */ - fmi_mute(fmi); return 0; } diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 52c7bbb32b8b..dc3f04c52d5e 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -376,7 +376,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations fmr2_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops fmr2_ioctl_ops = { @@ -424,6 +424,10 @@ static int __init fmr2_init(void) fmr2->vdev.release = video_device_release_empty; video_set_drvdata(&fmr2->vdev, fmr2); + /* mute card - prevents noisy bootups */ + fmr2_mute(fmr2->io); + fmr2_product_info(fmr2); + if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(v4l2_dev); release_region(fmr2->io, 2); @@ -431,11 +435,6 @@ static int __init fmr2_init(void) } v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io); - /* mute card - prevents noisy bootups */ - mutex_lock(&fmr2->lock); - fmr2_mute(fmr2->io); - fmr2_product_info(fmr2); - mutex_unlock(&fmr2->lock); debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type)); return 0; } diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 6a435786b63d..726d367ad8d0 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -53,7 +53,8 @@ struct radio_si4713_device { /* radio_si4713_fops - file operations interface */ static const struct v4l2_file_operations radio_si4713_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + /* Note: locking is done at the subdev level in the i2c driver. */ + .unlocked_ioctl = video_ioctl2, }; /* Video4Linux Interface */ @@ -291,7 +292,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev) goto unregister_v4l2_dev; } - sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, NULL, + sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, pdata->subdev_board_info, NULL); if (!sd) { dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n"); diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 789d2ec66e19..0e71d816c725 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -142,7 +142,6 @@ struct tea5764_device { struct video_device *videodev; struct tea5764_regs regs; struct mutex mutex; - int users; }; /* I2C code related */ @@ -458,41 +457,10 @@ static int vidioc_s_audio(struct file *file, void *priv, return 0; } -static int tea5764_open(struct file *file) -{ - /* Currently we support only one device */ - struct tea5764_device *radio = video_drvdata(file); - - mutex_lock(&radio->mutex); - /* Only exclusive access */ - if (radio->users) { - mutex_unlock(&radio->mutex); - return -EBUSY; - } - radio->users++; - mutex_unlock(&radio->mutex); - file->private_data = radio; - return 0; -} - -static int tea5764_close(struct file *file) -{ - struct tea5764_device *radio = video_drvdata(file); - - if (!radio) - return -ENODEV; - mutex_lock(&radio->mutex); - radio->users--; - mutex_unlock(&radio->mutex); - return 0; -} - /* File system interface */ static const struct v4l2_file_operations tea5764_fops = { .owner = THIS_MODULE, - .open = tea5764_open, - .release = tea5764_close, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops tea5764_ioctl_ops = { @@ -527,7 +495,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client, int ret; PDEBUG("probe"); - radio = kmalloc(sizeof(struct tea5764_device), GFP_KERNEL); + radio = kzalloc(sizeof(struct tea5764_device), GFP_KERNEL); if (!radio) return -ENOMEM; @@ -555,12 +523,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, radio); video_set_drvdata(radio->videodev, radio); - - ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); - if (ret < 0) { - PWARN("Could not register video device!"); - goto errrel; - } + radio->videodev->lock = &radio->mutex; /* initialize and power off the chip */ tea5764_i2c_read(radio); @@ -568,6 +531,12 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client, tea5764_mute(radio, 1); tea5764_power_down(radio); + ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); + if (ret < 0) { + PWARN("Could not register video device!"); + goto errrel; + } + PINFO("registered."); return 0; errrel: diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index fc1c860fd438..a32663917059 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -338,7 +338,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations terratec_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops terratec_ioctl_ops = { @@ -389,6 +389,9 @@ static int __init terratec_init(void) mutex_init(&tt->lock); + /* mute card - prevents noisy bootups */ + tt_write_vol(tt, 0); + if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(&tt->v4l2_dev); release_region(tt->io, 2); @@ -396,9 +399,6 @@ static int __init terratec_init(void) } v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n"); - - /* mute card - prevents noisy bootups */ - tt_write_vol(tt, 0); return 0; } diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index b8bb3ef47df5..a185610b376b 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -34,6 +34,7 @@ struct timbradio { struct v4l2_subdev *sd_dsp; struct video_device video_dev; struct v4l2_device v4l2_dev; + struct mutex lock; }; @@ -142,7 +143,7 @@ static const struct v4l2_ioctl_ops timbradio_ioctl_ops = { static const struct v4l2_file_operations timbradio_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static int __devinit timbradio_probe(struct platform_device *pdev) @@ -164,6 +165,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev) } tr->pdata = *pdata; + mutex_init(&tr->lock); strlcpy(tr->video_dev.name, "Timberdale Radio", sizeof(tr->video_dev.name)); @@ -171,6 +173,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev) tr->video_dev.ioctl_ops = &timbradio_ioctl_ops; tr->video_dev.release = video_device_release_empty; tr->video_dev.minor = -1; + tr->video_dev.lock = &tr->lock; strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name)); err = v4l2_device_register(NULL, &tr->v4l2_dev); diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index 9d6dcf8af5b0..22fa9cc28abe 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -344,7 +344,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations trust_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops trust_ioctl_ops = { @@ -396,14 +396,6 @@ static int __init trust_init(void) tr->vdev.release = video_device_release_empty; video_set_drvdata(&tr->vdev, tr); - if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(tr->io, 2); - return -EINVAL; - } - - v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n"); - write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ @@ -418,6 +410,14 @@ static int __init trust_init(void) /* mute card - prevents noisy bootups */ tr_setmute(tr, 1); + if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(tr->io, 2); + return -EINVAL; + } + + v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n"); + return 0; } diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index b1f630527dc1..8dbbf08f2207 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -317,7 +317,7 @@ static int vidioc_log_status(struct file *file, void *priv) static const struct v4l2_file_operations typhoon_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { @@ -344,18 +344,18 @@ static int __init typhoon_init(void) strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name)); dev->io = io; - dev->curfreq = dev->mutefreq = mutefreq; if (dev->io == -1) { v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n"); return -EINVAL; } - if (dev->mutefreq < 87000 || dev->mutefreq > 108500) { + if (mutefreq < 87000 || mutefreq > 108500) { v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n"); v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); return -EINVAL; } + dev->curfreq = dev->mutefreq = mutefreq << 4; mutex_init(&dev->lock); if (!request_region(dev->io, 8, "typhoon")) { @@ -378,17 +378,17 @@ static int __init typhoon_init(void) dev->vdev.ioctl_ops = &typhoon_ioctl_ops; dev->vdev.release = video_device_release_empty; video_set_drvdata(&dev->vdev, dev); + + /* mute card - prevents noisy bootups */ + typhoon_mute(dev); + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(&dev->v4l2_dev); release_region(dev->io, 8); return -EINVAL; } v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io); - v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", dev->mutefreq); - dev->mutefreq <<= 4; - - /* mute card - prevents noisy bootups */ - typhoon_mute(dev); + v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq); return 0; } diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index f31eab99c943..af99c5bd88c1 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -377,7 +377,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations zoltrix_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { @@ -424,20 +424,6 @@ static int __init zoltrix_init(void) return res; } - strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name)); - zol->vdev.v4l2_dev = v4l2_dev; - zol->vdev.fops = &zoltrix_fops; - zol->vdev.ioctl_ops = &zoltrix_ioctl_ops; - zol->vdev.release = video_device_release_empty; - video_set_drvdata(&zol->vdev, zol); - - if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(zol->io, 2); - return -EINVAL; - } - v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n"); - mutex_init(&zol->lock); /* mute card - prevents noisy bootups */ @@ -452,6 +438,20 @@ static int __init zoltrix_init(void) zol->curvol = 0; zol->stereo = 1; + strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name)); + zol->vdev.v4l2_dev = v4l2_dev; + zol->vdev.fops = &zoltrix_fops; + zol->vdev.ioctl_ops = &zoltrix_ioctl_ops; + zol->vdev.release = video_device_release_empty; + video_set_drvdata(&zol->vdev, zol); + + if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(zol->io, 2); + return -EINVAL; + } + v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n"); + return 0; } diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index ac16e815e275..6830d2848bd7 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -112,7 +112,7 @@ config VIDEO_IR_I2C # menu "Encoders/decoders and other helper chips" - depends on !VIDEO_HELPER_CHIPS_AUTO + visible if !VIDEO_HELPER_CHIPS_AUTO comment "Audio decoders" diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 31e7a123d19a..f989f2820d88 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -712,7 +712,7 @@ static int ar_initialize(struct ar *ar) static const struct v4l2_file_operations ar_fops = { .owner = THIS_MODULE, .read = ar_read, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops ar_ioctl_ops = { diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c index 0453816d4ec3..01be89fa5c78 100644 --- a/drivers/media/video/au0828/au0828-cards.c +++ b/drivers/media/video/au0828/au0828-cards.c @@ -212,7 +212,7 @@ void au0828_card_setup(struct au0828_dev *dev) be abstracted out if we ever need to support a different demod) */ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - NULL, "au8522", 0x8e >> 1, NULL); + "au8522", 0x8e >> 1, NULL); if (sd == NULL) printk(KERN_ERR "analog subdev registration failed\n"); } @@ -221,7 +221,7 @@ void au0828_card_setup(struct au0828_dev *dev) if (dev->board.tuner_type != TUNER_ABSENT) { /* Load the tuner module, which does the attach */ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - NULL, "tuner", dev->board.tuner_addr, NULL); + "tuner", dev->board.tuner_addr, NULL); if (sd == NULL) printk(KERN_ERR "tuner subdev registration fail\n"); diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 87d8b006ef77..49efcf660ba6 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -3529,7 +3529,7 @@ void __devinit bttv_init_card2(struct bttv *btv) struct v4l2_subdev *sd; sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, NULL, "saa6588", 0, addrs); + &btv->c.i2c_adap, "saa6588", 0, addrs); btv->has_saa6588 = (sd != NULL); } @@ -3554,7 +3554,7 @@ void __devinit bttv_init_card2(struct bttv *btv) }; btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, NULL, "msp3400", 0, addrs); + &btv->c.i2c_adap, "msp3400", 0, addrs); if (btv->sd_msp34xx) return; goto no_audio; @@ -3568,7 +3568,7 @@ void __devinit bttv_init_card2(struct bttv *btv) }; if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, NULL, "tda7432", 0, addrs)) + &btv->c.i2c_adap, "tda7432", 0, addrs)) return; goto no_audio; } @@ -3576,7 +3576,7 @@ void __devinit bttv_init_card2(struct bttv *btv) case 3: { /* The user specified that we should probe for tvaudio */ btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs()); + &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); if (btv->sd_tvaudio) return; goto no_audio; @@ -3596,11 +3596,11 @@ void __devinit bttv_init_card2(struct bttv *btv) found is really something else (e.g. a tea6300). */ if (!bttv_tvcards[btv->c.type].no_msp34xx) { btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, NULL, "msp3400", + &btv->c.i2c_adap, "msp3400", 0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1)); } else if (bttv_tvcards[btv->c.type].msp34xx_alt) { btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, NULL, "msp3400", + &btv->c.i2c_adap, "msp3400", 0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1)); } @@ -3616,13 +3616,13 @@ void __devinit bttv_init_card2(struct bttv *btv) }; if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, NULL, "tda7432", 0, addrs)) + &btv->c.i2c_adap, "tda7432", 0, addrs)) return; } /* Now see if we can find one of the tvaudio devices. */ btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs()); + &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); if (btv->sd_tvaudio) return; @@ -3646,13 +3646,13 @@ void __devinit bttv_init_tuner(struct bttv *btv) /* Load tuner module before issuing tuner config call! */ if (bttv_tvcards[btv->c.type].has_radio) v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, NULL, "tuner", + &btv->c.i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, NULL, "tuner", + &btv->c.i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, NULL, "tuner", + &btv->c.i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD)); tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index a529619e51f6..0902ec041c7a 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -854,7 +854,6 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM; /* is it free? */ - mutex_lock(&btv->lock); if (btv->resources & xbits) { /* no, someone else uses it */ goto fail; @@ -884,11 +883,9 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) /* it's free, grab it */ fh->resources |= bit; btv->resources |= bit; - mutex_unlock(&btv->lock); return 1; fail: - mutex_unlock(&btv->lock); return 0; } @@ -940,7 +937,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) /* trying to free ressources not allocated by us ... */ printk("bttv: BUG! (btres)\n"); } - mutex_lock(&btv->lock); fh->resources &= ~bits; btv->resources &= ~bits; @@ -951,8 +947,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) if (0 == (bits & VBI_RESOURCES)) disclaim_vbi_lines(btv); - - mutex_unlock(&btv->lock); } /* ----------------------------------------------------------------------- */ @@ -1713,28 +1707,20 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, /* Make sure tvnorm and vbi_end remain consistent until we're done. */ - mutex_lock(&btv->lock); norm = btv->tvnorm; /* In this mode capturing always starts at defrect.top (default VDELAY), ignoring cropping parameters. */ if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) { - mutex_unlock(&btv->lock); return -EINVAL; } - mutex_unlock(&btv->lock); - c.rect = bttv_tvnorms[norm].cropcap.defrect; } else { - mutex_lock(&btv->lock); - norm = btv->tvnorm; c = btv->crop[!!fh->do_crop]; - mutex_unlock(&btv->lock); - if (width < c.min_scaled_width || width > c.max_scaled_width || height < c.min_scaled_height) @@ -1858,7 +1844,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) unsigned int i; int err; - mutex_lock(&btv->lock); err = v4l2_prio_check(&btv->prio, fh->prio); if (err) goto err; @@ -1874,7 +1859,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) set_tvnorm(btv, i); err: - mutex_unlock(&btv->lock); return err; } @@ -1898,7 +1882,6 @@ static int bttv_enum_input(struct file *file, void *priv, struct bttv *btv = fh->btv; int rc = 0; - mutex_lock(&btv->lock); if (i->index >= bttv_tvcards[btv->c.type].video_inputs) { rc = -EINVAL; goto err; @@ -1928,7 +1911,6 @@ static int bttv_enum_input(struct file *file, void *priv, i->std = BTTV_NORMS; err: - mutex_unlock(&btv->lock); return rc; } @@ -1938,9 +1920,7 @@ static int bttv_g_input(struct file *file, void *priv, unsigned int *i) struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); *i = btv->input; - mutex_unlock(&btv->lock); return 0; } @@ -1952,7 +1932,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i) int err; - mutex_lock(&btv->lock); err = v4l2_prio_check(&btv->prio, fh->prio); if (unlikely(err)) goto err; @@ -1965,7 +1944,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i) set_input(btv, i, btv->tvnorm); err: - mutex_unlock(&btv->lock); return 0; } @@ -1979,7 +1957,6 @@ static int bttv_s_tuner(struct file *file, void *priv, if (unlikely(0 != t->index)) return -EINVAL; - mutex_lock(&btv->lock); if (unlikely(btv->tuner_type == TUNER_ABSENT)) { err = -EINVAL; goto err; @@ -1995,7 +1972,6 @@ static int bttv_s_tuner(struct file *file, void *priv, btv->audio_mode_gpio(btv, t, 1); err: - mutex_unlock(&btv->lock); return 0; } @@ -2006,10 +1982,8 @@ static int bttv_g_frequency(struct file *file, void *priv, struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = btv->freq; - mutex_unlock(&btv->lock); return 0; } @@ -2024,7 +1998,6 @@ static int bttv_s_frequency(struct file *file, void *priv, if (unlikely(f->tuner != 0)) return -EINVAL; - mutex_lock(&btv->lock); err = v4l2_prio_check(&btv->prio, fh->prio); if (unlikely(err)) goto err; @@ -2039,7 +2012,6 @@ static int bttv_s_frequency(struct file *file, void *priv, if (btv->has_matchbox && btv->radio_user) tea5757_set_freq(btv, btv->freq); err: - mutex_unlock(&btv->lock); return 0; } @@ -2172,7 +2144,6 @@ limit_scaled_size_lock (struct bttv_fh * fh, /* Make sure tvnorm, vbi_end and the current cropping parameters remain consistent until we're done. */ - mutex_lock(&btv->lock); b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; @@ -2250,7 +2221,6 @@ limit_scaled_size_lock (struct bttv_fh * fh, rc = 0; /* success */ fail: - mutex_unlock(&btv->lock); return rc; } @@ -2282,9 +2252,7 @@ verify_window_lock (struct bttv_fh * fh, if (V4L2_FIELD_ANY == field) { __s32 height2; - mutex_lock(&fh->btv->lock); height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1; - mutex_unlock(&fh->btv->lock); field = (win->w.height > height2) ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; @@ -2360,7 +2328,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, } } - mutex_lock(&fh->cap.vb_lock); /* clip against screen */ if (NULL != btv->fbuf.base) n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height, @@ -2391,13 +2358,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, fh->ov.field = win->field; fh->ov.setup_ok = 1; - /* - * FIXME: btv is protected by btv->lock mutex, while btv->init - * is protected by fh->cap.vb_lock. This seems to open the - * possibility for some race situations. Maybe the better would - * be to unify those locks or to use another way to store the - * init values that will be consumed by videobuf callbacks - */ btv->init.ov.w.width = win->w.width; btv->init.ov.w.height = win->w.height; btv->init.ov.field = win->field; @@ -2412,7 +2372,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); } - mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -2526,9 +2485,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, if (V4L2_FIELD_ANY == field) { __s32 height2; - mutex_lock(&btv->lock); height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - mutex_unlock(&btv->lock); field = (f->fmt.pix.height > height2) ? V4L2_FIELD_INTERLACED : V4L2_FIELD_BOTTOM; @@ -2614,7 +2571,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); /* update our state informations */ - mutex_lock(&fh->cap.vb_lock); fh->fmt = fmt; fh->cap.field = f->fmt.pix.field; fh->cap.last = V4L2_FIELD_NONE; @@ -2623,7 +2579,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; - mutex_unlock(&fh->cap.vb_lock); return 0; } @@ -2649,11 +2604,9 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) unsigned int i; struct bttv_fh *fh = priv; - mutex_lock(&fh->cap.vb_lock); retval = __videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize, V4L2_MEMORY_MMAP); if (retval < 0) { - mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -2665,7 +2618,6 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) for (i = 0; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; - mutex_unlock(&fh->cap.vb_lock); return 0; } #endif @@ -2775,10 +2727,8 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) int retval = 0; if (on) { - mutex_lock(&fh->cap.vb_lock); /* verify args */ if (unlikely(!btv->fbuf.base)) { - mutex_unlock(&fh->cap.vb_lock); return -EINVAL; } if (unlikely(!fh->ov.setup_ok)) { @@ -2787,13 +2737,11 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) } if (retval) return retval; - mutex_unlock(&fh->cap.vb_lock); } if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY)) return -EBUSY; - mutex_lock(&fh->cap.vb_lock); if (on) { fh->ov.tvnorm = btv->tvnorm; new = videobuf_sg_alloc(sizeof(*new)); @@ -2805,7 +2753,6 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) /* switch over */ retval = bttv_switch_overlay(btv, fh, new); - mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -2844,7 +2791,6 @@ static int bttv_s_fbuf(struct file *file, void *f, } /* ok, accept it */ - mutex_lock(&fh->cap.vb_lock); btv->fbuf.base = fb->base; btv->fbuf.fmt.width = fb->fmt.width; btv->fbuf.fmt.height = fb->fmt.height; @@ -2876,7 +2822,6 @@ static int bttv_s_fbuf(struct file *file, void *f, retval = bttv_switch_overlay(btv, fh, new); } } - mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -2955,7 +2900,6 @@ static int bttv_queryctrl(struct file *file, void *priv, c->id >= V4L2_CID_PRIVATE_LASTP1)) return -EINVAL; - mutex_lock(&btv->lock); if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) *c = no_ctl; else { @@ -2963,7 +2907,6 @@ static int bttv_queryctrl(struct file *file, void *priv, *c = (NULL != ctrl) ? *ctrl : no_ctl; } - mutex_unlock(&btv->lock); return 0; } @@ -2974,10 +2917,8 @@ static int bttv_g_parm(struct file *file, void *f, struct bttv_fh *fh = f; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id, &parm->parm.capture.timeperframe); - mutex_unlock(&btv->lock); return 0; } @@ -2993,7 +2934,6 @@ static int bttv_g_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; - mutex_lock(&btv->lock); t->rxsubchans = V4L2_TUNER_SUB_MONO; bttv_call_all(btv, tuner, g_tuner, t); strcpy(t->name, "Television"); @@ -3005,7 +2945,6 @@ static int bttv_g_tuner(struct file *file, void *priv, if (btv->audio_mode_gpio) btv->audio_mode_gpio(btv, t, 0); - mutex_unlock(&btv->lock); return 0; } @@ -3014,9 +2953,7 @@ static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) struct bttv_fh *fh = f; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); *p = v4l2_prio_max(&btv->prio); - mutex_unlock(&btv->lock); return 0; } @@ -3028,9 +2965,7 @@ static int bttv_s_priority(struct file *file, void *f, struct bttv *btv = fh->btv; int rc; - mutex_lock(&btv->lock); rc = v4l2_prio_change(&btv->prio, &fh->prio, prio); - mutex_unlock(&btv->lock); return rc; } @@ -3045,9 +2980,7 @@ static int bttv_cropcap(struct file *file, void *priv, cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) return -EINVAL; - mutex_lock(&btv->lock); *cap = bttv_tvnorms[btv->tvnorm].cropcap; - mutex_unlock(&btv->lock); return 0; } @@ -3065,9 +2998,7 @@ static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop) inconsistent with fh->width or fh->height and apps do not expect a change here. */ - mutex_lock(&btv->lock); crop->c = btv->crop[!!fh->do_crop].rect; - mutex_unlock(&btv->lock); return 0; } @@ -3091,17 +3022,14 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) /* Make sure tvnorm, vbi_end and the current cropping parameters remain consistent until we're done. Note read() may change vbi_end in check_alloc_btres_lock(). */ - mutex_lock(&btv->lock); retval = v4l2_prio_check(&btv->prio, fh->prio); if (0 != retval) { - mutex_unlock(&btv->lock); return retval; } retval = -EBUSY; if (locked_btres(fh->btv, VIDEO_RESOURCES)) { - mutex_unlock(&btv->lock); return retval; } @@ -3113,7 +3041,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) b_top = max(b->top, btv->vbi_end); if (b_top + 32 >= b_bottom) { - mutex_unlock(&btv->lock); return retval; } @@ -3136,12 +3063,8 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->crop[1] = c; - mutex_unlock(&btv->lock); - fh->do_crop = 1; - mutex_lock(&fh->cap.vb_lock); - if (fh->width < c.min_scaled_width) { fh->width = c.min_scaled_width; btv->init.width = c.min_scaled_width; @@ -3158,8 +3081,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->init.height = c.max_scaled_height; } - mutex_unlock(&fh->cap.vb_lock); - return 0; } @@ -3227,7 +3148,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) return videobuf_poll_stream(file, &fh->vbi, wait); } - mutex_lock(&fh->cap.vb_lock); if (check_btres(fh,RESOURCE_VIDEO_STREAM)) { /* streaming capture */ if (list_empty(&fh->cap.stream)) @@ -3262,7 +3182,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) else rc = 0; err: - mutex_unlock(&fh->cap.vb_lock); return rc; } @@ -3293,23 +3212,11 @@ static int bttv_open(struct file *file) return -ENOMEM; file->private_data = fh; - /* - * btv is protected by btv->lock mutex, while btv->init and other - * streaming vars are protected by fh->cap.vb_lock. We need to take - * care of both locks to avoid troubles. However, vb_lock is used also - * inside videobuf, without calling buf->lock. So, it is a very bad - * idea to hold both locks at the same time. - * Let's first copy btv->init at fh, holding cap.vb_lock, and then work - * with the rest of init, holding btv->lock. - */ - mutex_lock(&fh->cap.vb_lock); *fh = btv->init; - mutex_unlock(&fh->cap.vb_lock); fh->type = type; fh->ov.setup_ok = 0; - mutex_lock(&btv->lock); v4l2_prio_open(&btv->prio, &fh->prio); videobuf_queue_sg_init(&fh->cap, &bttv_video_qops, @@ -3317,13 +3224,13 @@ static int bttv_open(struct file *file) V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct bttv_buffer), - fh, NULL); + fh, &btv->lock); videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops, &btv->c.pci->dev, &btv->s_lock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, sizeof(struct bttv_buffer), - fh, NULL); + fh, &btv->lock); set_tvnorm(btv,btv->tvnorm); set_input(btv, btv->input, btv->tvnorm); @@ -3346,7 +3253,6 @@ static int bttv_open(struct file *file) bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm); bttv_field_count(btv); - mutex_unlock(&btv->lock); return 0; } @@ -3355,7 +3261,6 @@ static int bttv_release(struct file *file) struct bttv_fh *fh = file->private_data; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); /* turn off overlay */ if (check_btres(fh, RESOURCE_OVERLAY)) bttv_switch_overlay(btv,fh,NULL); @@ -3381,14 +3286,8 @@ static int bttv_release(struct file *file) /* free stuff */ - /* - * videobuf uses cap.vb_lock - we should avoid holding btv->lock, - * otherwise we may have dead lock conditions - */ - mutex_unlock(&btv->lock); videobuf_mmap_free(&fh->cap); videobuf_mmap_free(&fh->vbi); - mutex_lock(&btv->lock); v4l2_prio_close(&btv->prio, fh->prio); file->private_data = NULL; kfree(fh); @@ -3398,7 +3297,6 @@ static int bttv_release(struct file *file) if (!btv->users) audio_mute(btv, 1); - mutex_unlock(&btv->lock); return 0; } @@ -3502,11 +3400,8 @@ static int radio_open(struct file *file) if (unlikely(!fh)) return -ENOMEM; file->private_data = fh; - mutex_lock(&fh->cap.vb_lock); *fh = btv->init; - mutex_unlock(&fh->cap.vb_lock); - mutex_lock(&btv->lock); v4l2_prio_open(&btv->prio, &fh->prio); btv->radio_user++; @@ -3514,7 +3409,6 @@ static int radio_open(struct file *file) bttv_call_all(btv, tuner, s_radio); audio_input(btv,TVAUDIO_INPUT_RADIO); - mutex_unlock(&btv->lock); return 0; } @@ -3524,7 +3418,6 @@ static int radio_release(struct file *file) struct bttv *btv = fh->btv; struct rds_command cmd; - mutex_lock(&btv->lock); v4l2_prio_close(&btv->prio, fh->prio); file->private_data = NULL; kfree(fh); @@ -3532,7 +3425,6 @@ static int radio_release(struct file *file) btv->radio_user--; bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd); - mutex_unlock(&btv->lock); return 0; } @@ -3561,7 +3453,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return -EINVAL; if (0 != t->index) return -EINVAL; - mutex_lock(&btv->lock); strcpy(t->name, "Radio"); t->type = V4L2_TUNER_RADIO; @@ -3570,8 +3461,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) if (btv->audio_mode_gpio) btv->audio_mode_gpio(btv, t, 0); - mutex_unlock(&btv->lock); - return 0; } @@ -3692,7 +3581,7 @@ static const struct v4l2_file_operations radio_fops = .open = radio_open, .read = radio_read, .release = radio_release, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .poll = radio_poll, }; diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 935e0c9a9674..c1193506131c 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -860,7 +860,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf, static const struct v4l2_file_operations qcam_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .read = qcam_read, }; diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 6e4b19698c13..24fc00965a12 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -718,7 +718,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf, static const struct v4l2_file_operations qcam_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .read = qcam_read, }; diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 7bc36670071a..0dfff50891e4 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1775,7 +1775,7 @@ static const struct v4l2_file_operations cafe_v4l_fops = { .read = cafe_v4l_read, .poll = cafe_v4l_poll, .mmap = cafe_v4l_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = { @@ -2066,8 +2066,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, cam->sensor_addr = 0x42; cam->sensor = v4l2_i2c_new_subdev_cfg(&cam->v4l2_dev, &cam->i2c_adapter, - "ov7670", "ov7670", 0, &sensor_cfg, cam->sensor_addr, - NULL); + "ov7670", 0, &sensor_cfg, cam->sensor_addr, NULL); if (cam->sensor == NULL) { ret = -ENODEV; goto out_smbus; diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/video/cx18/cx18-alsa-pcm.c index 8f55692db36d..82d195be9197 100644 --- a/drivers/media/video/cx18/cx18-alsa-pcm.c +++ b/drivers/media/video/cx18/cx18-alsa-pcm.c @@ -218,7 +218,13 @@ static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream) static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { - return snd_pcm_lib_ioctl(substream, cmd, arg); + struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); + int ret; + + snd_cx18_lock(cxsc); + ret = snd_pcm_lib_ioctl(substream, cmd, arg); + snd_cx18_unlock(cxsc); + return ret; } diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index a09caf883170..e71a026f3419 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -122,15 +122,15 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx) if (hw == CX18_HW_TUNER) { /* special tuner group handling */ sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, - adap, NULL, type, 0, cx->card_i2c->radio); + adap, type, 0, cx->card_i2c->radio); if (sd != NULL) sd->grp_id = hw; sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, - adap, NULL, type, 0, cx->card_i2c->demod); + adap, type, 0, cx->card_i2c->demod); if (sd != NULL) sd->grp_id = hw; sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, - adap, NULL, type, 0, cx->card_i2c->tv); + adap, type, 0, cx->card_i2c->tv); if (sd != NULL) sd->grp_id = hw; return sd != NULL ? 0 : -1; @@ -144,7 +144,7 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx) return -1; /* It's an I2C device other than an analog tuner or IR chip */ - sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, NULL, type, hw_addrs[idx], + sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, type, hw_addrs[idx], NULL); if (sd != NULL) sd->grp_id = hw; diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 9045f1ece0eb..ab461e27d9dd 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -41,7 +41,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = { .read = cx18_v4l2_read, .open = cx18_v4l2_open, /* FIXME change to video_ioctl2 if serialization lock can be removed */ - .ioctl = cx18_v4l2_ioctl, + .unlocked_ioctl = cx18_v4l2_ioctl, .release = cx18_v4l2_close, .poll = cx18_v4l2_enc_poll, }; diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 56c2d8195ac6..2c78d188bb06 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -560,7 +560,7 @@ void cx231xx_card_setup(struct cx231xx *dev) if (dev->board.decoder == CX231XX_AVDECODER) { dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[0].i2c_adap, - NULL, "cx25840", 0x88 >> 1, NULL); + "cx25840", 0x88 >> 1, NULL); if (dev->sd_cx25840 == NULL) cx231xx_info("cx25840 subdev registration failure\n"); cx25840_call(dev, core, load_fw); @@ -571,7 +571,7 @@ void cx231xx_card_setup(struct cx231xx *dev) if (dev->board.tuner_type != TUNER_ABSENT) { dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, - NULL, "tuner", + "tuner", dev->tuner_addr, NULL); if (dev->sd_tuner == NULL) cx231xx_info("tuner subdev registration failure\n"); diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index db054004e462..8861309268b1 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -1247,7 +1247,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[2].i2c_adap, - NULL, "cx25840", 0x88 >> 1, NULL); + "cx25840", 0x88 >> 1, NULL); if (dev->sd_cx25840) { dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE; v4l2_subdev_call(dev->sd_cx25840, core, load_fw); diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 3cc9f462d08d..8b2fb8a4375c 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1507,10 +1507,10 @@ int cx23885_video_register(struct cx23885_dev *dev) if (dev->tuner_addr) sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[1].i2c_adap, - NULL, "tuner", dev->tuner_addr, NULL); + "tuner", dev->tuner_addr, NULL); else sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_bus[1].i2c_adap, NULL, + &dev->i2c_bus[1].i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV)); if (sd) { struct tuner_setup tun_setup; diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index b26fcba8600c..9b9e169cce90 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -3515,19 +3515,18 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) later code configures a tea5767. */ v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, - NULL, "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); + "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); if (has_demod) v4l2_i2c_new_subdev(&core->v4l2_dev, - &core->i2c_adap, NULL, "tuner", + &core->i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); if (core->board.tuner_addr == ADDR_UNSET) { v4l2_i2c_new_subdev(&core->v4l2_dev, - &core->i2c_adap, NULL, "tuner", + &core->i2c_adap, "tuner", 0, has_demod ? tv_addrs + 4 : tv_addrs); } else { v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, - NULL, "tuner", core->board.tuner_addr, NULL); + "tuner", core->board.tuner_addr, NULL); } } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 88b51194f917..62cea9549404 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1895,14 +1895,13 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, if (core->board.audio_chip == V4L2_IDENT_WM8775) v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, - NULL, "wm8775", 0x36 >> 1, NULL); + "wm8775", 0x36 >> 1, NULL); if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) { /* This probes for a tda9874 as is used on some Pixelview Ultra boards. */ - v4l2_i2c_new_subdev(&core->v4l2_dev, - &core->i2c_adap, - NULL, "tvaudio", 0, I2C_ADDRS(0xb0 >> 1)); + v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, + "tvaudio", 0, I2C_ADDRS(0xb0 >> 1)); } switch (core->boardnr) { diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index d8e38cc4ec40..7333a9bb2549 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -1986,7 +1986,6 @@ static __init int vpfe_probe(struct platform_device *pdev) vpfe_dev->sd[i] = v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, i2c_adap, - NULL, &sdinfo->board_info, NULL); if (vpfe_dev->sd[i]) { diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index 6ac6acd16352..193abab6b355 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -2013,7 +2013,6 @@ static __init int vpif_probe(struct platform_device *pdev) vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, i2c_adap, - NULL, &subdevdata->board_info, NULL); diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index 685f6a6ee603..412c65d54fe1 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -1553,7 +1553,7 @@ static __init int vpif_probe(struct platform_device *pdev) for (i = 0; i < subdev_count; i++) { vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, - i2c_adap, NULL, + i2c_adap, &subdevdata[i].board_info, NULL); if (!vpif_obj.sd[i]) { diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 54859233f311..f7e9168157a5 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -2554,39 +2554,39 @@ void em28xx_card_setup(struct em28xx *dev) /* request some modules */ if (dev->board.has_msp34xx) v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - NULL, "msp3400", 0, msp3400_addrs); + "msp3400", 0, msp3400_addrs); if (dev->board.decoder == EM28XX_SAA711X) v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - NULL, "saa7115_auto", 0, saa711x_addrs); + "saa7115_auto", 0, saa711x_addrs); if (dev->board.decoder == EM28XX_TVP5150) v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - NULL, "tvp5150", 0, tvp5150_addrs); + "tvp5150", 0, tvp5150_addrs); if (dev->em28xx_sensor == EM28XX_MT9V011) { struct v4l2_subdev *sd; sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, NULL, "mt9v011", 0, mt9v011_addrs); + &dev->i2c_adap, "mt9v011", 0, mt9v011_addrs); v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal); } if (dev->board.adecoder == EM28XX_TVAUDIO) v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - NULL, "tvaudio", dev->board.tvaudio_addr, NULL); + "tvaudio", dev->board.tvaudio_addr, NULL); if (dev->board.tuner_type != TUNER_ABSENT) { int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); if (dev->board.radio.type) v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - NULL, "tuner", dev->board.radio_addr, NULL); + "tuner", dev->board.radio_addr, NULL); if (has_demod) v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, NULL, "tuner", + &dev->i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); if (dev->tuner_addr == 0) { enum v4l2_i2c_tuner_type type = @@ -2594,14 +2594,14 @@ void em28xx_card_setup(struct em28xx *dev) struct v4l2_subdev *sd; sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, NULL, "tuner", + &dev->i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(type)); if (sd) dev->tuner_addr = v4l2_i2c_subdev_addr(sd); } else { v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - NULL, "tuner", dev->tuner_addr, NULL); + "tuner", dev->tuner_addr, NULL); } } diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index a5cfc76b40b7..bb164099ea2c 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -2530,7 +2530,7 @@ static const struct v4l2_file_operations et61x251_fops = { .owner = THIS_MODULE, .open = et61x251_open, .release = et61x251_release, - .ioctl = et61x251_ioctl, + .unlocked_ioctl = et61x251_ioctl, .read = et61x251_read, .poll = et61x251_poll, .mmap = et61x251_mmap, diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c index 9a075d83dd1f..b8faff2dd711 100644 --- a/drivers/media/video/fsl-viu.c +++ b/drivers/media/video/fsl-viu.c @@ -1486,7 +1486,7 @@ static int __devinit viu_of_probe(struct platform_device *op, ad = i2c_get_adapter(0); viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad, - NULL, "saa7113", VIU_VIDEO_DECODER_ADDR, NULL); + "saa7113", VIU_VIDEO_DECODER_ADDR, NULL); viu_dev->vidq.timeout.function = viu_vid_timeout; viu_dev->vidq.timeout.data = (unsigned long)viu_dev; diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 330dadc00106..e23de57e2c73 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -63,7 +63,10 @@ struct sd { #define QUALITY_DEF 80 u8 jpegqual; /* webcam quality */ + u8 reg01; + u8 reg17; u8 reg18; + u8 flags; s8 ag_cnt; #define AG_CNT_START 13 @@ -96,6 +99,22 @@ enum sensors { SENSOR_SP80708, }; +/* device flags */ +#define PDN_INV 1 /* inverse pin S_PWR_DN / sn_xxx tables */ + +/* sn9c1xx definitions */ +/* register 0x01 */ +#define S_PWR_DN 0x01 /* sensor power down */ +#define S_PDN_INV 0x02 /* inverse pin S_PWR_DN */ +#define V_TX_EN 0x04 /* video transfer enable */ +#define LED 0x08 /* output to pin LED */ +#define SCL_SEL_OD 0x20 /* open-drain mode */ +#define SYS_SEL_48M 0x40 /* system clock 0: 24MHz, 1: 48MHz */ +/* register 0x17 */ +#define MCK_SIZE_MASK 0x1f /* sensor master clock */ +#define SEN_CLK_EN 0x20 /* enable sensor clock */ +#define DEF_EN 0x80 /* defect pixel by 0: soft, 1: hard */ + /* V4L2 controls supported by the driver */ static void setbrightness(struct gspca_dev *gspca_dev); static void setcontrast(struct gspca_dev *gspca_dev); @@ -1755,141 +1774,6 @@ static void po2030n_probe(struct gspca_dev *gspca_dev) } } -static void bridge_init(struct gspca_dev *gspca_dev, - const u8 *sn9c1xx) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 reg0102[2]; - const u8 *reg9a; - static const u8 reg9a_def[] = - {0x00, 0x40, 0x20, 0x00, 0x00, 0x00}; - static const u8 reg9a_spec[] = - {0x00, 0x40, 0x38, 0x30, 0x00, 0x20}; - static const u8 regd4[] = {0x60, 0x00, 0x00}; - - /* sensor clock already enabled in sd_init */ - /* reg_w1(gspca_dev, 0xf1, 0x00); */ - reg_w1(gspca_dev, 0x01, sn9c1xx[1]); - - /* configure gpio */ - reg0102[0] = sn9c1xx[1]; - reg0102[1] = sn9c1xx[2]; - if (gspca_dev->audio) - reg0102[1] |= 0x04; /* keep the audio connection */ - reg_w(gspca_dev, 0x01, reg0102, 2); - reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2); - reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); - switch (sd->sensor) { - case SENSOR_GC0307: - case SENSOR_OV7660: - case SENSOR_PO1030: - case SENSOR_PO2030N: - case SENSOR_SOI768: - case SENSOR_SP80708: - reg9a = reg9a_spec; - break; - default: - reg9a = reg9a_def; - break; - } - reg_w(gspca_dev, 0x9a, reg9a, 6); - - reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); - - reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); - - switch (sd->sensor) { - case SENSOR_ADCM1700: - reg_w1(gspca_dev, 0x01, 0x43); - reg_w1(gspca_dev, 0x17, 0x62); - reg_w1(gspca_dev, 0x01, 0x42); - reg_w1(gspca_dev, 0x01, 0x42); - break; - case SENSOR_GC0307: - msleep(50); - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0x22); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - msleep(50); - break; - case SENSOR_MI0360B: - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0x60); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - break; - case SENSOR_MT9V111: - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0x61); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - break; - case SENSOR_OM6802: - msleep(10); - reg_w1(gspca_dev, 0x02, 0x73); - reg_w1(gspca_dev, 0x17, 0x60); - reg_w1(gspca_dev, 0x01, 0x22); - msleep(100); - reg_w1(gspca_dev, 0x01, 0x62); - reg_w1(gspca_dev, 0x17, 0x64); - reg_w1(gspca_dev, 0x17, 0x64); - reg_w1(gspca_dev, 0x01, 0x42); - msleep(10); - reg_w1(gspca_dev, 0x01, 0x42); - i2c_w8(gspca_dev, om6802_init0[0]); - i2c_w8(gspca_dev, om6802_init0[1]); - msleep(15); - reg_w1(gspca_dev, 0x02, 0x71); - msleep(150); - break; - case SENSOR_OV7630: - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0xe2); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - break; - case SENSOR_OV7648: - reg_w1(gspca_dev, 0x01, 0x63); - reg_w1(gspca_dev, 0x17, 0x20); - reg_w1(gspca_dev, 0x01, 0x62); - reg_w1(gspca_dev, 0x01, 0x42); - break; - case SENSOR_PO1030: - case SENSOR_SOI768: - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0x20); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - break; - case SENSOR_PO2030N: - case SENSOR_OV7660: - reg_w1(gspca_dev, 0x01, 0x63); - reg_w1(gspca_dev, 0x17, 0x20); - reg_w1(gspca_dev, 0x01, 0x62); - reg_w1(gspca_dev, 0x01, 0x42); - break; - case SENSOR_SP80708: - reg_w1(gspca_dev, 0x01, 0x63); - reg_w1(gspca_dev, 0x17, 0x20); - reg_w1(gspca_dev, 0x01, 0x62); - reg_w1(gspca_dev, 0x01, 0x42); - msleep(100); - reg_w1(gspca_dev, 0x02, 0x62); - break; - default: -/* case SENSOR_HV7131R: */ -/* case SENSOR_MI0360: */ -/* case SENSOR_MO4000: */ - reg_w1(gspca_dev, 0x01, 0x43); - reg_w1(gspca_dev, 0x17, 0x61); - reg_w1(gspca_dev, 0x01, 0x42); - if (sd->sensor == SENSOR_HV7131R) - hv7131r_probe(gspca_dev); - break; - } -} - /* this function is called at probe time */ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) @@ -1898,7 +1782,8 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam; sd->bridge = id->driver_info >> 16; - sd->sensor = id->driver_info; + sd->sensor = id->driver_info >> 8; + sd->flags = id->driver_info; cam = &gspca_dev->cam; if (sd->sensor == SENSOR_ADCM1700) { @@ -1929,7 +1814,7 @@ static int sd_init(struct gspca_dev *gspca_dev) /* setup a selector by bridge */ reg_w1(gspca_dev, 0xf1, 0x01); reg_r(gspca_dev, 0x00, 1); - reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]); + reg_w1(gspca_dev, 0xf1, 0x00); reg_r(gspca_dev, 0x00, 1); /* get sonix chip id */ regF1 = gspca_dev->usb_buf[0]; if (gspca_dev->usb_err < 0) @@ -2423,10 +2308,17 @@ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int i; - u8 reg1, reg17; + u8 reg01, reg17; + u8 reg0102[2]; const u8 *sn9c1xx; const u8 (*init)[8]; + const u8 *reg9a; int mode; + static const u8 reg9a_def[] = + {0x00, 0x40, 0x20, 0x00, 0x00, 0x00}; + static const u8 reg9a_spec[] = + {0x00, 0x40, 0x38, 0x30, 0x00, 0x20}; + static const u8 regd4[] = {0x60, 0x00, 0x00}; static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f }; static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; static const u8 CA_adcm1700[] = @@ -2448,7 +2340,85 @@ static int sd_start(struct gspca_dev *gspca_dev) /* initialize the bridge */ sn9c1xx = sn_tb[sd->sensor]; - bridge_init(gspca_dev, sn9c1xx); + + /* sensor clock already enabled in sd_init */ + /* reg_w1(gspca_dev, 0xf1, 0x00); */ + reg01 = sn9c1xx[1]; + if (sd->flags & PDN_INV) + reg01 ^= S_PDN_INV; /* power down inverted */ + reg_w1(gspca_dev, 0x01, reg01); + + /* configure gpio */ + reg0102[0] = reg01; + reg0102[1] = sn9c1xx[2]; + if (gspca_dev->audio) + reg0102[1] |= 0x04; /* keep the audio connection */ + reg_w(gspca_dev, 0x01, reg0102, 2); + reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2); + reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); + switch (sd->sensor) { + case SENSOR_GC0307: + case SENSOR_OV7660: + case SENSOR_PO1030: + case SENSOR_PO2030N: + case SENSOR_SOI768: + case SENSOR_SP80708: + reg9a = reg9a_spec; + break; + default: + reg9a = reg9a_def; + break; + } + reg_w(gspca_dev, 0x9a, reg9a, 6); + + reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); + + reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); + + reg17 = sn9c1xx[0x17]; + switch (sd->sensor) { + case SENSOR_GC0307: + msleep(50); /*fixme: is it useful? */ + break; + case SENSOR_OM6802: + msleep(10); + reg_w1(gspca_dev, 0x02, 0x73); + reg17 |= SEN_CLK_EN; + reg_w1(gspca_dev, 0x17, reg17); + reg_w1(gspca_dev, 0x01, 0x22); + msleep(100); + reg01 = SCL_SEL_OD | S_PDN_INV; + reg17 &= MCK_SIZE_MASK; + reg17 |= 0x04; /* clock / 4 */ + break; + } + reg01 |= SYS_SEL_48M; + reg_w1(gspca_dev, 0x01, reg01); + reg17 |= SEN_CLK_EN; + reg_w1(gspca_dev, 0x17, reg17); + reg01 &= ~S_PWR_DN; /* sensor power on */ + reg_w1(gspca_dev, 0x01, reg01); + reg01 &= ~SYS_SEL_48M; + reg_w1(gspca_dev, 0x01, reg01); + + switch (sd->sensor) { + case SENSOR_HV7131R: + hv7131r_probe(gspca_dev); /*fixme: is it useful? */ + break; + case SENSOR_OM6802: + msleep(10); + reg_w1(gspca_dev, 0x01, reg01); + i2c_w8(gspca_dev, om6802_init0[0]); + i2c_w8(gspca_dev, om6802_init0[1]); + msleep(15); + reg_w1(gspca_dev, 0x02, 0x71); + msleep(150); + break; + case SENSOR_SP80708: + msleep(100); + reg_w1(gspca_dev, 0x02, 0x62); + break; + } /* initialize the sensor */ i2c_w_seq(gspca_dev, sensor_init[sd->sensor]); @@ -2476,30 +2446,11 @@ static int sd_start(struct gspca_dev *gspca_dev) } reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); switch (sd->sensor) { - case SENSOR_GC0307: - reg17 = 0xa2; - break; - case SENSOR_MT9V111: - case SENSOR_MI0360B: - reg17 = 0xe0; - break; - case SENSOR_ADCM1700: - case SENSOR_OV7630: - reg17 = 0xe2; - break; - case SENSOR_OV7648: - reg17 = 0x20; - break; - case SENSOR_OV7660: - case SENSOR_SOI768: - reg17 = 0xa0; - break; - case SENSOR_PO1030: - case SENSOR_PO2030N: - reg17 = 0xa0; + case SENSOR_OM6802: +/* case SENSOR_OV7648: * fixme: sometimes */ break; default: - reg17 = 0x60; + reg17 |= DEF_EN; break; } reg_w1(gspca_dev, 0x17, reg17); @@ -2546,95 +2497,67 @@ static int sd_start(struct gspca_dev *gspca_dev) init = NULL; mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - if (mode) - reg1 = 0x46; /* 320x240: clk 48Mhz, video trf enable */ - else - reg1 = 0x06; /* 640x480: clk 24Mhz, video trf enable */ - reg17 = 0x61; /* 0x:20: enable sensor clock */ + reg01 |= SYS_SEL_48M | V_TX_EN; + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x02; /* clock / 2 */ switch (sd->sensor) { case SENSOR_ADCM1700: init = adcm1700_sensor_param1; - reg1 = 0x46; - reg17 = 0xe2; break; case SENSOR_GC0307: init = gc0307_sensor_param1; - reg17 = 0xa2; - reg1 = 0x44; + break; + case SENSOR_HV7131R: + case SENSOR_MI0360: + if (mode) + reg01 |= SYS_SEL_48M; /* 320x240: clk 48Mhz */ + else + reg01 &= ~SYS_SEL_48M; /* 640x480: clk 24Mhz */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x01; /* clock / 1 */ break; case SENSOR_MI0360B: init = mi0360b_sensor_param1; - reg1 &= ~0x02; /* don't inverse pin S_PWR_DN */ - reg17 = 0xe2; break; case SENSOR_MO4000: - if (mode) { -/* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */ - reg1 = 0x06; /* clk 24Mz */ - } else { - reg17 = 0x22; /* 640 MCKSIZE */ -/* reg1 = 0x06; * 640 clk 24Mz (done) */ + if (mode) { /* if 320x240 */ + reg01 &= ~SYS_SEL_48M; /* clk 24Mz */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x01; /* clock / 1 */ } break; case SENSOR_MT9V111: init = mt9v111_sensor_param1; - if (mode) { - reg1 = 0x04; /* 320 clk 48Mhz */ - } else { -/* reg1 = 0x06; * 640 clk 24Mz (done) */ - reg17 = 0xc2; - } break; case SENSOR_OM6802: init = om6802_sensor_param1; - reg17 = 0x64; /* 640 MCKSIZE */ + if (!mode) { /* if 640x480 */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x01; /* clock / 4 */ + } break; case SENSOR_OV7630: init = ov7630_sensor_param1; - reg17 = 0xe2; - reg1 = 0x44; break; case SENSOR_OV7648: init = ov7648_sensor_param1; - reg17 = 0x21; -/* reg1 = 0x42; * 42 - 46? */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x01; /* clock / 1 */ break; case SENSOR_OV7660: init = ov7660_sensor_param1; - if (sd->bridge == BRIDGE_SN9C120) { - if (mode) { /* 320x240 - 160x120 */ - reg17 = 0xa2; - reg1 = 0x44; /* 48 Mhz, video trf eneble */ - } - } else { - reg17 = 0x22; - reg1 = 0x06; /* 24 Mhz, video trf eneble - * inverse power down */ - } break; case SENSOR_PO1030: init = po1030_sensor_param1; - reg17 = 0xa2; - reg1 = 0x44; break; case SENSOR_PO2030N: init = po2030n_sensor_param1; - reg1 = 0x46; - reg17 = 0xa2; break; case SENSOR_SOI768: init = soi768_sensor_param1; - reg1 = 0x44; - reg17 = 0xa2; break; case SENSOR_SP80708: init = sp80708_sensor_param1; - if (mode) { -/*?? reg1 = 0x04; * 320 clk 48Mhz */ - } else { - reg1 = 0x46; /* 640 clk 48Mz */ - reg17 = 0xa2; - } break; } @@ -2684,7 +2607,9 @@ static int sd_start(struct gspca_dev *gspca_dev) setjpegqual(gspca_dev); reg_w1(gspca_dev, 0x17, reg17); - reg_w1(gspca_dev, 0x01, reg1); + reg_w1(gspca_dev, 0x01, reg01); + sd->reg01 = reg01; + sd->reg17 = reg17; sethvflip(gspca_dev); setbrightness(gspca_dev); @@ -2706,41 +2631,64 @@ static void sd_stopN(struct gspca_dev *gspca_dev) { 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 }; static const u8 stopsoi768[] = { 0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10 }; - u8 data; - const u8 *sn9c1xx; + u8 reg01; + u8 reg17; - data = 0x0b; + reg01 = sd->reg01; + reg17 = sd->reg17 & ~SEN_CLK_EN; switch (sd->sensor) { + case SENSOR_ADCM1700: case SENSOR_GC0307: - data = 0x29; + case SENSOR_PO2030N: + case SENSOR_SP80708: + reg01 |= LED; + reg_w1(gspca_dev, 0x01, reg01); + reg01 &= ~(LED | V_TX_EN); + reg_w1(gspca_dev, 0x01, reg01); +/* reg_w1(gspca_dev, 0x02, 0x??); * LED off ? */ break; case SENSOR_HV7131R: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); i2c_w8(gspca_dev, stophv7131); - data = 0x2b; break; case SENSOR_MI0360: case SENSOR_MI0360B: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); +/* reg_w1(gspca_dev, 0x02, 0x40); * LED off ? */ i2c_w8(gspca_dev, stopmi0360); - data = 0x29; break; - case SENSOR_OV7648: - i2c_w8(gspca_dev, stopov7648); - /* fall thru */ case SENSOR_MT9V111: - case SENSOR_OV7630: + case SENSOR_OM6802: case SENSOR_PO1030: - data = 0x29; + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); + break; + case SENSOR_OV7630: + case SENSOR_OV7648: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); + i2c_w8(gspca_dev, stopov7648); + break; + case SENSOR_OV7660: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); break; case SENSOR_SOI768: i2c_w8(gspca_dev, stopsoi768); - data = 0x29; break; } - sn9c1xx = sn_tb[sd->sensor]; - reg_w1(gspca_dev, 0x01, sn9c1xx[1]); - reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]); - reg_w1(gspca_dev, 0x01, sn9c1xx[1]); - reg_w1(gspca_dev, 0x01, data); + + reg01 |= SCL_SEL_OD; + reg_w1(gspca_dev, 0x01, reg01); + reg01 |= S_PWR_DN; /* sensor power down */ + reg_w1(gspca_dev, 0x01, reg01); + reg_w1(gspca_dev, 0x17, reg17); + reg01 &= ~SYS_SEL_48M; /* clock 24MHz */ + reg_w1(gspca_dev, 0x01, reg01); + reg01 |= LED; + reg_w1(gspca_dev, 0x01, reg01); /* Don't disable sensor clock as that disables the button on the cam */ /* reg_w1(gspca_dev, 0xf1, 0x01); */ } @@ -2954,14 +2902,18 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ #define BS(bridge, sensor) \ .driver_info = (BRIDGE_ ## bridge << 16) \ - | SENSOR_ ## sensor + | (SENSOR_ ## sensor << 8) +#define BSF(bridge, sensor, flags) \ + .driver_info = (BRIDGE_ ## bridge << 16) \ + | (SENSOR_ ## sensor << 8) \ + | (flags) static const __devinitdata struct usb_device_id device_table[] = { #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)}, {USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)}, #endif - {USB_DEVICE(0x045e, 0x00f5), BS(SN9C105, OV7660)}, - {USB_DEVICE(0x045e, 0x00f7), BS(SN9C105, OV7660)}, + {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, PDN_INV)}, + {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, PDN_INV)}, {USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)}, {USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)}, {USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)}, diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 9e8039ac909e..665191c9b407 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -239,19 +239,16 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx) return -1; if (hw == IVTV_HW_TUNER) { /* special tuner handling */ - sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, - adap, NULL, type, - 0, itv->card_i2c->radio); + sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, + itv->card_i2c->radio); if (sd) sd->grp_id = 1 << idx; - sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, - adap, NULL, type, - 0, itv->card_i2c->demod); + sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, + itv->card_i2c->demod); if (sd) sd->grp_id = 1 << idx; - sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, - adap, NULL, type, - 0, itv->card_i2c->tv); + sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0, + itv->card_i2c->tv); if (sd) sd->grp_id = 1 << idx; return sd ? 0 : -1; @@ -267,17 +264,16 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx) /* It's an I2C device other than an analog tuner or IR chip */ if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) { sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, - adap, NULL, type, 0, I2C_ADDRS(hw_addrs[idx])); + adap, type, 0, I2C_ADDRS(hw_addrs[idx])); } else if (hw == IVTV_HW_CX25840) { struct cx25840_platform_data pdata; pdata.pvr150_workaround = itv->pvr150_workaround; sd = v4l2_i2c_new_subdev_cfg(&itv->v4l2_dev, - adap, NULL, type, 0, &pdata, hw_addrs[idx], - NULL); + adap, type, 0, &pdata, hw_addrs[idx], NULL); } else { sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, - adap, NULL, type, hw_addrs[idx], NULL); + adap, type, hw_addrs[idx], NULL); } if (sd) sd->grp_id = 1 << idx; diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 2be23bccd3c8..48d2c2419c13 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -1659,7 +1659,7 @@ static const struct v4l2_file_operations meye_fops = { .open = meye_open, .release = meye_release, .mmap = meye_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .poll = meye_poll, }; @@ -1831,12 +1831,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev, msleep(1); mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); - if (video_register_device(meye.vdev, VFL_TYPE_GRABBER, - video_nr) < 0) { - v4l2_err(v4l2_dev, "video_register_device failed\n"); - goto outvideoreg; - } - mutex_init(&meye.lock); init_waitqueue_head(&meye.proc_list); meye.brightness = 32 << 10; @@ -1858,6 +1852,12 @@ static int __devinit meye_probe(struct pci_dev *pcidev, sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48); + if (video_register_device(meye.vdev, VFL_TYPE_GRABBER, + video_nr) < 0) { + v4l2_err(v4l2_dev, "video_register_device failed\n"); + goto outvideoreg; + } + v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n", MEYE_DRIVER_VERSION); v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n", diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index 94ba698d0ad4..4e8fd965f151 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -185,17 +185,17 @@ static int mxb_probe(struct saa7146_dev *dev) } mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - NULL, "saa7111", I2C_SAA7111A, NULL); + "saa7111", I2C_SAA7111A, NULL); mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - NULL, "tea6420", I2C_TEA6420_1, NULL); + "tea6420", I2C_TEA6420_1, NULL); mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - NULL, "tea6420", I2C_TEA6420_2, NULL); + "tea6420", I2C_TEA6420_2, NULL); mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - NULL, "tea6415c", I2C_TEA6415C, NULL); + "tea6415c", I2C_TEA6415C, NULL); mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - NULL, "tda9840", I2C_TDA9840, NULL); + "tda9840", I2C_TDA9840, NULL); mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - NULL, "tuner", I2C_TUNER, NULL); + "tuner", I2C_TUNER, NULL); /* check if all devices are present */ if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c || diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 7129b50757db..7551907f8c28 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -932,7 +932,7 @@ static ssize_t pms_read(struct file *file, char __user *buf, static const struct v4l2_file_operations pms_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .read = pms_read, }; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index bef202752cc8..66ad516bdfd9 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2088,16 +2088,14 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw, " Setting up with specified i2c address 0x%x", mid, i2caddr[0]); sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, - NULL, fname, - i2caddr[0], NULL); + fname, i2caddr[0], NULL); } else { pvr2_trace(PVR2_TRACE_INIT, "Module ID %u:" " Setting up with address probe list", mid); sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, - NULL, fname, - 0, i2caddr); + fname, 0, i2caddr); } if (!sd) { diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index e8f13d3e2df1..1b93207c89e8 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -44,7 +44,7 @@ static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc, return ERR_PTR(-ENOMEM); sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap, - MODULE_NAME, isp_info->board_info, NULL); + isp_info->board_info, NULL); if (!sd) { v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n"); return NULL; diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 0911cb580e18..1d4d0a49ea52 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -7551,22 +7551,22 @@ int saa7134_board_init2(struct saa7134_dev *dev) so we do not need to probe for a radio tuner device. */ if (dev->radio_type != UNSET) v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, NULL, "tuner", + &dev->i2c_adap, "tuner", dev->radio_addr, NULL); if (has_demod) v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, NULL, "tuner", + &dev->i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); if (dev->tuner_addr == ADDR_UNSET) { enum v4l2_i2c_tuner_type type = has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, NULL, "tuner", + &dev->i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(type)); } else { v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, NULL, "tuner", + &dev->i2c_adap, "tuner", dev->tuner_addr, NULL); } } diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 764d7d219fed..756a27812260 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -991,7 +991,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, if (card_is_empress(dev)) { struct v4l2_subdev *sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - NULL, "saa6752hs", + "saa6752hs", saa7134_boards[dev->board].empress_addr, NULL); if (sd) @@ -1002,7 +1002,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, struct v4l2_subdev *sd; sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, NULL, "saa6588", + &dev->i2c_adap, "saa6588", 0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr)); if (sd) { printk(KERN_INFO "%s: found RDS decoder\n", dev->name); diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c index 0f4906136b8f..07cf0c6c7c1f 100644 --- a/drivers/media/video/sh_vou.c +++ b/drivers/media/video/sh_vou.c @@ -75,6 +75,7 @@ struct sh_vou_device { int pix_idx; struct videobuf_buffer *active; enum sh_vou_status status; + struct mutex fop_lock; }; struct sh_vou_file { @@ -235,7 +236,7 @@ static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb) vb->state = VIDEOBUF_NEEDS_INIT; } -/* Locking: caller holds vq->vb_lock mutex */ +/* Locking: caller holds fop_lock mutex */ static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) { @@ -257,7 +258,7 @@ static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count, return 0; } -/* Locking: caller holds vq->vb_lock mutex */ +/* Locking: caller holds fop_lock mutex */ static int sh_vou_buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) @@ -306,7 +307,7 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq, return 0; } -/* Locking: caller holds vq->vb_lock mutex and vq->irqlock spinlock */ +/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */ static void sh_vou_buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { @@ -1190,7 +1191,7 @@ static int sh_vou_open(struct file *file) V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_FIELD_NONE, sizeof(struct videobuf_buffer), vdev, - NULL); + &vou_dev->fop_lock); return 0; } @@ -1292,7 +1293,7 @@ static const struct v4l2_file_operations sh_vou_fops = { .owner = THIS_MODULE, .open = sh_vou_open, .release = sh_vou_release, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .mmap = sh_vou_mmap, .poll = sh_vou_poll, }; @@ -1331,6 +1332,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev) INIT_LIST_HEAD(&vou_dev->queue); spin_lock_init(&vou_dev->lock); + mutex_init(&vou_dev->fop_lock); atomic_set(&vou_dev->use_count, 0); vou_dev->pdata = vou_pdata; vou_dev->status = SH_VOU_IDLE; @@ -1388,6 +1390,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev) vdev->tvnorms |= V4L2_STD_PAL; vdev->v4l2_dev = &vou_dev->v4l2_dev; vdev->release = video_device_release; + vdev->lock = &vou_dev->fop_lock; vou_dev->vdev = vdev; video_set_drvdata(vdev, vou_dev); @@ -1406,7 +1409,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev) goto ereset; subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap, - NULL, vou_pdata->board_info, NULL); + vou_pdata->board_info, NULL); if (!subdev) { ret = -ENOMEM; goto ei2cnd; diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 28e19daadec9..f49fbfb7dc13 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -3238,7 +3238,7 @@ static const struct v4l2_file_operations sn9c102_fops = { .owner = THIS_MODULE, .open = sn9c102_open, .release = sn9c102_release, - .ioctl = sn9c102_ioctl, + .unlocked_ioctl = sn9c102_ioctl, .read = sn9c102_read, .poll = sn9c102_poll, .mmap = sn9c102_mmap, diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 43848a751d11..335120c2021b 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -896,7 +896,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd, icl->board_info->platform_data = icd; subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, - NULL, icl->board_info, NULL); + icl->board_info, NULL); if (!subdev) goto ei2cnd; diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index e3bbae26e3ce..81dd53bb5267 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -251,7 +251,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision) hit-and-miss. */ mdelay(10); v4l2_i2c_new_subdev(&usbvision->v4l2_dev, - &usbvision->i2c_adap, NULL, + &usbvision->i2c_adap, "saa7115_auto", 0, saa711x_addrs); break; } @@ -261,14 +261,14 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision) struct tuner_setup tun_setup; sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev, - &usbvision->i2c_adap, NULL, + &usbvision->i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); /* depending on whether we found a demod or not, select the tuner type. */ type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev, - &usbvision->i2c_adap, NULL, + &usbvision->i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(type)); if (sd == NULL) diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index f169f7736677..59f8a9ad3796 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -785,7 +785,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, } } -struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, +static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, __u32 v4l2_id, struct uvc_control_mapping **mapping) { struct uvc_control *ctrl = NULL; @@ -944,6 +944,52 @@ done: return ret; } +/* + * Mapping V4L2 controls to UVC controls can be straighforward if done well. + * Most of the UVC controls exist in V4L2, and can be mapped directly. Some + * must be grouped (for instance the Red Balance, Blue Balance and Do White + * Balance V4L2 controls use the White Balance Component UVC control) or + * otherwise translated. The approach we take here is to use a translation + * table for the controls that can be mapped directly, and handle the others + * manually. + */ +int uvc_query_v4l2_menu(struct uvc_video_chain *chain, + struct v4l2_querymenu *query_menu) +{ + struct uvc_menu_info *menu_info; + struct uvc_control_mapping *mapping; + struct uvc_control *ctrl; + u32 index = query_menu->index; + u32 id = query_menu->id; + int ret; + + memset(query_menu, 0, sizeof(*query_menu)); + query_menu->id = id; + query_menu->index = index; + + ret = mutex_lock_interruptible(&chain->ctrl_mutex); + if (ret < 0) + return -ERESTARTSYS; + + ctrl = uvc_find_control(chain, query_menu->id, &mapping); + if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) { + ret = -EINVAL; + goto done; + } + + if (query_menu->index >= mapping->menu_count) { + ret = -EINVAL; + goto done; + } + + menu_info = &mapping->menu_info[query_menu->index]; + strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); + +done: + mutex_unlock(&chain->ctrl_mutex); + return ret; +} + /* -------------------------------------------------------------------------- * Control transactions diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index ed6d5449741c..f14581bd707f 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -90,6 +90,39 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, } /* + * Free the video buffers. + * + * This function must be called with the queue lock held. + */ +static int __uvc_free_buffers(struct uvc_video_queue *queue) +{ + unsigned int i; + + for (i = 0; i < queue->count; ++i) { + if (queue->buffer[i].vma_use_count != 0) + return -EBUSY; + } + + if (queue->count) { + vfree(queue->mem); + queue->count = 0; + } + + return 0; +} + +int uvc_free_buffers(struct uvc_video_queue *queue) +{ + int ret; + + mutex_lock(&queue->mutex); + ret = __uvc_free_buffers(queue); + mutex_unlock(&queue->mutex); + + return ret; +} + +/* * Allocate the video buffers. * * Pages are reserved to make sure they will not be swapped, as they will be @@ -110,7 +143,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, mutex_lock(&queue->mutex); - if ((ret = uvc_free_buffers(queue)) < 0) + if ((ret = __uvc_free_buffers(queue)) < 0) goto done; /* Bail out if no buffers should be allocated. */ @@ -152,28 +185,6 @@ done: } /* - * Free the video buffers. - * - * This function must be called with the queue lock held. - */ -int uvc_free_buffers(struct uvc_video_queue *queue) -{ - unsigned int i; - - for (i = 0; i < queue->count; ++i) { - if (queue->buffer[i].vma_use_count != 0) - return -EBUSY; - } - - if (queue->count) { - vfree(queue->mem); - queue->count = 0; - } - - return 0; -} - -/* * Check if buffers have been allocated. */ int uvc_queue_allocated(struct uvc_video_queue *queue) @@ -369,6 +380,82 @@ done: } /* + * VMA operations. + */ +static void uvc_vm_open(struct vm_area_struct *vma) +{ + struct uvc_buffer *buffer = vma->vm_private_data; + buffer->vma_use_count++; +} + +static void uvc_vm_close(struct vm_area_struct *vma) +{ + struct uvc_buffer *buffer = vma->vm_private_data; + buffer->vma_use_count--; +} + +static const struct vm_operations_struct uvc_vm_ops = { + .open = uvc_vm_open, + .close = uvc_vm_close, +}; + +/* + * Memory-map a video buffer. + * + * This function implements video buffers memory mapping and is intended to be + * used by the device mmap handler. + */ +int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) +{ + struct uvc_buffer *uninitialized_var(buffer); + struct page *page; + unsigned long addr, start, size; + unsigned int i; + int ret = 0; + + start = vma->vm_start; + size = vma->vm_end - vma->vm_start; + + mutex_lock(&queue->mutex); + + for (i = 0; i < queue->count; ++i) { + buffer = &queue->buffer[i]; + if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) + break; + } + + if (i == queue->count || size != queue->buf_size) { + ret = -EINVAL; + goto done; + } + + /* + * VM_IO marks the area as being an mmaped region for I/O to a + * device. It also prevents the region from being core dumped. + */ + vma->vm_flags |= VM_IO; + + addr = (unsigned long)queue->mem + buffer->buf.m.offset; + while (size > 0) { + page = vmalloc_to_page((void *)addr); + if ((ret = vm_insert_page(vma, start, page)) < 0) + goto done; + + start += PAGE_SIZE; + addr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + vma->vm_ops = &uvc_vm_ops; + vma->vm_private_data = buffer; + uvc_vm_open(vma); + +done: + mutex_unlock(&queue->mutex); + return ret; +} + +/* * Poll the video queue. * * This function implements video queue polling and is intended to be used by diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 6d15de9b5204..8cf61e8a634f 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -101,40 +101,6 @@ done: */ /* - * Mapping V4L2 controls to UVC controls can be straighforward if done well. - * Most of the UVC controls exist in V4L2, and can be mapped directly. Some - * must be grouped (for instance the Red Balance, Blue Balance and Do White - * Balance V4L2 controls use the White Balance Component UVC control) or - * otherwise translated. The approach we take here is to use a translation - * table for the controls that can be mapped directly, and handle the others - * manually. - */ -static int uvc_v4l2_query_menu(struct uvc_video_chain *chain, - struct v4l2_querymenu *query_menu) -{ - struct uvc_menu_info *menu_info; - struct uvc_control_mapping *mapping; - struct uvc_control *ctrl; - u32 index = query_menu->index; - u32 id = query_menu->id; - - ctrl = uvc_find_control(chain, query_menu->id, &mapping); - if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) - return -EINVAL; - - if (query_menu->index >= mapping->menu_count) - return -EINVAL; - - memset(query_menu, 0, sizeof(*query_menu)); - query_menu->id = id; - query_menu->index = index; - - menu_info = &mapping->menu_info[query_menu->index]; - strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); - return 0; -} - -/* * Find the frame interval closest to the requested frame interval for the * given frame format and size. This should be done by the device as part of * the Video Probe and Commit negotiation, but some hardware don't implement @@ -260,12 +226,14 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, * developers test their webcams with the Linux driver as well as with * the Windows driver). */ + mutex_lock(&stream->mutex); if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) probe->dwMaxVideoFrameSize = stream->ctrl.dwMaxVideoFrameSize; /* Probe the device. */ ret = uvc_probe_video(stream, probe); + mutex_unlock(&stream->mutex); if (ret < 0) goto done; @@ -289,14 +257,21 @@ done: static int uvc_v4l2_get_format(struct uvc_streaming *stream, struct v4l2_format *fmt) { - struct uvc_format *format = stream->cur_format; - struct uvc_frame *frame = stream->cur_frame; + struct uvc_format *format; + struct uvc_frame *frame; + int ret = 0; if (fmt->type != stream->type) return -EINVAL; - if (format == NULL || frame == NULL) - return -EINVAL; + mutex_lock(&stream->mutex); + format = stream->cur_format; + frame = stream->cur_frame; + + if (format == NULL || frame == NULL) { + ret = -EINVAL; + goto done; + } fmt->fmt.pix.pixelformat = format->fcc; fmt->fmt.pix.width = frame->wWidth; @@ -307,7 +282,9 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream, fmt->fmt.pix.colorspace = format->colorspace; fmt->fmt.pix.priv = 0; - return 0; +done: + mutex_unlock(&stream->mutex); + return ret; } static int uvc_v4l2_set_format(struct uvc_streaming *stream, @@ -321,18 +298,24 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream, if (fmt->type != stream->type) return -EINVAL; - if (uvc_queue_allocated(&stream->queue)) - return -EBUSY; - ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame); if (ret < 0) return ret; + mutex_lock(&stream->mutex); + + if (uvc_queue_allocated(&stream->queue)) { + ret = -EBUSY; + goto done; + } + memcpy(&stream->ctrl, &probe, sizeof probe); stream->cur_format = format; stream->cur_frame = frame; - return 0; +done: + mutex_unlock(&stream->mutex); + return ret; } static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, @@ -343,7 +326,10 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, if (parm->type != stream->type) return -EINVAL; + mutex_lock(&stream->mutex); numerator = stream->ctrl.dwFrameInterval; + mutex_unlock(&stream->mutex); + denominator = 10000000; uvc_simplify_fraction(&numerator, &denominator, 8, 333); @@ -370,7 +356,6 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, struct v4l2_streamparm *parm) { - struct uvc_frame *frame = stream->cur_frame; struct uvc_streaming_control probe; struct v4l2_fract timeperframe; uint32_t interval; @@ -379,28 +364,36 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, if (parm->type != stream->type) return -EINVAL; - if (uvc_queue_streaming(&stream->queue)) - return -EBUSY; - if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) timeperframe = parm->parm.capture.timeperframe; else timeperframe = parm->parm.output.timeperframe; - memcpy(&probe, &stream->ctrl, sizeof probe); interval = uvc_fraction_to_interval(timeperframe.numerator, timeperframe.denominator); - uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n", timeperframe.numerator, timeperframe.denominator, interval); - probe.dwFrameInterval = uvc_try_frame_interval(frame, interval); + + mutex_lock(&stream->mutex); + + if (uvc_queue_streaming(&stream->queue)) { + mutex_unlock(&stream->mutex); + return -EBUSY; + } + + memcpy(&probe, &stream->ctrl, sizeof probe); + probe.dwFrameInterval = + uvc_try_frame_interval(stream->cur_frame, interval); /* Probe the device with the new settings. */ ret = uvc_probe_video(stream, &probe); - if (ret < 0) + if (ret < 0) { + mutex_unlock(&stream->mutex); return ret; + } memcpy(&stream->ctrl, &probe, sizeof probe); + mutex_unlock(&stream->mutex); /* Return the actual frame period. */ timeperframe.numerator = probe.dwFrameInterval; @@ -528,11 +521,9 @@ static int uvc_v4l2_release(struct file *file) if (uvc_has_privileges(handle)) { uvc_video_enable(stream, 0); - mutex_lock(&stream->queue.mutex); if (uvc_free_buffers(&stream->queue) < 0) uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to " "free buffers.\n"); - mutex_unlock(&stream->queue.mutex); } /* Release the file handle. */ @@ -624,7 +615,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) } case VIDIOC_QUERYMENU: - return uvc_v4l2_query_menu(chain, arg); + return uvc_query_v4l2_menu(chain, arg); case VIDIOC_G_EXT_CTRLS: { @@ -905,15 +896,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_CROPCAP: { struct v4l2_cropcap *ccap = arg; - struct uvc_frame *frame = stream->cur_frame; if (ccap->type != stream->type) return -EINVAL; ccap->bounds.left = 0; ccap->bounds.top = 0; - ccap->bounds.width = frame->wWidth; - ccap->bounds.height = frame->wHeight; + + mutex_lock(&stream->mutex); + ccap->bounds.width = stream->cur_frame->wWidth; + ccap->bounds.height = stream->cur_frame->wHeight; + mutex_unlock(&stream->mutex); ccap->defrect = ccap->bounds; @@ -930,8 +923,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *rb = arg; - unsigned int bufsize = - stream->ctrl.dwMaxVideoFrameSize; if (rb->type != stream->type || rb->memory != V4L2_MEMORY_MMAP) @@ -940,7 +931,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; - ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize); + mutex_lock(&stream->mutex); + ret = uvc_alloc_buffers(&stream->queue, rb->count, + stream->ctrl.dwMaxVideoFrameSize); + mutex_unlock(&stream->mutex); if (ret < 0) return ret; @@ -988,7 +982,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (!uvc_has_privileges(handle)) return -EBUSY; + mutex_lock(&stream->mutex); ret = uvc_video_enable(stream, 1); + mutex_unlock(&stream->mutex); if (ret < 0) return ret; break; @@ -1068,79 +1064,14 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data, return -EINVAL; } -/* - * VMA operations. - */ -static void uvc_vm_open(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count++; -} - -static void uvc_vm_close(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count--; -} - -static const struct vm_operations_struct uvc_vm_ops = { - .open = uvc_vm_open, - .close = uvc_vm_close, -}; - static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) { struct uvc_fh *handle = file->private_data; struct uvc_streaming *stream = handle->stream; - struct uvc_video_queue *queue = &stream->queue; - struct uvc_buffer *uninitialized_var(buffer); - struct page *page; - unsigned long addr, start, size; - unsigned int i; - int ret = 0; uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n"); - start = vma->vm_start; - size = vma->vm_end - vma->vm_start; - - mutex_lock(&queue->mutex); - - for (i = 0; i < queue->count; ++i) { - buffer = &queue->buffer[i]; - if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - - if (i == queue->count || size != queue->buf_size) { - ret = -EINVAL; - goto done; - } - - /* - * VM_IO marks the area as being an mmaped region for I/O to a - * device. It also prevents the region from being core dumped. - */ - vma->vm_flags |= VM_IO; - - addr = (unsigned long)queue->mem + buffer->buf.m.offset; - while (size > 0) { - page = vmalloc_to_page((void *)addr); - if ((ret = vm_insert_page(vma, start, page)) < 0) - goto done; - - start += PAGE_SIZE; - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &uvc_vm_ops; - vma->vm_private_data = buffer; - uvc_vm_open(vma); - -done: - mutex_unlock(&queue->mutex); - return ret; + return uvc_queue_mmap(&stream->queue, vma); } static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) @@ -1157,7 +1088,7 @@ const struct v4l2_file_operations uvc_fops = { .owner = THIS_MODULE, .open = uvc_v4l2_open, .release = uvc_v4l2_release, - .ioctl = uvc_v4l2_ioctl, + .unlocked_ioctl = uvc_v4l2_ioctl, .read = uvc_v4l2_read, .mmap = uvc_v4l2_mmap, .poll = uvc_v4l2_poll, diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 5555f0102838..5673d673504b 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -293,8 +293,6 @@ int uvc_probe_video(struct uvc_streaming *stream, unsigned int i; int ret; - mutex_lock(&stream->mutex); - /* Perform probing. The device should adjust the requested values * according to its capabilities. However, some devices, namely the * first generation UVC Logitech webcams, don't implement the Video @@ -346,7 +344,6 @@ int uvc_probe_video(struct uvc_streaming *stream, } done: - mutex_unlock(&stream->mutex); return ret; } diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index d97cf6d6a4f9..45f01e7e13d2 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -436,7 +436,9 @@ struct uvc_streaming { struct uvc_streaming_control ctrl; struct uvc_format *cur_format; struct uvc_frame *cur_frame; - + /* Protect access to ctrl, cur_format, cur_frame and hardware video + * probe control. + */ struct mutex mutex; unsigned int frozen : 1; @@ -574,6 +576,8 @@ extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable); extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf); +extern int uvc_queue_mmap(struct uvc_video_queue *queue, + struct vm_area_struct *vma); extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, poll_table *wait); extern int uvc_queue_allocated(struct uvc_video_queue *queue); @@ -606,10 +610,10 @@ extern int uvc_status_suspend(struct uvc_device *dev); extern int uvc_status_resume(struct uvc_device *dev); /* Controls */ -extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, - __u32 v4l2_id, struct uvc_control_mapping **mapping); extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, struct v4l2_queryctrl *v4l2_ctrl); +extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain, + struct v4l2_querymenu *query_menu); extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, const struct uvc_control_mapping *mapping); diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 9294282b5add..b5eb1f3950b1 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -368,18 +368,15 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init); /* Load an i2c sub-device. */ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, const char *module_name, - struct i2c_board_info *info, const unsigned short *probe_addrs) + struct i2c_adapter *adapter, struct i2c_board_info *info, + const unsigned short *probe_addrs) { struct v4l2_subdev *sd = NULL; struct i2c_client *client; BUG_ON(!v4l2_dev); - if (module_name) - request_module(module_name); - else - request_module(I2C_MODULE_PREFIX "%s", info->type); + request_module(I2C_MODULE_PREFIX "%s", info->type); /* Create the i2c client */ if (info->addr == 0 && probe_addrs) @@ -432,8 +429,7 @@ error: EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board); struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, - const char *module_name, const char *client_type, + struct i2c_adapter *adapter, const char *client_type, int irq, void *platform_data, u8 addr, const unsigned short *probe_addrs) { @@ -447,8 +443,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev, info.irq = irq; info.platform_data = platform_data; - return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name, - &info, probe_addrs); + return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs); } EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg); diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 03f7f4670e9b..359e23290a7e 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -186,12 +186,12 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf, size_t sz, loff_t *off) { struct video_device *vdev = video_devdata(filp); - int ret = -EIO; + int ret = -ENODEV; if (!vdev->fops->read) return -EINVAL; - if (vdev->lock) - mutex_lock(vdev->lock); + if (vdev->lock && mutex_lock_interruptible(vdev->lock)) + return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->read(filp, buf, sz, off); if (vdev->lock) @@ -203,12 +203,12 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, size_t sz, loff_t *off) { struct video_device *vdev = video_devdata(filp); - int ret = -EIO; + int ret = -ENODEV; if (!vdev->fops->write) return -EINVAL; - if (vdev->lock) - mutex_lock(vdev->lock); + if (vdev->lock && mutex_lock_interruptible(vdev->lock)) + return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->write(filp, buf, sz, off); if (vdev->lock) @@ -219,10 +219,10 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll) { struct video_device *vdev = video_devdata(filp); - int ret = DEFAULT_POLLMASK; + int ret = POLLERR | POLLHUP; if (!vdev->fops->poll) - return ret; + return DEFAULT_POLLMASK; if (vdev->lock) mutex_lock(vdev->lock); if (video_is_registered(vdev)) @@ -238,20 +238,45 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) int ret = -ENODEV; if (vdev->fops->unlocked_ioctl) { - if (vdev->lock) - mutex_lock(vdev->lock); + if (vdev->lock && mutex_lock_interruptible(vdev->lock)) + return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); if (vdev->lock) mutex_unlock(vdev->lock); } else if (vdev->fops->ioctl) { - /* TODO: convert all drivers to unlocked_ioctl */ + /* This code path is a replacement for the BKL. It is a major + * hack but it will have to do for those drivers that are not + * yet converted to use unlocked_ioctl. + * + * There are two options: if the driver implements struct + * v4l2_device, then the lock defined there is used to + * serialize the ioctls. Otherwise the v4l2 core lock defined + * below is used. This lock is really bad since it serializes + * completely independent devices. + * + * Both variants suffer from the same problem: if the driver + * sleeps, then it blocks all ioctls since the lock is still + * held. This is very common for VIDIOC_DQBUF since that + * normally waits for a frame to arrive. As a result any other + * ioctl calls will proceed very, very slowly since each call + * will have to wait for the VIDIOC_QBUF to finish. Things that + * should take 0.01s may now take 10-20 seconds. + * + * The workaround is to *not* take the lock for VIDIOC_DQBUF. + * This actually works OK for videobuf-based drivers, since + * videobuf will take its own internal lock. + */ static DEFINE_MUTEX(v4l2_ioctl_mutex); + struct mutex *m = vdev->v4l2_dev ? + &vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex; - mutex_lock(&v4l2_ioctl_mutex); + if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m)) + return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->ioctl(filp, cmd, arg); - mutex_unlock(&v4l2_ioctl_mutex); + if (cmd != VIDIOC_DQBUF) + mutex_unlock(m); } else ret = -ENOTTY; @@ -265,8 +290,8 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) if (!vdev->fops->mmap) return ret; - if (vdev->lock) - mutex_lock(vdev->lock); + if (vdev->lock && mutex_lock_interruptible(vdev->lock)) + return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->mmap(filp, vm); if (vdev->lock) @@ -284,7 +309,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) mutex_lock(&videodev_lock); vdev = video_devdata(filp); /* return ENODEV if the video device has already been removed. */ - if (vdev == NULL) { + if (vdev == NULL || !video_is_registered(vdev)) { mutex_unlock(&videodev_lock); return -ENODEV; } @@ -292,8 +317,10 @@ static int v4l2_open(struct inode *inode, struct file *filp) video_get(vdev); mutex_unlock(&videodev_lock); if (vdev->fops->open) { - if (vdev->lock) - mutex_lock(vdev->lock); + if (vdev->lock && mutex_lock_interruptible(vdev->lock)) { + ret = -ERESTARTSYS; + goto err; + } if (video_is_registered(vdev)) ret = vdev->fops->open(filp); else @@ -302,6 +329,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) mutex_unlock(vdev->lock); } +err: /* decrease the refcount in case of an error */ if (ret) video_put(vdev); @@ -596,7 +624,12 @@ void video_unregister_device(struct video_device *vdev) if (!vdev || !video_is_registered(vdev)) return; + mutex_lock(&videodev_lock); + /* This must be in a critical section to prevent a race with v4l2_open. + * Once this bit has been cleared video_get may never be called again. + */ clear_bit(V4L2_FL_REGISTERED, &vdev->flags); + mutex_unlock(&videodev_lock); device_unregister(&vdev->dev); } EXPORT_SYMBOL(video_unregister_device); diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index 0b08f96b74a5..7fe6f92af480 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -35,6 +35,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) INIT_LIST_HEAD(&v4l2_dev->subdevs); spin_lock_init(&v4l2_dev->lock); + mutex_init(&v4l2_dev->ioctl_lock); v4l2_dev->dev = dev; if (dev == NULL) { /* If dev == NULL, then name must be filled in by the caller */ diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c index 02a21bccae18..9eda7cc03121 100644 --- a/drivers/media/video/via-camera.c +++ b/drivers/media/video/via-camera.c @@ -1360,7 +1360,7 @@ static __devinit int viacam_probe(struct platform_device *pdev) */ sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31); cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, sensor_adapter, - "ov7670", "ov7670", 0x42 >> 1, NULL); + "ov7670", 0x42 >> 1, NULL); if (cam->sensor == NULL) { dev_err(&pdev->dev, "Unable to find the sensor!\n"); ret = -ENODEV; diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index e5e005dc1554..7e7eec48f8b1 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -4334,10 +4334,10 @@ static int __init vino_module_init(void) vino_drvdata->decoder = v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter, - NULL, "saa7191", 0, I2C_ADDRS(0x45)); + "saa7191", 0, I2C_ADDRS(0x45)); vino_drvdata->camera = v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter, - NULL, "indycam", 0, I2C_ADDRS(0x2b)); + "indycam", 0, I2C_ADDRS(0x2b)); dprintk("init complete!\n"); diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index 635420d8d84a..019ee206cbee 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c @@ -815,7 +815,7 @@ out: static const struct v4l2_file_operations w9966_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .read = w9966_v4l_read, }; diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index 7e6d62467eaa..e520abf9f4c3 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c @@ -1343,13 +1343,12 @@ static int __devinit zoran_probe(struct pci_dev *pdev, } zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, - &zr->i2c_adapter, NULL, zr->card.i2c_decoder, + &zr->i2c_adapter, zr->card.i2c_decoder, 0, zr->card.addrs_decoder); if (zr->card.i2c_encoder) zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, - &zr->i2c_adapter, - NULL, zr->card.i2c_encoder, + &zr->i2c_adapter, zr->card.i2c_encoder, 0, zr->card.addrs_encoder); dprintk(2, diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c index ca47e6285075..307aada5fffe 100644 --- a/drivers/misc/isl29020.c +++ b/drivers/misc/isl29020.c @@ -183,9 +183,7 @@ static int isl29020_probe(struct i2c_client *client, static int isl29020_remove(struct i2c_client *client) { - struct als_data *data = i2c_get_clientdata(client); sysfs_remove_group(&client->dev.kobj, &m_als_gr); - kfree(data); return 0; } @@ -245,6 +243,6 @@ static void __exit sensor_isl29020_exit(void) module_init(sensor_isl29020_init); module_exit(sensor_isl29020_exit); -MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com"); +MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com>"); MODULE_DESCRIPTION("Intersil isl29020 ALS Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index d551f09ccb79..6956f7e7d439 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -439,18 +439,23 @@ xpc_discovery(void) * nodes that can comprise an access protection grouping. The access * protection is in regards to memory, IOI and IPI. */ - max_regions = 64; region_size = xp_region_size; - switch (region_size) { - case 128: - max_regions *= 2; - case 64: - max_regions *= 2; - case 32: - max_regions *= 2; - region_size = 16; - DBUG_ON(!is_shub2()); + if (is_uv()) + max_regions = 256; + else { + max_regions = 64; + + switch (region_size) { + case 128: + max_regions *= 2; + case 64: + max_regions *= 2; + case 32: + max_regions *= 2; + region_size = 16; + DBUG_ON(!is_shub2()); + } } for (region = 0; region < max_regions; region++) { diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 8f86d702e46e..31ae07a36576 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1559,7 +1559,7 @@ void mmc_stop_host(struct mmc_host *host) if (host->caps & MMC_CAP_DISABLE) cancel_delayed_work(&host->disable); - cancel_delayed_work(&host->detect); + cancel_delayed_work_sync(&host->detect); mmc_flush_scheduled_work(); /* clear pm flags now and let card drivers set them as needed */ diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 995261f7fd70..77f93c3b8808 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -375,7 +375,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, struct mmc_card *oldcard) { struct mmc_card *card; - int err, ddr = MMC_SDR_MODE; + int err, ddr = 0; u32 cid[4]; unsigned int max_dtr; @@ -562,7 +562,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, 1 << bus_width, ddr); err = 0; } else { - mmc_card_set_ddr_mode(card); + if (ddr) + mmc_card_set_ddr_mode(card); + else + ddr = MMC_SDR_MODE; + mmc_set_bus_width_ddr(card->host, bus_width, ddr); } } diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index c3ad1058cd31..efef5f94ac42 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -547,9 +547,11 @@ static void mmc_sdio_detect(struct mmc_host *host) BUG_ON(!host->card); /* Make sure card is powered before detecting it */ - err = pm_runtime_get_sync(&host->card->dev); - if (err < 0) - goto out; + if (host->caps & MMC_CAP_POWER_OFF_CARD) { + err = pm_runtime_get_sync(&host->card->dev); + if (err < 0) + goto out; + } mmc_claim_host(host); @@ -560,6 +562,20 @@ static void mmc_sdio_detect(struct mmc_host *host) mmc_release_host(host); + /* + * Tell PM core it's OK to power off the card now. + * + * The _sync variant is used in order to ensure that the card + * is left powered off in case an error occurred, and the card + * is going to be removed. + * + * Since there is no specific reason to believe a new user + * is about to show up at this point, the _sync variant is + * desirable anyway. + */ + if (host->caps & MMC_CAP_POWER_OFF_CARD) + pm_runtime_put_sync(&host->card->dev); + out: if (err) { mmc_sdio_remove(host); @@ -568,9 +584,6 @@ out: mmc_detach_bus(host); mmc_release_host(host); } - - /* Tell PM core that we're done */ - pm_runtime_put(&host->card->dev); } /* @@ -718,16 +731,21 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) card = host->card; /* - * Let runtime PM core know our card is active + * Enable runtime PM only if supported by host+card+board */ - err = pm_runtime_set_active(&card->dev); - if (err) - goto remove; + if (host->caps & MMC_CAP_POWER_OFF_CARD) { + /* + * Let runtime PM core know our card is active + */ + err = pm_runtime_set_active(&card->dev); + if (err) + goto remove; - /* - * Enable runtime PM for this card - */ - pm_runtime_enable(&card->dev); + /* + * Enable runtime PM for this card + */ + pm_runtime_enable(&card->dev); + } /* * The number of functions on the card is encoded inside @@ -745,9 +763,10 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) goto remove; /* - * Enable Runtime PM for this func + * Enable Runtime PM for this func (if supported) */ - pm_runtime_enable(&card->sdio_func[i]->dev); + if (host->caps & MMC_CAP_POWER_OFF_CARD) + pm_runtime_enable(&card->sdio_func[i]->dev); } mmc_release_host(host); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 2716c7ab6bbf..203da443e339 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -17,6 +17,7 @@ #include <linux/pm_runtime.h> #include <linux/mmc/card.h> +#include <linux/mmc/host.h> #include <linux/mmc/sdio_func.h> #include "sdio_cis.h" @@ -132,9 +133,11 @@ static int sdio_bus_probe(struct device *dev) * it should call pm_runtime_put_noidle() in its probe routine and * pm_runtime_get_noresume() in its remove routine. */ - ret = pm_runtime_get_sync(dev); - if (ret < 0) - goto out; + if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) { + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto out; + } /* Set the default block size so the driver is sure it's something * sensible. */ @@ -151,7 +154,8 @@ static int sdio_bus_probe(struct device *dev) return 0; disable_runtimepm: - pm_runtime_put_noidle(dev); + if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) + pm_runtime_put_noidle(dev); out: return ret; } @@ -160,12 +164,14 @@ static int sdio_bus_remove(struct device *dev) { struct sdio_driver *drv = to_sdio_driver(dev->driver); struct sdio_func *func = dev_to_sdio_func(dev); - int ret; + int ret = 0; /* Make sure card is powered before invoking ->remove() */ - ret = pm_runtime_get_sync(dev); - if (ret < 0) - goto out; + if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) { + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto out; + } drv->remove(func); @@ -178,10 +184,12 @@ static int sdio_bus_remove(struct device *dev) } /* First, undo the increment made directly above */ - pm_runtime_put_noidle(dev); + if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) + pm_runtime_put_noidle(dev); /* Then undo the runtime PM settings in sdio_bus_probe() */ - pm_runtime_put_noidle(dev); + if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) + pm_runtime_put_noidle(dev); out: return ret; @@ -191,6 +199,8 @@ out: static int sdio_bus_pm_prepare(struct device *dev) { + struct sdio_func *func = dev_to_sdio_func(dev); + /* * Resume an SDIO device which was suspended at run time at this * point, in order to allow standard SDIO suspend/resume paths @@ -212,7 +222,8 @@ static int sdio_bus_pm_prepare(struct device *dev) * since there is little point in failing system suspend if a * device can't be resumed. */ - pm_runtime_resume(dev); + if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) + pm_runtime_resume(dev); return 0; } diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 82a1079bbdc7..5d46021cbb57 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1002,7 +1002,7 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, * Monitor a 0->1 transition first */ if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) { - while ((!(OMAP_HSMMC_READ(host, SYSCTL) & bit)) + while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit)) && (i++ < limit)) cpu_relax(); } diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 2e9cca19c90b..9b82910b9dbb 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -17,6 +17,7 @@ #include <linux/clk.h> #include <linux/mmc/host.h> #include <linux/mmc/sdhci-pltfm.h> +#include <mach/hardware.h> #include "sdhci.h" #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" @@ -112,6 +113,13 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd clk_enable(clk); pltfm_host->clk = clk; + if (cpu_is_mx35() || cpu_is_mx51()) + host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; + + /* Fix errata ENGcm07207 which is present on i.MX25 and i.MX35 */ + if (cpu_is_mx25() || cpu_is_mx35()) + host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; + return 0; } @@ -133,10 +141,8 @@ static struct sdhci_ops sdhci_esdhc_ops = { }; struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { - .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_MULTIBLOCK - | SDHCI_QUIRK_BROKEN_ADMA, + .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA, /* ADMA has issues. Might be fixable */ - /* NO_MULTIBLOCK might be MX35 only (Errata: ENGcm07207) */ .ops = &sdhci_esdhc_ops, .init = esdhc_pltfm_init, .exit = esdhc_pltfm_exit, diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 55746bac2f44..3d9c2460d437 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -149,11 +149,11 @@ static const struct sdhci_pci_fixes sdhci_cafe = { * ADMA operation is disabled for Moorestown platform due to * hardware bugs. */ -static int mrst_hc1_probe(struct sdhci_pci_chip *chip) +static int mrst_hc_probe(struct sdhci_pci_chip *chip) { /* - * slots number is fixed here for MRST as SDIO3 is never used and has - * hardware bugs. + * slots number is fixed here for MRST as SDIO3/5 are never used and + * have hardware bugs. */ chip->num_slots = 1; return 0; @@ -163,9 +163,9 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, }; -static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1 = { +static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, - .probe = mrst_hc1_probe, + .probe = mrst_hc_probe, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { @@ -538,7 +538,15 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .device = PCI_DEVICE_ID_INTEL_MRST_SD1, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1, + .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2, + }, + + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_MRST_SD2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2, }, { @@ -637,6 +645,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) { struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; + mmc_pm_flag_t slot_pm_flags; mmc_pm_flag_t pm_flags = 0; int i, ret; @@ -657,7 +666,11 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) return ret; } - pm_flags |= slot->host->mmc->pm_flags; + slot_pm_flags = slot->host->mmc->pm_flags; + if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ) + sdhci_enable_irq_wakeups(slot->host); + + pm_flags |= slot_pm_flags; } if (chip->fixes && chip->fixes->suspend) { @@ -671,8 +684,10 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) pci_save_state(pdev); if (pm_flags & MMC_PM_KEEP_POWER) { - if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) + if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) { + pci_pme_active(pdev, true); pci_enable_wake(pdev, PCI_D3hot, 1); + } pci_set_power_state(pdev, PCI_D3hot); } else { pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); diff --git a/drivers/mmc/host/sdhci-pxa.c b/drivers/mmc/host/sdhci-pxa.c index fc406ac5d193..5a61208cbc66 100644 --- a/drivers/mmc/host/sdhci-pxa.c +++ b/drivers/mmc/host/sdhci-pxa.c @@ -141,6 +141,10 @@ static int __devinit sdhci_pxa_probe(struct platform_device *pdev) if (pdata->quirks) host->quirks |= pdata->quirks; + /* If slot design supports 8 bit data, indicate this to MMC. */ + if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) + host->mmc->caps |= MMC_CAP_8_BIT_DATA; + ret = sdhci_add_host(host); if (ret) { dev_err(&pdev->dev, "failed to add host\n"); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 782c0ee3c925..a25db426c910 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1185,17 +1185,31 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks(host, ios->power_mode); - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - - if (ios->bus_width == MMC_BUS_WIDTH_8) - ctrl |= SDHCI_CTRL_8BITBUS; - else - ctrl &= ~SDHCI_CTRL_8BITBUS; + /* + * If your platform has 8-bit width support but is not a v3 controller, + * or if it requires special setup code, you should implement that in + * platform_8bit_width(). + */ + if (host->ops->platform_8bit_width) + host->ops->platform_8bit_width(host, ios->bus_width); + else { + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + if (ios->bus_width == MMC_BUS_WIDTH_8) { + ctrl &= ~SDHCI_CTRL_4BITBUS; + if (host->version >= SDHCI_SPEC_300) + ctrl |= SDHCI_CTRL_8BITBUS; + } else { + if (host->version >= SDHCI_SPEC_300) + ctrl &= ~SDHCI_CTRL_8BITBUS; + if (ios->bus_width == MMC_BUS_WIDTH_4) + ctrl |= SDHCI_CTRL_4BITBUS; + else + ctrl &= ~SDHCI_CTRL_4BITBUS; + } + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + } - if (ios->bus_width == MMC_BUS_WIDTH_4) - ctrl |= SDHCI_CTRL_4BITBUS; - else - ctrl &= ~SDHCI_CTRL_4BITBUS; + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if ((ios->timing == MMC_TIMING_SD_HS || ios->timing == MMC_TIMING_MMC_HS) @@ -1681,6 +1695,16 @@ int sdhci_resume_host(struct sdhci_host *host) EXPORT_SYMBOL_GPL(sdhci_resume_host); +void sdhci_enable_irq_wakeups(struct sdhci_host *host) +{ + u8 val; + val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL); + val |= SDHCI_WAKE_ON_INT; + sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL); +} + +EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); + #endif /* CONFIG_PM */ /*****************************************************************************\ @@ -1845,11 +1869,19 @@ int sdhci_add_host(struct sdhci_host *host) mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; else mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; + mmc->f_max = host->max_clk; mmc->caps |= MMC_CAP_SDIO_IRQ; + /* + * A controller may support 8-bit width, but the board itself + * might not have the pins brought out. Boards that support + * 8-bit width must set "mmc->caps |= MMC_CAP_8_BIT_DATA;" in + * their platform code before calling sdhci_add_host(), and we + * won't assume 8-bit width for hosts without that CAP. + */ if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) - mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; + mmc->caps |= MMC_CAP_4_BIT_DATA; if (caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index b7b8a3b28b01..e42d7f00c060 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -76,7 +76,7 @@ #define SDHCI_CTRL_ADMA1 0x08 #define SDHCI_CTRL_ADMA32 0x10 #define SDHCI_CTRL_ADMA64 0x18 -#define SDHCI_CTRL_8BITBUS 0x20 +#define SDHCI_CTRL_8BITBUS 0x20 #define SDHCI_POWER_CONTROL 0x29 #define SDHCI_POWER_ON 0x01 @@ -87,6 +87,9 @@ #define SDHCI_BLOCK_GAP_CONTROL 0x2A #define SDHCI_WAKE_UP_CONTROL 0x2B +#define SDHCI_WAKE_ON_INT 0x01 +#define SDHCI_WAKE_ON_INSERT 0x02 +#define SDHCI_WAKE_ON_REMOVE 0x04 #define SDHCI_CLOCK_CONTROL 0x2C #define SDHCI_DIVIDER_SHIFT 8 @@ -152,6 +155,7 @@ #define SDHCI_CLOCK_BASE_SHIFT 8 #define SDHCI_MAX_BLOCK_MASK 0x00030000 #define SDHCI_MAX_BLOCK_SHIFT 16 +#define SDHCI_CAN_DO_8BIT 0x00040000 #define SDHCI_CAN_DO_ADMA2 0x00080000 #define SDHCI_CAN_DO_ADMA1 0x00100000 #define SDHCI_CAN_DO_HISPD 0x00200000 @@ -212,6 +216,8 @@ struct sdhci_ops { unsigned int (*get_max_clock)(struct sdhci_host *host); unsigned int (*get_min_clock)(struct sdhci_host *host); unsigned int (*get_timeout_clock)(struct sdhci_host *host); + int (*platform_8bit_width)(struct sdhci_host *host, + int width); void (*platform_send_init_74_clocks)(struct sdhci_host *host, u8 power_mode); unsigned int (*get_ro)(struct sdhci_host *host); @@ -317,6 +323,7 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead); #ifdef CONFIG_PM extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state); extern int sdhci_resume_host(struct sdhci_host *host); +extern void sdhci_enable_irq_wakeups(struct sdhci_host *host); #endif #endif /* __SDHCI_HW_H */ diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c index b4ead4a13c98..f8f65df9b017 100644 --- a/drivers/mmc/host/ushc.c +++ b/drivers/mmc/host/ushc.c @@ -425,7 +425,7 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id struct usb_device *usb_dev = interface_to_usbdev(intf); struct mmc_host *mmc; struct ushc_data *ushc; - int ret = -ENOMEM; + int ret; mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev); if (mmc == NULL) @@ -462,11 +462,15 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id mmc->max_blk_count = 511; ushc->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->int_urb == NULL) + if (ushc->int_urb == NULL) { + ret = -ENOMEM; goto err; + } ushc->int_data = kzalloc(sizeof(struct ushc_int_data), GFP_KERNEL); - if (ushc->int_data == NULL) + if (ushc->int_data == NULL) { + ret = -ENOMEM; goto err; + } usb_fill_int_urb(ushc->int_urb, ushc->usb_dev, usb_rcvintpipe(usb_dev, intf->cur_altsetting->endpoint[0].desc.bEndpointAddress), @@ -475,11 +479,15 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id intf->cur_altsetting->endpoint[0].desc.bInterval); ushc->cbw_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->cbw_urb == NULL) + if (ushc->cbw_urb == NULL) { + ret = -ENOMEM; goto err; + } ushc->cbw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL); - if (ushc->cbw == NULL) + if (ushc->cbw == NULL) { + ret = -ENOMEM; goto err; + } ushc->cbw->signature = USHC_CBW_SIGNATURE; usb_fill_bulk_urb(ushc->cbw_urb, ushc->usb_dev, usb_sndbulkpipe(usb_dev, 2), @@ -487,15 +495,21 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id cbw_callback, ushc); ushc->data_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->data_urb == NULL) + if (ushc->data_urb == NULL) { + ret = -ENOMEM; goto err; + } ushc->csw_urb = usb_alloc_urb(0, GFP_KERNEL); - if (ushc->csw_urb == NULL) + if (ushc->csw_urb == NULL) { + ret = -ENOMEM; goto err; + } ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL); - if (ushc->csw == NULL) + if (ushc->csw == NULL) { + ret = -ENOMEM; goto err; + } usb_fill_bulk_urb(ushc->csw_urb, ushc->usb_dev, usb_rcvbulkpipe(usb_dev, 6), ushc->csw, sizeof(struct ushc_csw), csw_callback, ushc); diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index dd90880048cf..d8ae634d347e 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -51,7 +51,7 @@ struct pxa2xx_flash_info { static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; -static int __init pxa2xx_flash_probe(struct platform_device *pdev) +static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) { struct flash_platform_data *flash = pdev->dev.platform_data; struct pxa2xx_flash_info *info; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index cd41c58b5bbd..15682ec8530e 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -7,7 +7,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#define CONFIG_MTD_NAND_OMAP_HWECC #include <linux/platform_device.h> #include <linux/dma-mapping.h> diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index c2960ac9f39c..811775aa8ee8 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -482,10 +482,17 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum) uint32_t data = 0; struct ubi_vid_hdr vid_hdr; - addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset; + /* + * It is important to first invalidate the EC header, and then the VID + * header. Otherwise a power cut may lead to valid EC header and + * invalid VID header, in which case UBI will treat this PEB as + * corrupted and will try to preserve it, and print scary warnings (see + * the header comment in scan.c for more information). + */ + addr = (loff_t)pnum * ubi->peb_size; err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); if (!err) { - addr -= ubi->vid_hdr_aloffset; + addr += ubi->vid_hdr_aloffset; err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); if (!err) @@ -494,18 +501,24 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum) /* * We failed to write to the media. This was observed with Spansion - * S29GL512N NOR flash. Most probably the eraseblock erasure was - * interrupted at a very inappropriate moment, so it became unwritable. - * In this case we probably anyway have garbage in this PEB. + * S29GL512N NOR flash. Most probably the previously eraseblock erasure + * was interrupted at a very inappropriate moment, so it became + * unwritable. In this case we probably anyway have garbage in this + * PEB. */ err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); - if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) - /* - * The VID header is corrupted, so we can safely erase this - * PEB and not afraid that it will be treated as a valid PEB in - * case of an unclean reboot. - */ - return 0; + if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) { + struct ubi_ec_hdr ec_hdr; + + err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0); + if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) + /* + * Both VID and EC headers are corrupted, so we can + * safely erase this PEB and not afraid that it will be + * treated as a valid PEB in case of an unclean reboot. + */ + return 0; + } /* * The PEB contains a valid VID header, but we cannot invalidate it. diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 3c631863bf40..79ca304fc4db 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -787,16 +787,15 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, * erased, so it became unstable and corrupted, and should be * erased. */ - return 0; + err = 0; + goto out_unlock; } if (err) - return err; + goto out_unlock; - if (ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->leb_size)) { - mutex_unlock(&ubi->buf_mutex); - return 0; - } + if (ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->leb_size)) + goto out_unlock; ubi_err("PEB %d contains corrupted VID header, and the data does not " "contain all 0xFF, this may be a non-UBI PEB or a severe VID " @@ -806,8 +805,11 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, pnum, ubi->leb_start, ubi->leb_size); ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, ubi->peb_buf1, ubi->leb_size, 1); + err = 1; + +out_unlock: mutex_unlock(&ubi->buf_mutex); - return 1; + return err; } /** @@ -951,6 +953,10 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, * impossible to distinguish it from a PEB which just * contains garbage because of a power cut during erase * operation. So we just schedule this PEB for erasure. + * + * Besides, in case of NOR flash, we deliberatly + * corrupt both headers because NOR flash erasure is + * slow and can start from the end. */ err = 0; else diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index e1da258bbfb7..0a92436f0538 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -699,7 +699,8 @@ DEFINE_WINDOW_IO(32) #define DEVICE_PCI(dev) NULL #endif -#define VORTEX_PCI(vp) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL) +#define VORTEX_PCI(vp) \ + ((struct pci_dev *) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL)) #ifdef CONFIG_EISA #define DEVICE_EISA(dev) (((dev)->bus == &eisa_bus_type) ? to_eisa_device((dev)) : NULL) @@ -707,7 +708,8 @@ DEFINE_WINDOW_IO(32) #define DEVICE_EISA(dev) NULL #endif -#define VORTEX_EISA(vp) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL) +#define VORTEX_EISA(vp) \ + ((struct eisa_device *) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL)) /* The action to take with a media selection timer tick. Note that we deviate from the 3Com order by checking 10base2 before AUI. diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index ac422cd332ea..dd16e83933a2 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -490,13 +490,11 @@ static inline unsigned int cp_rx_csum_ok (u32 status) { unsigned int protocol = (status >> 16) & 0x3; - if (likely((protocol == RxProtoTCP) && (!(status & TCPFail)))) + if (((protocol == RxProtoTCP) && !(status & TCPFail)) || + ((protocol == RxProtoUDP) && !(status & UDPFail))) return 1; - else if ((protocol == RxProtoUDP) && (!(status & UDPFail))) - return 1; - else if ((protocol == RxProtoIP) && (!(status & IPFail))) - return 1; - return 0; + else + return 0; } static int cp_rx_poll(struct napi_struct *napi, int budget) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f6668cdaac85..4f1755bddf6b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2543,10 +2543,10 @@ config PCH_GBE depends on PCI select MII ---help--- - This is a gigabit ethernet driver for Topcliff PCH. - Topcliff PCH is the platform controller hub that is used in Intel's + This is a gigabit ethernet driver for EG20T PCH. + EG20T PCH is the platform controller hub that is used in Intel's general embedded platform. - Topcliff PCH has Gigabit Ethernet interface. + EG20T PCH has Gigabit Ethernet interface. Using this interface, it is able to access system devices connected to Gigabit Ethernet. This driver enables Gigabit Ethernet function. @@ -2945,6 +2945,18 @@ source "drivers/s390/net/Kconfig" source "drivers/net/caif/Kconfig" +config TILE_NET + tristate "Tilera GBE/XGBE network driver support" + depends on TILE + default y + select CRC32 + help + This is a standard Linux network device driver for the + on-chip Tilera Gigabit Ethernet and XAUI interfaces. + + To compile this driver as a module, choose M here: the module + will be called tile_net. + config XEN_NETDEV_FRONTEND tristate "Xen network device frontend driver" depends on XEN diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 652fc6b98039..b90738d13994 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -301,3 +301,4 @@ obj-$(CONFIG_CAIF) += caif/ obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/ obj-$(CONFIG_PCH_GBE) += pch_gbe/ +obj-$(CONFIG_TILE_NET) += tile/ diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c index 919080b2c3a5..1bf672009948 100644 --- a/drivers/net/atl1c/atl1c_hw.c +++ b/drivers/net/atl1c/atl1c_hw.c @@ -82,7 +82,7 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw) addr[0] = addr[1] = 0; AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data); if (atl1c_check_eeprom_exist(hw)) { - if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) { + if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) { /* Enable OTP CLK */ if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) { otp_ctrl_data |= OTP_CTRL_CLK_EN; diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 43489f89c142..53eff9ba6e95 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -155,10 +155,10 @@ static void au1000_enable_mac(struct net_device *dev, int force_reset) spin_lock_irqsave(&aup->lock, flags); if (force_reset || (!aup->mac_enabled)) { - writel(MAC_EN_CLOCK_ENABLE, &aup->enable); + writel(MAC_EN_CLOCK_ENABLE, aup->enable); au_sync_delay(2); writel((MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 - | MAC_EN_CLOCK_ENABLE), &aup->enable); + | MAC_EN_CLOCK_ENABLE), aup->enable); au_sync_delay(2); aup->mac_enabled = 1; @@ -503,9 +503,9 @@ static void au1000_reset_mac_unlocked(struct net_device *dev) au1000_hard_stop(dev); - writel(MAC_EN_CLOCK_ENABLE, &aup->enable); + writel(MAC_EN_CLOCK_ENABLE, aup->enable); au_sync_delay(2); - writel(0, &aup->enable); + writel(0, aup->enable); au_sync_delay(2); aup->tx_full = 0; @@ -1119,7 +1119,7 @@ static int __devinit au1000_probe(struct platform_device *pdev) /* set a random MAC now in case platform_data doesn't provide one */ random_ether_addr(dev->dev_addr); - writel(0, &aup->enable); + writel(0, aup->enable); aup->mac_enabled = 0; pd = pdev->dev.platform_data; diff --git a/drivers/net/b44.c b/drivers/net/b44.c index c6e86315b3f8..2e2b76258ab4 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -381,11 +381,11 @@ static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) __b44_set_flow_ctrl(bp, pause_enab); } -#ifdef SSB_DRIVER_MIPS -extern char *nvram_get(char *name); +#ifdef CONFIG_BCM47XX +#include <asm/mach-bcm47xx/nvram.h> static void b44_wap54g10_workaround(struct b44 *bp) { - const char *str; + char buf[20]; u32 val; int err; @@ -394,10 +394,9 @@ static void b44_wap54g10_workaround(struct b44 *bp) * see https://dev.openwrt.org/ticket/146 * check and reset bit "isolate" */ - str = nvram_get("boardnum"); - if (!str) + if (nvram_getenv("boardnum", buf, sizeof(buf)) < 0) return; - if (simple_strtoul(str, NULL, 0) == 2) { + if (simple_strtoul(buf, NULL, 0) == 2) { err = __b44_readphy(bp, 0, MII_BMCR, &val); if (err) goto error; diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 36eca1ce75d4..e4465d222a7d 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1235,7 +1235,7 @@ int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id, i = 0; netdev_for_each_mc_addr(ha, netdev) - memcpy(req->mac[i].byte, ha->addr, ETH_ALEN); + memcpy(req->mac[i++].byte, ha->addr, ETH_ALEN); } else { req->promiscuous = 1; } diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index c36cd2ffbadc..93354eee2cfd 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2458,6 +2458,12 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) int status, i = 0, num_imgs = 0; const u8 *p; + if (!netif_running(adapter->netdev)) { + dev_err(&adapter->pdev->dev, + "Firmware load not allowed (interface is down)\n"); + return -EPERM; + } + strcpy(fw_file, func); status = request_firmware(&fw, fw_file, &adapter->pdev->dev); diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 863e73a85fbe..d255428122fc 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -20,8 +20,8 @@ * (you will need to reboot afterwards) */ /* #define BNX2X_STOP_ON_ERROR */ -#define DRV_MODULE_VERSION "1.60.00-4" -#define DRV_MODULE_RELDATE "2010/11/01" +#define DRV_MODULE_VERSION "1.60.01-0" +#define DRV_MODULE_RELDATE "2010/11/12" #define BNX2X_BC_VER 0x040200 #define BNX2X_MULTI_QUEUE diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 94d5f59d5a6f..0af361e4e3d1 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -1782,15 +1782,15 @@ exit_lbl: } #endif -static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, - struct eth_tx_parse_bd_e2 *pbd, - u32 xmit_type) +static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data, + u32 xmit_type) { - pbd->parsing_data |= cpu_to_le16(skb_shinfo(skb)->gso_size) << - ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT; + *parsing_data |= (skb_shinfo(skb)->gso_size << + ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) & + ETH_TX_PARSE_BD_E2_LSO_MSS; if ((xmit_type & XMIT_GSO_V6) && (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6)) - pbd->parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR; + *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR; } /** @@ -1835,15 +1835,15 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb, * @return header len */ static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, - struct eth_tx_parse_bd_e2 *pbd, - u32 xmit_type) + u32 *parsing_data, u32 xmit_type) { - pbd->parsing_data |= cpu_to_le16(tcp_hdrlen(skb)/4) << - ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT; + *parsing_data |= ((tcp_hdrlen(skb)/4) << + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; - pbd->parsing_data |= cpu_to_le16(((unsigned char *)tcp_hdr(skb) - - skb->data) / 2) << - ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT; + *parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) << + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W; return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; } @@ -1912,6 +1912,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL; struct eth_tx_parse_bd_e1x *pbd_e1x = NULL; struct eth_tx_parse_bd_e2 *pbd_e2 = NULL; + u32 pbd_e2_parsing_data = 0; u16 pkt_prod, bd_prod; int nbd, fp_index; dma_addr_t mapping; @@ -2033,8 +2034,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2)); /* Set PBD in checksum offload case */ if (xmit_type & XMIT_CSUM) - hlen = bnx2x_set_pbd_csum_e2(bp, - skb, pbd_e2, xmit_type); + hlen = bnx2x_set_pbd_csum_e2(bp, skb, + &pbd_e2_parsing_data, + xmit_type); } else { pbd_e1x = &fp->tx_desc_ring[bd_prod].parse_bd_e1x; memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x)); @@ -2076,10 +2078,18 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd, hlen, bd_prod, ++nbd); if (CHIP_IS_E2(bp)) - bnx2x_set_pbd_gso_e2(skb, pbd_e2, xmit_type); + bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data, + xmit_type); else bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type); } + + /* Set the PBD's parsing_data field if not zero + * (for the chips newer than 57711). + */ + if (pbd_e2_parsing_data) + pbd_e2->parsing_data = cpu_to_le32(pbd_e2_parsing_data); + tx_data_bd = (struct eth_tx_bd *)tx_start_bd; /* Handle fragmented skb */ diff --git a/drivers/net/bnx2x/bnx2x_init_ops.h b/drivers/net/bnx2x/bnx2x_init_ops.h index a306b0e46b61..66df29fcf751 100644 --- a/drivers/net/bnx2x/bnx2x_init_ops.h +++ b/drivers/net/bnx2x/bnx2x_init_ops.h @@ -838,7 +838,7 @@ static void bnx2x_qm_init_ptr_table(struct bnx2x *bp, int qm_cid_count, /**************************************************************************** * SRC initializations ****************************************************************************/ - +#ifdef BCM_CNIC /* called during init func stage */ static void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2, dma_addr_t t2_mapping, int src_cid_count) @@ -862,5 +862,5 @@ static void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2, U64_HI((u64)t2_mapping + (src_cid_count-1) * sizeof(struct src_ent))); } - +#endif #endif /* BNX2X_INIT_OPS_H */ diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index e9ad16f00b56..9709b8569666 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -9064,7 +9064,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, default: pr_err("Unknown board_type (%ld), aborting\n", ent->driver_data); - return ENODEV; + return -ENODEV; } cid_count += CNIC_CONTEXT_USE; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index bdb68a600382..d0ea760ce419 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -171,7 +171,7 @@ MODULE_PARM_DESC(resend_igmp, "Number of IGMP membership reports to send on link /*----------------------------- Global variables ----------------------------*/ #ifdef CONFIG_NET_POLL_CONTROLLER -cpumask_var_t netpoll_block_tx; +atomic_t netpoll_block_tx = ATOMIC_INIT(0); #endif static const char * const version = @@ -878,8 +878,10 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev) rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); if (in_dev) { + read_lock(&in_dev->mc_list_lock); for (im = in_dev->mc_list; im; im = im->next) ip_mc_rejoin_group(im); + read_unlock(&in_dev->mc_list_lock); } rcu_read_unlock(); @@ -1574,7 +1576,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* If this is the first slave, then we need to set the master's hardware * address to be the same as the slave's. */ - if (bond->slave_cnt == 0) + if (is_zero_ether_addr(bond->dev->dev_addr)) memcpy(bond->dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len); @@ -5297,13 +5299,6 @@ static int __init bonding_init(void) if (res) goto out; -#ifdef CONFIG_NET_POLL_CONTROLLER - if (!alloc_cpumask_var(&netpoll_block_tx, GFP_KERNEL)) { - res = -ENOMEM; - goto out; - } -#endif - res = register_pernet_subsys(&bond_net_ops); if (res) goto out; @@ -5332,9 +5327,6 @@ err: rtnl_link_unregister(&bond_link_ops); err_link: unregister_pernet_subsys(&bond_net_ops); -#ifdef CONFIG_NET_POLL_CONTROLLER - free_cpumask_var(netpoll_block_tx); -#endif goto out; } @@ -5351,7 +5343,10 @@ static void __exit bonding_exit(void) unregister_pernet_subsys(&bond_net_ops); #ifdef CONFIG_NET_POLL_CONTROLLER - free_cpumask_var(netpoll_block_tx); + /* + * Make sure we don't have an imbalance on our netpoll blocking + */ + WARN_ON(atomic_read(&netpoll_block_tx)); #endif } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 4eedb12df6ca..c2f081352a03 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -119,26 +119,22 @@ #ifdef CONFIG_NET_POLL_CONTROLLER -extern cpumask_var_t netpoll_block_tx; +extern atomic_t netpoll_block_tx; static inline void block_netpoll_tx(void) { - preempt_disable(); - BUG_ON(cpumask_test_and_set_cpu(smp_processor_id(), - netpoll_block_tx)); + atomic_inc(&netpoll_block_tx); } static inline void unblock_netpoll_tx(void) { - BUG_ON(!cpumask_test_and_clear_cpu(smp_processor_id(), - netpoll_block_tx)); - preempt_enable(); + atomic_dec(&netpoll_block_tx); } static inline int is_netpoll_tx_blocked(struct net_device *dev) { if (unlikely(dev->priv_flags & IFF_IN_NETPOLL)) - return cpumask_test_cpu(smp_processor_id(), netpoll_block_tx); + return atomic_read(&netpoll_block_tx); return 0; } #else diff --git a/drivers/net/caif/caif_shm_u5500.c b/drivers/net/caif/caif_shm_u5500.c index 1cd90da86f13..32b1c6fb2de1 100644 --- a/drivers/net/caif/caif_shm_u5500.c +++ b/drivers/net/caif/caif_shm_u5500.c @@ -5,7 +5,7 @@ * License terms: GNU General Public License (GPL) version 2 */ -#define pr_fmt(fmt) KBUILD_MODNAME ":" __func__ "():" fmt +#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt #include <linux/version.h> #include <linux/init.h> diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c index 19f9c0656667..80511167f35b 100644 --- a/drivers/net/caif/caif_shmcore.c +++ b/drivers/net/caif/caif_shmcore.c @@ -6,7 +6,7 @@ * License terms: GNU General Public License (GPL) version 2 */ -#define pr_fmt(fmt) KBUILD_MODNAME ":" __func__ "():" fmt +#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt #include <linux/spinlock.h> #include <linux/sched.h> diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index 8b4cea57a6c5..20da1996d354 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -635,8 +635,8 @@ int cfspi_spi_probe(struct platform_device *pdev) ndev = alloc_netdev(sizeof(struct cfspi), "cfspi%d", cfspi_setup); - if (!dev) - return -ENODEV; + if (!ndev) + return -ENOMEM; cfspi = netdev_priv(ndev); netif_stop_queue(ndev); diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c index bb813d94aea8..e97521c801ea 100644 --- a/drivers/net/cxgb4/t4_hw.c +++ b/drivers/net/cxgb4/t4_hw.c @@ -2408,7 +2408,7 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, if (index < NEXACT_MAC) ret++; else if (hash) - *hash |= (1 << hash_mac_addr(addr[i])); + *hash |= (1ULL << hash_mac_addr(addr[i])); } return ret; } diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index c3449bbc585a..6bf464afa90e 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -816,40 +816,48 @@ static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev) } /* - * Collect up to maxaddrs worth of a netdevice's unicast addresses into an - * array of addrss pointers and return the number collected. + * Collect up to maxaddrs worth of a netdevice's unicast addresses, starting + * at a specified offset within the list, into an array of addrss pointers and + * return the number collected. */ -static inline int collect_netdev_uc_list_addrs(const struct net_device *dev, - const u8 **addr, - unsigned int maxaddrs) +static inline unsigned int collect_netdev_uc_list_addrs(const struct net_device *dev, + const u8 **addr, + unsigned int offset, + unsigned int maxaddrs) { + unsigned int index = 0; unsigned int naddr = 0; const struct netdev_hw_addr *ha; - for_each_dev_addr(dev, ha) { - addr[naddr++] = ha->addr; - if (naddr >= maxaddrs) - break; - } + for_each_dev_addr(dev, ha) + if (index++ >= offset) { + addr[naddr++] = ha->addr; + if (naddr >= maxaddrs) + break; + } return naddr; } /* - * Collect up to maxaddrs worth of a netdevice's multicast addresses into an - * array of addrss pointers and return the number collected. + * Collect up to maxaddrs worth of a netdevice's multicast addresses, starting + * at a specified offset within the list, into an array of addrss pointers and + * return the number collected. */ -static inline int collect_netdev_mc_list_addrs(const struct net_device *dev, - const u8 **addr, - unsigned int maxaddrs) +static inline unsigned int collect_netdev_mc_list_addrs(const struct net_device *dev, + const u8 **addr, + unsigned int offset, + unsigned int maxaddrs) { + unsigned int index = 0; unsigned int naddr = 0; const struct netdev_hw_addr *ha; - netdev_for_each_mc_addr(ha, dev) { - addr[naddr++] = ha->addr; - if (naddr >= maxaddrs) - break; - } + netdev_for_each_mc_addr(ha, dev) + if (index++ >= offset) { + addr[naddr++] = ha->addr; + if (naddr >= maxaddrs) + break; + } return naddr; } @@ -862,16 +870,20 @@ static int set_addr_filters(const struct net_device *dev, bool sleep) u64 mhash = 0; u64 uhash = 0; bool free = true; - u16 filt_idx[7]; + unsigned int offset, naddr; const u8 *addr[7]; - int ret, naddr = 0; + int ret; const struct port_info *pi = netdev_priv(dev); /* first do the secondary unicast addresses */ - naddr = collect_netdev_uc_list_addrs(dev, addr, ARRAY_SIZE(addr)); - if (naddr > 0) { + for (offset = 0; ; offset += naddr) { + naddr = collect_netdev_uc_list_addrs(dev, addr, offset, + ARRAY_SIZE(addr)); + if (naddr == 0) + break; + ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, - naddr, addr, filt_idx, &uhash, sleep); + naddr, addr, NULL, &uhash, sleep); if (ret < 0) return ret; @@ -879,12 +891,17 @@ static int set_addr_filters(const struct net_device *dev, bool sleep) } /* next set up the multicast addresses */ - naddr = collect_netdev_mc_list_addrs(dev, addr, ARRAY_SIZE(addr)); - if (naddr > 0) { + for (offset = 0; ; offset += naddr) { + naddr = collect_netdev_mc_list_addrs(dev, addr, offset, + ARRAY_SIZE(addr)); + if (naddr == 0) + break; + ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, - naddr, addr, filt_idx, &mhash, sleep); + naddr, addr, NULL, &mhash, sleep); if (ret < 0) return ret; + free = false; } return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0, @@ -2252,6 +2269,7 @@ static void __devinit cfg_queues(struct adapter *adapter) { struct sge *s = &adapter->sge; int q10g, n10g, qidx, pidx, qs; + size_t iqe_size; /* * We should not be called till we know how many Queue Sets we can @@ -2296,6 +2314,13 @@ static void __devinit cfg_queues(struct adapter *adapter) s->ethqsets = qidx; /* + * The Ingress Queue Entry Size for our various Response Queues needs + * to be big enough to accommodate the largest message we can receive + * from the chip/firmware; which is 64 bytes ... + */ + iqe_size = 64; + + /* * Set up default Queue Set parameters ... Start off with the * shortest interrupt holdoff timer. */ @@ -2303,7 +2328,7 @@ static void __devinit cfg_queues(struct adapter *adapter) struct sge_eth_rxq *rxq = &s->ethrxq[qs]; struct sge_eth_txq *txq = &s->ethtxq[qs]; - init_rspq(&rxq->rspq, 0, 0, 1024, L1_CACHE_BYTES); + init_rspq(&rxq->rspq, 0, 0, 1024, iqe_size); rxq->fl.size = 72; txq->q.size = 1024; } @@ -2312,8 +2337,7 @@ static void __devinit cfg_queues(struct adapter *adapter) * The firmware event queue is used for link state changes and * notifications of TX DMA completions. */ - init_rspq(&s->fw_evtq, SGE_TIMER_RSTRT_CNTR, 0, 512, - L1_CACHE_BYTES); + init_rspq(&s->fw_evtq, SGE_TIMER_RSTRT_CNTR, 0, 512, iqe_size); /* * The forwarded interrupt queue is used when we're in MSI interrupt @@ -2329,7 +2353,7 @@ static void __devinit cfg_queues(struct adapter *adapter) * any time ... */ init_rspq(&s->intrq, SGE_TIMER_RSTRT_CNTR, 0, MSIX_ENTRIES + 1, - L1_CACHE_BYTES); + iqe_size); } /* diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c index e306c20dfaee..19520afe1a12 100644 --- a/drivers/net/cxgb4vf/t4vf_hw.c +++ b/drivers/net/cxgb4vf/t4vf_hw.c @@ -1014,48 +1014,72 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free, unsigned int naddr, const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok) { - int i, ret; + int offset, ret = 0; + unsigned nfilters = 0; + unsigned int rem = naddr; struct fw_vi_mac_cmd cmd, rpl; - struct fw_vi_mac_exact *p; - size_t len16; - if (naddr > ARRAY_SIZE(cmd.u.exact)) + if (naddr > FW_CLS_TCAM_NUM_ENTRIES) return -EINVAL; - len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, - u.exact[naddr]), 16); - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | - FW_CMD_REQUEST | - FW_CMD_WRITE | - (free ? FW_CMD_EXEC : 0) | - FW_VI_MAC_CMD_VIID(viid)); - cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) | - FW_CMD_LEN16(len16)); + for (offset = 0; offset < naddr; /**/) { + unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact) + ? rem + : ARRAY_SIZE(cmd.u.exact)); + size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, + u.exact[fw_naddr]), 16); + struct fw_vi_mac_exact *p; + int i; - for (i = 0, p = cmd.u.exact; i < naddr; i++, p++) { - p->valid_to_idx = - cpu_to_be16(FW_VI_MAC_CMD_VALID | - FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); - memcpy(p->macaddr, addr[i], sizeof(p->macaddr)); - } + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | + FW_CMD_REQUEST | + FW_CMD_WRITE | + (free ? FW_CMD_EXEC : 0) | + FW_VI_MAC_CMD_VIID(viid)); + cmd.freemacs_to_len16 = + cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) | + FW_CMD_LEN16(len16)); + + for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) { + p->valid_to_idx = cpu_to_be16( + FW_VI_MAC_CMD_VALID | + FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); + memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr)); + } + + + ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, + sleep_ok); + if (ret && ret != -ENOMEM) + break; - ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, sleep_ok); - if (ret) - return ret; - - for (i = 0, p = rpl.u.exact; i < naddr; i++, p++) { - u16 index = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx)); - - if (idx) - idx[i] = (index >= FW_CLS_TCAM_NUM_ENTRIES - ? 0xffff - : index); - if (index < FW_CLS_TCAM_NUM_ENTRIES) - ret++; - else if (hash) - *hash |= (1 << hash_mac_addr(addr[i])); + for (i = 0, p = rpl.u.exact; i < fw_naddr; i++, p++) { + u16 index = FW_VI_MAC_CMD_IDX_GET( + be16_to_cpu(p->valid_to_idx)); + + if (idx) + idx[offset+i] = + (index >= FW_CLS_TCAM_NUM_ENTRIES + ? 0xffff + : index); + if (index < FW_CLS_TCAM_NUM_ENTRIES) + nfilters++; + else if (hash) + *hash |= (1ULL << hash_mac_addr(addr[offset+i])); + } + + free = false; + offset += fw_naddr; + rem -= fw_naddr; } + + /* + * If there were no errors or we merely ran out of room in our MAC + * address arena, return the number of filters actually written. + */ + if (ret == 0 || ret == -ENOMEM) + ret = nfilters; return ret; } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4686c3983fc3..4d62f7bfa036 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -31,7 +31,7 @@ char e1000_driver_name[] = "e1000"; static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -#define DRV_VERSION "7.3.21-k6-NAPI" +#define DRV_VERSION "7.3.21-k8-NAPI" const char e1000_driver_version[] = DRV_VERSION; static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; @@ -485,9 +485,6 @@ void e1000_down(struct e1000_adapter *adapter) struct net_device *netdev = adapter->netdev; u32 rctl, tctl; - /* signal that we're down so the interrupt handler does not - * reschedule our watchdog timer */ - set_bit(__E1000_DOWN, &adapter->flags); /* disable receives in the hardware */ rctl = er32(RCTL); @@ -508,6 +505,13 @@ void e1000_down(struct e1000_adapter *adapter) e1000_irq_disable(adapter); + /* + * Setting DOWN must be after irq_disable to prevent + * a screaming interrupt. Setting DOWN also prevents + * timers and tasks from rescheduling. + */ + set_bit(__E1000_DOWN, &adapter->flags); + del_timer_sync(&adapter->tx_fifo_stall_timer); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 75b099ce49c9..1f37ee6b2a26 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -261,6 +261,13 @@ static void ehea_get_ethtool_stats(struct net_device *dev, } +static int ehea_set_flags(struct net_device *dev, u32 data) +{ + return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO + | ETH_FLAG_TXVLAN + | ETH_FLAG_RXVLAN); +} + const struct ethtool_ops ehea_ethtool_ops = { .get_settings = ehea_get_settings, .get_drvinfo = ehea_get_drvinfo, @@ -273,6 +280,8 @@ const struct ethtool_ops ehea_ethtool_ops = { .get_ethtool_stats = ehea_get_ethtool_stats, .get_rx_csum = ehea_get_rx_csum, .set_settings = ehea_set_settings, + .get_flags = ethtool_op_get_flags, + .set_flags = ehea_set_flags, .nway_reset = ehea_nway_reset, /* Restart autonegotiation */ }; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 182b2a7be8dc..b95f087cd5a9 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -400,6 +400,7 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes) skb_arr_rq1[index] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE); if (!skb_arr_rq1[index]) { + ehea_info("Unable to allocate enough skb in the array\n"); pr->rq1_skba.os_skbs = fill_wqes - i; break; } @@ -422,13 +423,20 @@ static void ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a) struct net_device *dev = pr->port->netdev; int i; - for (i = 0; i < pr->rq1_skba.len; i++) { + if (nr_rq1a > pr->rq1_skba.len) { + ehea_error("NR_RQ1A bigger than skb array len\n"); + return; + } + + for (i = 0; i < nr_rq1a; i++) { skb_arr_rq1[i] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE); - if (!skb_arr_rq1[i]) + if (!skb_arr_rq1[i]) { + ehea_info("No enough memory to allocate skb array\n"); break; + } } /* Ring doorbell */ - ehea_update_rq1a(pr->qp, nr_rq1a); + ehea_update_rq1a(pr->qp, i); } static int ehea_refill_rq_def(struct ehea_port_res *pr, @@ -675,7 +683,7 @@ static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe, int vlan_extracted = ((cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) && pr->port->vgrp); - if (use_lro) { + if (skb->dev->features & NETIF_F_LRO) { if (vlan_extracted) lro_vlan_hwaccel_receive_skb(&pr->lro_mgr, skb, pr->port->vgrp, @@ -735,8 +743,10 @@ static int ehea_proc_rwqes(struct net_device *dev, skb = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE); - if (!skb) + if (!skb) { + ehea_info("Not enough memory to allocate skb\n"); break; + } } skb_copy_to_linear_data(skb, ((char *)cqe) + 64, cqe->num_bytes_transfered - 4); @@ -777,7 +787,7 @@ static int ehea_proc_rwqes(struct net_device *dev, } cqe = ehea_poll_rq1(qp, &wqe_index); } - if (use_lro) + if (dev->features & NETIF_F_LRO) lro_flush_all(&pr->lro_mgr); pr->rx_packets += processed; @@ -3268,6 +3278,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, | NETIF_F_LLTX; dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT; + if (use_lro) + dev->features |= NETIF_F_LRO; + INIT_WORK(&port->reset_task, ehea_reset_port); ret = register_netdev(dev); diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index a466ef91dd43..aa28b270c045 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1962,7 +1962,8 @@ static void enic_poll_controller(struct net_device *netdev) case VNIC_DEV_INTR_MODE_MSIX: for (i = 0; i < enic->rq_count; i++) { intr = enic_msix_rq_intr(enic, i); - enic_isr_msix_rq(enic->msix_entry[intr].vector, enic); + enic_isr_msix_rq(enic->msix_entry[intr].vector, + &enic->napi[i]); } intr = enic_msix_wq_intr(enic, i); enic_isr_msix_wq(enic->msix_entry[intr].vector, enic); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 49e4ce1246a7..d1bec6269173 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -577,11 +577,10 @@ static int gfar_parse_group(struct device_node *np, irq_of_parse_and_map(np, 1); priv->gfargrp[priv->num_grps].interruptError = irq_of_parse_and_map(np,2); - if (priv->gfargrp[priv->num_grps].interruptTransmit < 0 || - priv->gfargrp[priv->num_grps].interruptReceive < 0 || - priv->gfargrp[priv->num_grps].interruptError < 0) { + if (priv->gfargrp[priv->num_grps].interruptTransmit == NO_IRQ || + priv->gfargrp[priv->num_grps].interruptReceive == NO_IRQ || + priv->gfargrp[priv->num_grps].interruptError == NO_IRQ) return -EINVAL; - } } priv->gfargrp[priv->num_grps].grp_id = priv->num_grps; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index ab9f675c5b8b..fe337bd121aa 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -104,6 +104,8 @@ static void ri_tasklet(unsigned long dev) rcu_read_unlock(); dev_kfree_skb(skb); stats->tx_dropped++; + if (skb_queue_len(&dp->tq) != 0) + goto resched; break; } rcu_read_unlock(); diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index dc0198092343..aa93655c3aa7 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -88,16 +88,14 @@ static const char *ipg_brand_name[] = { "IC PLUS IP1000 1000/100/10 based NIC", "Sundance Technology ST2021 based NIC", "Tamarack Microelectronics TC9020/9021 based NIC", - "Tamarack Microelectronics TC9020/9021 based NIC", "D-Link NIC IP1000A" }; static DEFINE_PCI_DEVICE_TABLE(ipg_pci_tbl) = { { PCI_VDEVICE(SUNDANCE, 0x1023), 0 }, { PCI_VDEVICE(SUNDANCE, 0x2021), 1 }, - { PCI_VDEVICE(SUNDANCE, 0x1021), 2 }, - { PCI_VDEVICE(DLINK, 0x9021), 3 }, - { PCI_VDEVICE(DLINK, 0x4020), 4 }, + { PCI_VDEVICE(DLINK, 0x9021), 2 }, + { PCI_VDEVICE(DLINK, 0x4020), 3 }, { 0, } }; diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c index 00b38bccd6d0..52a7c86af663 100644 --- a/drivers/net/irda/sh_sir.c +++ b/drivers/net/irda/sh_sir.c @@ -258,7 +258,7 @@ static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate) /* Baud Rate Error Correction x 10000 */ u32 rate_err_array[] = { - 0000, 0625, 1250, 1875, + 0, 625, 1250, 1875, 2500, 3125, 3750, 4375, 5000, 5625, 6250, 6875, 7500, 8125, 8750, 9375, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index fbad4d819608..eee0b298bd36 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4771,6 +4771,9 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter) adapter->rx_ring[i] = NULL; } + adapter->num_tx_queues = 0; + adapter->num_rx_queues = 0; + ixgbe_free_q_vectors(adapter); ixgbe_reset_interrupt_capability(adapter); } diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index b68eee2414c2..7a7e18ba278a 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c @@ -289,6 +289,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET); dev_cap->bf_reg_size = 1 << (field & 0x1f); MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET); + if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size)) { + mlx4_warn(dev, "firmware bug: log2 # of blue flame regs is invalid (%d), forcing 3\n", field & 0x1f); + field = 3; + } dev_cap->bf_regs_per_page = 1 << (field & 0x3f); mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n", dev_cap->bf_reg_size, dev_cap->bf_regs_per_page); diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 472056b47440..03a1d280105f 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -1,6 +1,6 @@ /* * Copyright (C) 1999 - 2010 Intel Corporation. - * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD. + * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. * * This code was derived from the Intel e1000e Linux driver. * @@ -2464,8 +2464,8 @@ static void __exit pch_gbe_exit_module(void) module_init(pch_gbe_init_module); module_exit(pch_gbe_exit_module); -MODULE_DESCRIPTION("OKI semiconductor PCH Gigabit ethernet Driver"); -MODULE_AUTHOR("OKI semiconductor, <masa-korg@dsn.okisemi.com>"); +MODULE_DESCRIPTION("EG20T PCH Gigabit ethernet Driver"); +MODULE_AUTHOR("OKI SEMICONDUCTOR, <toshiharu-linux@dsn.okisemi.com>"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); MODULE_DEVICE_TABLE(pci, pch_gbe_pcidev_id); diff --git a/drivers/net/pch_gbe/pch_gbe_param.c b/drivers/net/pch_gbe/pch_gbe_param.c index 2510146fc560..ef0996a0eaaa 100644 --- a/drivers/net/pch_gbe/pch_gbe_param.c +++ b/drivers/net/pch_gbe/pch_gbe_param.c @@ -434,8 +434,8 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter) .err = "using default of " __MODULE_STRING(PCH_GBE_DEFAULT_TXD), .def = PCH_GBE_DEFAULT_TXD, - .arg = { .r = { .min = PCH_GBE_MIN_TXD } }, - .arg = { .r = { .max = PCH_GBE_MAX_TXD } } + .arg = { .r = { .min = PCH_GBE_MIN_TXD, + .max = PCH_GBE_MAX_TXD } } }; struct pch_gbe_tx_ring *tx_ring = adapter->tx_ring; tx_ring->count = TxDescriptors; @@ -450,8 +450,8 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter) .err = "using default of " __MODULE_STRING(PCH_GBE_DEFAULT_RXD), .def = PCH_GBE_DEFAULT_RXD, - .arg = { .r = { .min = PCH_GBE_MIN_RXD } }, - .arg = { .r = { .max = PCH_GBE_MAX_RXD } } + .arg = { .r = { .min = PCH_GBE_MIN_RXD, + .max = PCH_GBE_MAX_RXD } } }; struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring; rx_ring->count = RxDescriptors; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index cb3d13e4e074..35fda5ac8120 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -64,7 +64,7 @@ config BCM63XX_PHY config ICPLUS_PHY tristate "Drivers for ICPlus PHYs" ---help--- - Currently supports the IP175C PHY. + Currently supports the IP175C and IP1001 PHYs. config REALTEK_PHY tristate "Drivers for Realtek PHYs" diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index c1d2d251fe8b..9a09e24c30bc 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -30,7 +30,7 @@ #include <asm/irq.h> #include <asm/uaccess.h> -MODULE_DESCRIPTION("ICPlus IP175C PHY driver"); +MODULE_DESCRIPTION("ICPlus IP175C/IC1001 PHY drivers"); MODULE_AUTHOR("Michael Barkowski"); MODULE_LICENSE("GPL"); @@ -89,6 +89,33 @@ static int ip175c_config_init(struct phy_device *phydev) return 0; } +static int ip1001_config_init(struct phy_device *phydev) +{ + int err, value; + + /* Software Reset PHY */ + value = phy_read(phydev, MII_BMCR); + value |= BMCR_RESET; + err = phy_write(phydev, MII_BMCR, value); + if (err < 0) + return err; + + do { + value = phy_read(phydev, MII_BMCR); + } while (value & BMCR_RESET); + + /* Additional delay (2ns) used to adjust RX clock phase + * at GMII/ RGMII interface */ + value = phy_read(phydev, 16); + value |= 0x3; + + err = phy_write(phydev, 16, value); + if (err < 0) + return err; + + return err; +} + static int ip175c_read_status(struct phy_device *phydev) { if (phydev->addr == 4) /* WAN port */ @@ -121,21 +148,43 @@ static struct phy_driver ip175c_driver = { .driver = { .owner = THIS_MODULE,}, }; -static int __init ip175c_init(void) +static struct phy_driver ip1001_driver = { + .phy_id = 0x02430d90, + .name = "ICPlus IP1001", + .phy_id_mask = 0x0ffffff0, + .features = PHY_GBIT_FEATURES | SUPPORTED_Pause | + SUPPORTED_Asym_Pause, + .config_init = &ip1001_config_init, + .config_aneg = &genphy_config_aneg, + .read_status = &genphy_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init icplus_init(void) { + int ret = 0; + + ret = phy_driver_register(&ip1001_driver); + if (ret < 0) + return -ENODEV; + return phy_driver_register(&ip175c_driver); } -static void __exit ip175c_exit(void) +static void __exit icplus_exit(void) { + phy_driver_unregister(&ip1001_driver); phy_driver_unregister(&ip175c_driver); } -module_init(ip175c_init); -module_exit(ip175c_exit); +module_init(icplus_init); +module_exit(icplus_exit); static struct mdio_device_id __maybe_unused icplus_tbl[] = { { 0x02430d80, 0x0ffffff0 }, + { 0x02430d90, 0x0ffffff0 }, { } }; diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index f0bd1a1aba3a..e8b9c53c304b 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -30,11 +30,14 @@ #include <linux/ethtool.h> #include <linux/phy.h> #include <linux/marvell_phy.h> +#include <linux/of.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/uaccess.h> +#define MII_MARVELL_PHY_PAGE 22 + #define MII_M1011_IEVENT 0x13 #define MII_M1011_IEVENT_CLEAR 0x0000 @@ -80,7 +83,6 @@ #define MII_88E1121_PHY_LED_CTRL 16 #define MII_88E1121_PHY_LED_PAGE 3 #define MII_88E1121_PHY_LED_DEF 0x0030 -#define MII_88E1121_PHY_PAGE 22 #define MII_M1011_PHY_STATUS 0x11 #define MII_M1011_PHY_STATUS_1000 0x8000 @@ -186,13 +188,94 @@ static int marvell_config_aneg(struct phy_device *phydev) return 0; } +#ifdef CONFIG_OF_MDIO +/* + * Set and/or override some configuration registers based on the + * marvell,reg-init property stored in the of_node for the phydev. + * + * marvell,reg-init = <reg-page reg mask value>,...; + * + * There may be one or more sets of <reg-page reg mask value>: + * + * reg-page: which register bank to use. + * reg: the register. + * mask: if non-zero, ANDed with existing register value. + * value: ORed with the masked value and written to the regiser. + * + */ +static int marvell_of_reg_init(struct phy_device *phydev) +{ + const __be32 *paddr; + int len, i, saved_page, current_page, page_changed, ret; + + if (!phydev->dev.of_node) + return 0; + + paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len); + if (!paddr || len < (4 * sizeof(*paddr))) + return 0; + + saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE); + if (saved_page < 0) + return saved_page; + page_changed = 0; + current_page = saved_page; + + ret = 0; + len /= sizeof(*paddr); + for (i = 0; i < len - 3; i += 4) { + u16 reg_page = be32_to_cpup(paddr + i); + u16 reg = be32_to_cpup(paddr + i + 1); + u16 mask = be32_to_cpup(paddr + i + 2); + u16 val_bits = be32_to_cpup(paddr + i + 3); + int val; + + if (reg_page != current_page) { + current_page = reg_page; + page_changed = 1; + ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page); + if (ret < 0) + goto err; + } + + val = 0; + if (mask) { + val = phy_read(phydev, reg); + if (val < 0) { + ret = val; + goto err; + } + val &= mask; + } + val |= val_bits; + + ret = phy_write(phydev, reg, val); + if (ret < 0) + goto err; + + } +err: + if (page_changed) { + i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page); + if (ret == 0) + ret = i; + } + return ret; +} +#else +static int marvell_of_reg_init(struct phy_device *phydev) +{ + return 0; +} +#endif /* CONFIG_OF_MDIO */ + static int m88e1121_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE); + oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - err = phy_write(phydev, MII_88E1121_PHY_PAGE, + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_MSCR_PAGE); if (err < 0) return err; @@ -218,7 +301,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev) return err; } - phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage); + phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); err = phy_write(phydev, MII_BMCR, BMCR_RESET); if (err < 0) @@ -229,11 +312,11 @@ static int m88e1121_config_aneg(struct phy_device *phydev) if (err < 0) return err; - oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE); + oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); + phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF); - phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage); + phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); err = genphy_config_aneg(phydev); @@ -244,9 +327,9 @@ static int m88e1318_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE); + oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - err = phy_write(phydev, MII_88E1121_PHY_PAGE, + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_MSCR_PAGE); if (err < 0) return err; @@ -258,7 +341,7 @@ static int m88e1318_config_aneg(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage); + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); if (err < 0) return err; @@ -368,6 +451,9 @@ static int m88e1111_config_init(struct phy_device *phydev) return err; } + err = marvell_of_reg_init(phydev); + if (err < 0) + return err; err = phy_write(phydev, MII_BMCR, BMCR_RESET); if (err < 0) @@ -398,7 +484,7 @@ static int m88e1118_config_init(struct phy_device *phydev) int err; /* Change address */ - err = phy_write(phydev, 0x16, 0x0002); + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); if (err < 0) return err; @@ -408,7 +494,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Change address */ - err = phy_write(phydev, 0x16, 0x0003); + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003); if (err < 0) return err; @@ -420,8 +506,42 @@ static int m88e1118_config_init(struct phy_device *phydev) if (err < 0) return err; + err = marvell_of_reg_init(phydev); + if (err < 0) + return err; + /* Reset address */ - err = phy_write(phydev, 0x16, 0x0); + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); + if (err < 0) + return err; + + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + + return 0; +} + +static int m88e1149_config_init(struct phy_device *phydev) +{ + int err; + + /* Change address */ + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); + if (err < 0) + return err; + + /* Enable 1000 Mbit */ + err = phy_write(phydev, 0x15, 0x1048); + if (err < 0) + return err; + + err = marvell_of_reg_init(phydev); + if (err < 0) + return err; + + /* Reset address */ + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); if (err < 0) return err; @@ -491,6 +611,10 @@ static int m88e1145_config_init(struct phy_device *phydev) } } + err = marvell_of_reg_init(phydev); + if (err < 0) + return err; + return 0; } @@ -685,6 +809,19 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { + .phy_id = MARVELL_PHY_ID_88E1149R, + .phy_id_mask = MARVELL_PHY_ID_MASK, + .name = "Marvell 88E1149R", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = &m88e1149_config_init, + .config_aneg = &m88e1118_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .driver = { .owner = THIS_MODULE }, + }, + { .phy_id = MARVELL_PHY_ID_88E1240, .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1240", @@ -735,6 +872,7 @@ static struct mdio_device_id __maybe_unused marvell_tbl[] = { { 0x01410e10, 0xfffffff0 }, { 0x01410cb0, 0xfffffff0 }, { 0x01410cd0, 0xfffffff0 }, + { 0x01410e50, 0xfffffff0 }, { 0x01410e30, 0xfffffff0 }, { 0x01410e90, 0xfffffff0 }, { } diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 09cf56d0416a..39659976a1ac 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -2584,16 +2584,16 @@ ppp_create_interface(struct net *net, int unit, int *retp) */ dev_net_set(dev, net); - ret = -EEXIST; mutex_lock(&pn->all_ppp_mutex); if (unit < 0) { unit = unit_get(&pn->units_idr, ppp); if (unit < 0) { - *retp = unit; + ret = unit; goto out2; } } else { + ret = -EEXIST; if (unit_find(&pn->units_idr, unit)) goto out2; /* unit already exists */ /* @@ -2668,10 +2668,10 @@ static void ppp_shutdown_interface(struct ppp *ppp) ppp->closing = 1; ppp_unlock(ppp); unregister_netdev(ppp->dev); + unit_put(&pn->units_idr, ppp->file.index); } else ppp_unlock(ppp); - unit_put(&pn->units_idr, ppp->file.index); ppp->file.dead = 1; ppp->owner = NULL; wake_up_interruptible(&ppp->file.rwait); @@ -2859,8 +2859,7 @@ static void __exit ppp_cleanup(void) * by holding all_ppp_mutex */ -/* associate pointer with specified number */ -static int unit_set(struct idr *p, void *ptr, int n) +static int __unit_alloc(struct idr *p, void *ptr, int n) { int unit, err; @@ -2871,10 +2870,24 @@ again: } err = idr_get_new_above(p, ptr, n, &unit); - if (err == -EAGAIN) - goto again; + if (err < 0) { + if (err == -EAGAIN) + goto again; + return err; + } + + return unit; +} + +/* associate pointer with specified number */ +static int unit_set(struct idr *p, void *ptr, int n) +{ + int unit; - if (unit != n) { + unit = __unit_alloc(p, ptr, n); + if (unit < 0) + return unit; + else if (unit != n) { idr_remove(p, unit); return -EINVAL; } @@ -2885,19 +2898,7 @@ again: /* get new free unit number and associate pointer with it */ static int unit_get(struct idr *p, void *ptr) { - int unit, err; - -again: - if (!idr_pre_get(p, GFP_KERNEL)) { - printk(KERN_ERR "PPP: No free memory for idr\n"); - return -ENOMEM; - } - - err = idr_get_new_above(p, ptr, 0, &unit); - if (err == -EAGAIN) - goto again; - - return unit; + return __unit_alloc(p, ptr, 0); } /* put unit number back to a pool */ diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index d72fb0519a2a..78c0e3c9b2b5 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -948,7 +948,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) abort: kfree_skb(skb); - return 0; + return 1; } /************************************************************************ diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 22821398fc63..9787dff90d3f 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -2083,6 +2083,7 @@ struct ql_adapter { u32 mailbox_in; u32 mailbox_out; struct mbox_params idc_mbc; + struct mutex mpi_mutex; int tx_ring_size; int rx_ring_size; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index c30e0fe55a31..2555b1d34f34 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -62,15 +62,15 @@ static const u32 default_msg = /* NETIF_MSG_PKTDATA | */ NETIF_MSG_HW | NETIF_MSG_WOL | 0; -static int debug = 0x00007fff; /* defaults above */ -module_param(debug, int, 0); +static int debug = -1; /* defaults above */ +module_param(debug, int, 0664); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); #define MSIX_IRQ 0 #define MSI_IRQ 1 #define LEG_IRQ 2 static int qlge_irq_type = MSIX_IRQ; -module_param(qlge_irq_type, int, MSIX_IRQ); +module_param(qlge_irq_type, int, 0664); MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy."); static int qlge_mpi_coredump; @@ -4629,6 +4629,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev, INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work); INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log); init_completion(&qdev->ide_completion); + mutex_init(&qdev->mpi_mutex); if (!cards_found) { dev_info(&pdev->dev, "%s\n", DRV_STRING); diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 0e7c7c7ee164..a2e919bcb3c6 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -534,6 +534,7 @@ static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp) int status; unsigned long count; + mutex_lock(&qdev->mpi_mutex); /* Begin polled mode for MPI */ ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16)); @@ -603,6 +604,7 @@ done: end: /* End polled mode for MPI */ ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI); + mutex_unlock(&qdev->mpi_mutex); return status; } @@ -1099,9 +1101,7 @@ int ql_wait_fifo_empty(struct ql_adapter *qdev) static int ql_set_port_cfg(struct ql_adapter *qdev) { int status; - rtnl_lock(); status = ql_mb_set_port_cfg(qdev); - rtnl_unlock(); if (status) return status; status = ql_idc_wait(qdev); @@ -1122,9 +1122,7 @@ void ql_mpi_port_cfg_work(struct work_struct *work) container_of(work, struct ql_adapter, mpi_port_cfg_work.work); int status; - rtnl_lock(); status = ql_mb_get_port_cfg(qdev); - rtnl_unlock(); if (status) { netif_err(qdev, drv, qdev->ndev, "Bug: Failed to get port config data.\n"); @@ -1167,7 +1165,6 @@ void ql_mpi_idc_work(struct work_struct *work) u32 aen; int timeout; - rtnl_lock(); aen = mbcp->mbox_out[1] >> 16; timeout = (mbcp->mbox_out[1] >> 8) & 0xf; @@ -1231,7 +1228,6 @@ void ql_mpi_idc_work(struct work_struct *work) } break; } - rtnl_unlock(); } void ql_mpi_work(struct work_struct *work) @@ -1242,7 +1238,7 @@ void ql_mpi_work(struct work_struct *work) struct mbox_params *mbcp = &mbc; int err = 0; - rtnl_lock(); + mutex_lock(&qdev->mpi_mutex); /* Begin polled mode for MPI */ ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16)); @@ -1259,7 +1255,7 @@ void ql_mpi_work(struct work_struct *work) /* End polled mode for MPI */ ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI); - rtnl_unlock(); + mutex_unlock(&qdev->mpi_mutex); ql_enable_completion_interrupt(qdev, 0); } diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 4c4d16905efb..53b13deade95 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -744,26 +744,36 @@ static void rtl8169_xmii_reset_enable(void __iomem *ioaddr) mdio_write(ioaddr, MII_BMCR, val & 0xffff); } -static void rtl8169_check_link_status(struct net_device *dev, +static void __rtl8169_check_link_status(struct net_device *dev, struct rtl8169_private *tp, - void __iomem *ioaddr) + void __iomem *ioaddr, + bool pm) { unsigned long flags; spin_lock_irqsave(&tp->lock, flags); if (tp->link_ok(ioaddr)) { /* This is to cancel a scheduled suspend if there's one. */ - pm_request_resume(&tp->pci_dev->dev); + if (pm) + pm_request_resume(&tp->pci_dev->dev); netif_carrier_on(dev); netif_info(tp, ifup, dev, "link up\n"); } else { netif_carrier_off(dev); netif_info(tp, ifdown, dev, "link down\n"); - pm_schedule_suspend(&tp->pci_dev->dev, 100); + if (pm) + pm_schedule_suspend(&tp->pci_dev->dev, 100); } spin_unlock_irqrestore(&tp->lock, flags); } +static void rtl8169_check_link_status(struct net_device *dev, + struct rtl8169_private *tp, + void __iomem *ioaddr) +{ + __rtl8169_check_link_status(dev, tp, ioaddr, false); +} + #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) static u32 __rtl8169_get_wol(struct rtl8169_private *tp) @@ -4440,8 +4450,7 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1) u32 status = opts1 & RxProtoMask; if (((status == RxProtoTCP) && !(opts1 & TCPFail)) || - ((status == RxProtoUDP) && !(opts1 & UDPFail)) || - ((status == RxProtoIP) && !(opts1 & IPFail))) + ((status == RxProtoUDP) && !(opts1 & UDPFail))) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); @@ -4601,7 +4610,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) } if (status & LinkChg) - rtl8169_check_link_status(dev, tp, ioaddr); + __rtl8169_check_link_status(dev, tp, ioaddr, true); /* We need to see the lastest version of tp->intr_mask to * avoid ignoring an MSI interrupt and having to wait for @@ -4891,11 +4900,7 @@ static int rtl8169_runtime_idle(struct device *device) struct net_device *dev = pci_get_drvdata(pdev); struct rtl8169_private *tp = netdev_priv(dev); - if (!tp->TxDescArray) - return 0; - - rtl8169_check_link_status(dev, tp, tp->mmio_addr); - return -EBUSY; + return tp->TxDescArray ? -EBUSY : 0; } static const struct dev_pm_ops rtl8169_pm_ops = { diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 05df20e47976..fb83cdd94643 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -197,7 +197,9 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value"); static void efx_remove_channels(struct efx_nic *efx); static void efx_remove_port(struct efx_nic *efx); +static void efx_init_napi(struct efx_nic *efx); static void efx_fini_napi(struct efx_nic *efx); +static void efx_fini_napi_channel(struct efx_channel *channel); static void efx_fini_struct(struct efx_nic *efx); static void efx_start_all(struct efx_nic *efx); static void efx_stop_all(struct efx_nic *efx); @@ -335,8 +337,10 @@ void efx_process_channel_now(struct efx_channel *channel) /* Disable interrupts and wait for ISRs to complete */ efx_nic_disable_interrupts(efx); - if (efx->legacy_irq) + if (efx->legacy_irq) { synchronize_irq(efx->legacy_irq); + efx->legacy_irq_enabled = false; + } if (channel->irq) synchronize_irq(channel->irq); @@ -351,6 +355,8 @@ void efx_process_channel_now(struct efx_channel *channel) efx_channel_processed(channel); napi_enable(&channel->napi_str); + if (efx->legacy_irq) + efx->legacy_irq_enabled = true; efx_nic_enable_interrupts(efx); } @@ -426,6 +432,7 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel) *channel = *old_channel; + channel->napi_dev = NULL; memset(&channel->eventq, 0, sizeof(channel->eventq)); rx_queue = &channel->rx_queue; @@ -736,9 +743,13 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) if (rc) goto rollback; + efx_init_napi(efx); + /* Destroy old channels */ - for (i = 0; i < efx->n_channels; i++) + for (i = 0; i < efx->n_channels; i++) { + efx_fini_napi_channel(other_channel[i]); efx_remove_channel(other_channel[i]); + } out: /* Free unused channel structures */ for (i = 0; i < efx->n_channels; i++) @@ -1400,6 +1411,8 @@ static void efx_start_all(struct efx_nic *efx) efx_start_channel(channel); } + if (efx->legacy_irq) + efx->legacy_irq_enabled = true; efx_nic_enable_interrupts(efx); /* Switch to event based MCDI completions after enabling interrupts. @@ -1460,8 +1473,10 @@ static void efx_stop_all(struct efx_nic *efx) /* Disable interrupts and wait for ISR to complete */ efx_nic_disable_interrupts(efx); - if (efx->legacy_irq) + if (efx->legacy_irq) { synchronize_irq(efx->legacy_irq); + efx->legacy_irq_enabled = false; + } efx_for_each_channel(channel, efx) { if (channel->irq) synchronize_irq(channel->irq); @@ -1593,7 +1608,7 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) * **************************************************************************/ -static int efx_init_napi(struct efx_nic *efx) +static void efx_init_napi(struct efx_nic *efx) { struct efx_channel *channel; @@ -1602,18 +1617,21 @@ static int efx_init_napi(struct efx_nic *efx) netif_napi_add(channel->napi_dev, &channel->napi_str, efx_poll, napi_weight); } - return 0; +} + +static void efx_fini_napi_channel(struct efx_channel *channel) +{ + if (channel->napi_dev) + netif_napi_del(&channel->napi_str); + channel->napi_dev = NULL; } static void efx_fini_napi(struct efx_nic *efx) { struct efx_channel *channel; - efx_for_each_channel(channel, efx) { - if (channel->napi_dev) - netif_napi_del(&channel->napi_str); - channel->napi_dev = NULL; - } + efx_for_each_channel(channel, efx) + efx_fini_napi_channel(channel); } /************************************************************************** @@ -2335,9 +2353,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) if (rc) goto fail1; - rc = efx_init_napi(efx); - if (rc) - goto fail2; + efx_init_napi(efx); rc = efx->type->init(efx); if (rc) { @@ -2368,7 +2384,6 @@ static int efx_pci_probe_main(struct efx_nic *efx) efx->type->fini(efx); fail3: efx_fini_napi(efx); - fail2: efx_remove_all(efx); fail1: return rc; diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 0a7e26d73b52..b137c889152b 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -621,6 +621,7 @@ struct efx_filter_state; * @pci_dev: The PCI device * @type: Controller type attributes * @legacy_irq: IRQ number + * @legacy_irq_enabled: Are IRQs enabled on NIC (INT_EN_KER register)? * @workqueue: Workqueue for port reconfigures and the HW monitor. * Work items do not hold and must not acquire RTNL. * @workqueue_name: Name of workqueue @@ -709,6 +710,7 @@ struct efx_nic { struct pci_dev *pci_dev; const struct efx_nic_type *type; int legacy_irq; + bool legacy_irq_enabled; struct workqueue_struct *workqueue; char workqueue_name[16]; struct work_struct reset_work; diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 41c36b9a4244..67cb0c96838c 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1418,6 +1418,12 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) u32 queues; int syserr; + /* Could this be ours? If interrupts are disabled then the + * channel state may not be valid. + */ + if (!efx->legacy_irq_enabled) + return result; + /* Read the ISR which also ACKs the interrupts */ efx_readd(efx, ®, FR_BZ_INT_ISR0); queues = EFX_EXTRACT_DWORD(reg, 0, 31); diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 06bc6034ce81..2114837809e7 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -1509,6 +1509,8 @@ static int stmmac_probe(struct net_device *dev) pr_warning("\tno valid MAC address;" "please, use ifconfig or nwhwconfig!\n"); + spin_lock_init(&priv->lock); + ret = register_netdev(dev); if (ret) { pr_err("%s: ERROR %i registering the device\n", @@ -1520,8 +1522,6 @@ static int stmmac_probe(struct net_device *dev) dev->name, (dev->features & NETIF_F_SG) ? "on" : "off", (dev->features & NETIF_F_HW_CSUM) ? "on" : "off"); - spin_lock_init(&priv->lock); - return ret; } diff --git a/drivers/net/tile/Makefile b/drivers/net/tile/Makefile new file mode 100644 index 000000000000..f634f142cab4 --- /dev/null +++ b/drivers/net/tile/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the TILE on-chip networking support. +# + +obj-$(CONFIG_TILE_NET) += tile_net.o +ifdef CONFIG_TILEGX +tile_net-objs := tilegx.o mpipe.o iorpc_mpipe.o dma_queue.o +else +tile_net-objs := tilepro.o +endif diff --git a/drivers/net/tile/tilepro.c b/drivers/net/tile/tilepro.c new file mode 100644 index 000000000000..0e6bac5ec65b --- /dev/null +++ b/drivers/net/tile/tilepro.c @@ -0,0 +1,2406 @@ +/* + * Copyright 2010 Tilera 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, version 2. + * + * 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. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/moduleparam.h> +#include <linux/sched.h> +#include <linux/kernel.h> /* printk() */ +#include <linux/slab.h> /* kmalloc() */ +#include <linux/errno.h> /* error codes */ +#include <linux/types.h> /* size_t */ +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/netdevice.h> /* struct device, and other headers */ +#include <linux/etherdevice.h> /* eth_type_trans */ +#include <linux/skbuff.h> +#include <linux/ioctl.h> +#include <linux/cdev.h> +#include <linux/hugetlb.h> +#include <linux/in6.h> +#include <linux/timer.h> +#include <linux/io.h> +#include <asm/checksum.h> +#include <asm/homecache.h> + +#include <hv/drv_xgbe_intf.h> +#include <hv/drv_xgbe_impl.h> +#include <hv/hypervisor.h> +#include <hv/netio_intf.h> + +/* For TSO */ +#include <linux/ip.h> +#include <linux/tcp.h> + + +/* There is no singlethread_cpu, so schedule work on the current cpu. */ +#define singlethread_cpu -1 + + +/* + * First, "tile_net_init_module()" initializes all four "devices" which + * can be used by linux. + * + * Then, "ifconfig DEVICE up" calls "tile_net_open()", which analyzes + * the network cpus, then uses "tile_net_open_aux()" to initialize + * LIPP/LEPP, and then uses "tile_net_open_inner()" to register all + * the tiles, provide buffers to LIPP, allow ingress to start, and + * turn on hypervisor interrupt handling (and NAPI) on all tiles. + * + * If registration fails due to the link being down, then "retry_work" + * is used to keep calling "tile_net_open_inner()" until it succeeds. + * + * If "ifconfig DEVICE down" is called, it uses "tile_net_stop()" to + * stop egress, drain the LIPP buffers, unregister all the tiles, stop + * LIPP/LEPP, and wipe the LEPP queue. + * + * We start out with the ingress interrupt enabled on each CPU. When + * this interrupt fires, we disable it, and call "napi_schedule()". + * This will cause "tile_net_poll()" to be called, which will pull + * packets from the netio queue, filtering them out, or passing them + * to "netif_receive_skb()". If our budget is exhausted, we will + * return, knowing we will be called again later. Otherwise, we + * reenable the ingress interrupt, and call "napi_complete()". + * + * + * NOTE: The use of "native_driver" ensures that EPP exists, and that + * "epp_sendv" is legal, and that "LIPP" is being used. + * + * NOTE: Failing to free completions for an arbitrarily long time + * (which is defined to be illegal) does in fact cause bizarre + * problems. The "egress_timer" helps prevent this from happening. + * + * NOTE: The egress code can be interrupted by the interrupt handler. + */ + + +/* HACK: Allow use of "jumbo" packets. */ +/* This should be 1500 if "jumbo" is not set in LIPP. */ +/* This should be at most 10226 (10240 - 14) if "jumbo" is set in LIPP. */ +/* ISSUE: This has not been thoroughly tested (except at 1500). */ +#define TILE_NET_MTU 1500 + +/* HACK: Define to support GSO. */ +/* ISSUE: This may actually hurt performance of the TCP blaster. */ +/* #define TILE_NET_GSO */ + +/* Define this to collapse "duplicate" acks. */ +/* #define IGNORE_DUP_ACKS */ + +/* HACK: Define this to verify incoming packets. */ +/* #define TILE_NET_VERIFY_INGRESS */ + +/* Use 3000 to enable the Linux Traffic Control (QoS) layer, else 0. */ +#define TILE_NET_TX_QUEUE_LEN 0 + +/* Define to dump packets (prints out the whole packet on tx and rx). */ +/* #define TILE_NET_DUMP_PACKETS */ + +/* Define to enable debug spew (all PDEBUG's are enabled). */ +/* #define TILE_NET_DEBUG */ + + +/* Define to activate paranoia checks. */ +/* #define TILE_NET_PARANOIA */ + +/* Default transmit lockup timeout period, in jiffies. */ +#define TILE_NET_TIMEOUT (5 * HZ) + +/* Default retry interval for bringing up the NetIO interface, in jiffies. */ +#define TILE_NET_RETRY_INTERVAL (5 * HZ) + +/* Number of ports (xgbe0, xgbe1, gbe0, gbe1). */ +#define TILE_NET_DEVS 4 + + + +/* Paranoia. */ +#if NET_IP_ALIGN != LIPP_PACKET_PADDING +#error "NET_IP_ALIGN must match LIPP_PACKET_PADDING." +#endif + + +/* Debug print. */ +#ifdef TILE_NET_DEBUG +#define PDEBUG(fmt, args...) net_printk(fmt, ## args) +#else +#define PDEBUG(fmt, args...) +#endif + + +MODULE_AUTHOR("Tilera"); +MODULE_LICENSE("GPL"); + + +#define IS_MULTICAST(mac_addr) \ + (((u8 *)(mac_addr))[0] & 0x01) + +#define IS_BROADCAST(mac_addr) \ + (((u16 *)(mac_addr))[0] == 0xffff) + + +/* + * Queue of incoming packets for a specific cpu and device. + * + * Includes a pointer to the "system" data, and the actual "user" data. + */ +struct tile_netio_queue { + netio_queue_impl_t *__system_part; + netio_queue_user_impl_t __user_part; + +}; + + +/* + * Statistics counters for a specific cpu and device. + */ +struct tile_net_stats_t { + u32 rx_packets; + u32 rx_bytes; + u32 tx_packets; + u32 tx_bytes; +}; + + +/* + * Info for a specific cpu and device. + * + * ISSUE: There is a "dev" pointer in "napi" as well. + */ +struct tile_net_cpu { + /* The NAPI struct. */ + struct napi_struct napi; + /* Packet queue. */ + struct tile_netio_queue queue; + /* Statistics. */ + struct tile_net_stats_t stats; + /* ISSUE: Is this needed? */ + bool napi_enabled; + /* True if this tile has succcessfully registered with the IPP. */ + bool registered; + /* True if the link was down last time we tried to register. */ + bool link_down; + /* True if "egress_timer" is scheduled. */ + bool egress_timer_scheduled; + /* Number of small sk_buffs which must still be provided. */ + unsigned int num_needed_small_buffers; + /* Number of large sk_buffs which must still be provided. */ + unsigned int num_needed_large_buffers; + /* A timer for handling egress completions. */ + struct timer_list egress_timer; +}; + + +/* + * Info for a specific device. + */ +struct tile_net_priv { + /* Our network device. */ + struct net_device *dev; + /* The actual egress queue. */ + lepp_queue_t *epp_queue; + /* Protects "epp_queue->cmd_tail" and "epp_queue->comp_tail" */ + spinlock_t cmd_lock; + /* Protects "epp_queue->comp_head". */ + spinlock_t comp_lock; + /* The hypervisor handle for this interface. */ + int hv_devhdl; + /* The intr bit mask that IDs this device. */ + u32 intr_id; + /* True iff "tile_net_open_aux()" has succeeded. */ + int partly_opened; + /* True iff "tile_net_open_inner()" has succeeded. */ + int fully_opened; + /* Effective network cpus. */ + struct cpumask network_cpus_map; + /* Number of network cpus. */ + int network_cpus_count; + /* Credits per network cpu. */ + int network_cpus_credits; + /* Network stats. */ + struct net_device_stats stats; + /* For NetIO bringup retries. */ + struct delayed_work retry_work; + /* Quick access to per cpu data. */ + struct tile_net_cpu *cpu[NR_CPUS]; +}; + + +/* + * The actual devices (xgbe0, xgbe1, gbe0, gbe1). + */ +static struct net_device *tile_net_devs[TILE_NET_DEVS]; + +/* + * The "tile_net_cpu" structures for each device. + */ +static DEFINE_PER_CPU(struct tile_net_cpu, hv_xgbe0); +static DEFINE_PER_CPU(struct tile_net_cpu, hv_xgbe1); +static DEFINE_PER_CPU(struct tile_net_cpu, hv_gbe0); +static DEFINE_PER_CPU(struct tile_net_cpu, hv_gbe1); + + +/* + * True if "network_cpus" was specified. + */ +static bool network_cpus_used; + +/* + * The actual cpus in "network_cpus". + */ +static struct cpumask network_cpus_map; + + + +#ifdef TILE_NET_DEBUG +/* + * printk with extra stuff. + * + * We print the CPU we're running in brackets. + */ +static void net_printk(char *fmt, ...) +{ + int i; + int len; + va_list args; + static char buf[256]; + + len = sprintf(buf, "tile_net[%2.2d]: ", smp_processor_id()); + va_start(args, fmt); + i = vscnprintf(buf + len, sizeof(buf) - len - 1, fmt, args); + va_end(args); + buf[255] = '\0'; + pr_notice(buf); +} +#endif + + +#ifdef TILE_NET_DUMP_PACKETS +/* + * Dump a packet. + */ +static void dump_packet(unsigned char *data, unsigned long length, char *s) +{ + unsigned long i; + static unsigned int count; + + pr_info("dump_packet(data %p, length 0x%lx s %s count 0x%x)\n", + data, length, s, count++); + + pr_info("\n"); + + for (i = 0; i < length; i++) { + if ((i & 0xf) == 0) + sprintf(buf, "%8.8lx:", i); + sprintf(buf + strlen(buf), " %2.2x", data[i]); + if ((i & 0xf) == 0xf || i == length - 1) + pr_info("%s\n", buf); + } +} +#endif + + +/* + * Provide support for the __netio_fastio1() swint + * (see <hv/drv_xgbe_intf.h> for how it is used). + * + * The fastio swint2 call may clobber all the caller-saved registers. + * It rarely clobbers memory, but we allow for the possibility in + * the signature just to be on the safe side. + * + * Also, gcc doesn't seem to allow an input operand to be + * clobbered, so we fake it with dummy outputs. + * + * This function can't be static because of the way it is declared + * in the netio header. + */ +inline int __netio_fastio1(u32 fastio_index, u32 arg0) +{ + long result, clobber_r1, clobber_r10; + asm volatile("swint2" + : "=R00" (result), + "=R01" (clobber_r1), "=R10" (clobber_r10) + : "R10" (fastio_index), "R01" (arg0) + : "memory", "r2", "r3", "r4", + "r5", "r6", "r7", "r8", "r9", + "r11", "r12", "r13", "r14", + "r15", "r16", "r17", "r18", "r19", + "r20", "r21", "r22", "r23", "r24", + "r25", "r26", "r27", "r28", "r29"); + return result; +} + + +/* + * Provide a linux buffer to LIPP. + */ +static void tile_net_provide_linux_buffer(struct tile_net_cpu *info, + void *va, bool small) +{ + struct tile_netio_queue *queue = &info->queue; + + /* Convert "va" and "small" to "linux_buffer_t". */ + unsigned int buffer = ((unsigned int)(__pa(va) >> 7) << 1) + small; + + __netio_fastio_free_buffer(queue->__user_part.__fastio_index, buffer); +} + + +/* + * Provide a linux buffer for LIPP. + */ +static bool tile_net_provide_needed_buffer(struct tile_net_cpu *info, + bool small) +{ + /* ISSUE: What should we use here? */ + unsigned int large_size = NET_IP_ALIGN + TILE_NET_MTU + 100; + + /* Round up to ensure to avoid "false sharing" with last cache line. */ + unsigned int buffer_size = + (((small ? LIPP_SMALL_PACKET_SIZE : large_size) + + CHIP_L2_LINE_SIZE() - 1) & -CHIP_L2_LINE_SIZE()); + + /* + * ISSUE: Since CPAs are 38 bits, and we can only encode the + * high 31 bits in a "linux_buffer_t", the low 7 bits must be + * zero, and thus, we must align the actual "va" mod 128. + */ + const unsigned long align = 128; + + struct sk_buff *skb; + void *va; + + struct sk_buff **skb_ptr; + + /* Note that "dev_alloc_skb()" adds NET_SKB_PAD more bytes, */ + /* and also "reserves" that many bytes. */ + /* ISSUE: Can we "share" the NET_SKB_PAD bytes with "skb_ptr"? */ + int len = sizeof(*skb_ptr) + align + buffer_size; + + while (1) { + + /* Allocate (or fail). */ + skb = dev_alloc_skb(len); + if (skb == NULL) + return false; + + /* Make room for a back-pointer to 'skb'. */ + skb_reserve(skb, sizeof(*skb_ptr)); + + /* Make sure we are aligned. */ + skb_reserve(skb, -(long)skb->data & (align - 1)); + + /* This address is given to IPP. */ + va = skb->data; + + if (small) + break; + + /* ISSUE: This has never been observed! */ + /* Large buffers must not span a huge page. */ + if (((((long)va & ~HPAGE_MASK) + 1535) & HPAGE_MASK) == 0) + break; + pr_err("Leaking unaligned linux buffer at %p.\n", va); + } + + /* Skip two bytes to satisfy LIPP assumptions. */ + /* Note that this aligns IP on a 16 byte boundary. */ + /* ISSUE: Do this when the packet arrives? */ + skb_reserve(skb, NET_IP_ALIGN); + + /* Save a back-pointer to 'skb'. */ + skb_ptr = va - sizeof(*skb_ptr); + *skb_ptr = skb; + + /* Invalidate the packet buffer. */ + if (!hash_default) + __inv_buffer(skb->data, buffer_size); + + /* Make sure "skb_ptr" has been flushed. */ + __insn_mf(); + +#ifdef TILE_NET_PARANOIA +#if CHIP_HAS_CBOX_HOME_MAP() + if (hash_default) { + HV_PTE pte = *virt_to_pte(current->mm, (unsigned long)va); + if (hv_pte_get_mode(pte) != HV_PTE_MODE_CACHE_HASH_L3) + panic("Non-coherent ingress buffer!"); + } +#endif +#endif + + /* Provide the new buffer. */ + tile_net_provide_linux_buffer(info, va, small); + + return true; +} + + +/* + * Provide linux buffers for LIPP. + */ +static void tile_net_provide_needed_buffers(struct tile_net_cpu *info) +{ + while (info->num_needed_small_buffers != 0) { + if (!tile_net_provide_needed_buffer(info, true)) + goto oops; + info->num_needed_small_buffers--; + } + + while (info->num_needed_large_buffers != 0) { + if (!tile_net_provide_needed_buffer(info, false)) + goto oops; + info->num_needed_large_buffers--; + } + + return; + +oops: + + /* Add a description to the page allocation failure dump. */ + pr_notice("Could not provide a linux buffer to LIPP.\n"); +} + + +/* + * Grab some LEPP completions, and store them in "comps", of size + * "comps_size", and return the number of completions which were + * stored, so the caller can free them. + * + * If "pending" is not NULL, it will be set to true if there might + * still be some pending completions caused by this tile, else false. + */ +static unsigned int tile_net_lepp_grab_comps(struct net_device *dev, + struct sk_buff *comps[], + unsigned int comps_size, + bool *pending) +{ + struct tile_net_priv *priv = netdev_priv(dev); + + lepp_queue_t *eq = priv->epp_queue; + + unsigned int n = 0; + + unsigned int comp_head; + unsigned int comp_busy; + unsigned int comp_tail; + + spin_lock(&priv->comp_lock); + + comp_head = eq->comp_head; + comp_busy = eq->comp_busy; + comp_tail = eq->comp_tail; + + while (comp_head != comp_busy && n < comps_size) { + comps[n++] = eq->comps[comp_head]; + LEPP_QINC(comp_head); + } + + if (pending != NULL) + *pending = (comp_head != comp_tail); + + eq->comp_head = comp_head; + + spin_unlock(&priv->comp_lock); + + return n; +} + + +/* + * Make sure the egress timer is scheduled. + * + * Note that we use "schedule if not scheduled" logic instead of the more + * obvious "reschedule" logic, because "reschedule" is fairly expensive. + */ +static void tile_net_schedule_egress_timer(struct tile_net_cpu *info) +{ + if (!info->egress_timer_scheduled) { + mod_timer_pinned(&info->egress_timer, jiffies + 1); + info->egress_timer_scheduled = true; + } +} + + +/* + * The "function" for "info->egress_timer". + * + * This timer will reschedule itself as long as there are any pending + * completions expected (on behalf of any tile). + * + * ISSUE: Realistically, will the timer ever stop scheduling itself? + * + * ISSUE: This timer is almost never actually needed, so just use a global + * timer that can run on any tile. + * + * ISSUE: Maybe instead track number of expected completions, and free + * only that many, resetting to zero if "pending" is ever false. + */ +static void tile_net_handle_egress_timer(unsigned long arg) +{ + struct tile_net_cpu *info = (struct tile_net_cpu *)arg; + struct net_device *dev = info->napi.dev; + + struct sk_buff *olds[32]; + unsigned int wanted = 32; + unsigned int i, nolds = 0; + bool pending; + + /* The timer is no longer scheduled. */ + info->egress_timer_scheduled = false; + + nolds = tile_net_lepp_grab_comps(dev, olds, wanted, &pending); + + for (i = 0; i < nolds; i++) + kfree_skb(olds[i]); + + /* Reschedule timer if needed. */ + if (pending) + tile_net_schedule_egress_timer(info); +} + + +#ifdef IGNORE_DUP_ACKS + +/* + * Help detect "duplicate" ACKs. These are sequential packets (for a + * given flow) which are exactly 66 bytes long, sharing everything but + * ID=2@0x12, Hsum=2@0x18, Ack=4@0x2a, WinSize=2@0x30, Csum=2@0x32, + * Tstamps=10@0x38. The ID's are +1, the Hsum's are -1, the Ack's are + * +N, and the Tstamps are usually identical. + * + * NOTE: Apparently truly duplicate acks (with identical "ack" values), + * should not be collapsed, as they are used for some kind of flow control. + */ +static bool is_dup_ack(char *s1, char *s2, unsigned int len) +{ + int i; + + unsigned long long ignorable = 0; + + /* Identification. */ + ignorable |= (1ULL << 0x12); + ignorable |= (1ULL << 0x13); + + /* Header checksum. */ + ignorable |= (1ULL << 0x18); + ignorable |= (1ULL << 0x19); + + /* ACK. */ + ignorable |= (1ULL << 0x2a); + ignorable |= (1ULL << 0x2b); + ignorable |= (1ULL << 0x2c); + ignorable |= (1ULL << 0x2d); + + /* WinSize. */ + ignorable |= (1ULL << 0x30); + ignorable |= (1ULL << 0x31); + + /* Checksum. */ + ignorable |= (1ULL << 0x32); + ignorable |= (1ULL << 0x33); + + for (i = 0; i < len; i++, ignorable >>= 1) { + + if ((ignorable & 1) || (s1[i] == s2[i])) + continue; + +#ifdef TILE_NET_DEBUG + /* HACK: Mention non-timestamp diffs. */ + if (i < 0x38 && i != 0x2f && + net_ratelimit()) + pr_info("Diff at 0x%x\n", i); +#endif + + return false; + } + +#ifdef TILE_NET_NO_SUPPRESS_DUP_ACKS + /* HACK: Do not suppress truly duplicate ACKs. */ + /* ISSUE: Is this actually necessary or helpful? */ + if (s1[0x2a] == s2[0x2a] && + s1[0x2b] == s2[0x2b] && + s1[0x2c] == s2[0x2c] && + s1[0x2d] == s2[0x2d]) { + return false; + } +#endif + + return true; +} + +#endif + + + +/* + * Like "tile_net_handle_packets()", but just discard packets. + */ +static void tile_net_discard_packets(struct net_device *dev) +{ + struct tile_net_priv *priv = netdev_priv(dev); + int my_cpu = smp_processor_id(); + struct tile_net_cpu *info = priv->cpu[my_cpu]; + struct tile_netio_queue *queue = &info->queue; + netio_queue_impl_t *qsp = queue->__system_part; + netio_queue_user_impl_t *qup = &queue->__user_part; + + while (qup->__packet_receive_read != + qsp->__packet_receive_queue.__packet_write) { + + int index = qup->__packet_receive_read; + + int index2_aux = index + sizeof(netio_pkt_t); + int index2 = + ((index2_aux == + qsp->__packet_receive_queue.__last_packet_plus_one) ? + 0 : index2_aux); + + netio_pkt_t *pkt = (netio_pkt_t *) + ((unsigned long) &qsp[1] + index); + + /* Extract the "linux_buffer_t". */ + unsigned int buffer = pkt->__packet.word; + + /* Convert "linux_buffer_t" to "va". */ + void *va = __va((phys_addr_t)(buffer >> 1) << 7); + + /* Acquire the associated "skb". */ + struct sk_buff **skb_ptr = va - sizeof(*skb_ptr); + struct sk_buff *skb = *skb_ptr; + + kfree_skb(skb); + + /* Consume this packet. */ + qup->__packet_receive_read = index2; + } +} + + +/* + * Handle the next packet. Return true if "processed", false if "filtered". + */ +static bool tile_net_poll_aux(struct tile_net_cpu *info, int index) +{ + struct net_device *dev = info->napi.dev; + + struct tile_netio_queue *queue = &info->queue; + netio_queue_impl_t *qsp = queue->__system_part; + netio_queue_user_impl_t *qup = &queue->__user_part; + struct tile_net_stats_t *stats = &info->stats; + + int filter; + + int index2_aux = index + sizeof(netio_pkt_t); + int index2 = + ((index2_aux == + qsp->__packet_receive_queue.__last_packet_plus_one) ? + 0 : index2_aux); + + netio_pkt_t *pkt = (netio_pkt_t *)((unsigned long) &qsp[1] + index); + + netio_pkt_metadata_t *metadata = NETIO_PKT_METADATA(pkt); + + /* Extract the packet size. */ + unsigned long len = + (NETIO_PKT_CUSTOM_LENGTH(pkt) + + NET_IP_ALIGN - NETIO_PACKET_PADDING); + + /* Extract the "linux_buffer_t". */ + unsigned int buffer = pkt->__packet.word; + + /* Extract "small" (vs "large"). */ + bool small = ((buffer & 1) != 0); + + /* Convert "linux_buffer_t" to "va". */ + void *va = __va((phys_addr_t)(buffer >> 1) << 7); + + /* Extract the packet data pointer. */ + /* Compare to "NETIO_PKT_CUSTOM_DATA(pkt)". */ + unsigned char *buf = va + NET_IP_ALIGN; + +#ifdef IGNORE_DUP_ACKS + + static int other; + static int final; + static int keep; + static int skip; + +#endif + + /* Invalidate the packet buffer. */ + if (!hash_default) + __inv_buffer(buf, len); + + /* ISSUE: Is this needed? */ + dev->last_rx = jiffies; + +#ifdef TILE_NET_DUMP_PACKETS + dump_packet(buf, len, "rx"); +#endif /* TILE_NET_DUMP_PACKETS */ + +#ifdef TILE_NET_VERIFY_INGRESS + if (!NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt) && + NETIO_PKT_L4_CSUM_CALCULATED_M(metadata, pkt)) { + /* + * FIXME: This complains about UDP packets + * with a "zero" checksum (bug 6624). + */ +#ifdef TILE_NET_PANIC_ON_BAD + dump_packet(buf, len, "rx"); + panic("Bad L4 checksum."); +#else + pr_warning("Bad L4 checksum on %d byte packet.\n", len); +#endif + } + if (!NETIO_PKT_L3_CSUM_CORRECT_M(metadata, pkt) && + NETIO_PKT_L3_CSUM_CALCULATED_M(metadata, pkt)) { + dump_packet(buf, len, "rx"); + panic("Bad L3 checksum."); + } + switch (NETIO_PKT_STATUS_M(metadata, pkt)) { + case NETIO_PKT_STATUS_OVERSIZE: + if (len >= 64) { + dump_packet(buf, len, "rx"); + panic("Unexpected OVERSIZE."); + } + break; + case NETIO_PKT_STATUS_BAD: +#ifdef TILE_NET_PANIC_ON_BAD + dump_packet(buf, len, "rx"); + panic("Unexpected BAD packet."); +#else + pr_warning("Unexpected BAD %d byte packet.\n", len); +#endif + } +#endif + + filter = 0; + + if (!(dev->flags & IFF_UP)) { + /* Filter packets received before we're up. */ + filter = 1; + } else if (!(dev->flags & IFF_PROMISC)) { + /* + * FIXME: Implement HW multicast filter. + */ + if (!IS_MULTICAST(buf) && !IS_BROADCAST(buf)) { + /* Filter packets not for our address. */ + const u8 *mine = dev->dev_addr; + filter = compare_ether_addr(mine, buf); + } + } + +#ifdef IGNORE_DUP_ACKS + + if (len != 66) { + /* FIXME: Must check "is_tcp_ack(buf, len)" somehow. */ + + other++; + + } else if (index2 == + qsp->__packet_receive_queue.__packet_write) { + + final++; + + } else { + + netio_pkt_t *pkt2 = (netio_pkt_t *) + ((unsigned long) &qsp[1] + index2); + + netio_pkt_metadata_t *metadata2 = + NETIO_PKT_METADATA(pkt2); + + /* Extract the packet size. */ + unsigned long len2 = + (NETIO_PKT_CUSTOM_LENGTH(pkt2) + + NET_IP_ALIGN - NETIO_PACKET_PADDING); + + if (len2 == 66 && + NETIO_PKT_FLOW_HASH_M(metadata, pkt) == + NETIO_PKT_FLOW_HASH_M(metadata2, pkt2)) { + + /* Extract the "linux_buffer_t". */ + unsigned int buffer2 = pkt2->__packet.word; + + /* Convert "linux_buffer_t" to "va". */ + void *va2 = + __va((phys_addr_t)(buffer2 >> 1) << 7); + + /* Extract the packet data pointer. */ + /* Compare to "NETIO_PKT_CUSTOM_DATA(pkt)". */ + unsigned char *buf2 = va2 + NET_IP_ALIGN; + + /* Invalidate the packet buffer. */ + if (!hash_default) + __inv_buffer(buf2, len2); + + if (is_dup_ack(buf, buf2, len)) { + skip++; + filter = 1; + } else { + keep++; + } + } + } + + if (net_ratelimit()) + pr_info("Other %d Final %d Keep %d Skip %d.\n", + other, final, keep, skip); + +#endif + + if (filter) { + + /* ISSUE: Update "drop" statistics? */ + + tile_net_provide_linux_buffer(info, va, small); + + } else { + + /* Acquire the associated "skb". */ + struct sk_buff **skb_ptr = va - sizeof(*skb_ptr); + struct sk_buff *skb = *skb_ptr; + + /* Paranoia. */ + if (skb->data != buf) + panic("Corrupt linux buffer from LIPP! " + "VA=%p, skb=%p, skb->data=%p\n", + va, skb, skb->data); + + /* Encode the actual packet length. */ + skb_put(skb, len); + + /* NOTE: This call also sets "skb->dev = dev". */ + skb->protocol = eth_type_trans(skb, dev); + + /* ISSUE: Discard corrupt packets? */ + /* ISSUE: Discard packets with bad checksums? */ + + /* Avoid recomputing TCP/UDP checksums. */ + if (NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + netif_receive_skb(skb); + + stats->rx_packets++; + stats->rx_bytes += len; + + if (small) + info->num_needed_small_buffers++; + else + info->num_needed_large_buffers++; + } + + /* Return four credits after every fourth packet. */ + if (--qup->__receive_credit_remaining == 0) { + u32 interval = qup->__receive_credit_interval; + qup->__receive_credit_remaining = interval; + __netio_fastio_return_credits(qup->__fastio_index, interval); + } + + /* Consume this packet. */ + qup->__packet_receive_read = index2; + + return !filter; +} + + +/* + * Handle some packets for the given device on the current CPU. + * + * ISSUE: The "rotting packet" race condition occurs if a packet + * arrives after the queue appears to be empty, and before the + * hypervisor interrupt is re-enabled. + */ +static int tile_net_poll(struct napi_struct *napi, int budget) +{ + struct net_device *dev = napi->dev; + struct tile_net_priv *priv = netdev_priv(dev); + int my_cpu = smp_processor_id(); + struct tile_net_cpu *info = priv->cpu[my_cpu]; + struct tile_netio_queue *queue = &info->queue; + netio_queue_impl_t *qsp = queue->__system_part; + netio_queue_user_impl_t *qup = &queue->__user_part; + + unsigned int work = 0; + + while (1) { + int index = qup->__packet_receive_read; + if (index == qsp->__packet_receive_queue.__packet_write) + break; + + if (tile_net_poll_aux(info, index)) { + if (++work >= budget) + goto done; + } + } + + napi_complete(&info->napi); + + /* Re-enable hypervisor interrupts. */ + enable_percpu_irq(priv->intr_id); + + /* HACK: Avoid the "rotting packet" problem. */ + if (qup->__packet_receive_read != + qsp->__packet_receive_queue.__packet_write) + napi_schedule(&info->napi); + + /* ISSUE: Handle completions? */ + +done: + + tile_net_provide_needed_buffers(info); + + return work; +} + + +/* + * Handle an ingress interrupt for the given device on the current cpu. + */ +static irqreturn_t tile_net_handle_ingress_interrupt(int irq, void *dev_ptr) +{ + struct net_device *dev = (struct net_device *)dev_ptr; + struct tile_net_priv *priv = netdev_priv(dev); + int my_cpu = smp_processor_id(); + struct tile_net_cpu *info = priv->cpu[my_cpu]; + + /* Disable hypervisor interrupt. */ + disable_percpu_irq(priv->intr_id); + + napi_schedule(&info->napi); + + return IRQ_HANDLED; +} + + +/* + * One time initialization per interface. + */ +static int tile_net_open_aux(struct net_device *dev) +{ + struct tile_net_priv *priv = netdev_priv(dev); + + int ret; + int dummy; + unsigned int epp_lotar; + + /* + * Find out where EPP memory should be homed. + */ + ret = hv_dev_pread(priv->hv_devhdl, 0, + (HV_VirtAddr)&epp_lotar, sizeof(epp_lotar), + NETIO_EPP_SHM_OFF); + if (ret < 0) { + pr_err("could not read epp_shm_queue lotar.\n"); + return -EIO; + } + + /* + * Home the page on the EPP. + */ + { + int epp_home = hv_lotar_to_cpu(epp_lotar); + struct page *page = virt_to_page(priv->epp_queue); + homecache_change_page_home(page, 0, epp_home); + } + + /* + * Register the EPP shared memory queue. + */ + { + netio_ipp_address_t ea = { + .va = 0, + .pa = __pa(priv->epp_queue), + .pte = hv_pte(0), + .size = PAGE_SIZE, + }; + ea.pte = hv_pte_set_lotar(ea.pte, epp_lotar); + ea.pte = hv_pte_set_mode(ea.pte, HV_PTE_MODE_CACHE_TILE_L3); + ret = hv_dev_pwrite(priv->hv_devhdl, 0, + (HV_VirtAddr)&ea, + sizeof(ea), + NETIO_EPP_SHM_OFF); + if (ret < 0) + return -EIO; + } + + /* + * Start LIPP/LEPP. + */ + if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy, + sizeof(dummy), NETIO_IPP_START_SHIM_OFF) < 0) { + pr_warning("Failed to start LIPP/LEPP.\n"); + return -EIO; + } + + return 0; +} + + +/* + * Register with hypervisor on each CPU. + * + * Strangely, this function does important things even if it "fails", + * which is especially common if the link is not up yet. Hopefully + * these things are all "harmless" if done twice! + */ +static void tile_net_register(void *dev_ptr) +{ + struct net_device *dev = (struct net_device *)dev_ptr; + struct tile_net_priv *priv = netdev_priv(dev); + int my_cpu = smp_processor_id(); + struct tile_net_cpu *info; + + struct tile_netio_queue *queue; + + /* Only network cpus can receive packets. */ + int queue_id = + cpumask_test_cpu(my_cpu, &priv->network_cpus_map) ? 0 : 255; + + netio_input_config_t config = { + .flags = 0, + .num_receive_packets = priv->network_cpus_credits, + .queue_id = queue_id + }; + + int ret = 0; + netio_queue_impl_t *queuep; + + PDEBUG("tile_net_register(queue_id %d)\n", queue_id); + + if (!strcmp(dev->name, "xgbe0")) + info = &__get_cpu_var(hv_xgbe0); + else if (!strcmp(dev->name, "xgbe1")) + info = &__get_cpu_var(hv_xgbe1); + else if (!strcmp(dev->name, "gbe0")) + info = &__get_cpu_var(hv_gbe0); + else if (!strcmp(dev->name, "gbe1")) + info = &__get_cpu_var(hv_gbe1); + else + BUG(); + + /* Initialize the egress timer. */ + init_timer(&info->egress_timer); + info->egress_timer.data = (long)info; + info->egress_timer.function = tile_net_handle_egress_timer; + + priv->cpu[my_cpu] = info; + + /* + * Register ourselves with the IPP. + */ + ret = hv_dev_pwrite(priv->hv_devhdl, 0, + (HV_VirtAddr)&config, + sizeof(netio_input_config_t), + NETIO_IPP_INPUT_REGISTER_OFF); + PDEBUG("hv_dev_pwrite(NETIO_IPP_INPUT_REGISTER_OFF) returned %d\n", + ret); + if (ret < 0) { + printk(KERN_DEBUG "hv_dev_pwrite NETIO_IPP_INPUT_REGISTER_OFF" + " failure %d\n", ret); + info->link_down = (ret == NETIO_LINK_DOWN); + return; + } + + /* + * Get the pointer to our queue's system part. + */ + + ret = hv_dev_pread(priv->hv_devhdl, 0, + (HV_VirtAddr)&queuep, + sizeof(netio_queue_impl_t *), + NETIO_IPP_INPUT_REGISTER_OFF); + PDEBUG("hv_dev_pread(NETIO_IPP_INPUT_REGISTER_OFF) returned %d\n", + ret); + PDEBUG("queuep %p\n", queuep); + if (ret <= 0) { + /* ISSUE: Shouldn't this be a fatal error? */ + pr_err("hv_dev_pread NETIO_IPP_INPUT_REGISTER_OFF failure\n"); + return; + } + + queue = &info->queue; + + queue->__system_part = queuep; + + memset(&queue->__user_part, 0, sizeof(netio_queue_user_impl_t)); + + /* This is traditionally "config.num_receive_packets / 2". */ + queue->__user_part.__receive_credit_interval = 4; + queue->__user_part.__receive_credit_remaining = + queue->__user_part.__receive_credit_interval; + + /* + * Get a fastio index from the hypervisor. + * ISSUE: Shouldn't this check the result? + */ + ret = hv_dev_pread(priv->hv_devhdl, 0, + (HV_VirtAddr)&queue->__user_part.__fastio_index, + sizeof(queue->__user_part.__fastio_index), + NETIO_IPP_GET_FASTIO_OFF); + PDEBUG("hv_dev_pread(NETIO_IPP_GET_FASTIO_OFF) returned %d\n", ret); + + netif_napi_add(dev, &info->napi, tile_net_poll, 64); + + /* Now we are registered. */ + info->registered = true; +} + + +/* + * Unregister with hypervisor on each CPU. + */ +static void tile_net_unregister(void *dev_ptr) +{ + struct net_device *dev = (struct net_device *)dev_ptr; + struct tile_net_priv *priv = netdev_priv(dev); + int my_cpu = smp_processor_id(); + struct tile_net_cpu *info = priv->cpu[my_cpu]; + + int ret = 0; + int dummy = 0; + + /* Do nothing if never registered. */ + if (info == NULL) + return; + + /* Do nothing if already unregistered. */ + if (!info->registered) + return; + + /* + * Unregister ourselves with LIPP. + */ + ret = hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy, + sizeof(dummy), NETIO_IPP_INPUT_UNREGISTER_OFF); + PDEBUG("hv_dev_pwrite(NETIO_IPP_INPUT_UNREGISTER_OFF) returned %d\n", + ret); + if (ret < 0) { + /* FIXME: Just panic? */ + pr_err("hv_dev_pwrite NETIO_IPP_INPUT_UNREGISTER_OFF" + " failure %d\n", ret); + } + + /* + * Discard all packets still in our NetIO queue. Hopefully, + * once the unregister call is complete, there will be no + * packets still in flight on the IDN. + */ + tile_net_discard_packets(dev); + + /* Reset state. */ + info->num_needed_small_buffers = 0; + info->num_needed_large_buffers = 0; + + /* Cancel egress timer. */ + del_timer(&info->egress_timer); + info->egress_timer_scheduled = false; + + netif_napi_del(&info->napi); + + /* Now we are unregistered. */ + info->registered = false; +} + + +/* + * Helper function for "tile_net_stop()". + * + * Also used to handle registration failure in "tile_net_open_inner()", + * when "fully_opened" is known to be false, and the various extra + * steps in "tile_net_stop()" are not necessary. ISSUE: It might be + * simpler if we could just call "tile_net_stop()" anyway. + */ +static void tile_net_stop_aux(struct net_device *dev) +{ + struct tile_net_priv *priv = netdev_priv(dev); + + int dummy = 0; + + /* Unregister all tiles, so LIPP will stop delivering packets. */ + on_each_cpu(tile_net_unregister, (void *)dev, 1); + + /* Stop LIPP/LEPP. */ + if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy, + sizeof(dummy), NETIO_IPP_STOP_SHIM_OFF) < 0) + panic("Failed to stop LIPP/LEPP!\n"); + + priv->partly_opened = 0; +} + + +/* + * Disable ingress interrupts for the given device on the current cpu. + */ +static void tile_net_disable_intr(void *dev_ptr) +{ + struct net_device *dev = (struct net_device *)dev_ptr; + struct tile_net_priv *priv = netdev_priv(dev); + int my_cpu = smp_processor_id(); + struct tile_net_cpu *info = priv->cpu[my_cpu]; + + /* Disable hypervisor interrupt. */ + disable_percpu_irq(priv->intr_id); + + /* Disable NAPI if needed. */ + if (info != NULL && info->napi_enabled) { + napi_disable(&info->napi); + info->napi_enabled = false; + } +} + + +/* + * Enable ingress interrupts for the given device on the current cpu. + */ +static void tile_net_enable_intr(void *dev_ptr) +{ + struct net_device *dev = (struct net_device *)dev_ptr; + struct tile_net_priv *priv = netdev_priv(dev); + int my_cpu = smp_processor_id(); + struct tile_net_cpu *info = priv->cpu[my_cpu]; + + /* Enable hypervisor interrupt. */ + enable_percpu_irq(priv->intr_id); + + /* Enable NAPI. */ + napi_enable(&info->napi); + info->napi_enabled = true; +} + + +/* + * tile_net_open_inner does most of the work of bringing up the interface. + * It's called from tile_net_open(), and also from tile_net_retry_open(). + * The return value is 0 if the interface was brought up, < 0 if + * tile_net_open() should return the return value as an error, and > 0 if + * tile_net_open() should return success and schedule a work item to + * periodically retry the bringup. + */ +static int tile_net_open_inner(struct net_device *dev) +{ + struct tile_net_priv *priv = netdev_priv(dev); + int my_cpu = smp_processor_id(); + struct tile_net_cpu *info; + struct tile_netio_queue *queue; + unsigned int irq; + int i; + + /* + * First try to register just on the local CPU, and handle any + * semi-expected "link down" failure specially. Note that we + * do NOT call "tile_net_stop_aux()", unlike below. + */ + tile_net_register(dev); + info = priv->cpu[my_cpu]; + if (!info->registered) { + if (info->link_down) + return 1; + return -EAGAIN; + } + + /* + * Now register everywhere else. If any registration fails, + * even for "link down" (which might not be possible), we + * clean up using "tile_net_stop_aux()". + */ + smp_call_function(tile_net_register, (void *)dev, 1); + for_each_online_cpu(i) { + if (!priv->cpu[i]->registered) { + tile_net_stop_aux(dev); + return -EAGAIN; + } + } + + queue = &info->queue; + + /* + * Set the device intr bit mask. + * The tile_net_register above sets per tile __intr_id. + */ + priv->intr_id = queue->__system_part->__intr_id; + BUG_ON(!priv->intr_id); + + /* + * Register the device interrupt handler. + * The __ffs() function returns the index into the interrupt handler + * table from the interrupt bit mask which should have one bit + * and one bit only set. + */ + irq = __ffs(priv->intr_id); + tile_irq_activate(irq, TILE_IRQ_PERCPU); + BUG_ON(request_irq(irq, tile_net_handle_ingress_interrupt, + 0, dev->name, (void *)dev) != 0); + + /* ISSUE: How could "priv->fully_opened" ever be "true" here? */ + + if (!priv->fully_opened) { + + int dummy = 0; + + /* Allocate initial buffers. */ + + int max_buffers = + priv->network_cpus_count * priv->network_cpus_credits; + + info->num_needed_small_buffers = + min(LIPP_SMALL_BUFFERS, max_buffers); + + info->num_needed_large_buffers = + min(LIPP_LARGE_BUFFERS, max_buffers); + + tile_net_provide_needed_buffers(info); + + if (info->num_needed_small_buffers != 0 || + info->num_needed_large_buffers != 0) + panic("Insufficient memory for buffer stack!"); + + /* Start LIPP/LEPP and activate "ingress" at the shim. */ + if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy, + sizeof(dummy), NETIO_IPP_INPUT_INIT_OFF) < 0) + panic("Failed to activate the LIPP Shim!\n"); + + priv->fully_opened = 1; + } + + /* On each tile, enable the hypervisor to trigger interrupts. */ + /* ISSUE: Do this before starting LIPP/LEPP? */ + on_each_cpu(tile_net_enable_intr, (void *)dev, 1); + + /* Start our transmit queue. */ + netif_start_queue(dev); + + return 0; +} + + +/* + * Called periodically to retry bringing up the NetIO interface, + * if it doesn't come up cleanly during tile_net_open(). + */ +static void tile_net_open_retry(struct work_struct *w) +{ + struct delayed_work *dw = + container_of(w, struct delayed_work, work); + + struct tile_net_priv *priv = + container_of(dw, struct tile_net_priv, retry_work); + + /* + * Try to bring the NetIO interface up. If it fails, reschedule + * ourselves to try again later; otherwise, tell Linux we now have + * a working link. ISSUE: What if the return value is negative? + */ + if (tile_net_open_inner(priv->dev)) + schedule_delayed_work_on(singlethread_cpu, &priv->retry_work, + TILE_NET_RETRY_INTERVAL); + else + netif_carrier_on(priv->dev); +} + + +/* + * Called when a network interface is made active. + * + * Returns 0 on success, negative value on failure. + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + * + * If the actual link is not available yet, then we tell Linux that + * we have no carrier, and we keep checking until the link comes up. + */ +static int tile_net_open(struct net_device *dev) +{ + int ret = 0; + struct tile_net_priv *priv = netdev_priv(dev); + + /* + * We rely on priv->partly_opened to tell us if this is the + * first time this interface is being brought up. If it is + * set, the IPP was already initialized and should not be + * initialized again. + */ + if (!priv->partly_opened) { + + int count; + int credits; + + /* Initialize LIPP/LEPP, and start the Shim. */ + ret = tile_net_open_aux(dev); + if (ret < 0) { + pr_err("tile_net_open_aux failed: %d\n", ret); + return ret; + } + + /* Analyze the network cpus. */ + + if (network_cpus_used) + cpumask_copy(&priv->network_cpus_map, + &network_cpus_map); + else + cpumask_copy(&priv->network_cpus_map, cpu_online_mask); + + + count = cpumask_weight(&priv->network_cpus_map); + + /* Limit credits to available buffers, and apply min. */ + credits = max(16, (LIPP_LARGE_BUFFERS / count) & ~1); + + /* Apply "GBE" max limit. */ + /* ISSUE: Use higher limit for XGBE? */ + credits = min(NETIO_MAX_RECEIVE_PKTS, credits); + + priv->network_cpus_count = count; + priv->network_cpus_credits = credits; + +#ifdef TILE_NET_DEBUG + pr_info("Using %d network cpus, with %d credits each\n", + priv->network_cpus_count, priv->network_cpus_credits); +#endif + + priv->partly_opened = 1; + } + + /* + * Attempt to bring up the link. + */ + ret = tile_net_open_inner(dev); + if (ret <= 0) { + if (ret == 0) + netif_carrier_on(dev); + return ret; + } + + /* + * We were unable to bring up the NetIO interface, but we want to + * try again in a little bit. Tell Linux that we have no carrier + * so it doesn't try to use the interface before the link comes up + * and then remember to try again later. + */ + netif_carrier_off(dev); + schedule_delayed_work_on(singlethread_cpu, &priv->retry_work, + TILE_NET_RETRY_INTERVAL); + + return 0; +} + + +/* + * Disables a network interface. + * + * Returns 0, this is not allowed to fail. + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + * + * ISSUE: Can this can be called while "tile_net_poll()" is running? + */ +static int tile_net_stop(struct net_device *dev) +{ + struct tile_net_priv *priv = netdev_priv(dev); + + bool pending = true; + + PDEBUG("tile_net_stop()\n"); + + /* ISSUE: Only needed if not yet fully open. */ + cancel_delayed_work_sync(&priv->retry_work); + + /* Can't transmit any more. */ + netif_stop_queue(dev); + + /* + * Disable hypervisor interrupts on each tile. + */ + on_each_cpu(tile_net_disable_intr, (void *)dev, 1); + + /* + * Unregister the interrupt handler. + * The __ffs() function returns the index into the interrupt handler + * table from the interrupt bit mask which should have one bit + * and one bit only set. + */ + if (priv->intr_id) + free_irq(__ffs(priv->intr_id), dev); + + /* + * Drain all the LIPP buffers. + */ + + while (true) { + int buffer; + + /* NOTE: This should never fail. */ + if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&buffer, + sizeof(buffer), NETIO_IPP_DRAIN_OFF) < 0) + break; + + /* Stop when done. */ + if (buffer == 0) + break; + + { + /* Convert "linux_buffer_t" to "va". */ + void *va = __va((phys_addr_t)(buffer >> 1) << 7); + + /* Acquire the associated "skb". */ + struct sk_buff **skb_ptr = va - sizeof(*skb_ptr); + struct sk_buff *skb = *skb_ptr; + + kfree_skb(skb); + } + } + + /* Stop LIPP/LEPP. */ + tile_net_stop_aux(dev); + + + priv->fully_opened = 0; + + + /* + * XXX: ISSUE: It appears that, in practice anyway, by the + * time we get here, there are no pending completions. + */ + while (pending) { + + struct sk_buff *olds[32]; + unsigned int wanted = 32; + unsigned int i, nolds = 0; + + nolds = tile_net_lepp_grab_comps(dev, olds, + wanted, &pending); + + /* ISSUE: We have never actually seen this debug spew. */ + if (nolds != 0) + pr_info("During tile_net_stop(), grabbed %d comps.\n", + nolds); + + for (i = 0; i < nolds; i++) + kfree_skb(olds[i]); + } + + + /* Wipe the EPP queue. */ + memset(priv->epp_queue, 0, sizeof(lepp_queue_t)); + + /* Evict the EPP queue. */ + finv_buffer(priv->epp_queue, PAGE_SIZE); + + return 0; +} + + +/* + * Prepare the "frags" info for the resulting LEPP command. + * + * If needed, flush the memory used by the frags. + */ +static unsigned int tile_net_tx_frags(lepp_frag_t *frags, + struct sk_buff *skb, + void *b_data, unsigned int b_len) +{ + unsigned int i, n = 0; + + struct skb_shared_info *sh = skb_shinfo(skb); + + phys_addr_t cpa; + + if (b_len != 0) { + + if (!hash_default) + finv_buffer_remote(b_data, b_len); + + cpa = __pa(b_data); + frags[n].cpa_lo = cpa; + frags[n].cpa_hi = cpa >> 32; + frags[n].length = b_len; + frags[n].hash_for_home = hash_default; + n++; + } + + for (i = 0; i < sh->nr_frags; i++) { + + skb_frag_t *f = &sh->frags[i]; + unsigned long pfn = page_to_pfn(f->page); + + /* FIXME: Compute "hash_for_home" properly. */ + /* ISSUE: The hypervisor checks CHIP_HAS_REV1_DMA_PACKETS(). */ + int hash_for_home = hash_default; + + /* FIXME: Hmmm. */ + if (!hash_default) { + void *va = pfn_to_kaddr(pfn) + f->page_offset; + BUG_ON(PageHighMem(f->page)); + finv_buffer_remote(va, f->size); + } + + cpa = ((phys_addr_t)pfn << PAGE_SHIFT) + f->page_offset; + frags[n].cpa_lo = cpa; + frags[n].cpa_hi = cpa >> 32; + frags[n].length = f->size; + frags[n].hash_for_home = hash_for_home; + n++; + } + + return n; +} + + +/* + * This function takes "skb", consisting of a header template and a + * payload, and hands it to LEPP, to emit as one or more segments, + * each consisting of a possibly modified header, plus a piece of the + * payload, via a process known as "tcp segmentation offload". + * + * Usually, "data" will contain the header template, of size "sh_len", + * and "sh->frags" will contain "skb->data_len" bytes of payload, and + * there will be "sh->gso_segs" segments. + * + * Sometimes, if "sendfile()" requires copying, we will be called with + * "data" containing the header and payload, with "frags" being empty. + * + * In theory, "sh->nr_frags" could be 3, but in practice, it seems + * that this will never actually happen. + * + * See "emulate_large_send_offload()" for some reference code, which + * does not handle checksumming. + * + * ISSUE: How do we make sure that high memory DMA does not migrate? + */ +static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev) +{ + struct tile_net_priv *priv = netdev_priv(dev); + int my_cpu = smp_processor_id(); + struct tile_net_cpu *info = priv->cpu[my_cpu]; + struct tile_net_stats_t *stats = &info->stats; + + struct skb_shared_info *sh = skb_shinfo(skb); + + unsigned char *data = skb->data; + + /* The ip header follows the ethernet header. */ + struct iphdr *ih = ip_hdr(skb); + unsigned int ih_len = ih->ihl * 4; + + /* Note that "nh == ih", by definition. */ + unsigned char *nh = skb_network_header(skb); + unsigned int eh_len = nh - data; + + /* The tcp header follows the ip header. */ + struct tcphdr *th = (struct tcphdr *)(nh + ih_len); + unsigned int th_len = th->doff * 4; + + /* The total number of header bytes. */ + /* NOTE: This may be less than skb_headlen(skb). */ + unsigned int sh_len = eh_len + ih_len + th_len; + + /* The number of payload bytes at "skb->data + sh_len". */ + /* This is non-zero for sendfile() without HIGHDMA. */ + unsigned int b_len = skb_headlen(skb) - sh_len; + + /* The total number of payload bytes. */ + unsigned int d_len = b_len + skb->data_len; + + /* The maximum payload size. */ + unsigned int p_len = sh->gso_size; + + /* The total number of segments. */ + unsigned int num_segs = sh->gso_segs; + + /* The temporary copy of the command. */ + u32 cmd_body[(LEPP_MAX_CMD_SIZE + 3) / 4]; + lepp_tso_cmd_t *cmd = (lepp_tso_cmd_t *)cmd_body; + + /* Analyze the "frags". */ + unsigned int num_frags = + tile_net_tx_frags(cmd->frags, skb, data + sh_len, b_len); + + /* The size of the command, including frags and header. */ + size_t cmd_size = LEPP_TSO_CMD_SIZE(num_frags, sh_len); + + /* The command header. */ + lepp_tso_cmd_t cmd_init = { + .tso = true, + .header_size = sh_len, + .ip_offset = eh_len, + .tcp_offset = eh_len + ih_len, + .payload_size = p_len, + .num_frags = num_frags, + }; + + unsigned long irqflags; + + lepp_queue_t *eq = priv->epp_queue; + + struct sk_buff *olds[4]; + unsigned int wanted = 4; + unsigned int i, nolds = 0; + + unsigned int cmd_head, cmd_tail, cmd_next; + unsigned int comp_tail; + + unsigned int free_slots; + + + /* Paranoia. */ + BUG_ON(skb->protocol != htons(ETH_P_IP)); + BUG_ON(ih->protocol != IPPROTO_TCP); + BUG_ON(skb->ip_summed != CHECKSUM_PARTIAL); + BUG_ON(num_frags > LEPP_MAX_FRAGS); + /*--BUG_ON(num_segs != (d_len + (p_len - 1)) / p_len); */ + BUG_ON(num_segs <= 1); + + + /* Finish preparing the command. */ + + /* Copy the command header. */ + *cmd = cmd_init; + + /* Copy the "header". */ + memcpy(&cmd->frags[num_frags], data, sh_len); + + + /* Prefetch and wait, to minimize time spent holding the spinlock. */ + prefetch_L1(&eq->comp_tail); + prefetch_L1(&eq->cmd_tail); + mb(); + + + /* Enqueue the command. */ + + spin_lock_irqsave(&priv->cmd_lock, irqflags); + + /* + * Handle completions if needed to make room. + * HACK: Spin until there is sufficient room. + */ + free_slots = lepp_num_free_comp_slots(eq); + if (free_slots < 1) { +spin: + nolds += tile_net_lepp_grab_comps(dev, olds + nolds, + wanted - nolds, NULL); + if (lepp_num_free_comp_slots(eq) < 1) + goto spin; + } + + cmd_head = eq->cmd_head; + cmd_tail = eq->cmd_tail; + + /* NOTE: The "gotos" below are untested. */ + + /* Prepare to advance, detecting full queue. */ + cmd_next = cmd_tail + cmd_size; + if (cmd_tail < cmd_head && cmd_next >= cmd_head) + goto spin; + if (cmd_next > LEPP_CMD_LIMIT) { + cmd_next = 0; + if (cmd_next == cmd_head) + goto spin; + } + + /* Copy the command. */ + memcpy(&eq->cmds[cmd_tail], cmd, cmd_size); + + /* Advance. */ + cmd_tail = cmd_next; + + /* Record "skb" for eventual freeing. */ + comp_tail = eq->comp_tail; + eq->comps[comp_tail] = skb; + LEPP_QINC(comp_tail); + eq->comp_tail = comp_tail; + + /* Flush before allowing LEPP to handle the command. */ + __insn_mf(); + + eq->cmd_tail = cmd_tail; + + spin_unlock_irqrestore(&priv->cmd_lock, irqflags); + + if (nolds == 0) + nolds = tile_net_lepp_grab_comps(dev, olds, wanted, NULL); + + /* Handle completions. */ + for (i = 0; i < nolds; i++) + kfree_skb(olds[i]); + + /* Update stats. */ + stats->tx_packets += num_segs; + stats->tx_bytes += (num_segs * sh_len) + d_len; + + /* Make sure the egress timer is scheduled. */ + tile_net_schedule_egress_timer(info); + + return NETDEV_TX_OK; +} + + +/* + * Transmit a packet (called by the kernel via "hard_start_xmit" hook). + */ +static int tile_net_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct tile_net_priv *priv = netdev_priv(dev); + int my_cpu = smp_processor_id(); + struct tile_net_cpu *info = priv->cpu[my_cpu]; + struct tile_net_stats_t *stats = &info->stats; + + unsigned long irqflags; + + struct skb_shared_info *sh = skb_shinfo(skb); + + unsigned int len = skb->len; + unsigned char *data = skb->data; + + unsigned int csum_start = skb->csum_start - skb_headroom(skb); + + lepp_frag_t frags[LEPP_MAX_FRAGS]; + + unsigned int num_frags; + + lepp_queue_t *eq = priv->epp_queue; + + struct sk_buff *olds[4]; + unsigned int wanted = 4; + unsigned int i, nolds = 0; + + unsigned int cmd_size = sizeof(lepp_cmd_t); + + unsigned int cmd_head, cmd_tail, cmd_next; + unsigned int comp_tail; + + lepp_cmd_t cmds[LEPP_MAX_FRAGS]; + + unsigned int free_slots; + + + /* + * This is paranoia, since we think that if the link doesn't come + * up, telling Linux we have no carrier will keep it from trying + * to transmit. If it does, though, we can't execute this routine, + * since data structures we depend on aren't set up yet. + */ + if (!info->registered) + return NETDEV_TX_BUSY; + + + /* Save the timestamp. */ + dev->trans_start = jiffies; + + +#ifdef TILE_NET_PARANOIA +#if CHIP_HAS_CBOX_HOME_MAP() + if (hash_default) { + HV_PTE pte = *virt_to_pte(current->mm, (unsigned long)data); + if (hv_pte_get_mode(pte) != HV_PTE_MODE_CACHE_HASH_L3) + panic("Non-coherent egress buffer!"); + } +#endif +#endif + + +#ifdef TILE_NET_DUMP_PACKETS + /* ISSUE: Does not dump the "frags". */ + dump_packet(data, skb_headlen(skb), "tx"); +#endif /* TILE_NET_DUMP_PACKETS */ + + + if (sh->gso_size != 0) + return tile_net_tx_tso(skb, dev); + + + /* Prepare the commands. */ + + num_frags = tile_net_tx_frags(frags, skb, data, skb_headlen(skb)); + + for (i = 0; i < num_frags; i++) { + + bool final = (i == num_frags - 1); + + lepp_cmd_t cmd = { + .cpa_lo = frags[i].cpa_lo, + .cpa_hi = frags[i].cpa_hi, + .length = frags[i].length, + .hash_for_home = frags[i].hash_for_home, + .send_completion = final, + .end_of_packet = final + }; + + if (i == 0 && skb->ip_summed == CHECKSUM_PARTIAL) { + cmd.compute_checksum = 1; + cmd.checksum_data.bits.start_byte = csum_start; + cmd.checksum_data.bits.count = len - csum_start; + cmd.checksum_data.bits.destination_byte = + csum_start + skb->csum_offset; + } + + cmds[i] = cmd; + } + + + /* Prefetch and wait, to minimize time spent holding the spinlock. */ + prefetch_L1(&eq->comp_tail); + prefetch_L1(&eq->cmd_tail); + mb(); + + + /* Enqueue the commands. */ + + spin_lock_irqsave(&priv->cmd_lock, irqflags); + + /* + * Handle completions if needed to make room. + * HACK: Spin until there is sufficient room. + */ + free_slots = lepp_num_free_comp_slots(eq); + if (free_slots < 1) { +spin: + nolds += tile_net_lepp_grab_comps(dev, olds + nolds, + wanted - nolds, NULL); + if (lepp_num_free_comp_slots(eq) < 1) + goto spin; + } + + cmd_head = eq->cmd_head; + cmd_tail = eq->cmd_tail; + + /* NOTE: The "gotos" below are untested. */ + + /* Copy the commands, or fail. */ + for (i = 0; i < num_frags; i++) { + + /* Prepare to advance, detecting full queue. */ + cmd_next = cmd_tail + cmd_size; + if (cmd_tail < cmd_head && cmd_next >= cmd_head) + goto spin; + if (cmd_next > LEPP_CMD_LIMIT) { + cmd_next = 0; + if (cmd_next == cmd_head) + goto spin; + } + + /* Copy the command. */ + *(lepp_cmd_t *)&eq->cmds[cmd_tail] = cmds[i]; + + /* Advance. */ + cmd_tail = cmd_next; + } + + /* Record "skb" for eventual freeing. */ + comp_tail = eq->comp_tail; + eq->comps[comp_tail] = skb; + LEPP_QINC(comp_tail); + eq->comp_tail = comp_tail; + + /* Flush before allowing LEPP to handle the command. */ + __insn_mf(); + + eq->cmd_tail = cmd_tail; + + spin_unlock_irqrestore(&priv->cmd_lock, irqflags); + + if (nolds == 0) + nolds = tile_net_lepp_grab_comps(dev, olds, wanted, NULL); + + /* Handle completions. */ + for (i = 0; i < nolds; i++) + kfree_skb(olds[i]); + + /* HACK: Track "expanded" size for short packets (e.g. 42 < 60). */ + stats->tx_packets++; + stats->tx_bytes += ((len >= ETH_ZLEN) ? len : ETH_ZLEN); + + /* Make sure the egress timer is scheduled. */ + tile_net_schedule_egress_timer(info); + + return NETDEV_TX_OK; +} + + +/* + * Deal with a transmit timeout. + */ +static void tile_net_tx_timeout(struct net_device *dev) +{ + PDEBUG("tile_net_tx_timeout()\n"); + PDEBUG("Transmit timeout at %ld, latency %ld\n", jiffies, + jiffies - dev->trans_start); + + /* XXX: ISSUE: This doesn't seem useful for us. */ + netif_wake_queue(dev); +} + + +/* + * Ioctl commands. + */ +static int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + return -EOPNOTSUPP; +} + + +/* + * Get System Network Statistics. + * + * Returns the address of the device statistics structure. + */ +static struct net_device_stats *tile_net_get_stats(struct net_device *dev) +{ + struct tile_net_priv *priv = netdev_priv(dev); + u32 rx_packets = 0; + u32 tx_packets = 0; + u32 rx_bytes = 0; + u32 tx_bytes = 0; + int i; + + for_each_online_cpu(i) { + if (priv->cpu[i]) { + rx_packets += priv->cpu[i]->stats.rx_packets; + rx_bytes += priv->cpu[i]->stats.rx_bytes; + tx_packets += priv->cpu[i]->stats.tx_packets; + tx_bytes += priv->cpu[i]->stats.tx_bytes; + } + } + + priv->stats.rx_packets = rx_packets; + priv->stats.rx_bytes = rx_bytes; + priv->stats.tx_packets = tx_packets; + priv->stats.tx_bytes = tx_bytes; + + return &priv->stats; +} + + +/* + * Change the "mtu". + * + * The "change_mtu" method is usually not needed. + * If you need it, it must be like this. + */ +static int tile_net_change_mtu(struct net_device *dev, int new_mtu) +{ + PDEBUG("tile_net_change_mtu()\n"); + + /* Check ranges. */ + if ((new_mtu < 68) || (new_mtu > 1500)) + return -EINVAL; + + /* Accept the value. */ + dev->mtu = new_mtu; + + return 0; +} + + +/* + * Change the Ethernet Address of the NIC. + * + * The hypervisor driver does not support changing MAC address. However, + * the IPP does not do anything with the MAC address, so the address which + * gets used on outgoing packets, and which is accepted on incoming packets, + * is completely up to the NetIO program or kernel driver which is actually + * handling them. + * + * Returns 0 on success, negative on failure. + */ +static int tile_net_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + /* ISSUE: Note that "dev_addr" is now a pointer. */ + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + return 0; +} + + +/* + * Obtain the MAC address from the hypervisor. + * This must be done before opening the device. + */ +static int tile_net_get_mac(struct net_device *dev) +{ + struct tile_net_priv *priv = netdev_priv(dev); + + char hv_dev_name[32]; + int len; + + __netio_getset_offset_t offset = { .word = NETIO_IPP_PARAM_OFF }; + + int ret; + + /* For example, "xgbe0". */ + strcpy(hv_dev_name, dev->name); + len = strlen(hv_dev_name); + + /* For example, "xgbe/0". */ + hv_dev_name[len] = hv_dev_name[len - 1]; + hv_dev_name[len - 1] = '/'; + len++; + + /* For example, "xgbe/0/native_hash". */ + strcpy(hv_dev_name + len, hash_default ? "/native_hash" : "/native"); + + /* Get the hypervisor handle for this device. */ + priv->hv_devhdl = hv_dev_open((HV_VirtAddr)hv_dev_name, 0); + PDEBUG("hv_dev_open(%s) returned %d %p\n", + hv_dev_name, priv->hv_devhdl, &priv->hv_devhdl); + if (priv->hv_devhdl < 0) { + if (priv->hv_devhdl == HV_ENODEV) + printk(KERN_DEBUG "Ignoring unconfigured device %s\n", + hv_dev_name); + else + printk(KERN_DEBUG "hv_dev_open(%s) returned %d\n", + hv_dev_name, priv->hv_devhdl); + return -1; + } + + /* + * Read the hardware address from the hypervisor. + * ISSUE: Note that "dev_addr" is now a pointer. + */ + offset.bits.class = NETIO_PARAM; + offset.bits.addr = NETIO_PARAM_MAC; + ret = hv_dev_pread(priv->hv_devhdl, 0, + (HV_VirtAddr)dev->dev_addr, dev->addr_len, + offset.word); + PDEBUG("hv_dev_pread(NETIO_PARAM_MAC) returned %d\n", ret); + if (ret <= 0) { + printk(KERN_DEBUG "hv_dev_pread(NETIO_PARAM_MAC) %s failed\n", + dev->name); + /* + * Since the device is configured by the hypervisor but we + * can't get its MAC address, we are most likely running + * the simulator, so let's generate a random MAC address. + */ + random_ether_addr(dev->dev_addr); + } + + return 0; +} + + +static struct net_device_ops tile_net_ops = { + .ndo_open = tile_net_open, + .ndo_stop = tile_net_stop, + .ndo_start_xmit = tile_net_tx, + .ndo_do_ioctl = tile_net_ioctl, + .ndo_get_stats = tile_net_get_stats, + .ndo_change_mtu = tile_net_change_mtu, + .ndo_tx_timeout = tile_net_tx_timeout, + .ndo_set_mac_address = tile_net_set_mac_address +}; + + +/* + * The setup function. + * + * This uses ether_setup() to assign various fields in dev, including + * setting IFF_BROADCAST and IFF_MULTICAST, then sets some extra fields. + */ +static void tile_net_setup(struct net_device *dev) +{ + PDEBUG("tile_net_setup()\n"); + + ether_setup(dev); + + dev->netdev_ops = &tile_net_ops; + + dev->watchdog_timeo = TILE_NET_TIMEOUT; + + /* We want lockless xmit. */ + dev->features |= NETIF_F_LLTX; + + /* We support hardware tx checksums. */ + dev->features |= NETIF_F_HW_CSUM; + + /* We support scatter/gather. */ + dev->features |= NETIF_F_SG; + + /* We support TSO. */ + dev->features |= NETIF_F_TSO; + +#ifdef TILE_NET_GSO + /* We support GSO. */ + dev->features |= NETIF_F_GSO; +#endif + + if (hash_default) + dev->features |= NETIF_F_HIGHDMA; + + /* ISSUE: We should support NETIF_F_UFO. */ + + dev->tx_queue_len = TILE_NET_TX_QUEUE_LEN; + + dev->mtu = TILE_NET_MTU; +} + + +/* + * Allocate the device structure, register the device, and obtain the + * MAC address from the hypervisor. + */ +static struct net_device *tile_net_dev_init(const char *name) +{ + int ret; + struct net_device *dev; + struct tile_net_priv *priv; + struct page *page; + + /* + * Allocate the device structure. This allocates "priv", calls + * tile_net_setup(), and saves "name". Normally, "name" is a + * template, instantiated by register_netdev(), but not for us. + */ + dev = alloc_netdev(sizeof(*priv), name, tile_net_setup); + if (!dev) { + pr_err("alloc_netdev(%s) failed\n", name); + return NULL; + } + + priv = netdev_priv(dev); + + /* Initialize "priv". */ + + memset(priv, 0, sizeof(*priv)); + + /* Save "dev" for "tile_net_open_retry()". */ + priv->dev = dev; + + INIT_DELAYED_WORK(&priv->retry_work, tile_net_open_retry); + + spin_lock_init(&priv->cmd_lock); + spin_lock_init(&priv->comp_lock); + + /* Allocate "epp_queue". */ + BUG_ON(get_order(sizeof(lepp_queue_t)) != 0); + page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0); + if (!page) { + free_netdev(dev); + return NULL; + } + priv->epp_queue = page_address(page); + + /* Register the network device. */ + ret = register_netdev(dev); + if (ret) { + pr_err("register_netdev %s failed %d\n", dev->name, ret); + free_page((unsigned long)priv->epp_queue); + free_netdev(dev); + return NULL; + } + + /* Get the MAC address. */ + ret = tile_net_get_mac(dev); + if (ret < 0) { + unregister_netdev(dev); + free_page((unsigned long)priv->epp_queue); + free_netdev(dev); + return NULL; + } + + return dev; +} + + +/* + * Module cleanup. + */ +static void tile_net_cleanup(void) +{ + int i; + + for (i = 0; i < TILE_NET_DEVS; i++) { + if (tile_net_devs[i]) { + struct net_device *dev = tile_net_devs[i]; + struct tile_net_priv *priv = netdev_priv(dev); + unregister_netdev(dev); + finv_buffer(priv->epp_queue, PAGE_SIZE); + free_page((unsigned long)priv->epp_queue); + free_netdev(dev); + } + } +} + + +/* + * Module initialization. + */ +static int tile_net_init_module(void) +{ + pr_info("Tilera IPP Net Driver\n"); + + tile_net_devs[0] = tile_net_dev_init("xgbe0"); + tile_net_devs[1] = tile_net_dev_init("xgbe1"); + tile_net_devs[2] = tile_net_dev_init("gbe0"); + tile_net_devs[3] = tile_net_dev_init("gbe1"); + + return 0; +} + + +#ifndef MODULE +/* + * The "network_cpus" boot argument specifies the cpus that are dedicated + * to handle ingress packets. + * + * The parameter should be in the form "network_cpus=m-n[,x-y]", where + * m, n, x, y are integer numbers that represent the cpus that can be + * neither a dedicated cpu nor a dataplane cpu. + */ +static int __init network_cpus_setup(char *str) +{ + int rc = cpulist_parse_crop(str, &network_cpus_map); + if (rc != 0) { + pr_warning("network_cpus=%s: malformed cpu list\n", + str); + } else { + + /* Remove dedicated cpus. */ + cpumask_and(&network_cpus_map, &network_cpus_map, + cpu_possible_mask); + + + if (cpumask_empty(&network_cpus_map)) { + pr_warning("Ignoring network_cpus='%s'.\n", + str); + } else { + char buf[1024]; + cpulist_scnprintf(buf, sizeof(buf), &network_cpus_map); + pr_info("Linux network CPUs: %s\n", buf); + network_cpus_used = true; + } + } + + return 0; +} +__setup("network_cpus=", network_cpus_setup); +#endif + + +module_init(tile_net_init_module); +module_exit(tile_net_cleanup); diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index a9f7d5d1a269..7064e035757a 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -688,9 +688,6 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb, DMFE_DBUG(0, "dmfe_start_xmit", 0); - /* Resource flag check */ - netif_stop_queue(dev); - /* Too large packet check */ if (skb->len > MAX_PACKET_SIZE) { pr_err("big packet = %d\n", (u16)skb->len); @@ -698,6 +695,9 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } + /* Resource flag check */ + netif_stop_queue(dev); + spin_lock_irqsave(&db->lock, flags); /* No Tx resource check, it never happen nromally */ diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 05a95586f3c5..055b87ab4f07 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -899,7 +899,8 @@ struct ucc_geth_hardware_statistics { #define UCC_GETH_UTFS_INIT 512 /* Tx virtual FIFO size */ #define UCC_GETH_UTFET_INIT 256 /* 1/2 utfs */ -#define UCC_GETH_UTFTT_INIT 512 +#define UCC_GETH_UTFTT_INIT 256 /* 1/2 utfs + due to errata */ /* Gigabit Ethernet (1000 Mbps) */ #define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/ /* Rx virtual FIFO size */ diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index b154a94de03e..812edf85d6d3 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -958,10 +958,6 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, /* Packet is complete. Inject into stack. */ /* We have IP packet here */ odev->skb_rx_buf->protocol = cpu_to_be16(ETH_P_IP); - /* don't check it */ - odev->skb_rx_buf->ip_summed = - CHECKSUM_UNNECESSARY; - skb_reset_mac_header(odev->skb_rx_buf); /* Ship it off to the kernel */ @@ -2994,12 +2990,14 @@ static int hso_probe(struct usb_interface *interface, case HSO_INTF_BULK: /* It's a regular bulk interface */ - if (((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) && - !disable_net) - hso_dev = hso_create_net_device(interface, port_spec); - else + if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { + if (!disable_net) + hso_dev = + hso_create_net_device(interface, port_spec); + } else { hso_dev = hso_create_bulk_serial_device(interface, port_spec); + } if (!hso_dev) goto exit; break; diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c index ea476cbd38b5..e305274f83fb 100644 --- a/drivers/net/wan/hd64572.c +++ b/drivers/net/wan/hd64572.c @@ -293,6 +293,7 @@ static inline void sca_tx_done(port_t *port) struct net_device *dev = port->netdev; card_t* card = port->card; u8 stat; + unsigned count = 0; spin_lock(&port->lock); @@ -316,10 +317,12 @@ static inline void sca_tx_done(port_t *port) dev->stats.tx_bytes += readw(&desc->len); } writeb(0, &desc->stat); /* Free descriptor */ + count++; port->txlast = (port->txlast + 1) % card->tx_ring_buffers; } - netif_wake_queue(dev); + if (count) + netif_wake_queue(dev); spin_unlock(&port->lock); } diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index d81ad8397885..24297b274cd4 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -498,7 +498,6 @@ norbuff: static int x25_asy_close(struct net_device *dev) { struct x25_asy *sl = netdev_priv(dev); - int err; spin_lock(&sl->lock); if (sl->tty) @@ -507,10 +506,6 @@ static int x25_asy_close(struct net_device *dev) netif_stop_queue(dev); sl->rcount = 0; sl->xleft = 0; - err = lapb_unregister(dev); - if (err != LAPB_OK) - printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n", - err); spin_unlock(&sl->lock); return 0; } @@ -582,7 +577,7 @@ static int x25_asy_open_tty(struct tty_struct *tty) if (err) return err; /* Done. We have linked the TTY line to a channel. */ - return sl->dev->base_addr; + return 0; } @@ -595,6 +590,7 @@ static int x25_asy_open_tty(struct tty_struct *tty) static void x25_asy_close_tty(struct tty_struct *tty) { struct x25_asy *sl = tty->disc_data; + int err; /* First make sure we're connected. */ if (!sl || sl->magic != X25_ASY_MAGIC) @@ -605,6 +601,11 @@ static void x25_asy_close_tty(struct tty_struct *tty) dev_close(sl->dev); rtnl_unlock(); + err = lapb_unregister(sl->dev); + if (err != LAPB_OK) + printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n", + err); + tty->disc_data = NULL; sl->tty = NULL; x25_asy_free(sl); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 8251946842e6..42ed923cdb1a 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1917,7 +1917,8 @@ ath5k_beacon_send(struct ath5k_softc *sc) sc->bmisscount = 0; } - if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) { + if ((sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) || + sc->opmode == NL80211_IFTYPE_MESH_POINT) { u64 tsf = ath5k_hw_get_tsf64(ah); u32 tsftu = TSF_TO_TU(tsf); int slot = ((tsftu % sc->bintval) * ATH_BCBUF) / sc->bintval; @@ -1949,8 +1950,9 @@ ath5k_beacon_send(struct ath5k_softc *sc) /* NB: hw still stops DMA, so proceed */ } - /* refresh the beacon for AP mode */ - if (sc->opmode == NL80211_IFTYPE_AP) + /* refresh the beacon for AP or MESH mode */ + if (sc->opmode == NL80211_IFTYPE_AP || + sc->opmode == NL80211_IFTYPE_MESH_POINT) ath5k_beacon_update(sc->hw, vif); ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); @@ -2851,7 +2853,8 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, /* Assign the vap/adhoc to a beacon xmit slot. */ if ((avf->opmode == NL80211_IFTYPE_AP) || - (avf->opmode == NL80211_IFTYPE_ADHOC)) { + (avf->opmode == NL80211_IFTYPE_ADHOC) || + (avf->opmode == NL80211_IFTYPE_MESH_POINT)) { int slot; WARN_ON(list_empty(&sc->bcbuf)); @@ -2870,7 +2873,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, sc->bslot[avf->bslot] = vif; if (avf->opmode == NL80211_IFTYPE_AP) sc->num_ap_vifs++; - else + else if (avf->opmode == NL80211_IFTYPE_ADHOC) sc->num_adhoc_vifs++; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index c4182359bee4..a7b82f0085d2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -55,6 +55,8 @@ #define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */ #define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ +#define CTL(_tpower, _flag) ((_tpower) | ((_flag) << 6)) + static const struct ar9300_eeprom ar9300_default = { .eepromVersion = 2, .templateVersion = 2, @@ -290,20 +292,21 @@ static const struct ar9300_eeprom ar9300_default = { } }, .ctlPowerData_2G = { - { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, - { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, - { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } }, + { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } }, + { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } }, + { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } }, - { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } }, - { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, - { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } }, + { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } }, + { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } }, - { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } }, - { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, - { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } }, + { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } }, + { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } }, - { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, - { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, + { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } }, + { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } }, + { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } }, }, .modalHeader5G = { /* 4 idle,t1,t2,b (4 bits per setting) */ @@ -568,56 +571,56 @@ static const struct ar9300_eeprom ar9300_default = { .ctlPowerData_5G = { { { - {60, 1}, {60, 1}, {60, 1}, {60, 1}, - {60, 1}, {60, 1}, {60, 1}, {60, 0}, + CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1), + CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0), } }, { { - {60, 1}, {60, 1}, {60, 1}, {60, 1}, - {60, 1}, {60, 1}, {60, 1}, {60, 0}, + CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1), + CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0), } }, { { - {60, 0}, {60, 1}, {60, 0}, {60, 1}, - {60, 1}, {60, 1}, {60, 1}, {60, 1}, + CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1), + CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1), } }, { { - {60, 0}, {60, 1}, {60, 1}, {60, 0}, - {60, 1}, {60, 0}, {60, 0}, {60, 0}, + CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0), + CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0), } }, { { - {60, 1}, {60, 1}, {60, 1}, {60, 0}, - {60, 0}, {60, 0}, {60, 0}, {60, 0}, + CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0), + CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0), } }, { { - {60, 1}, {60, 1}, {60, 1}, {60, 1}, - {60, 1}, {60, 0}, {60, 0}, {60, 0}, + CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1), + CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0), } }, { { - {60, 1}, {60, 1}, {60, 1}, {60, 1}, - {60, 1}, {60, 1}, {60, 1}, {60, 1}, + CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1), + CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1), } }, { { - {60, 1}, {60, 1}, {60, 0}, {60, 1}, - {60, 1}, {60, 1}, {60, 1}, {60, 0}, + CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1), + CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0), } }, { { - {60, 1}, {60, 0}, {60, 1}, {60, 1}, - {60, 1}, {60, 1}, {60, 0}, {60, 1}, + CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1), + CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1), } }, } @@ -1827,9 +1830,9 @@ static u16 ar9003_hw_get_direct_edge_power(struct ar9300_eeprom *eep, struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G; if (is2GHz) - return ctl_2g[idx].ctlEdges[edge].tPower; + return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge]); else - return ctl_5g[idx].ctlEdges[edge].tPower; + return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge]); } static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep, @@ -1847,12 +1850,12 @@ static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep, if (is2GHz) { if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 1) < freq && - ctl_2g[idx].ctlEdges[edge - 1].flag) - return ctl_2g[idx].ctlEdges[edge - 1].tPower; + CTL_EDGE_FLAGS(ctl_2g[idx].ctlEdges[edge - 1])) + return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge - 1]); } else { if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 0) < freq && - ctl_5g[idx].ctlEdges[edge - 1].flag) - return ctl_5g[idx].ctlEdges[edge - 1].tPower; + CTL_EDGE_FLAGS(ctl_5g[idx].ctlEdges[edge - 1])) + return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge - 1]); } return AR9300_MAX_RATE_POWER; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 3c533bb983c7..655b3033396c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -261,17 +261,12 @@ struct cal_tgt_pow_ht { u8 tPow2x[14]; } __packed; -struct cal_ctl_edge_pwr { - u8 tPower:6, - flag:2; -} __packed; - struct cal_ctl_data_2g { - struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_2G]; + u8 ctlEdges[AR9300_NUM_BAND_EDGES_2G]; } __packed; struct cal_ctl_data_5g { - struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_5G]; + u8 ctlEdges[AR9300_NUM_BAND_EDGES_5G]; } __packed; struct ar9300_eeprom { diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 170d44a35ccb..0963071e8f90 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -21,6 +21,7 @@ #include <linux/device.h> #include <linux/leds.h> #include <linux/completion.h> +#include <linux/pm_qos_params.h> #include "debug.h" #include "common.h" @@ -328,7 +329,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp); struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_setup(struct ath_softc *sc, int haltype); -void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx); +bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx); void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx); void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); @@ -646,6 +647,8 @@ struct ath_softc { struct ath_descdma txsdma; struct ath_ant_comb ant_comb; + + struct pm_qos_request_list pm_qos_req; }; struct ath_wiphy { @@ -675,7 +678,6 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz) } extern struct ieee80211_ops ath9k_ops; -extern struct pm_qos_request_list ath9k_pm_qos_req; extern int modparam_nohwcrypt; extern int led_blink; diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 1266333f586d..2bbf94d0191e 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -240,16 +240,16 @@ u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, for (i = 0; (i < num_band_edges) && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { - twiceMaxEdgePower = pRdEdgesPower[i].tPower; + twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl); break; } else if ((i > 0) && (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz))) { if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, is2GHz) < freq && - pRdEdgesPower[i - 1].flag) { + CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) { twiceMaxEdgePower = - pRdEdgesPower[i - 1].tPower; + CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl); } break; } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index dacb45e1b906..dd59f09441a3 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -233,6 +233,18 @@ #define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1) +#define CTL_EDGE_TPOWER(_ctl) ((_ctl) & 0x3f) +#define CTL_EDGE_FLAGS(_ctl) (((_ctl) >> 6) & 0x03) + +#define LNA_CTL_BUF_MODE BIT(0) +#define LNA_CTL_ISEL_LO BIT(1) +#define LNA_CTL_ISEL_HI BIT(2) +#define LNA_CTL_BUF_IN BIT(3) +#define LNA_CTL_FEM_BAND BIT(4) +#define LNA_CTL_LOCAL_BIAS BIT(5) +#define LNA_CTL_FORCE_XPA BIT(6) +#define LNA_CTL_USE_ANT1 BIT(7) + enum eeprom_param { EEP_NFTHRESH_5, EEP_NFTHRESH_2, @@ -378,10 +390,7 @@ struct modal_eep_header { u8 xatten2Margin[AR5416_MAX_CHAINS]; u8 ob_ch1; u8 db_ch1; - u8 useAnt1:1, - force_xpaon:1, - local_bias:1, - femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1; + u8 lna_ctl; u8 miscBits; u16 xpaBiasLvlFreq[3]; u8 futureModal[6]; @@ -535,18 +544,10 @@ struct cal_target_power_ht { u8 tPow2x[8]; } __packed; - -#ifdef __BIG_ENDIAN_BITFIELD -struct cal_ctl_edges { - u8 bChannel; - u8 flag:2, tPower:6; -} __packed; -#else struct cal_ctl_edges { u8 bChannel; - u8 tPower:6, flag:2; + u8 ctl; } __packed; -#endif struct cal_data_op_loop_ar9287 { u8 pwrPdg[2][5]; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 966b9496a9dd..195406db3bd8 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -37,7 +37,7 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) int addr, eep_start_loc; eep_data = (u16 *)eep; - if (ah->hw_version.devid == 0x7015) + if (AR9287_HTC_DEVID(ah)) eep_start_loc = AR9287_HTC_EEP_START_LOC; else eep_start_loc = AR9287_EEP_START_LOC; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 76b4d65472dd..a3ccb1b9638d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -451,9 +451,10 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, AR_AN_TOP2_LOCALBIAS, AR_AN_TOP2_LOCALBIAS_S, - pModal->local_bias); + !!(pModal->lna_ctl & + LNA_CTL_LOCAL_BIAS)); REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, - pModal->force_xpaon); + !!(pModal->lna_ctl & LNA_CTL_FORCE_XPA)); } REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, @@ -1062,15 +1063,19 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, case 1: break; case 2: - scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN) + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + else + scaledPower = 0; break; case 3: - scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN) + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + else + scaledPower = 0; break; } - scaledPower = max((u16)0, scaledPower); - if (IS_CHAN_2GHZ(chan)) { numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; @@ -1428,9 +1433,9 @@ static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, num_ant_config = 1; - if (pBase->version >= 0x0E0D) - if (pModal->useAnt1) - num_ant_config += 1; + if (pBase->version >= 0x0E0D && + (pModal->lna_ctl & LNA_CTL_USE_ANT1)) + num_ant_config += 1; return num_ant_config; } diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index f7ec31b4ddd3..0de3c3d3c245 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -36,8 +36,13 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */ { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */ { USB_DEVICE(0x13D3, 0x3346) }, /* IMC Networks */ + { USB_DEVICE(0x13D3, 0x3348) }, /* Azurewave */ + { USB_DEVICE(0x13D3, 0x3349) }, /* Azurewave */ + { USB_DEVICE(0x13D3, 0x3350) }, /* Azurewave */ { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */ + { USB_DEVICE(0x040D, 0x3801) }, /* VIA */ + { USB_DEVICE(0x1668, 0x1200) }, /* Verizon */ { }, }; @@ -806,6 +811,8 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) case 0x7010: case 0x7015: case 0x9018: + case 0xA704: + case 0x1200: firm_offset = AR7010_FIRMWARE_TEXT; break; default: @@ -928,6 +935,8 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, case 0x7010: case 0x7015: case 0x9018: + case 0xA704: + case 0x1200: if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) hif_dev->fw_name = FIRMWARE_AR7010_1_1; else @@ -1015,6 +1024,13 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface, struct hif_device_usb *hif_dev = (struct hif_device_usb *) usb_get_intfdata(interface); + /* + * The device has to be set to FULLSLEEP mode in case no + * interface is up. + */ + if (!(hif_dev->flags & HIF_USB_START)) + ath9k_htc_suspend(hif_dev->htc_handle); + ath9k_hif_usb_dealloc_urbs(hif_dev); return 0; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 75ecf6a30d25..c3b561daa6c1 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -455,6 +455,8 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv); void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv); void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv); void ath9k_ps_work(struct work_struct *work); +bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, + enum ath9k_power_mode mode); void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); void ath9k_init_leds(struct ath9k_htc_priv *priv); @@ -464,6 +466,7 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, u16 devid, char *product); void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug); #ifdef CONFIG_PM +void ath9k_htc_suspend(struct htc_target *htc_handle); int ath9k_htc_resume(struct htc_target *htc_handle); #endif #ifdef CONFIG_ATH9K_HTC_DEBUGFS diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 3d7b97f1b3ae..8776f49ffd41 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -249,6 +249,8 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid) case 0x7010: case 0x7015: case 0x9018: + case 0xA704: + case 0x1200: priv->htc->credits = 45; break; default: @@ -889,6 +891,12 @@ void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug) } #ifdef CONFIG_PM + +void ath9k_htc_suspend(struct htc_target *htc_handle) +{ + ath9k_htc_setpower(htc_handle->drv_priv, ATH9K_PM_FULL_SLEEP); +} + int ath9k_htc_resume(struct htc_target *htc_handle) { int ret; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 9a3be8da755d..51977caca47f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -63,8 +63,8 @@ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv, return mode; } -static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, - enum ath9k_power_mode mode) +bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, + enum ath9k_power_mode mode) { bool ret; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 3d19b5bc937f..29d80ca78393 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -121,7 +121,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) tx_hdr.data_type = ATH9K_HTC_NORMAL; } - if (ieee80211_is_data(fc)) { + if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6ebc68bca91f..c7fbe25cc128 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2044,7 +2044,8 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) val = REG_READ(ah, AR7010_GPIO_IN); return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0; } else if (AR_SREV_9300_20_OR_LATER(ah)) - return MS_REG_READ(AR9300, gpio) != 0; + return (MS(REG_READ(ah, AR_GPIO_IN), AR9300_GPIO_IN_VAL) & + AR_GPIO_BIT(gpio)) != 0; else if (AR_SREV_9271(ah)) return MS_REG_READ(AR9271, gpio) != 0; else if (AR_SREV_9287_11_OR_LATER(ah)) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 6a0d99eff404..14b8ab386daf 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -15,7 +15,6 @@ */ #include <linux/slab.h> -#include <linux/pm_qos_params.h> #include "ath9k.h" @@ -180,8 +179,6 @@ static const struct ath_ops ath9k_common_ops = { .write = ath9k_iowrite32, }; -struct pm_qos_request_list ath9k_pm_qos_req; - /**************************/ /* Initialization */ /**************************/ @@ -664,6 +661,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->flags |= IEEE80211_HW_MFP_CAPABLE; hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_STATION) | @@ -759,7 +758,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, ath_init_leds(sc); ath_start_rfkill_poll(sc); - pm_qos_add_request(&ath9k_pm_qos_req, PM_QOS_CPU_DMA_LATENCY, + pm_qos_add_request(&sc->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); return 0; @@ -817,8 +816,6 @@ void ath9k_deinit_device(struct ath_softc *sc) ath9k_ps_wakeup(sc); - pm_qos_remove_request(&ath9k_pm_qos_req); - wiphy_rfkill_stop_polling(sc->hw->wiphy); ath_deinit_leds(sc); @@ -832,6 +829,7 @@ void ath9k_deinit_device(struct ath_softc *sc) } ieee80211_unregister_hw(hw); + pm_qos_remove_request(&sc->pm_qos_req); ath_rx_cleanup(sc); ath_tx_cleanup(sc); ath9k_deinit_softc(sc); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 8c13479b17cd..c996963ab339 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -703,8 +703,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, rs->rs_phyerr = phyerr; } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) rs->rs_status |= ATH9K_RXERR_DECRYPT; - else if ((ads.ds_rxstatus8 & AR_MichaelErr) && - rs->rs_keyix != ATH9K_RXKEYIX_INVALID) + else if (ads.ds_rxstatus8 & AR_MichaelErr) rs->rs_status |= ATH9K_RXERR_MIC; else if (ads.ds_rxstatus8 & AR_KeyMiss) rs->rs_status |= ATH9K_RXERR_DECRYPT; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 25d3ef4c338e..c0c3464d3a86 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -15,7 +15,6 @@ */ #include <linux/nl80211.h> -#include <linux/pm_qos_params.h> #include "ath9k.h" #include "btcoex.h" @@ -245,11 +244,12 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, * the relevant bits of the h/w. */ ath9k_hw_set_interrupts(ah, 0); - ath_drain_all_txq(sc, false); + stopped = ath_drain_all_txq(sc, false); spin_lock_bh(&sc->rx.pcu_lock); - stopped = ath_stoprecv(sc); + if (!ath_stoprecv(sc)) + stopped = false; /* XXX: do not flush receive queue here. We don't want * to flush data frames already in queue because of @@ -1244,7 +1244,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ath9k_btcoex_timer_resume(sc); } - pm_qos_update_request(&ath9k_pm_qos_req, 55); + pm_qos_update_request(&sc->pm_qos_req, 55); mutex_unlock: mutex_unlock(&sc->mutex); @@ -1423,7 +1423,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) sc->sc_flags |= SC_OP_INVALID; - pm_qos_update_request(&ath9k_pm_qos_req, PM_QOS_DEFAULT_VALUE); + pm_qos_update_request(&sc->pm_qos_req, PM_QOS_DEFAULT_VALUE); mutex_unlock(&sc->mutex); @@ -1520,7 +1520,6 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp = (void *)vif->drv_priv; - int i; ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); @@ -1534,21 +1533,24 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { + /* Disable SWBA interrupt */ + sc->sc_ah->imask &= ~ATH9K_INT_SWBA; ath9k_ps_wakeup(sc); + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); ath9k_ps_restore(sc); + tasklet_kill(&sc->bcon_tasklet); } ath_beacon_return(sc, avp); sc->sc_flags &= ~SC_OP_BEACONS; - for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { - if (sc->beacon.bslot[i] == vif) { - printk(KERN_DEBUG "%s: vif had allocated beacon " - "slot\n", __func__); - sc->beacon.bslot[i] = NULL; - sc->beacon.bslot_aphy[i] = NULL; - } + if (sc->nbcnvifs) { + /* Re-enable SWBA interrupt */ + sc->sc_ah->imask |= ATH9K_INT_SWBA; + ath9k_ps_wakeup(sc); + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask); + ath9k_ps_restore(sc); } sc->nvifs--; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c76ea53c20ce..fdc2ec52b42f 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -518,7 +518,7 @@ bool ath_stoprecv(struct ath_softc *sc) bool stopped; spin_lock_bh(&sc->rx.rxbuflock); - ath9k_hw_stoppcurecv(ah); + ath9k_hw_abortpcurecv(ah); ath9k_hw_setrxfilter(ah, 0); stopped = ath9k_hw_stopdmarecv(ah); @@ -838,6 +838,10 @@ static bool ath9k_rx_accept(struct ath_common *common, struct ath_rx_status *rx_stats, bool *decrypt_error) { +#define is_mc_or_valid_tkip_keyix ((is_mc || \ + (rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && \ + test_bit(rx_stats->rs_keyix, common->tkip_keymap)))) + struct ath_hw *ah = common->ah; __le16 fc; u8 rx_status_len = ah->caps.rx_status_len; @@ -879,15 +883,18 @@ static bool ath9k_rx_accept(struct ath_common *common, if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) { *decrypt_error = true; } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) { + bool is_mc; /* * The MIC error bit is only valid if the frame * is not a control frame or fragment, and it was * decrypted using a valid TKIP key. */ + is_mc = !!is_multicast_ether_addr(hdr->addr1); + if (!ieee80211_is_ctl(fc) && !ieee80211_has_morefrags(fc) && !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && - test_bit(rx_stats->rs_keyix, common->tkip_keymap)) + is_mc_or_valid_tkip_keyix) rxs->flag |= RX_FLAG_MMIC_ERROR; else rx_stats->rs_status &= ~ATH9K_RXERR_MIC; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index fa05b711e5cd..2c6a22fbb0f0 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -866,7 +866,13 @@ #define AR_DEVID_7010(_ah) \ (((_ah)->hw_version.devid == 0x7010) || \ ((_ah)->hw_version.devid == 0x7015) || \ - ((_ah)->hw_version.devid == 0x9018)) + ((_ah)->hw_version.devid == 0x9018) || \ + ((_ah)->hw_version.devid == 0xA704) || \ + ((_ah)->hw_version.devid == 0x1200)) + +#define AR9287_HTC_DEVID(_ah) \ + (((_ah)->hw_version.devid == 0x7015) || \ + ((_ah)->hw_version.devid == 0x1200)) #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 @@ -978,11 +984,13 @@ enum { #define AR9287_GPIO_IN_VAL_S 11 #define AR9271_GPIO_IN_VAL 0xFFFF0000 #define AR9271_GPIO_IN_VAL_S 16 -#define AR9300_GPIO_IN_VAL 0x0001FFFF -#define AR9300_GPIO_IN_VAL_S 0 #define AR7010_GPIO_IN_VAL 0x0000FFFF #define AR7010_GPIO_IN_VAL_S 0 +#define AR_GPIO_IN 0x404c +#define AR9300_GPIO_IN_VAL 0x0001FFFF +#define AR9300_GPIO_IN_VAL_S 0 + #define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c) #define AR_GPIO_OE_OUT_DRV 0x3 #define AR_GPIO_OE_OUT_DRV_NO 0x0 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f2ade2402ce2..aff04789f794 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1120,7 +1120,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) } } -void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) +bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -1128,7 +1128,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) int i, npend = 0; if (sc->sc_flags & SC_OP_INVALID) - return; + return true; /* Stop beacon queue */ ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); @@ -1142,25 +1142,15 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) } } - if (npend) { - int r; - - ath_print(common, ATH_DBG_FATAL, - "Failed to stop TX DMA. Resetting hardware!\n"); - - spin_lock_bh(&sc->sc_resetlock); - r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); - if (r) - ath_print(common, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %d\n", - r); - spin_unlock_bh(&sc->sc_resetlock); - } + if (npend) + ath_print(common, ATH_DBG_FATAL, "Failed to stop TX DMA!\n"); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) ath_draintxq(sc, &sc->tx.txq[i], retry_tx); } + + return !npend; } void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index ae6c006bbc56..546b4e4ec5ea 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -291,7 +291,8 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) if (SUPP(CARL9170FW_WLANTX_CAB)) { ar->hw->wiphy->interface_modes |= - BIT(NL80211_IFTYPE_AP); + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO); } } diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 980ae70ea424..dc7b30b170d0 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -647,7 +647,7 @@ init: } unlock: - if (err && (vif_id != -1)) { + if (err && (vif_id >= 0)) { vif_priv->active = false; bitmap_release_region(&ar->vif_bitmap, vif_id, 0); ar->vifs--; @@ -1631,7 +1631,8 @@ void *carl9170_alloc(size_t priv_size) * supports these modes. The code which will add the * additional interface_modes is in fw.c. */ - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_P2P_CLIENT); hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_REPORTS_TX_ACK_STATUS | diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index b575c865142d..7e6506a77bbb 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -810,7 +810,7 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) mac_tmp = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | AR9170_TX_MAC_BACKOFF); - mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) && + mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) & AR9170_TX_MAC_QOS); no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK); diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 3317039cd28f..7504ed14c725 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -553,12 +553,12 @@ static int carl9170_usb_flush(struct ar9170 *ar) usb_free_urb(urb); } - ret = usb_wait_anchor_empty_timeout(&ar->tx_cmd, HZ); + ret = usb_wait_anchor_empty_timeout(&ar->tx_cmd, 1000); if (ret == 0) err = -ETIMEDOUT; /* lets wait a while until the tx - queues are dried out */ - ret = usb_wait_anchor_empty_timeout(&ar->tx_anch, HZ); + ret = usb_wait_anchor_empty_timeout(&ar->tx_anch, 1000); if (ret == 0) err = -ETIMEDOUT; diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c index 9a55338d957f..09e2dfd7b175 100644 --- a/drivers/net/wireless/b43/sdio.c +++ b/drivers/net/wireless/b43/sdio.c @@ -163,6 +163,7 @@ static int b43_sdio_probe(struct sdio_func *func, err_free_ssb: kfree(sdio); err_disable_func: + sdio_claim_host(func); sdio_disable_func(func); err_release_host: sdio_release_host(func); diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index e5685dc317a8..b4de0ca10feb 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -1170,7 +1170,6 @@ static void if_sdio_remove(struct sdio_func *func) lbs_deb_sdio("call remove card\n"); lbs_stop_card(card->priv); lbs_remove_card(card->priv); - card->priv->surpriseremoved = 1; flush_workqueue(card->workqueue); destroy_workqueue(card->workqueue); diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 79bcb4e5d2ca..ecd4d04b2c3c 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -1055,7 +1055,6 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) lbs_stop_card(priv); lbs_remove_card(priv); /* will call free_netdev */ - priv->surpriseremoved = 1; free_irq(spi->irq, card); if_spi_terminate_spi_thread(card); if (card->pdata->teardown) diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 46b88b118c99..fcd1bbfc632d 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -915,8 +915,6 @@ void lbs_remove_card(struct lbs_private *priv) lbs_free_adapter(priv); lbs_cfg_free(priv); - - priv->dev = NULL; free_netdev(dev); lbs_deb_leave(LBS_DEB_MAIN); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index e8e2d0f4763d..f3d396e7544b 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -1392,10 +1392,9 @@ static void orinoco_process_scan_results(struct work_struct *work) orinoco_add_hostscan_results(priv, buf, len); kfree(buf); - } else if (priv->scan_request) { + } else { /* Either abort or complete the scan */ - cfg80211_scan_done(priv->scan_request, (len < 0)); - priv->scan_request = NULL; + orinoco_scan_done(priv, (len < 0)); } spin_lock_irqsave(&priv->scan_lock, flags); @@ -1684,6 +1683,8 @@ static int __orinoco_down(struct orinoco_private *priv) hermes_write_regn(hw, EVACK, 0xffff); } + orinoco_scan_done(priv, true); + /* firmware will have to reassociate */ netif_carrier_off(dev); priv->last_linkstatus = 0xffff; @@ -1762,10 +1763,7 @@ void orinoco_reset(struct work_struct *work) orinoco_unlock(priv, &flags); /* Scanning support: Notify scan cancellation */ - if (priv->scan_request) { - cfg80211_scan_done(priv->scan_request, 1); - priv->scan_request = NULL; - } + orinoco_scan_done(priv, true); if (priv->hard_reset) { err = (*priv->hard_reset)(priv); @@ -1813,6 +1811,12 @@ static int __orinoco_commit(struct orinoco_private *priv) struct net_device *dev = priv->ndev; int err = 0; + /* If we've called commit, we are reconfiguring or bringing the + * interface up. Maintaining countermeasures across this would + * be confusing, so note that we've disabled them. The port will + * be enabled later in orinoco_commit or __orinoco_up. */ + priv->tkip_cm_active = 0; + err = orinoco_hw_program_rids(priv); /* FIXME: what about netif_tx_lock */ diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index 71b3d68b9403..32954c4b243a 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -151,20 +151,20 @@ orinoco_cs_config(struct pcmcia_device *link) goto failed; } - ret = pcmcia_request_irq(link, orinoco_interrupt); - if (ret) - goto failed; - - /* We initialize the hermes structure before completing PCMCIA - * configuration just in case the interrupt handler gets - * called. */ mem = ioport_map(link->resource[0]->start, resource_size(link->resource[0])); if (!mem) goto failed; + /* We initialize the hermes structure before completing PCMCIA + * configuration just in case the interrupt handler gets + * called. */ hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); + ret = pcmcia_request_irq(link, orinoco_interrupt); + if (ret) + goto failed; + ret = pcmcia_enable_device(link); if (ret) goto failed; diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c index 4300d9db7d8c..86cb54c842e7 100644 --- a/drivers/net/wireless/orinoco/scan.c +++ b/drivers/net/wireless/orinoco/scan.c @@ -229,3 +229,11 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv, priv->scan_request = NULL; } } + +void orinoco_scan_done(struct orinoco_private *priv, bool abort) +{ + if (priv->scan_request) { + cfg80211_scan_done(priv->scan_request, abort); + priv->scan_request = NULL; + } +} diff --git a/drivers/net/wireless/orinoco/scan.h b/drivers/net/wireless/orinoco/scan.h index 2dc4e046dbdb..27281fb0a6dc 100644 --- a/drivers/net/wireless/orinoco/scan.h +++ b/drivers/net/wireless/orinoco/scan.h @@ -16,5 +16,6 @@ void orinoco_add_extscan_result(struct orinoco_private *priv, void orinoco_add_hostscan_results(struct orinoco_private *dev, unsigned char *buf, size_t len); +void orinoco_scan_done(struct orinoco_private *priv, bool abort); #endif /* _ORINOCO_SCAN_H_ */ diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index fb859a5ad2eb..db34c282e59b 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -214,21 +214,21 @@ spectrum_cs_config(struct pcmcia_device *link) goto failed; } - ret = pcmcia_request_irq(link, orinoco_interrupt); - if (ret) - goto failed; - - /* We initialize the hermes structure before completing PCMCIA - * configuration just in case the interrupt handler gets - * called. */ mem = ioport_map(link->resource[0]->start, resource_size(link->resource[0])); if (!mem) goto failed; + /* We initialize the hermes structure before completing PCMCIA + * configuration just in case the interrupt handler gets + * called. */ hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); hw->eeprom_pda = true; + ret = pcmcia_request_irq(link, orinoco_interrupt); + if (ret) + goto failed; + ret = pcmcia_enable_device(link); if (ret) goto failed; diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 93505f93bf97..e5afabee60d1 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -911,10 +911,10 @@ static int orinoco_ioctl_set_auth(struct net_device *dev, */ if (param->value) { priv->tkip_cm_active = 1; - ret = hermes_enable_port(hw, 0); + ret = hermes_disable_port(hw, 0); } else { priv->tkip_cm_active = 0; - ret = hermes_disable_port(hw, 0); + ret = hermes_enable_port(hw, 0); } break; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 458bb57914a3..cdbeec9f83ea 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -66,8 +66,8 @@ struct netfront_cb { #define GRANT_INVALID_REF 0 -#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE) -#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE) +#define NET_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE) +#define NET_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE) #define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256) struct netfront_info { diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index d9f51485beee..9383063d2b16 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -349,7 +349,6 @@ static struct irq_chip dino_interrupt_type = { .name = "GSC-PCI", .unmask = dino_unmask_irq, .mask = dino_mask_irq, - .ack = no_ack_irq, }; diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index 1211974f55aa..e860038b0b84 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -186,7 +186,6 @@ static struct irq_chip eisa_interrupt_type = { .name = "EISA", .unmask = eisa_unmask_irq, .mask = eisa_mask_irq, - .ack = no_ack_irq, }; static irqreturn_t eisa_irq(int wax_irq, void *intr_dev) @@ -340,7 +339,7 @@ static int __init eisa_probe(struct parisc_device *dev) setup_irq(2, &irq2_action); for (i = 0; i < 16; i++) { set_irq_chip_and_handler(i, &eisa_interrupt_type, - handle_level_irq); + handle_simple_irq); } EISA_bus = 1; diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c index e605298e3aee..772b1939ac21 100644 --- a/drivers/parisc/gsc.c +++ b/drivers/parisc/gsc.c @@ -143,7 +143,6 @@ static struct irq_chip gsc_asic_interrupt_type = { .name = "GSC-ASIC", .unmask = gsc_asic_unmask_irq, .mask = gsc_asic_mask_irq, - .ack = no_ack_irq, }; int gsc_assign_irq(struct irq_chip *type, void *data) @@ -153,7 +152,7 @@ int gsc_assign_irq(struct irq_chip *type, void *data) if (irq > GSC_IRQ_MAX) return NO_IRQ; - set_irq_chip_and_handler(irq, type, handle_level_irq); + set_irq_chip_and_handler(irq, type, handle_simple_irq); set_irq_chip_data(irq, data); return irq++; diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index a3120a09c43d..0327894bf235 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -669,6 +669,13 @@ printk("\n"); DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", irq, vi->eoi_addr, vi->eoi_data); iosapic_eoi(vi->eoi_addr, vi->eoi_data); +} + +static void iosapic_eoi_irq(unsigned int irq) +{ + struct vector_info *vi = get_irq_chip_data(irq); + + iosapic_eoi(vi->eoi_addr, vi->eoi_data); cpu_eoi_irq(irq); } @@ -705,6 +712,7 @@ static struct irq_chip iosapic_interrupt_type = { .unmask = iosapic_unmask_irq, .mask = iosapic_mask_irq, .ack = cpu_ack_irq, + .eoi = iosapic_eoi_irq, #ifdef CONFIG_SMP .set_affinity = iosapic_set_affinity_irq, #endif diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 2350e8a86eef..f2f501e5b6a0 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -64,6 +64,7 @@ static unsigned int led_diskio __read_mostly = 1; static unsigned int led_lanrxtx __read_mostly = 1; static char lcd_text[32] __read_mostly; static char lcd_text_default[32] __read_mostly; +static int lcd_no_led_support __read_mostly = 0; /* KittyHawk doesn't support LED on its LCD */ static struct workqueue_struct *led_wq; @@ -115,7 +116,7 @@ lcd_info __attribute__((aligned(8))) __read_mostly = .lcd_width = 16, .lcd_cmd_reg_addr = KITTYHAWK_LCD_CMD, .lcd_data_reg_addr = KITTYHAWK_LCD_DATA, - .min_cmd_delay = 40, + .min_cmd_delay = 80, .reset_cmd1 = 0x80, .reset_cmd2 = 0xc0, }; @@ -135,6 +136,9 @@ static int start_task(void) /* Display the default text now */ if (led_type == LED_HASLCD) lcd_print( lcd_text_default ); + /* KittyHawk has no LED support on its LCD */ + if (lcd_no_led_support) return 0; + /* Create the work queue and queue the LED task */ led_wq = create_singlethread_workqueue("led_wq"); queue_delayed_work(led_wq, &led_task, 0); @@ -248,9 +252,13 @@ static int __init led_create_procfs(void) proc_pdc_root = proc_mkdir("pdc", 0); if (!proc_pdc_root) return -1; - ent = proc_create_data("led", S_IRUGO|S_IWUSR, proc_pdc_root, - &led_proc_fops, (void *)LED_NOLCD); /* LED */ - if (!ent) return -1; + + if (!lcd_no_led_support) + { + ent = proc_create_data("led", S_IRUGO|S_IWUSR, proc_pdc_root, + &led_proc_fops, (void *)LED_NOLCD); /* LED */ + if (!ent) return -1; + } if (led_type == LED_HASLCD) { @@ -692,6 +700,7 @@ int __init led_init(void) case 0x58B: /* KittyHawk DC2 100 (K200) */ printk(KERN_INFO "%s: KittyHawk-Machine (hversion 0x%x) found, " "LED detection skipped.\n", __FILE__, CPU_HVERSION); + lcd_no_led_support = 1; goto found; /* use the preinitialized values of lcd_info */ } diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index 0846dafdfff1..28241532c0fd 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -323,7 +323,6 @@ static struct irq_chip superio_interrupt_type = { .name = SUPERIO, .unmask = superio_unmask_irq, .mask = superio_mask_irq, - .ack = no_ack_irq, }; #ifdef DEBUG_SUPERIO_INIT @@ -354,7 +353,7 @@ int superio_fixup_irq(struct pci_dev *pcidev) #endif for (i = 0; i < 16; i++) { - set_irq_chip_and_handler(i, &superio_interrupt_type, handle_level_irq); + set_irq_chip_and_handler(i, &superio_interrupt_type, handle_simple_irq); } /* diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index f01e344cf4bd..98e6fdf34d30 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o obj-$(CONFIG_MN10300) += setup-bus.o obj-$(CONFIG_MICROBLAZE) += setup-bus.o +obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o # # ACPI Related PCI FW Functions diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 003170ea2e39..69546e9213dd 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -64,77 +64,6 @@ void pci_bus_remove_resources(struct pci_bus *bus) } } -static bool pci_bus_resource_better(struct resource *res1, bool pos1, - struct resource *res2, bool pos2) -{ - /* If exactly one is positive decode, always prefer that one */ - if (pos1 != pos2) - return pos1 ? true : false; - - /* Prefer the one that contains the highest address */ - if (res1->end != res2->end) - return (res1->end > res2->end) ? true : false; - - /* Otherwise, prefer the one with highest "center of gravity" */ - if (res1->start != res2->start) - return (res1->start > res2->start) ? true : false; - - /* Otherwise, choose one arbitrarily (but consistently) */ - return (res1 > res2) ? true : false; -} - -static bool pci_bus_resource_positive(struct pci_bus *bus, struct resource *res) -{ - struct pci_bus_resource *bus_res; - - /* - * This relies on the fact that pci_bus.resource[] refers to P2P or - * CardBus bridge base/limit registers, which are always positively - * decoded. The pci_bus.resources list contains host bridge or - * subtractively decoded resources. - */ - list_for_each_entry(bus_res, &bus->resources, list) { - if (bus_res->res == res) - return (bus_res->flags & PCI_SUBTRACTIVE_DECODE) ? - false : true; - } - return true; -} - -/* - * Find the next-best bus resource after the cursor "res". If the cursor is - * NULL, return the best resource. "Best" means that we prefer positive - * decode regions over subtractive decode, then those at higher addresses. - */ -static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus, - unsigned int type, - struct resource *res) -{ - bool res_pos, r_pos, prev_pos = false; - struct resource *r, *prev = NULL; - int i; - - res_pos = pci_bus_resource_positive(bus, res); - pci_bus_for_each_resource(bus, r, i) { - if (!r) - continue; - - if ((r->flags & IORESOURCE_TYPE_BITS) != type) - continue; - - r_pos = pci_bus_resource_positive(bus, r); - if (!res || pci_bus_resource_better(res, res_pos, r, r_pos)) { - if (!prev || pci_bus_resource_better(r, r_pos, - prev, prev_pos)) { - prev = r; - prev_pos = r_pos; - } - } - } - - return prev; -} - /** * pci_bus_alloc_resource - allocate a resource from a parent bus * @bus: PCI bus @@ -160,10 +89,9 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t), void *alignf_data) { - int ret = -ENOMEM; + int i, ret = -ENOMEM; struct resource *r; resource_size_t max = -1; - unsigned int type = res->flags & IORESOURCE_TYPE_BITS; type_mask |= IORESOURCE_IO | IORESOURCE_MEM; @@ -171,9 +99,10 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, if (!(res->flags & IORESOURCE_MEM_64)) max = PCIBIOS_MAX_MEM_32; - /* Look for space at highest addresses first */ - r = pci_bus_find_resource_prev(bus, type, NULL); - for ( ; r; r = pci_bus_find_resource_prev(bus, type, r)) { + pci_bus_for_each_resource(bus, r, i) { + if (!r) + continue; + /* type_mask must match */ if ((res->flags ^ r->flags) & type_mask) continue; diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 0157708d474d..09933eb9126b 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -1417,6 +1417,11 @@ int __init enable_drhd_fault_handling(void) (unsigned long long)drhd->reg_base_addr, ret); return -1; } + + /* + * Clear any previous faults. + */ + dmar_fault(iommu->irq, iommu); } return 0; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f5c63fe9db5c..53a786fd0d40 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2136,6 +2136,24 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB, quirk_unhide_mch_dev6); +#ifdef CONFIG_TILE +/* + * The Tilera TILEmpower platform needs to set the link speed + * to 2.5GT(Giga-Transfers)/s (Gen 1). The default link speed + * setting is 5GT/s (Gen 2). 0x98 is the Link Control2 PCIe + * capability register of the PEX8624 PCIe switch. The switch + * supports link speed auto negotiation, but falsely sets + * the link speed to 5GT/s. + */ +static void __devinit quirk_tile_plx_gen1(struct pci_dev *dev) +{ + if (tile_plx_gen1) { + pci_write_config_dword(dev, 0x98, 0x1); + mdelay(50); + } +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8624, quirk_tile_plx_gen1); +#endif /* CONFIG_TILE */ #ifdef CONFIG_PCI_MSI /* Some chipsets do not support MSI. We cannot easily rely on setting @@ -2311,6 +2329,9 @@ static void __devinit nvbridge_check_legacy_irq_routing(struct pci_dev *dev) { u32 cfg; + if (!pci_find_capability(dev, PCI_CAP_ID_HT)) + return; + pci_read_config_dword(dev, 0x74, &cfg); if (cfg & ((1 << 2) | (1 << 15))) { @@ -2746,6 +2767,29 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_m DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); #endif /*CONFIG_MMC_RICOH_MMC*/ +#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP) +#define VTUNCERRMSK_REG 0x1ac +#define VTD_MSK_SPEC_ERRORS (1 << 31) +/* + * This is a quirk for masking vt-d spec defined errors to platform error + * handling logic. With out this, platforms using Intel 7500, 5500 chipsets + * (and the derivative chipsets like X58 etc) seem to generate NMI/SMI (based + * on the RAS config settings of the platform) when a vt-d fault happens. + * The resulting SMI caused the system to hang. + * + * VT-d spec related errors are already handled by the VT-d OS code, so no + * need to report the same error through other channels. + */ +static void vtd_mask_spec_errors(struct pci_dev *dev) +{ + u32 word; + + pci_read_config_dword(dev, VTUNCERRMSK_REG, &word); + pci_write_config_dword(dev, VTUNCERRMSK_REG, word | VTD_MSK_SPEC_ERRORS); +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x342e, vtd_mask_spec_errors); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x3c28, vtd_mask_spec_errors); +#endif static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 3753fd0722e7..2fe8cb8e95cd 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -70,6 +70,7 @@ void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func, va_end(args); } } +EXPORT_SYMBOL(soc_pcmcia_debug); #endif diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 60a5a5c6b50a..d235f44fd7a3 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -81,6 +81,8 @@ MODULE_PARM_DESC(wapf, "WAPF value"); static int wlan_status = 1; static int bluetooth_status = 1; +static int wimax_status = -1; +static int wwan_status = -1; module_param(wlan_status, int, 0444); MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot " @@ -92,6 +94,16 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " "(0 = disabled, 1 = enabled, -1 = don't do anything). " "default is 1"); +module_param(wimax_status, int, 0444); +MODULE_PARM_DESC(wimax_status, "Set the wireless status on boot " + "(0 = disabled, 1 = enabled, -1 = don't do anything). " + "default is 1"); + +module_param(wwan_status, int, 0444); +MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot " + "(0 = disabled, 1 = enabled, -1 = don't do anything). " + "default is 1"); + /* * Some events we use, same for all Asus */ @@ -114,6 +126,8 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " */ #define WL_RSTS 0x01 /* internal Wifi */ #define BT_RSTS 0x02 /* internal Bluetooth */ +#define WM_RSTS 0x08 /* internal wimax */ +#define WW_RSTS 0x20 /* internal wwan */ /* LED */ #define METHOD_MLED "MLED" @@ -132,6 +146,11 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " */ #define METHOD_WLAN "WLED" #define METHOD_BLUETOOTH "BLED" + +/* WWAN and WIMAX */ +#define METHOD_WWAN "GSMC" +#define METHOD_WIMAX "WMXC" + #define METHOD_WL_STATUS "RSTS" /* Brightness */ @@ -883,6 +902,64 @@ static ssize_t store_bluetooth(struct device *dev, } /* + * Wimax + */ +static int asus_wimax_set(struct asus_laptop *asus, int status) +{ + if (write_acpi_int(asus->handle, METHOD_WIMAX, !!status)) { + pr_warning("Error setting wimax status to %d", status); + return -EIO; + } + return 0; +} + +static ssize_t show_wimax(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", asus_wireless_status(asus, WM_RSTS)); +} + +static ssize_t store_wimax(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sysfs_acpi_set(asus, buf, count, METHOD_WIMAX); +} + +/* + * Wwan + */ +static int asus_wwan_set(struct asus_laptop *asus, int status) +{ + if (write_acpi_int(asus->handle, METHOD_WWAN, !!status)) { + pr_warning("Error setting wwan status to %d", status); + return -EIO; + } + return 0; +} + +static ssize_t show_wwan(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", asus_wireless_status(asus, WW_RSTS)); +} + +static ssize_t store_wwan(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sysfs_acpi_set(asus, buf, count, METHOD_WWAN); +} + +/* * Display */ static void asus_set_display(struct asus_laptop *asus, int value) @@ -1202,6 +1279,8 @@ static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL); static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan); static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, show_bluetooth, store_bluetooth); +static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); +static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); @@ -1212,6 +1291,8 @@ static struct attribute *asus_attributes[] = { &dev_attr_infos.attr, &dev_attr_wlan.attr, &dev_attr_bluetooth.attr, + &dev_attr_wimax.attr, + &dev_attr_wwan.attr, &dev_attr_display.attr, &dev_attr_ledd.attr, &dev_attr_ls_level.attr, @@ -1239,6 +1320,13 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj, } else if (attr == &dev_attr_display.attr) { supported = !acpi_check_handle(handle, METHOD_SWITCH_DISPLAY, NULL); + } else if (attr == &dev_attr_wimax.attr) { + supported = + !acpi_check_handle(asus->handle, METHOD_WIMAX, NULL); + + } else if (attr == &dev_attr_wwan.attr) { + supported = !acpi_check_handle(asus->handle, METHOD_WWAN, NULL); + } else if (attr == &dev_attr_ledd.attr) { supported = !acpi_check_handle(handle, METHOD_LEDD, NULL); @@ -1397,7 +1485,8 @@ static int asus_laptop_get_info(struct asus_laptop *asus) /* * The HWRS method return informations about the hardware. - * 0x80 bit is for WLAN, 0x100 for Bluetooth. + * 0x80 bit is for WLAN, 0x100 for Bluetooth, + * 0x40 for WWAN, 0x10 for WIMAX. * The significance of others is yet to be found. */ status = @@ -1440,6 +1529,12 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) if (wlan_status >= 0) asus_wlan_set(asus, !!wlan_status); + if (wimax_status >= 0) + asus_wimax_set(asus, !!wimax_status); + + if (wwan_status >= 0) + asus_wwan_set(asus, !!wwan_status); + /* Keyboard Backlight is on by default */ if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL)) asus_kled_set(asus, 1); diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 462ceab93f87..0d50fbbe2478 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -298,8 +298,8 @@ static void eeepc_wmi_notify(u32 value, void *context) kfree(obj); } -static int store_cpufv(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { int value; struct acpi_buffer input = { (acpi_size)sizeof(value), &value }; diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 1dac659b5e0c..9e05af9c41cb 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -172,6 +172,8 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer, bios_return = *((struct bios_return *)obj->buffer.pointer); memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); + + kfree(obj); return 0; } diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c index 3c2c6b91ecb3..94a114aa8e28 100644 --- a/drivers/platform/x86/ibm_rtl.c +++ b/drivers/platform/x86/ibm_rtl.c @@ -28,6 +28,7 @@ #include <linux/io.h> #include <linux/sysdev.h> #include <linux/dmi.h> +#include <linux/efi.h> #include <linux/mutex.h> #include <asm/bios_ebda.h> @@ -220,32 +221,13 @@ static void rtl_teardown_sysfs(void) { sysdev_class_unregister(&class_rtl); } -static int dmi_check_cb(const struct dmi_system_id *id) -{ - RTL_DEBUG("found IBM server '%s'\n", id->ident); - return 0; -} - -#define ibm_dmi_entry(NAME, TYPE) \ -{ \ - .ident = NAME, \ - .matches = { \ - DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \ - DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \ - }, \ - .callback = dmi_check_cb \ -} static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = { - ibm_dmi_entry("BladeCenter LS21", "7971"), - ibm_dmi_entry("BladeCenter LS22", "7901"), - ibm_dmi_entry("BladeCenter HS21 XM", "7995"), - ibm_dmi_entry("BladeCenter HS22", "7870"), - ibm_dmi_entry("BladeCenter HS22V", "7871"), - ibm_dmi_entry("System x3550 M2", "7946"), - ibm_dmi_entry("System x3650 M2", "7947"), - ibm_dmi_entry("System x3550 M3", "7944"), - ibm_dmi_entry("System x3650 M3", "7945"), + { \ + .matches = { \ + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \ + }, \ + }, { } }; @@ -257,7 +239,7 @@ static int __init ibm_rtl_init(void) { if (force) pr_warning("ibm-rtl: module loaded by force\n"); /* first ensure that we are running on IBM HW */ - else if (!dmi_check_system(ibm_rtl_dmi_table)) + else if (efi_enabled || !dmi_check_system(ibm_rtl_dmi_table)) return -ENODEV; /* Get the address for the Extended BIOS Data Area */ @@ -302,7 +284,7 @@ static int __init ibm_rtl_init(void) { RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n", rtl_cmd_width, rtl_cmd_type); addr = ioread32(&rtl_table->cmd_port_address); - RTL_DEBUG("addr = %#llx\n", addr); + RTL_DEBUG("addr = %#llx\n", (unsigned long long)addr); plen = rtl_cmd_width/sizeof(char); rtl_cmd_addr = rtl_port_map(addr, plen); RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr); diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c index 42a5469a2459..35278ad7e628 100644 --- a/drivers/platform/x86/msi-wmi.c +++ b/drivers/platform/x86/msi-wmi.c @@ -43,16 +43,18 @@ MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"); #define dprintk(msg...) pr_debug(DRV_PFX msg) -#define KEYCODE_BASE 0xD0 -#define MSI_WMI_BRIGHTNESSUP KEYCODE_BASE -#define MSI_WMI_BRIGHTNESSDOWN (KEYCODE_BASE + 1) -#define MSI_WMI_VOLUMEUP (KEYCODE_BASE + 2) -#define MSI_WMI_VOLUMEDOWN (KEYCODE_BASE + 3) +#define SCANCODE_BASE 0xD0 +#define MSI_WMI_BRIGHTNESSUP SCANCODE_BASE +#define MSI_WMI_BRIGHTNESSDOWN (SCANCODE_BASE + 1) +#define MSI_WMI_VOLUMEUP (SCANCODE_BASE + 2) +#define MSI_WMI_VOLUMEDOWN (SCANCODE_BASE + 3) +#define MSI_WMI_MUTE (SCANCODE_BASE + 4) static struct key_entry msi_wmi_keymap[] = { { KE_KEY, MSI_WMI_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} }, { KE_KEY, MSI_WMI_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} }, { KE_KEY, MSI_WMI_VOLUMEUP, {KEY_VOLUMEUP} }, { KE_KEY, MSI_WMI_VOLUMEDOWN, {KEY_VOLUMEDOWN} }, + { KE_KEY, MSI_WMI_MUTE, {KEY_MUTE} }, { KE_END, 0} }; static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1]; @@ -169,7 +171,7 @@ static void msi_wmi_notify(u32 value, void *context) ktime_t diff; cur = ktime_get_real(); diff = ktime_sub(cur, last_pressed[key->code - - KEYCODE_BASE]); + SCANCODE_BASE]); /* Ignore event if the same event happened in a 50 ms timeframe -> Key press may result in 10-20 GPEs */ if (ktime_to_us(diff) < 1000 * 50) { @@ -178,7 +180,7 @@ static void msi_wmi_notify(u32 value, void *context) key->code, ktime_to_us(diff)); return; } - last_pressed[key->code - KEYCODE_BASE] = cur; + last_pressed[key->code - SCANCODE_BASE] = cur; if (key->type == KE_KEY && /* Brightness is served via acpi video driver */ diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 2d61186ad5a2..e8c21994b36d 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -8497,7 +8497,6 @@ static void ibm_exit(struct ibm_struct *ibm) ibm->acpi->type, dispatch_acpi_notify); ibm->flags.acpi_notify_installed = 0; - ibm->flags.acpi_notify_installed = 0; } if (ibm->flags.proc_created) { diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 06f304f46e02..4276da7291b8 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -135,6 +135,7 @@ static const struct key_entry toshiba_acpi_keymap[] __initconst = { { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, { KE_KEY, 0x142, { KEY_WLAN } }, { KE_KEY, 0x143, { KEY_PROG1 } }, + { KE_KEY, 0x17f, { KEY_FN } }, { KE_KEY, 0xb05, { KEY_PROG2 } }, { KE_KEY, 0xb06, { KEY_WWW } }, { KE_KEY, 0xb07, { KEY_MAIL } }, diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 104b77c87ef5..aecd9a9b549f 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -755,7 +755,7 @@ static bool guid_already_parsed(const char *guid_string) struct wmi_block *wblock; list_for_each_entry(wblock, &wmi_block_list, list) - if (strncmp(wblock->gblock.guid, guid_string, 16) == 0) + if (memcmp(wblock->gblock.guid, guid_string, 16) == 0) return true; return false; diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 2d73dfcecdbb..57313f4658bc 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -180,7 +180,7 @@ struct pnp_protocol pnpacpi_protocol = { }; EXPORT_SYMBOL(pnpacpi_protocol); -static char *pnpacpi_get_id(struct acpi_device *device) +static char *__init pnpacpi_get_id(struct acpi_device *device) { struct acpi_hardware_id *id; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index f1d10c974cd4..ba521f0f0fac 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -911,7 +911,7 @@ out: } /** - * set_consumer_device_supply: Bind a regulator to a symbolic supply + * set_consumer_device_supply - Bind a regulator to a symbolic supply * @rdev: regulator source * @consumer_dev: device the supply applies to * @consumer_dev_name: dev_name() string for device supply applies to @@ -1052,7 +1052,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, printk(KERN_WARNING "%s: could not add device link %s err %d\n", __func__, dev->kobj.name, err); - device_remove_file(dev, ®ulator->dev_attr); goto link_name_err; } } @@ -1268,13 +1267,17 @@ static int _regulator_enable(struct regulator_dev *rdev) { int ret, delay; - /* do we need to enable the supply regulator first */ - if (rdev->supply) { - ret = _regulator_enable(rdev->supply); - if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s: %d\n", - __func__, rdev_get_name(rdev), ret); - return ret; + if (rdev->use_count == 0) { + /* do we need to enable the supply regulator first */ + if (rdev->supply) { + mutex_lock(&rdev->supply->mutex); + ret = _regulator_enable(rdev->supply); + mutex_unlock(&rdev->supply->mutex); + if (ret < 0) { + printk(KERN_ERR "%s: failed to enable %s: %d\n", + __func__, rdev_get_name(rdev), ret); + return ret; + } } } @@ -1313,10 +1316,12 @@ static int _regulator_enable(struct regulator_dev *rdev) if (ret < 0) return ret; - if (delay >= 1000) + if (delay >= 1000) { mdelay(delay / 1000); - else if (delay) + udelay(delay % 1000); + } else if (delay) { udelay(delay); + } } else if (ret < 0) { printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", @@ -1359,6 +1364,7 @@ static int _regulator_disable(struct regulator_dev *rdev, struct regulator_dev **supply_rdev_ptr) { int ret = 0; + *supply_rdev_ptr = NULL; if (WARN(rdev->use_count <= 0, "unbalanced disables for %s\n", @@ -2346,6 +2352,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (init_data->supply_regulator && init_data->supply_regulator_dev) { dev_err(dev, "Supply regulator specified by both name and dev\n"); + ret = -EINVAL; goto scrub; } @@ -2364,6 +2371,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (!found) { dev_err(dev, "Failed to find supply %s\n", init_data->supply_regulator); + ret = -ENODEV; goto scrub; } diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 4597d508a229..ecd99f59dba8 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -465,8 +465,8 @@ static struct regulator_ops mc13783_fixed_regulator_ops = { .get_voltage = mc13783_fixed_regulator_get_voltage, }; -int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask, - u32 val) +static int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask, + u32 val) { struct mc13783 *mc13783 = priv->mc13783; int ret; diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 51237fbb1bbb..6d20b0454a1d 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -231,8 +231,7 @@ static int tps6586x_dvm_voltages[] = { }; #define TPS6586X_REGULATOR(_id, vdata, _ops, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ -{ \ + ereg0, ebit0, ereg1, ebit1) \ .desc = { \ .name = "REG-" #_id, \ .ops = &tps6586x_regulator_##_ops, \ @@ -248,18 +247,26 @@ static int tps6586x_dvm_voltages[] = { .enable_bit[0] = (ebit0), \ .enable_reg[1] = TPS6586X_SUPPLY##ereg1, \ .enable_bit[1] = (ebit1), \ - .voltages = tps6586x_##vdata##_voltages, \ -} + .voltages = tps6586x_##vdata##_voltages, + +#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ + .go_reg = TPS6586X_##goreg, \ + .go_bit = (gobit), #define TPS6586X_LDO(_id, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ +{ \ TPS6586X_REGULATOR(_id, vdata, ldo_ops, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1, 0, 0) + ereg0, ebit0, ereg1, ebit1) \ +} #define TPS6586X_DVM(_id, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ +{ \ TPS6586X_REGULATOR(_id, vdata, dvm_ops, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1, goreg, gobit) + ereg0, ebit0, ereg1, ebit1) \ + TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ +} static struct tps6586x_regulator tps6586x_regulator[] = { TPS6586X_LDO(LDO_0, ldo, SUPPLYV1, 5, 3, ENC, 0, END, 0), @@ -267,11 +274,11 @@ static struct tps6586x_regulator tps6586x_regulator[] = { TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6), TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4), TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5), - TPS6586X_LDO(LDO_8, ldo, SUPPLYV1, 5, 3, ENC, 6, END, 6), + TPS6586X_LDO(LDO_8, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6), TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7), - TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, ENE, 7, ENE, 7), + TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7), TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1), - TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 1, END, 1), + TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7), TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6), TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6), @@ -290,6 +297,10 @@ static inline int tps6586x_regulator_preinit(struct device *parent, uint8_t val1, val2; int ret; + if (ri->enable_reg[0] == ri->enable_reg[1] && + ri->enable_bit[0] == ri->enable_bit[1]) + return 0; + ret = tps6586x_read(parent, ri->enable_reg[0], &val1); if (ret) return ret; @@ -298,14 +309,14 @@ static inline int tps6586x_regulator_preinit(struct device *parent, if (ret) return ret; - if (!(val2 & ri->enable_bit[1])) + if (!(val2 & (1 << ri->enable_bit[1]))) return 0; /* * The regulator is on, but it's enabled with the bit we don't * want to use, so we switch the enable bits */ - if (!(val1 & ri->enable_bit[0])) { + if (!(val1 & (1 << ri->enable_bit[0]))) { ret = tps6586x_set_bits(parent, ri->enable_reg[0], 1 << ri->enable_bit[0]); if (ret) diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 7e5892efc437..a57262a4fa6c 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -219,12 +219,12 @@ static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode) return -EACCES; status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, - message >> 8, 0x15 /* PB_WORD_MSB */ ); - if (status >= 0) + message >> 8, TWL4030_PM_MASTER_PB_WORD_MSB); + if (status < 0) return status; return twl_i2c_write_u8(TWL_MODULE_PM_MASTER, - message, 0x16 /* PB_WORD_LSB */ ); + message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB); } /*----------------------------------------------------------------------*/ diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index a5050e217150..825951b6b83f 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -635,7 +635,7 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) init_subchannel_id(&mchk_schid); mchk_schid.sch_no = crw0->rsid; if (crw1) - mchk_schid.ssid = (crw1->rsid >> 8) & 3; + mchk_schid.ssid = (crw1->rsid >> 4) & 3; /* * Since we are always presented with IPI in the CRW, we have to diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 752dbee06af5..5d9c66627b6e 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -292,8 +292,8 @@ void qdio_shutdown_thinint(struct qdio_irq *irq_ptr) return; /* reset adapter interrupt indicators */ - put_indicator(irq_ptr->dsci); set_subchannel_ind(irq_ptr, 1); + put_indicator(irq_ptr->dsci); } void __exit tiqdio_unregister_thinints(void) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index d37c7331f244..0bcd5806bd9a 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -156,6 +156,8 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) || a_status & ZFCP_STATUS_COMMON_ERP_FAILED) return 0; + if (p_status & ZFCP_STATUS_COMMON_NOESC) + return need; if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED)) need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; /* fall through */ @@ -188,6 +190,9 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &zfcp_sdev->status); erp_action = &zfcp_sdev->erp_action; + memset(erp_action, 0, sizeof(struct zfcp_erp_action)); + erp_action->port = port; + erp_action->sdev = sdev; if (!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_RUNNING)) act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; @@ -200,6 +205,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, zfcp_erp_action_dismiss_port(port); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); erp_action = &port->erp_action; + memset(erp_action, 0, sizeof(struct zfcp_erp_action)); + erp_action->port = port; if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; break; @@ -209,6 +216,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, zfcp_erp_action_dismiss_adapter(adapter); atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); erp_action = &adapter->erp_action; + memset(erp_action, 0, sizeof(struct zfcp_erp_action)); if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; @@ -218,10 +226,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, return NULL; } - memset(erp_action, 0, sizeof(struct zfcp_erp_action)); erp_action->adapter = adapter; - erp_action->port = port; - erp_action->sdev = sdev; erp_action->action = need; erp_action->status = act_status; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index be0317457147..2eb7dd56ab80 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -851,7 +851,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd) zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); - req->data = zfcp_sdev; + req->data = sdev; req->handler = zfcp_fsf_abort_fcp_command_handler; req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; req->qtcb->header.port_handle = zfcp_sdev->port->handle; @@ -2069,8 +2069,6 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req) struct fcp_resp_with_ext *fcp_rsp; unsigned long flags; - zfcp_fsf_fcp_handler_common(req); - read_lock_irqsave(&req->adapter->abort_lock, flags); scpnt = req->data; @@ -2079,6 +2077,8 @@ static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req) return; } + zfcp_fsf_fcp_handler_common(req); + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED); goto skip_fsfstatus; @@ -2170,12 +2170,13 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct zfcp_qdio *qdio = adapter->qdio; struct fsf_qtcb_bottom_io *io; + unsigned long flags; if (unlikely(!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) return -EBUSY; - spin_lock(&qdio->req_q_lock); + spin_lock_irqsave(&qdio->req_q_lock, flags); if (atomic_read(&qdio->req_q_free) <= 0) { atomic_inc(&qdio->req_q_full); goto out; @@ -2239,7 +2240,7 @@ failed_scsi_cmnd: zfcp_fsf_req_free(req); scsi_cmnd->host_scribble = NULL; out: - spin_unlock(&qdio->req_q_lock); + spin_unlock_irqrestore(&qdio->req_q_lock, flags); return retval; } diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 6bd2dbc4c316..63529ed801eb 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -76,8 +76,8 @@ static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) scpnt->scsi_done(scpnt); } -static int zfcp_scsi_queuecommand_lck(struct scsi_cmnd *scpnt, - void (*done) (struct scsi_cmnd *)) +static +int zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; @@ -87,7 +87,6 @@ static int zfcp_scsi_queuecommand_lck(struct scsi_cmnd *scpnt, /* reset the status for this request */ scpnt->result = 0; scpnt->host_scribble = NULL; - scpnt->scsi_done = done; scsi_result = fc_remote_port_chkready(rport); if (unlikely(scsi_result)) { @@ -127,8 +126,6 @@ static int zfcp_scsi_queuecommand_lck(struct scsi_cmnd *scpnt, return ret; } -static DEF_SCSI_QCMD(zfcp_scsi_queuecommand) - static int zfcp_scsi_slave_alloc(struct scsi_device *sdev) { struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h index 377cfb72cc66..f30f8d659dc4 100644 --- a/drivers/scsi/arm/fas216.h +++ b/drivers/scsi/arm/fas216.h @@ -345,7 +345,7 @@ extern int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt); * : SCpnt - Command to queue * Returns : 0 - success, else error */ -extern int fas216_noqueue_command(struct Scsi_Host *, struct scsi_cmnd *) +extern int fas216_noqueue_command(struct Scsi_Host *, struct scsi_cmnd *); /* Function: irqreturn_t fas216_intr (FAS216_Info *info) * Purpose : handle interrupts from the interface to progress a command diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b2fb2b2a6e70..a6dea08664fc 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -90,11 +90,7 @@ static const struct pci_device_id hpsa_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3252}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3253}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3254}, -#define PCI_DEVICE_ID_HP_CISSF 0x333f - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x333F}, - {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, - {PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, {0,} }; @@ -113,8 +109,6 @@ static struct board_type products[] = { {0x3249103C, "Smart Array P812", &SA5_access}, {0x324a103C, "Smart Array P712m", &SA5_access}, {0x324b103C, "Smart Array P711m", &SA5_access}, - {0x3233103C, "StorageWorks P1210m", &SA5_access}, - {0x333F103C, "StorageWorks P1210m", &SA5_access}, {0x3250103C, "Smart Array", &SA5_access}, {0x3250113C, "Smart Array", &SA5_access}, {0x3250123C, "Smart Array", &SA5_access}, diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 0433ea6f27c9..b37c8a3c1bb0 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -951,8 +951,8 @@ static int _osd_req_finalize_cdb_cont(struct osd_request *or, const u8 *cap_key) /* create a bio for continuation segment */ bio = bio_map_kern(req_q, or->cdb_cont.buff, or->cdb_cont.total_bytes, GFP_KERNEL); - if (unlikely(!bio)) - return -ENOMEM; + if (IS_ERR(bio)) + return PTR_ERR(bio); bio->bi_rw |= REQ_WRITE; diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 5e76a624cb08..300d59f389da 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -62,6 +62,7 @@ static unsigned int pmcraid_debug_log; static unsigned int pmcraid_disable_aen; static unsigned int pmcraid_log_level = IOASC_LOG_LEVEL_MUST; +static unsigned int pmcraid_enable_msix; /* * Data structures to support multiple adapters by the LLD. @@ -4691,7 +4692,8 @@ pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) int rc; struct pci_dev *pdev = pinstance->pdev; - if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) { + if ((pmcraid_enable_msix) && + (pci_find_capability(pdev, PCI_CAP_ID_MSIX))) { int num_hrrq = PMCRAID_NUM_MSIX_VECTORS; struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS]; int i; diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index 1134279604e8..4db210d93947 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -42,7 +42,7 @@ */ #define PMCRAID_DRIVER_NAME "PMC MaxRAID" #define PMCRAID_DEVFILE "pmcsas" -#define PMCRAID_DRIVER_VERSION "2.0.3" +#define PMCRAID_DRIVER_VERSION "1.0.3" #define PMCRAID_DRIVER_DATE __DATE__ #define PMCRAID_FW_VERSION_1 0x002 @@ -333,11 +333,9 @@ struct pmcraid_config_table_entry { __u8 lun[PMCRAID_LUN_LEN]; } __attribute__((packed, aligned(4))); -/* extended configuration table sizes are of 64 bytes in size */ -#define PMCRAID_CFGTE_EXT_SIZE 32 +/* extended configuration table sizes are also of 32 bytes in size */ struct pmcraid_config_table_entry_ext { struct pmcraid_config_table_entry cfgte; - __u8 cfgte_ext[PMCRAID_CFGTE_EXT_SIZE]; }; /* resource types (config_table_entry.resource_type values) */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 3a22effced5f..9ce539d4557e 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2409,7 +2409,6 @@ struct qla_hw_data { uint32_t enable_target_reset :1; uint32_t enable_lip_full_login :1; uint32_t enable_led_scheme :1; - uint32_t inta_enabled :1; uint32_t msi_enabled :1; uint32_t msix_enabled :1; uint32_t disable_serdes :1; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 5f94430b42f0..4c1ba6263eb3 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1061,6 +1061,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, fcp_cmnd->additional_cdb_len |= 2; int_to_scsilun(sp->cmd->device->lun, &fcp_cmnd->lun); + host_to_fcp_swap((uint8_t *)&fcp_cmnd->lun, sizeof(fcp_cmnd->lun)); memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len); cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32( diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 1f06ddd9bdd1..7f77898486a9 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2491,14 +2491,15 @@ skip_msix: skip_msi: ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, - IRQF_SHARED, QLA2XXX_DRIVER_NAME, rsp); + ha->flags.msi_enabled ? 0 : IRQF_SHARED, + QLA2XXX_DRIVER_NAME, rsp); if (ret) { qla_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d already in use.\n", ha->pdev->irq); goto fail; } - ha->flags.inta_enabled = 1; + clear_risc_ints: /* diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 8d9edfb39803..ae2acacc0003 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -2749,6 +2749,7 @@ sufficient_dsds: goto queuing_error_fcp_cmnd; int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); + host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); /* build FCP_CMND IU */ memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 1644eabaafeb..2c0876c81a3f 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -829,7 +829,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) { scsi_qla_host_t *vha = shost_priv(cmd->device->host); srb_t *sp; - int ret; + int ret = SUCCESS; unsigned int id, lun; unsigned long flags; int wait = 0; @@ -2064,6 +2064,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->init_cb_size = sizeof(struct mid_init_cb_81xx); ha->gid_list_info_size = 8; ha->optrom_size = OPTROM_SIZE_82XX; + ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; ha->isp_ops = &qla82xx_isp_ops; ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; ha->flash_data_off = FARX_ACCESS_FLASH_DATA; diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 8edbccb3232d..cf0075a2d0c2 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.04-k0" +#define QLA2XXX_VERSION "8.03.05-k0" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 -#define QLA_DRIVER_PATCH_VER 4 +#define QLA_DRIVER_PATCH_VER 5 #define QLA_DRIVER_BETA_VER 0 diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 824b8fc03ce5..30ac116186f5 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -615,7 +615,7 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) return rtn; } -static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd) +static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd) { if (!scmd->device->host->hostt->eh_abort_handler) return FAILED; @@ -623,31 +623,9 @@ static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd) return scmd->device->host->hostt->eh_abort_handler(scmd); } -/** - * scsi_try_to_abort_cmd - Ask host to abort a running command. - * @scmd: SCSI cmd to abort from Lower Level. - * - * Notes: - * This function will not return until the user's completion function - * has been called. there is no timeout on this operation. if the - * author of the low-level driver wishes this operation to be timed, - * they can provide this facility themselves. helper functions in - * scsi_error.c can be supplied to make this easier to do. - */ -static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd) -{ - /* - * scsi_done was called just after the command timed out and before - * we had a chance to process it. (db) - */ - if (scmd->serial_number == 0) - return SUCCESS; - return __scsi_try_to_abort_cmd(scmd); -} - static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd) { - if (__scsi_try_to_abort_cmd(scmd) != SUCCESS) + if (scsi_try_to_abort_cmd(scmd) != SUCCESS) if (scsi_try_bus_device_reset(scmd) != SUCCESS) if (scsi_try_target_reset(scmd) != SUCCESS) if (scsi_try_bus_reset(scmd) != SUCCESS) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index eafeeda6e194..4a3842212c50 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1403,11 +1403,6 @@ static void scsi_softirq_done(struct request *rq) INIT_LIST_HEAD(&cmd->eh_entry); - /* - * Set the serial numbers back to zero - */ - cmd->serial_number = 0; - atomic_inc(&cmd->device->iodone_cnt); if (cmd->result) atomic_inc(&cmd->device->ioerr_cnt); @@ -1642,9 +1637,8 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, blk_queue_max_segment_size(q, dma_get_max_seg_size(dev)); - /* New queue, no concurrency on queue_flags */ if (!shost->use_clustering) - queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); + q->limits.cluster = 0; /* * set a reasonable default alignment on word boundaries: the diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 4d8e14b7aa93..09a550860dcf 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2872,7 +2872,7 @@ static struct console serial8250_console = { .device = uart_console_device, .setup = serial8250_console_setup, .early_setup = serial8250_console_early_setup, - .flags = CON_PRINTBUFFER, + .flags = CON_PRINTBUFFER | CON_ANYTIME, .index = -1, .data = &serial8250_reg, }; diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index 3374618300af..25a8bc565f40 100644 --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -90,7 +90,8 @@ static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper); static void kgdboc_restore_input(void) { - schedule_work(&kgdboc_restore_input_work); + if (likely(system_state == SYSTEM_RUNNING)) + schedule_work(&kgdboc_restore_input_work); } static int kgdboc_register_kbd(char **cptr) diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c index 5fc699e929dc..d40010a22ecd 100644 --- a/drivers/serial/mfd.c +++ b/drivers/serial/mfd.c @@ -900,8 +900,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, unsigned char cval, fcr = 0; unsigned long flags; unsigned int baud, quot; - u32 mul = 0x3600; - u32 ps = 0x10; + u32 ps, mul; switch (termios->c_cflag & CSIZE) { case CS5: @@ -943,31 +942,24 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, 4000000); quot = 1; + ps = 0x10; + mul = 0x3600; switch (baud) { case 3500000: mul = 0x3345; ps = 0xC; break; - case 3000000: - mul = 0x2EE0; - break; - case 2500000: - mul = 0x2710; - break; - case 2000000: - mul = 0x1F40; - break; case 1843200: mul = 0x2400; break; + case 3000000: + case 2500000: + case 2000000: case 1500000: - mul = 0x1770; - break; case 1000000: - mul = 0xFA0; - break; case 500000: - mul = 0x7D0; + /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */ + mul = baud / 500000 * 0x9C4; break; default: /* Use uart_get_divisor to get quot for other baud rates */ diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index cb12a8e1466b..3f5e387ed564 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -418,8 +418,11 @@ int clk_register(struct clk *clk) list_add(&clk->sibling, &root_clks); list_add(&clk->node, &clock_list); + +#ifdef CONFIG_SH_CLK_CPG_LEGACY if (clk->ops && clk->ops->init) clk->ops->init(clk); +#endif out_unlock: mutex_unlock(&clock_list_sem); @@ -455,19 +458,13 @@ 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; unsigned long flags; spin_lock_irqsave(&clock_lock, flags); if (likely(clk->ops && clk->ops->set_rate)) { - ret = clk->ops->set_rate(clk, rate, algo_id); + ret = clk->ops->set_rate(clk, rate); if (ret != 0) goto out_unlock; } else { @@ -485,7 +482,7 @@ out_unlock: return ret; } -EXPORT_SYMBOL_GPL(clk_set_rate_ex); +EXPORT_SYMBOL_GPL(clk_set_rate); int clk_set_parent(struct clk *clk, struct clk *parent) { @@ -653,8 +650,7 @@ static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state) clkp->ops->set_parent(clkp, clkp->parent); if (likely(clkp->ops->set_rate)) - clkp->ops->set_rate(clkp, - rate, NO_CHANGE); + clkp->ops->set_rate(clkp, rate); else if (likely(clkp->ops->recalc)) clkp->rate = clkp->ops->recalc(clkp); } diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index 3aea5f0ceb09..6172335ae323 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c @@ -110,8 +110,7 @@ static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent) return 0; } -static int sh_clk_div6_set_rate(struct clk *clk, - unsigned long rate, int algo_id) +static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate) { unsigned long value; int idx; @@ -132,7 +131,7 @@ static int sh_clk_div6_enable(struct clk *clk) unsigned long value; int ret; - ret = sh_clk_div6_set_rate(clk, clk->rate, 0); + ret = sh_clk_div6_set_rate(clk, clk->rate); if (ret == 0) { value = __raw_readl(clk->enable_reg); value &= ~0x100; /* clear stop bit to enable clock */ @@ -253,7 +252,7 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent) return 0; } -static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate, int algo_id) +static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate) { struct clk_div4_table *d4t = clk->priv; unsigned long value; diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 154529aacc03..a067046c9da2 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -352,8 +352,12 @@ atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer) xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS; if (xfer->tx_buf) { + /* tx_buf is a const void* where we need a void * for the dma + * mapping */ + void *nonconst_tx = (void *)xfer->tx_buf; + xfer->tx_dma = dma_map_single(dev, - (void *) xfer->tx_buf, xfer->len, + nonconst_tx, xfer->len, DMA_TO_DEVICE); if (dma_mapping_error(dev, xfer->tx_dma)) return -ENOMEM; diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 90439314cf67..0838c79861e4 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -413,6 +413,11 @@ static void poll_transfer(struct dw_spi *dws) { while (dws->write(dws)) dws->read(dws); + /* + * There is a possibility that the last word of a transaction + * will be lost if data is not ready. Re-read to solve this issue. + */ + dws->read(dws); transfer_complete(dws); } diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c index ef9c6a04ad8f..744d3f6e4709 100644 --- a/drivers/ssb/b43_pci_bridge.c +++ b/drivers/ssb/b43_pci_bridge.c @@ -24,6 +24,7 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4315) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) }, + { PCI_DEVICE(PCI_VENDOR_ID_BCM_GVC, 0x4318) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) }, diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c index 8c95d8c2a4f4..016c6f7f8630 100644 --- a/drivers/staging/asus_oled/asus_oled.c +++ b/drivers/staging/asus_oled/asus_oled.c @@ -620,13 +620,13 @@ static ssize_t class_set_picture(struct device *device, #define ASUS_OLED_DEVICE_ATTR(_file) dev_attr_asus_oled_##_file -static DEVICE_ATTR(asus_oled_enabled, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(asus_oled_enabled, S_IWUSR | S_IRUGO, get_enabled, set_enabled); -static DEVICE_ATTR(asus_oled_picture, S_IWUGO , NULL, set_picture); +static DEVICE_ATTR(asus_oled_picture, S_IWUSR , NULL, set_picture); -static DEVICE_ATTR(enabled, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO, class_get_enabled, class_set_enabled); -static DEVICE_ATTR(picture, S_IWUGO, NULL, class_set_picture); +static DEVICE_ATTR(picture, S_IWUSR, NULL, class_set_picture); static int asus_oled_probe(struct usb_interface *interface, const struct usb_device_id *id) diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index b68a7e5173be..d85de82f941a 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -463,9 +463,6 @@ static void hardif_remove_interface(struct batman_if *batman_if) return; batman_if->if_status = IF_TO_BE_REMOVED; - - /* caller must take if_list_lock */ - list_del_rcu(&batman_if->list); synchronize_rcu(); sysfs_del_hardif(&batman_if->hardif_obj); hardif_put(batman_if); @@ -474,13 +471,21 @@ static void hardif_remove_interface(struct batman_if *batman_if) void hardif_remove_interfaces(void) { struct batman_if *batman_if, *batman_if_tmp; + struct list_head if_queue; + + INIT_LIST_HEAD(&if_queue); - rtnl_lock(); spin_lock(&if_list_lock); list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) { - hardif_remove_interface(batman_if); + list_del_rcu(&batman_if->list); + list_add_tail(&batman_if->list, &if_queue); } spin_unlock(&if_list_lock); + + rtnl_lock(); + list_for_each_entry_safe(batman_if, batman_if_tmp, &if_queue, list) { + hardif_remove_interface(batman_if); + } rtnl_unlock(); } @@ -507,8 +512,10 @@ static int hard_if_event(struct notifier_block *this, break; case NETDEV_UNREGISTER: spin_lock(&if_list_lock); - hardif_remove_interface(batman_if); + list_del_rcu(&batman_if->list); spin_unlock(&if_list_lock); + + hardif_remove_interface(batman_if); break; case NETDEV_CHANGEMTU: if (batman_if->soft_iface) diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index 3904db9ce7b1..0e996181daf7 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -194,14 +194,15 @@ void interface_rx(struct net_device *soft_iface, struct bat_priv *priv = netdev_priv(soft_iface); /* check if enough space is available for pulling, and pull */ - if (!pskb_may_pull(skb, hdr_size)) { - kfree_skb(skb); - return; - } + if (!pskb_may_pull(skb, hdr_size)) + goto dropped; + skb_pull_rcsum(skb, hdr_size); /* skb_set_mac_header(skb, -sizeof(struct ethhdr));*/ /* skb->dev & skb->pkt_type are set here */ + if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) + goto dropped; skb->protocol = eth_type_trans(skb, soft_iface); /* should not be neccesary anymore as we use skb_pull_rcsum() @@ -216,6 +217,11 @@ void interface_rx(struct net_device *soft_iface, soft_iface->last_rx = jiffies; netif_rx(skb); + return; + +dropped: + kfree_skb(skb); + return; } #ifdef HAVE_NET_DEVICE_OPS diff --git a/drivers/staging/brcm80211/README b/drivers/staging/brcm80211/README index c8f1cf1b4409..a27bb0b4f581 100644 --- a/drivers/staging/brcm80211/README +++ b/drivers/staging/brcm80211/README @@ -88,7 +88,9 @@ with the driver. Contact Info: ============= -Brett Rudley brudley@broadcom.com -Henry Ptasinski henryp@broadcom.com -Dowan Kim dowan@broadcom.com +Brett Rudley brudley@broadcom.com +Henry Ptasinski henryp@broadcom.com +Dowan Kim dowan@broadcom.com +Roland Vossen rvossen@broadcom.com +Arend van Spriel arend@broadcom.com diff --git a/drivers/staging/brcm80211/TODO b/drivers/staging/brcm80211/TODO index dbf904184899..24ebadbe4241 100644 --- a/drivers/staging/brcm80211/TODO +++ b/drivers/staging/brcm80211/TODO @@ -46,4 +46,6 @@ Contact Brett Rudley <brudley@broadcom.com> Henry Ptasinski <henryp@broadcom.com> Dowan Kim <dowan@broadcom.com> +Roland Vossen <rvossen@broadcom.com> +Arend van Spriel <arend@broadcom.com> diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 1f177a67ff11..de784ff08caa 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -2295,8 +2295,8 @@ static void tidy_up(struct usbduxsub *usbduxsub_tmp) usbduxsub_tmp->inBuffer = NULL; kfree(usbduxsub_tmp->insnBuffer); usbduxsub_tmp->insnBuffer = NULL; - kfree(usbduxsub_tmp->inBuffer); - usbduxsub_tmp->inBuffer = NULL; + kfree(usbduxsub_tmp->outBuffer); + usbduxsub_tmp->outBuffer = NULL; kfree(usbduxsub_tmp->dac_commands); usbduxsub_tmp->dac_commands = NULL; kfree(usbduxsub_tmp->dux_commands); diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/staging/cx25821/cx25821-video.c index e7f1d5778cec..52389308f333 100644 --- a/drivers/staging/cx25821/cx25821-video.c +++ b/drivers/staging/cx25821/cx25821-video.c @@ -92,7 +92,7 @@ int cx25821_get_format_size(void) return ARRAY_SIZE(formats); } -struct cx25821_fmt *format_by_fourcc(unsigned int fourcc) +struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc) { unsigned int i; @@ -848,7 +848,7 @@ static int video_open(struct file *file) pix_format = (dev->channels[ch_id].pixel_formats == PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV; - fh->fmt = format_by_fourcc(pix_format); + fh->fmt = cx25821_format_by_fourcc(pix_format); v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio); @@ -1010,7 +1010,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (0 != err) return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); fh->vidq.field = f->fmt.pix.field; /* check if width and height is valid based on set standard */ @@ -1119,7 +1119,7 @@ int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fo enum v4l2_field field; unsigned int maxw, maxh; - fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL; diff --git a/drivers/staging/cx25821/cx25821-video.h b/drivers/staging/cx25821/cx25821-video.h index cc6034b1a95d..a2415d33235b 100644 --- a/drivers/staging/cx25821/cx25821-video.h +++ b/drivers/staging/cx25821/cx25821-video.h @@ -87,7 +87,7 @@ extern unsigned int vid_limit; #define FORMAT_FLAGS_PACKED 0x01 extern struct cx25821_fmt formats[]; -extern struct cx25821_fmt *format_by_fourcc(unsigned int fourcc); +extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc); extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM]; extern void cx25821_dump_video_queue(struct cx25821_dev *dev, diff --git a/drivers/staging/cx25821/cx25821.h b/drivers/staging/cx25821/cx25821.h index acfd0176a184..c94000125782 100644 --- a/drivers/staging/cx25821/cx25821.h +++ b/drivers/staging/cx25821/cx25821.h @@ -31,6 +31,7 @@ #include <linux/delay.h> #include <linux/sched.h> #include <linux/kdev_t.h> +#include <linux/smp_lock.h> #include <media/v4l2-common.h> #include <media/v4l2-device.h> diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h index 25961c23dc0f..884263b2775d 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/easycap/easycap.h @@ -75,6 +75,7 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/module.h> #include <linux/kref.h> #include <linux/usb.h> diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c index a145a15cfdb3..8894ab14f167 100644 --- a/drivers/staging/frontier/tranzport.c +++ b/drivers/staging/frontier/tranzport.c @@ -204,7 +204,7 @@ static void usb_tranzport_abort_transfers(struct usb_tranzport *dev) t->value = temp; \ return count; \ } \ - static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value); + static DEVICE_ATTR(value, S_IWUSR | S_IRUGO, show_##value, set_##value); show_int(enable); show_int(offline); diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c index b3f42f37a313..48d4e483d8a4 100644 --- a/drivers/staging/go7007/go7007-driver.c +++ b/drivers/staging/go7007/go7007-driver.c @@ -199,7 +199,7 @@ static int init_i2c_module(struct i2c_adapter *adapter, const char *type, struct go7007 *go = i2c_get_adapdata(adapter); struct v4l2_device *v4l2_dev = &go->v4l2_dev; - if (v4l2_i2c_new_subdev(v4l2_dev, adapter, NULL, type, addr, NULL)) + if (v4l2_i2c_new_subdev(v4l2_dev, adapter, type, addr, NULL)) return 0; printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", type); diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c index c86d1498737d..1c1e98aee2d9 100644 --- a/drivers/staging/iio/accel/adis16220_core.c +++ b/drivers/staging/iio/accel/adis16220_core.c @@ -507,7 +507,7 @@ static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16220_write_reset, 0); #define IIO_DEV_ATTR_CAPTURE(_store) \ - IIO_DEVICE_ATTR(capture, S_IWUGO, NULL, _store, 0) + IIO_DEVICE_ATTR(capture, S_IWUSR, NULL, _store, 0) static IIO_DEV_ATTR_CAPTURE(adis16220_write_capture); diff --git a/drivers/staging/intel_sst/intel_sst_stream_encoded.c b/drivers/staging/intel_sst/intel_sst_stream_encoded.c index fbae39fda5c0..5c455608b024 100644 --- a/drivers/staging/intel_sst/intel_sst_stream_encoded.c +++ b/drivers/staging/intel_sst/intel_sst_stream_encoded.c @@ -1269,7 +1269,7 @@ finish: dbufs->output_bytes_produced = total_output; str_info->status = str_info->prev; str_info->prev = STREAM_DECODE; - str_info->decode_ibuf = NULL; kfree(str_info->decode_ibuf); + str_info->decode_ibuf = NULL; return retval; } diff --git a/drivers/staging/line6/control.c b/drivers/staging/line6/control.c index 040e25ca6d33..67e23b6e2d35 100644 --- a/drivers/staging/line6/control.c +++ b/drivers/staging/line6/control.c @@ -266,210 +266,210 @@ VARIAX_PARAM_R(float, mix2); VARIAX_PARAM_R(float, mix1); VARIAX_PARAM_R(int, pickup_wiring); -static DEVICE_ATTR(tweak, S_IWUGO | S_IRUGO, pod_get_tweak, pod_set_tweak); -static DEVICE_ATTR(wah_position, S_IWUGO | S_IRUGO, pod_get_wah_position, +static DEVICE_ATTR(tweak, S_IWUSR | S_IRUGO, pod_get_tweak, pod_set_tweak); +static DEVICE_ATTR(wah_position, S_IWUSR | S_IRUGO, pod_get_wah_position, pod_set_wah_position); -static DEVICE_ATTR(compression_gain, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(compression_gain, S_IWUSR | S_IRUGO, pod_get_compression_gain, pod_set_compression_gain); -static DEVICE_ATTR(vol_pedal_position, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(vol_pedal_position, S_IWUSR | S_IRUGO, pod_get_vol_pedal_position, pod_set_vol_pedal_position); -static DEVICE_ATTR(compression_threshold, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(compression_threshold, S_IWUSR | S_IRUGO, pod_get_compression_threshold, pod_set_compression_threshold); -static DEVICE_ATTR(pan, S_IWUGO | S_IRUGO, pod_get_pan, pod_set_pan); -static DEVICE_ATTR(amp_model_setup, S_IWUGO | S_IRUGO, pod_get_amp_model_setup, +static DEVICE_ATTR(pan, S_IWUSR | S_IRUGO, pod_get_pan, pod_set_pan); +static DEVICE_ATTR(amp_model_setup, S_IWUSR | S_IRUGO, pod_get_amp_model_setup, pod_set_amp_model_setup); -static DEVICE_ATTR(amp_model, S_IWUGO | S_IRUGO, pod_get_amp_model, +static DEVICE_ATTR(amp_model, S_IWUSR | S_IRUGO, pod_get_amp_model, pod_set_amp_model); -static DEVICE_ATTR(drive, S_IWUGO | S_IRUGO, pod_get_drive, pod_set_drive); -static DEVICE_ATTR(bass, S_IWUGO | S_IRUGO, pod_get_bass, pod_set_bass); -static DEVICE_ATTR(mid, S_IWUGO | S_IRUGO, pod_get_mid, pod_set_mid); -static DEVICE_ATTR(lowmid, S_IWUGO | S_IRUGO, pod_get_lowmid, pod_set_lowmid); -static DEVICE_ATTR(treble, S_IWUGO | S_IRUGO, pod_get_treble, pod_set_treble); -static DEVICE_ATTR(highmid, S_IWUGO | S_IRUGO, pod_get_highmid, +static DEVICE_ATTR(drive, S_IWUSR | S_IRUGO, pod_get_drive, pod_set_drive); +static DEVICE_ATTR(bass, S_IWUSR | S_IRUGO, pod_get_bass, pod_set_bass); +static DEVICE_ATTR(mid, S_IWUSR | S_IRUGO, pod_get_mid, pod_set_mid); +static DEVICE_ATTR(lowmid, S_IWUSR | S_IRUGO, pod_get_lowmid, pod_set_lowmid); +static DEVICE_ATTR(treble, S_IWUSR | S_IRUGO, pod_get_treble, pod_set_treble); +static DEVICE_ATTR(highmid, S_IWUSR | S_IRUGO, pod_get_highmid, pod_set_highmid); -static DEVICE_ATTR(chan_vol, S_IWUGO | S_IRUGO, pod_get_chan_vol, +static DEVICE_ATTR(chan_vol, S_IWUSR | S_IRUGO, pod_get_chan_vol, pod_set_chan_vol); -static DEVICE_ATTR(reverb_mix, S_IWUGO | S_IRUGO, pod_get_reverb_mix, +static DEVICE_ATTR(reverb_mix, S_IWUSR | S_IRUGO, pod_get_reverb_mix, pod_set_reverb_mix); -static DEVICE_ATTR(effect_setup, S_IWUGO | S_IRUGO, pod_get_effect_setup, +static DEVICE_ATTR(effect_setup, S_IWUSR | S_IRUGO, pod_get_effect_setup, pod_set_effect_setup); -static DEVICE_ATTR(band_1_frequency, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(band_1_frequency, S_IWUSR | S_IRUGO, pod_get_band_1_frequency, pod_set_band_1_frequency); -static DEVICE_ATTR(presence, S_IWUGO | S_IRUGO, pod_get_presence, +static DEVICE_ATTR(presence, S_IWUSR | S_IRUGO, pod_get_presence, pod_set_presence); -static DEVICE_ATTR2(treble__bass, treble, S_IWUGO | S_IRUGO, +static DEVICE_ATTR2(treble__bass, treble, S_IWUSR | S_IRUGO, pod_get_treble__bass, pod_set_treble__bass); -static DEVICE_ATTR(noise_gate_enable, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(noise_gate_enable, S_IWUSR | S_IRUGO, pod_get_noise_gate_enable, pod_set_noise_gate_enable); -static DEVICE_ATTR(gate_threshold, S_IWUGO | S_IRUGO, pod_get_gate_threshold, +static DEVICE_ATTR(gate_threshold, S_IWUSR | S_IRUGO, pod_get_gate_threshold, pod_set_gate_threshold); -static DEVICE_ATTR(gate_decay_time, S_IWUGO | S_IRUGO, pod_get_gate_decay_time, +static DEVICE_ATTR(gate_decay_time, S_IWUSR | S_IRUGO, pod_get_gate_decay_time, pod_set_gate_decay_time); -static DEVICE_ATTR(stomp_enable, S_IWUGO | S_IRUGO, pod_get_stomp_enable, +static DEVICE_ATTR(stomp_enable, S_IWUSR | S_IRUGO, pod_get_stomp_enable, pod_set_stomp_enable); -static DEVICE_ATTR(comp_enable, S_IWUGO | S_IRUGO, pod_get_comp_enable, +static DEVICE_ATTR(comp_enable, S_IWUSR | S_IRUGO, pod_get_comp_enable, pod_set_comp_enable); -static DEVICE_ATTR(stomp_time, S_IWUGO | S_IRUGO, pod_get_stomp_time, +static DEVICE_ATTR(stomp_time, S_IWUSR | S_IRUGO, pod_get_stomp_time, pod_set_stomp_time); -static DEVICE_ATTR(delay_enable, S_IWUGO | S_IRUGO, pod_get_delay_enable, +static DEVICE_ATTR(delay_enable, S_IWUSR | S_IRUGO, pod_get_delay_enable, pod_set_delay_enable); -static DEVICE_ATTR(mod_param_1, S_IWUGO | S_IRUGO, pod_get_mod_param_1, +static DEVICE_ATTR(mod_param_1, S_IWUSR | S_IRUGO, pod_get_mod_param_1, pod_set_mod_param_1); -static DEVICE_ATTR(delay_param_1, S_IWUGO | S_IRUGO, pod_get_delay_param_1, +static DEVICE_ATTR(delay_param_1, S_IWUSR | S_IRUGO, pod_get_delay_param_1, pod_set_delay_param_1); -static DEVICE_ATTR(delay_param_1_note_value, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(delay_param_1_note_value, S_IWUSR | S_IRUGO, pod_get_delay_param_1_note_value, pod_set_delay_param_1_note_value); -static DEVICE_ATTR2(band_2_frequency__bass, band_2_frequency, S_IWUGO | S_IRUGO, +static DEVICE_ATTR2(band_2_frequency__bass, band_2_frequency, S_IWUSR | S_IRUGO, pod_get_band_2_frequency__bass, pod_set_band_2_frequency__bass); -static DEVICE_ATTR(delay_param_2, S_IWUGO | S_IRUGO, pod_get_delay_param_2, +static DEVICE_ATTR(delay_param_2, S_IWUSR | S_IRUGO, pod_get_delay_param_2, pod_set_delay_param_2); -static DEVICE_ATTR(delay_volume_mix, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(delay_volume_mix, S_IWUSR | S_IRUGO, pod_get_delay_volume_mix, pod_set_delay_volume_mix); -static DEVICE_ATTR(delay_param_3, S_IWUGO | S_IRUGO, pod_get_delay_param_3, +static DEVICE_ATTR(delay_param_3, S_IWUSR | S_IRUGO, pod_get_delay_param_3, pod_set_delay_param_3); -static DEVICE_ATTR(reverb_enable, S_IWUGO | S_IRUGO, pod_get_reverb_enable, +static DEVICE_ATTR(reverb_enable, S_IWUSR | S_IRUGO, pod_get_reverb_enable, pod_set_reverb_enable); -static DEVICE_ATTR(reverb_type, S_IWUGO | S_IRUGO, pod_get_reverb_type, +static DEVICE_ATTR(reverb_type, S_IWUSR | S_IRUGO, pod_get_reverb_type, pod_set_reverb_type); -static DEVICE_ATTR(reverb_decay, S_IWUGO | S_IRUGO, pod_get_reverb_decay, +static DEVICE_ATTR(reverb_decay, S_IWUSR | S_IRUGO, pod_get_reverb_decay, pod_set_reverb_decay); -static DEVICE_ATTR(reverb_tone, S_IWUGO | S_IRUGO, pod_get_reverb_tone, +static DEVICE_ATTR(reverb_tone, S_IWUSR | S_IRUGO, pod_get_reverb_tone, pod_set_reverb_tone); -static DEVICE_ATTR(reverb_pre_delay, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(reverb_pre_delay, S_IWUSR | S_IRUGO, pod_get_reverb_pre_delay, pod_set_reverb_pre_delay); -static DEVICE_ATTR(reverb_pre_post, S_IWUGO | S_IRUGO, pod_get_reverb_pre_post, +static DEVICE_ATTR(reverb_pre_post, S_IWUSR | S_IRUGO, pod_get_reverb_pre_post, pod_set_reverb_pre_post); -static DEVICE_ATTR(band_2_frequency, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(band_2_frequency, S_IWUSR | S_IRUGO, pod_get_band_2_frequency, pod_set_band_2_frequency); -static DEVICE_ATTR2(band_3_frequency__bass, band_3_frequency, S_IWUGO | S_IRUGO, +static DEVICE_ATTR2(band_3_frequency__bass, band_3_frequency, S_IWUSR | S_IRUGO, pod_get_band_3_frequency__bass, pod_set_band_3_frequency__bass); -static DEVICE_ATTR(wah_enable, S_IWUGO | S_IRUGO, pod_get_wah_enable, +static DEVICE_ATTR(wah_enable, S_IWUSR | S_IRUGO, pod_get_wah_enable, pod_set_wah_enable); -static DEVICE_ATTR(modulation_lo_cut, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(modulation_lo_cut, S_IWUSR | S_IRUGO, pod_get_modulation_lo_cut, pod_set_modulation_lo_cut); -static DEVICE_ATTR(delay_reverb_lo_cut, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(delay_reverb_lo_cut, S_IWUSR | S_IRUGO, pod_get_delay_reverb_lo_cut, pod_set_delay_reverb_lo_cut); -static DEVICE_ATTR(volume_pedal_minimum, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(volume_pedal_minimum, S_IWUSR | S_IRUGO, pod_get_volume_pedal_minimum, pod_set_volume_pedal_minimum); -static DEVICE_ATTR(eq_pre_post, S_IWUGO | S_IRUGO, pod_get_eq_pre_post, +static DEVICE_ATTR(eq_pre_post, S_IWUSR | S_IRUGO, pod_get_eq_pre_post, pod_set_eq_pre_post); -static DEVICE_ATTR(volume_pre_post, S_IWUGO | S_IRUGO, pod_get_volume_pre_post, +static DEVICE_ATTR(volume_pre_post, S_IWUSR | S_IRUGO, pod_get_volume_pre_post, pod_set_volume_pre_post); -static DEVICE_ATTR(di_model, S_IWUGO | S_IRUGO, pod_get_di_model, +static DEVICE_ATTR(di_model, S_IWUSR | S_IRUGO, pod_get_di_model, pod_set_di_model); -static DEVICE_ATTR(di_delay, S_IWUGO | S_IRUGO, pod_get_di_delay, +static DEVICE_ATTR(di_delay, S_IWUSR | S_IRUGO, pod_get_di_delay, pod_set_di_delay); -static DEVICE_ATTR(mod_enable, S_IWUGO | S_IRUGO, pod_get_mod_enable, +static DEVICE_ATTR(mod_enable, S_IWUSR | S_IRUGO, pod_get_mod_enable, pod_set_mod_enable); -static DEVICE_ATTR(mod_param_1_note_value, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(mod_param_1_note_value, S_IWUSR | S_IRUGO, pod_get_mod_param_1_note_value, pod_set_mod_param_1_note_value); -static DEVICE_ATTR(mod_param_2, S_IWUGO | S_IRUGO, pod_get_mod_param_2, +static DEVICE_ATTR(mod_param_2, S_IWUSR | S_IRUGO, pod_get_mod_param_2, pod_set_mod_param_2); -static DEVICE_ATTR(mod_param_3, S_IWUGO | S_IRUGO, pod_get_mod_param_3, +static DEVICE_ATTR(mod_param_3, S_IWUSR | S_IRUGO, pod_get_mod_param_3, pod_set_mod_param_3); -static DEVICE_ATTR(mod_param_4, S_IWUGO | S_IRUGO, pod_get_mod_param_4, +static DEVICE_ATTR(mod_param_4, S_IWUSR | S_IRUGO, pod_get_mod_param_4, pod_set_mod_param_4); -static DEVICE_ATTR(mod_param_5, S_IWUGO | S_IRUGO, pod_get_mod_param_5, +static DEVICE_ATTR(mod_param_5, S_IWUSR | S_IRUGO, pod_get_mod_param_5, pod_set_mod_param_5); -static DEVICE_ATTR(mod_volume_mix, S_IWUGO | S_IRUGO, pod_get_mod_volume_mix, +static DEVICE_ATTR(mod_volume_mix, S_IWUSR | S_IRUGO, pod_get_mod_volume_mix, pod_set_mod_volume_mix); -static DEVICE_ATTR(mod_pre_post, S_IWUGO | S_IRUGO, pod_get_mod_pre_post, +static DEVICE_ATTR(mod_pre_post, S_IWUSR | S_IRUGO, pod_get_mod_pre_post, pod_set_mod_pre_post); -static DEVICE_ATTR(modulation_model, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(modulation_model, S_IWUSR | S_IRUGO, pod_get_modulation_model, pod_set_modulation_model); -static DEVICE_ATTR(band_3_frequency, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(band_3_frequency, S_IWUSR | S_IRUGO, pod_get_band_3_frequency, pod_set_band_3_frequency); -static DEVICE_ATTR2(band_4_frequency__bass, band_4_frequency, S_IWUGO | S_IRUGO, +static DEVICE_ATTR2(band_4_frequency__bass, band_4_frequency, S_IWUSR | S_IRUGO, pod_get_band_4_frequency__bass, pod_set_band_4_frequency__bass); -static DEVICE_ATTR(mod_param_1_double_precision, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(mod_param_1_double_precision, S_IWUSR | S_IRUGO, pod_get_mod_param_1_double_precision, pod_set_mod_param_1_double_precision); -static DEVICE_ATTR(delay_param_1_double_precision, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(delay_param_1_double_precision, S_IWUSR | S_IRUGO, pod_get_delay_param_1_double_precision, pod_set_delay_param_1_double_precision); -static DEVICE_ATTR(eq_enable, S_IWUGO | S_IRUGO, pod_get_eq_enable, +static DEVICE_ATTR(eq_enable, S_IWUSR | S_IRUGO, pod_get_eq_enable, pod_set_eq_enable); -static DEVICE_ATTR(tap, S_IWUGO | S_IRUGO, pod_get_tap, pod_set_tap); -static DEVICE_ATTR(volume_tweak_pedal_assign, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(tap, S_IWUSR | S_IRUGO, pod_get_tap, pod_set_tap); +static DEVICE_ATTR(volume_tweak_pedal_assign, S_IWUSR | S_IRUGO, pod_get_volume_tweak_pedal_assign, pod_set_volume_tweak_pedal_assign); -static DEVICE_ATTR(band_5_frequency, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(band_5_frequency, S_IWUSR | S_IRUGO, pod_get_band_5_frequency, pod_set_band_5_frequency); -static DEVICE_ATTR(tuner, S_IWUGO | S_IRUGO, pod_get_tuner, pod_set_tuner); -static DEVICE_ATTR(mic_selection, S_IWUGO | S_IRUGO, pod_get_mic_selection, +static DEVICE_ATTR(tuner, S_IWUSR | S_IRUGO, pod_get_tuner, pod_set_tuner); +static DEVICE_ATTR(mic_selection, S_IWUSR | S_IRUGO, pod_get_mic_selection, pod_set_mic_selection); -static DEVICE_ATTR(cabinet_model, S_IWUGO | S_IRUGO, pod_get_cabinet_model, +static DEVICE_ATTR(cabinet_model, S_IWUSR | S_IRUGO, pod_get_cabinet_model, pod_set_cabinet_model); -static DEVICE_ATTR(stomp_model, S_IWUGO | S_IRUGO, pod_get_stomp_model, +static DEVICE_ATTR(stomp_model, S_IWUSR | S_IRUGO, pod_get_stomp_model, pod_set_stomp_model); -static DEVICE_ATTR(roomlevel, S_IWUGO | S_IRUGO, pod_get_roomlevel, +static DEVICE_ATTR(roomlevel, S_IWUSR | S_IRUGO, pod_get_roomlevel, pod_set_roomlevel); -static DEVICE_ATTR(band_4_frequency, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(band_4_frequency, S_IWUSR | S_IRUGO, pod_get_band_4_frequency, pod_set_band_4_frequency); -static DEVICE_ATTR(band_6_frequency, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(band_6_frequency, S_IWUSR | S_IRUGO, pod_get_band_6_frequency, pod_set_band_6_frequency); -static DEVICE_ATTR(stomp_param_1_note_value, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(stomp_param_1_note_value, S_IWUSR | S_IRUGO, pod_get_stomp_param_1_note_value, pod_set_stomp_param_1_note_value); -static DEVICE_ATTR(stomp_param_2, S_IWUGO | S_IRUGO, pod_get_stomp_param_2, +static DEVICE_ATTR(stomp_param_2, S_IWUSR | S_IRUGO, pod_get_stomp_param_2, pod_set_stomp_param_2); -static DEVICE_ATTR(stomp_param_3, S_IWUGO | S_IRUGO, pod_get_stomp_param_3, +static DEVICE_ATTR(stomp_param_3, S_IWUSR | S_IRUGO, pod_get_stomp_param_3, pod_set_stomp_param_3); -static DEVICE_ATTR(stomp_param_4, S_IWUGO | S_IRUGO, pod_get_stomp_param_4, +static DEVICE_ATTR(stomp_param_4, S_IWUSR | S_IRUGO, pod_get_stomp_param_4, pod_set_stomp_param_4); -static DEVICE_ATTR(stomp_param_5, S_IWUGO | S_IRUGO, pod_get_stomp_param_5, +static DEVICE_ATTR(stomp_param_5, S_IWUSR | S_IRUGO, pod_get_stomp_param_5, pod_set_stomp_param_5); -static DEVICE_ATTR(stomp_param_6, S_IWUGO | S_IRUGO, pod_get_stomp_param_6, +static DEVICE_ATTR(stomp_param_6, S_IWUSR | S_IRUGO, pod_get_stomp_param_6, pod_set_stomp_param_6); -static DEVICE_ATTR(amp_switch_select, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(amp_switch_select, S_IWUSR | S_IRUGO, pod_get_amp_switch_select, pod_set_amp_switch_select); -static DEVICE_ATTR(delay_param_4, S_IWUGO | S_IRUGO, pod_get_delay_param_4, +static DEVICE_ATTR(delay_param_4, S_IWUSR | S_IRUGO, pod_get_delay_param_4, pod_set_delay_param_4); -static DEVICE_ATTR(delay_param_5, S_IWUGO | S_IRUGO, pod_get_delay_param_5, +static DEVICE_ATTR(delay_param_5, S_IWUSR | S_IRUGO, pod_get_delay_param_5, pod_set_delay_param_5); -static DEVICE_ATTR(delay_pre_post, S_IWUGO | S_IRUGO, pod_get_delay_pre_post, +static DEVICE_ATTR(delay_pre_post, S_IWUSR | S_IRUGO, pod_get_delay_pre_post, pod_set_delay_pre_post); -static DEVICE_ATTR(delay_model, S_IWUGO | S_IRUGO, pod_get_delay_model, +static DEVICE_ATTR(delay_model, S_IWUSR | S_IRUGO, pod_get_delay_model, pod_set_delay_model); -static DEVICE_ATTR(delay_verb_model, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(delay_verb_model, S_IWUSR | S_IRUGO, pod_get_delay_verb_model, pod_set_delay_verb_model); -static DEVICE_ATTR(tempo_msb, S_IWUGO | S_IRUGO, pod_get_tempo_msb, +static DEVICE_ATTR(tempo_msb, S_IWUSR | S_IRUGO, pod_get_tempo_msb, pod_set_tempo_msb); -static DEVICE_ATTR(tempo_lsb, S_IWUGO | S_IRUGO, pod_get_tempo_lsb, +static DEVICE_ATTR(tempo_lsb, S_IWUSR | S_IRUGO, pod_get_tempo_lsb, pod_set_tempo_lsb); -static DEVICE_ATTR(wah_model, S_IWUGO | S_IRUGO, pod_get_wah_model, +static DEVICE_ATTR(wah_model, S_IWUSR | S_IRUGO, pod_get_wah_model, pod_set_wah_model); -static DEVICE_ATTR(bypass_volume, S_IWUGO | S_IRUGO, pod_get_bypass_volume, +static DEVICE_ATTR(bypass_volume, S_IWUSR | S_IRUGO, pod_get_bypass_volume, pod_set_bypass_volume); -static DEVICE_ATTR(fx_loop_on_off, S_IWUGO | S_IRUGO, pod_get_fx_loop_on_off, +static DEVICE_ATTR(fx_loop_on_off, S_IWUSR | S_IRUGO, pod_get_fx_loop_on_off, pod_set_fx_loop_on_off); -static DEVICE_ATTR(tweak_param_select, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(tweak_param_select, S_IWUSR | S_IRUGO, pod_get_tweak_param_select, pod_set_tweak_param_select); -static DEVICE_ATTR(amp1_engage, S_IWUGO | S_IRUGO, pod_get_amp1_engage, +static DEVICE_ATTR(amp1_engage, S_IWUSR | S_IRUGO, pod_get_amp1_engage, pod_set_amp1_engage); -static DEVICE_ATTR(band_1_gain, S_IWUGO | S_IRUGO, pod_get_band_1_gain, +static DEVICE_ATTR(band_1_gain, S_IWUSR | S_IRUGO, pod_get_band_1_gain, pod_set_band_1_gain); -static DEVICE_ATTR2(band_2_gain__bass, band_2_gain, S_IWUGO | S_IRUGO, +static DEVICE_ATTR2(band_2_gain__bass, band_2_gain, S_IWUSR | S_IRUGO, pod_get_band_2_gain__bass, pod_set_band_2_gain__bass); -static DEVICE_ATTR(band_2_gain, S_IWUGO | S_IRUGO, pod_get_band_2_gain, +static DEVICE_ATTR(band_2_gain, S_IWUSR | S_IRUGO, pod_get_band_2_gain, pod_set_band_2_gain); -static DEVICE_ATTR2(band_3_gain__bass, band_3_gain, S_IWUGO | S_IRUGO, +static DEVICE_ATTR2(band_3_gain__bass, band_3_gain, S_IWUSR | S_IRUGO, pod_get_band_3_gain__bass, pod_set_band_3_gain__bass); -static DEVICE_ATTR(band_3_gain, S_IWUGO | S_IRUGO, pod_get_band_3_gain, +static DEVICE_ATTR(band_3_gain, S_IWUSR | S_IRUGO, pod_get_band_3_gain, pod_set_band_3_gain); -static DEVICE_ATTR2(band_4_gain__bass, band_4_gain, S_IWUGO | S_IRUGO, +static DEVICE_ATTR2(band_4_gain__bass, band_4_gain, S_IWUSR | S_IRUGO, pod_get_band_4_gain__bass, pod_set_band_4_gain__bass); -static DEVICE_ATTR2(band_5_gain__bass, band_5_gain, S_IWUGO | S_IRUGO, +static DEVICE_ATTR2(band_5_gain__bass, band_5_gain, S_IWUSR | S_IRUGO, pod_get_band_5_gain__bass, pod_set_band_5_gain__bass); -static DEVICE_ATTR(band_4_gain, S_IWUGO | S_IRUGO, pod_get_band_4_gain, +static DEVICE_ATTR(band_4_gain, S_IWUSR | S_IRUGO, pod_get_band_4_gain, pod_set_band_4_gain); -static DEVICE_ATTR2(band_6_gain__bass, band_6_gain, S_IWUGO | S_IRUGO, +static DEVICE_ATTR2(band_6_gain__bass, band_6_gain, S_IWUSR | S_IRUGO, pod_get_band_6_gain__bass, pod_set_band_6_gain__bass); static DEVICE_ATTR(body, S_IRUGO, variax_get_body, line6_nop_write); static DEVICE_ATTR(pickup1_enable, S_IRUGO, variax_get_pickup1_enable, diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c index 4304dfe6c166..ab67e889d2c4 100644 --- a/drivers/staging/line6/midi.c +++ b/drivers/staging/line6/midi.c @@ -350,9 +350,9 @@ static ssize_t midi_set_midi_mask_receive(struct device *dev, return count; } -static DEVICE_ATTR(midi_mask_transmit, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(midi_mask_transmit, S_IWUSR | S_IRUGO, midi_get_midi_mask_transmit, midi_set_midi_mask_transmit); -static DEVICE_ATTR(midi_mask_receive, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(midi_mask_receive, S_IWUSR | S_IRUGO, midi_get_midi_mask_receive, midi_set_midi_mask_receive); /* MIDI device destructor */ diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index e54770e34d2e..b9c55f9eb501 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -79,9 +79,9 @@ static ssize_t pcm_set_impulse_period(struct device *dev, return count; } -static DEVICE_ATTR(impulse_volume, S_IWUGO | S_IRUGO, pcm_get_impulse_volume, +static DEVICE_ATTR(impulse_volume, S_IWUSR | S_IRUGO, pcm_get_impulse_volume, pcm_set_impulse_volume); -static DEVICE_ATTR(impulse_period, S_IWUGO | S_IRUGO, pcm_get_impulse_period, +static DEVICE_ATTR(impulse_period, S_IWUSR | S_IRUGO, pcm_get_impulse_period, pcm_set_impulse_period); #endif diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c index 22e2cedcacf7..d9b30212585c 100644 --- a/drivers/staging/line6/pod.c +++ b/drivers/staging/line6/pod.c @@ -1051,48 +1051,48 @@ POD_GET_SYSTEM_PARAM(tuner_pitch, 1); #undef GET_SYSTEM_PARAM /* POD special files: */ -static DEVICE_ATTR(channel, S_IWUGO | S_IRUGO, pod_get_channel, +static DEVICE_ATTR(channel, S_IWUSR | S_IRUGO, pod_get_channel, pod_set_channel); static DEVICE_ATTR(clip, S_IRUGO, pod_wait_for_clip, line6_nop_write); static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write); static DEVICE_ATTR(dirty, S_IRUGO, pod_get_dirty, line6_nop_write); -static DEVICE_ATTR(dump, S_IWUGO | S_IRUGO, pod_get_dump, pod_set_dump); -static DEVICE_ATTR(dump_buf, S_IWUGO | S_IRUGO, pod_get_dump_buf, +static DEVICE_ATTR(dump, S_IWUSR | S_IRUGO, pod_get_dump, pod_set_dump); +static DEVICE_ATTR(dump_buf, S_IWUSR | S_IRUGO, pod_get_dump_buf, pod_set_dump_buf); -static DEVICE_ATTR(finish, S_IWUGO, line6_nop_read, pod_set_finish); +static DEVICE_ATTR(finish, S_IWUSR, line6_nop_read, pod_set_finish); static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version, line6_nop_write); -static DEVICE_ATTR(midi_postprocess, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(midi_postprocess, S_IWUSR | S_IRUGO, pod_get_midi_postprocess, pod_set_midi_postprocess); -static DEVICE_ATTR(monitor_level, S_IWUGO | S_IRUGO, pod_get_monitor_level, +static DEVICE_ATTR(monitor_level, S_IWUSR | S_IRUGO, pod_get_monitor_level, pod_set_monitor_level); static DEVICE_ATTR(name, S_IRUGO, pod_get_name, line6_nop_write); static DEVICE_ATTR(name_buf, S_IRUGO, pod_get_name_buf, line6_nop_write); -static DEVICE_ATTR(retrieve_amp_setup, S_IWUGO, line6_nop_read, +static DEVICE_ATTR(retrieve_amp_setup, S_IWUSR, line6_nop_read, pod_set_retrieve_amp_setup); -static DEVICE_ATTR(retrieve_channel, S_IWUGO, line6_nop_read, +static DEVICE_ATTR(retrieve_channel, S_IWUSR, line6_nop_read, pod_set_retrieve_channel); -static DEVICE_ATTR(retrieve_effects_setup, S_IWUGO, line6_nop_read, +static DEVICE_ATTR(retrieve_effects_setup, S_IWUSR, line6_nop_read, pod_set_retrieve_effects_setup); -static DEVICE_ATTR(routing, S_IWUGO | S_IRUGO, pod_get_routing, +static DEVICE_ATTR(routing, S_IWUSR | S_IRUGO, pod_get_routing, pod_set_routing); static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number, line6_nop_write); -static DEVICE_ATTR(store_amp_setup, S_IWUGO, line6_nop_read, +static DEVICE_ATTR(store_amp_setup, S_IWUSR, line6_nop_read, pod_set_store_amp_setup); -static DEVICE_ATTR(store_channel, S_IWUGO, line6_nop_read, +static DEVICE_ATTR(store_channel, S_IWUSR, line6_nop_read, pod_set_store_channel); -static DEVICE_ATTR(store_effects_setup, S_IWUGO, line6_nop_read, +static DEVICE_ATTR(store_effects_setup, S_IWUSR, line6_nop_read, pod_set_store_effects_setup); -static DEVICE_ATTR(tuner_freq, S_IWUGO | S_IRUGO, pod_get_tuner_freq, +static DEVICE_ATTR(tuner_freq, S_IWUSR | S_IRUGO, pod_get_tuner_freq, pod_set_tuner_freq); -static DEVICE_ATTR(tuner_mute, S_IWUGO | S_IRUGO, pod_get_tuner_mute, +static DEVICE_ATTR(tuner_mute, S_IWUSR | S_IRUGO, pod_get_tuner_mute, pod_set_tuner_mute); static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write); static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write); #ifdef CONFIG_LINE6_USB_RAW -static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw); +static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw); #endif /* control info callback */ diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c index 6a10b0f9749a..879e6992bbc6 100644 --- a/drivers/staging/line6/toneport.c +++ b/drivers/staging/line6/toneport.c @@ -154,9 +154,9 @@ static ssize_t toneport_set_led_green(struct device *dev, return count; } -static DEVICE_ATTR(led_red, S_IWUGO | S_IRUGO, line6_nop_read, +static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read, toneport_set_led_red); -static DEVICE_ATTR(led_green, S_IWUGO | S_IRUGO, line6_nop_read, +static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read, toneport_set_led_green); static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c index 894eee7f2317..81241cdf1be9 100644 --- a/drivers/staging/line6/variax.c +++ b/drivers/staging/line6/variax.c @@ -549,21 +549,21 @@ static ssize_t variax_set_raw2(struct device *dev, #endif /* Variax workbench special files: */ -static DEVICE_ATTR(model, S_IWUGO | S_IRUGO, variax_get_model, +static DEVICE_ATTR(model, S_IWUSR | S_IRUGO, variax_get_model, variax_set_model); -static DEVICE_ATTR(volume, S_IWUGO | S_IRUGO, variax_get_volume, +static DEVICE_ATTR(volume, S_IWUSR | S_IRUGO, variax_get_volume, variax_set_volume); -static DEVICE_ATTR(tone, S_IWUGO | S_IRUGO, variax_get_tone, variax_set_tone); +static DEVICE_ATTR(tone, S_IWUSR | S_IRUGO, variax_get_tone, variax_set_tone); static DEVICE_ATTR(name, S_IRUGO, variax_get_name, line6_nop_write); static DEVICE_ATTR(bank, S_IRUGO, variax_get_bank, line6_nop_write); static DEVICE_ATTR(dump, S_IRUGO, variax_get_dump, line6_nop_write); -static DEVICE_ATTR(active, S_IWUGO | S_IRUGO, variax_get_active, +static DEVICE_ATTR(active, S_IWUSR | S_IRUGO, variax_get_active, variax_set_active); static DEVICE_ATTR(guitar, S_IRUGO, variax_get_guitar, line6_nop_write); #ifdef CONFIG_LINE6_USB_RAW -static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw); -static DEVICE_ATTR(raw2, S_IWUGO, line6_nop_read, variax_set_raw2); +static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw); +static DEVICE_ATTR(raw2, S_IWUSR, line6_nop_read, variax_set_raw2); #endif /* diff --git a/drivers/staging/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c index d746715d3d89..d83bec876d2e 100644 --- a/drivers/staging/quickstart/quickstart.c +++ b/drivers/staging/quickstart/quickstart.c @@ -355,7 +355,6 @@ static int quickstart_acpi_remove(struct acpi_device *device, int type) static void quickstart_exit(void) { input_unregister_device(quickstart_input); - input_free_device(quickstart_input); device_remove_file(&pf_device->dev, &dev_attr_pressed_button); device_remove_file(&pf_device->dev, &dev_attr_buttons); @@ -375,6 +374,7 @@ static int __init quickstart_init_input(void) { struct quickstart_btn **ptr = &quickstart_data.btn_lst; int count; + int ret; quickstart_input = input_allocate_device(); @@ -391,7 +391,13 @@ static int __init quickstart_init_input(void) ptr = &((*ptr)->next); } - return input_register_device(quickstart_input); + ret = input_register_device(quickstart_input); + if (ret) { + input_free_device(quickstart_input); + return ret; + } + + return 0; } static int __init quickstart_init(void) diff --git a/drivers/staging/rt2860/usb_main_dev.c b/drivers/staging/rt2860/usb_main_dev.c index ddacfc6c4861..cd15daae5412 100644 --- a/drivers/staging/rt2860/usb_main_dev.c +++ b/drivers/staging/rt2860/usb_main_dev.c @@ -182,6 +182,7 @@ struct usb_device_id rtusb_usb_id[] = { {USB_DEVICE(0x2001, 0x3C09)}, /* D-Link */ {USB_DEVICE(0x2001, 0x3C0A)}, /* D-Link 3072 */ {USB_DEVICE(0x2019, 0xED14)}, /* Planex Communications, Inc. */ + {USB_DEVICE(0x0411, 0x015D)}, /* Buffalo Airstation WLI-UC-GN */ {} /* Terminating entry */ }; diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c index 46000d72f4c4..3bdf9b31cc4e 100644 --- a/drivers/staging/rtl8187se/r8185b_init.c +++ b/drivers/staging/rtl8187se/r8185b_init.c @@ -264,8 +264,12 @@ HwHSSIThreeWire( udelay(10); } - if (TryCnt == TC_3W_POLL_MAX_TRY_CNT) - panic("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear!!\n", u1bTmp); + if (TryCnt == TC_3W_POLL_MAX_TRY_CNT) { + printk(KERN_ERR "rtl8187se: HwThreeWire(): CmdReg:" + " %#X RE|WE bits are not clear!!\n", u1bTmp); + dump_stack(); + return 0; + } /* RTL8187S HSSI Read/Write Function */ u1bTmp = read_nic_byte(dev, RF_SW_CONFIG); @@ -298,13 +302,23 @@ HwHSSIThreeWire( int idx; int ByteCnt = nDataBufBitCnt / 8; /* printk("%d\n",nDataBufBitCnt); */ - if ((nDataBufBitCnt % 8) != 0) - panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n", - nDataBufBitCnt); + if ((nDataBufBitCnt % 8) != 0) { + printk(KERN_ERR "rtl8187se: " + "HwThreeWire(): nDataBufBitCnt(%d)" + " should be multiple of 8!!!\n", + nDataBufBitCnt); + dump_stack(); + nDataBufBitCnt += 8; + nDataBufBitCnt &= ~7; + } - if (nDataBufBitCnt > 64) - panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n", - nDataBufBitCnt); + if (nDataBufBitCnt > 64) { + printk(KERN_ERR "rtl8187se: HwThreeWire():" + " nDataBufBitCnt(%d) should <= 64!!!\n", + nDataBufBitCnt); + dump_stack(); + nDataBufBitCnt = 64; + } for (idx = 0; idx < ByteCnt; idx++) write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx)); diff --git a/drivers/staging/rtl8712/usb_halinit.c b/drivers/staging/rtl8712/usb_halinit.c index f6569dce3012..0e9483bbabe1 100644 --- a/drivers/staging/rtl8712/usb_halinit.c +++ b/drivers/staging/rtl8712/usb_halinit.c @@ -37,7 +37,7 @@ u8 r8712_usb_hal_bus_init(struct _adapter *padapter) { u8 val8 = 0; u8 ret = _SUCCESS; - u8 PollingCnt = 20; + int PollingCnt = 20; struct registry_priv *pregistrypriv = &padapter->registrypriv; if (pregistrypriv->chip_version == RTL8712_FPGA) { diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c index eb44b60e1eb5..ac2bf11e1119 100644 --- a/drivers/staging/samsung-laptop/samsung-laptop.c +++ b/drivers/staging/samsung-laptop/samsung-laptop.c @@ -356,7 +356,7 @@ static ssize_t set_silent_state(struct device *dev, } return count; } -static DEVICE_ATTR(silent, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(silent, S_IWUSR | S_IRUGO, get_silent_state, set_silent_state); diff --git a/drivers/staging/speakup/fakekey.c b/drivers/staging/speakup/fakekey.c index adb93f21c0d6..65b231178f05 100644 --- a/drivers/staging/speakup/fakekey.c +++ b/drivers/staging/speakup/fakekey.c @@ -62,7 +62,6 @@ void speakup_remove_virtual_keyboard(void) { if (virt_keyboard != NULL) { input_unregister_device(virt_keyboard); - input_free_device(virt_keyboard); virt_keyboard = NULL; } } diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index c7932da03c56..63a9d0adf32d 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -656,7 +656,7 @@ static int SBD_setup_device(struct spectra_nand_dev *dev, int which) /* Here we force report 512 byte hardware sector size to Kernel */ blk_queue_logical_block_size(dev->queue, 512); - blk_queue_ordered(dev->queue, QUEUE_ORDERED_DRAIN_FLUSH); + blk_queue_flush(dev->queue, REQ_FLUSH); dev->thread = kthread_run(spectra_trans_thread, dev, "nand_thd"); if (IS_ERR(dev->thread)) { diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 664e6038090d..b143258f094a 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -545,7 +545,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev) /* Load tuner module */ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - NULL, "tuner", dev->tuner_addr, NULL); + "tuner", dev->tuner_addr, NULL); memset(&tun_setup, 0, sizeof(tun_setup)); tun_setup.type = dev->tuner_type; @@ -683,7 +683,7 @@ static int tm6000_init_dev(struct tm6000_core *dev) if (dev->caps.has_tda9874) v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - NULL, "tvaudio", I2C_ADDR_TDA9874, NULL); + "tvaudio", I2C_ADDR_TDA9874, NULL); /* register and initialize V4L2 */ rc = tm6000_v4l2_register(dev); diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c index fed25105970a..b7ac16005265 100644 --- a/drivers/staging/udlfb/udlfb.c +++ b/drivers/staging/udlfb/udlfb.c @@ -1441,7 +1441,7 @@ static struct device_attribute fb_device_attrs[] = { __ATTR_RO(metrics_bytes_identical), __ATTR_RO(metrics_bytes_sent), __ATTR_RO(metrics_cpu_kcycles_used), - __ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store), + __ATTR(metrics_reset, S_IWUSR, NULL, metrics_reset_store), }; /* diff --git a/drivers/staging/winbond/sysdef.h b/drivers/staging/winbond/sysdef.h index 9195adf98e14..d0d71f69bc8c 100644 --- a/drivers/staging/winbond/sysdef.h +++ b/drivers/staging/winbond/sysdef.h @@ -2,6 +2,9 @@ #ifndef SYS_DEF_H #define SYS_DEF_H + +#include <linux/delay.h> + #define WB_LINUX #define WB_LINUX_WPA_PSK diff --git a/drivers/staging/zram/zram_sysfs.c b/drivers/staging/zram/zram_sysfs.c index 6c574a994d11..6b3cf00b0ff4 100644 --- a/drivers/staging/zram/zram_sysfs.c +++ b/drivers/staging/zram/zram_sysfs.c @@ -189,10 +189,10 @@ static ssize_t mem_used_total_show(struct device *dev, return sprintf(buf, "%llu\n", val); } -static DEVICE_ATTR(disksize, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR, disksize_show, disksize_store); static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL); -static DEVICE_ATTR(reset, S_IWUGO, NULL, reset_store); +static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store); static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL); static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL); static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL); diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 81b46585edf7..c5f8e5bda2b2 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -716,8 +716,8 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg) if (msg->len < 128) *--dp = (msg->len << 1) | EA; else { - *--dp = ((msg->len & 127) << 1) | EA; - *--dp = (msg->len >> 6) & 0xfe; + *--dp = (msg->len >> 7); /* bits 7 - 15 */ + *--dp = (msg->len & 127) << 1; /* bits 0 - 6 */ } } @@ -968,6 +968,8 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data, { struct gsm_msg *msg; msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype); + if (msg == NULL) + return; msg->data[0] = (cmd & 0xFE) << 1 | EA; /* Clear C/R */ msg->data[1] = (dlen << 1) | EA; memcpy(msg->data + 2, data, dlen); diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index eaa5d3efa79d..c556ed9db13d 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -554,7 +554,7 @@ EXPORT_SYMBOL(handle_sysrq); #ifdef CONFIG_INPUT /* Simple translation table for the SysRq keys */ -static const unsigned char sysrq_xlate[KEY_MAX + 1] = +static const unsigned char sysrq_xlate[KEY_CNT] = "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ @@ -563,53 +563,129 @@ static const unsigned char sysrq_xlate[KEY_MAX + 1] = "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ "\r\000/"; /* 0x60 - 0x6f */ -static bool sysrq_down; -static int sysrq_alt_use; -static int sysrq_alt; -static DEFINE_SPINLOCK(sysrq_event_lock); +struct sysrq_state { + struct input_handle handle; + struct work_struct reinject_work; + unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; + unsigned int alt; + unsigned int alt_use; + bool active; + bool need_reinject; +}; + +static void sysrq_reinject_alt_sysrq(struct work_struct *work) +{ + struct sysrq_state *sysrq = + container_of(work, struct sysrq_state, reinject_work); + struct input_handle *handle = &sysrq->handle; + unsigned int alt_code = sysrq->alt_use; + + if (sysrq->need_reinject) { + /* Simulate press and release of Alt + SysRq */ + input_inject_event(handle, EV_KEY, alt_code, 1); + input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1); + input_inject_event(handle, EV_SYN, SYN_REPORT, 1); + + input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0); + input_inject_event(handle, EV_KEY, alt_code, 0); + input_inject_event(handle, EV_SYN, SYN_REPORT, 1); + } +} -static bool sysrq_filter(struct input_handle *handle, unsigned int type, - unsigned int code, int value) +static bool sysrq_filter(struct input_handle *handle, + unsigned int type, unsigned int code, int value) { + struct sysrq_state *sysrq = handle->private; + bool was_active = sysrq->active; bool suppress; - /* We are called with interrupts disabled, just take the lock */ - spin_lock(&sysrq_event_lock); + switch (type) { - if (type != EV_KEY) - goto out; + case EV_SYN: + suppress = false; + break; - switch (code) { + case EV_KEY: + switch (code) { - case KEY_LEFTALT: - case KEY_RIGHTALT: - if (value) - sysrq_alt = code; - else { - if (sysrq_down && code == sysrq_alt_use) - sysrq_down = false; + case KEY_LEFTALT: + case KEY_RIGHTALT: + if (!value) { + /* One of ALTs is being released */ + if (sysrq->active && code == sysrq->alt_use) + sysrq->active = false; - sysrq_alt = 0; + sysrq->alt = KEY_RESERVED; + + } else if (value != 2) { + sysrq->alt = code; + sysrq->need_reinject = false; + } + break; + + case KEY_SYSRQ: + if (value == 1 && sysrq->alt != KEY_RESERVED) { + sysrq->active = true; + sysrq->alt_use = sysrq->alt; + /* + * If nothing else will be pressed we'll need + * to * re-inject Alt-SysRq keysroke. + */ + sysrq->need_reinject = true; + } + + /* + * Pretend that sysrq was never pressed at all. This + * is needed to properly handle KGDB which will try + * to release all keys after exiting debugger. If we + * do not clear key bit it KGDB will end up sending + * release events for Alt and SysRq, potentially + * triggering print screen function. + */ + if (sysrq->active) + clear_bit(KEY_SYSRQ, handle->dev->key); + + break; + + default: + if (sysrq->active && value && value != 2) { + sysrq->need_reinject = false; + __handle_sysrq(sysrq_xlate[code], true); + } + break; } - break; - case KEY_SYSRQ: - if (value == 1 && sysrq_alt) { - sysrq_down = true; - sysrq_alt_use = sysrq_alt; + suppress = sysrq->active; + + if (!sysrq->active) { + /* + * If we are not suppressing key presses keep track of + * keyboard state so we can release keys that have been + * pressed before entering SysRq mode. + */ + if (value) + set_bit(code, sysrq->key_down); + else + clear_bit(code, sysrq->key_down); + + if (was_active) + schedule_work(&sysrq->reinject_work); + + } else if (value == 0 && + test_and_clear_bit(code, sysrq->key_down)) { + /* + * Pass on release events for keys that was pressed before + * entering SysRq mode. + */ + suppress = false; } break; default: - if (sysrq_down && value && value != 2) - __handle_sysrq(sysrq_xlate[code], true); + suppress = sysrq->active; break; } -out: - suppress = sysrq_down; - spin_unlock(&sysrq_event_lock); - return suppress; } @@ -617,28 +693,28 @@ static int sysrq_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { - struct input_handle *handle; + struct sysrq_state *sysrq; int error; - sysrq_down = false; - sysrq_alt = 0; - - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); - if (!handle) + sysrq = kzalloc(sizeof(struct sysrq_state), GFP_KERNEL); + if (!sysrq) return -ENOMEM; - handle->dev = dev; - handle->handler = handler; - handle->name = "sysrq"; + INIT_WORK(&sysrq->reinject_work, sysrq_reinject_alt_sysrq); + + sysrq->handle.dev = dev; + sysrq->handle.handler = handler; + sysrq->handle.name = "sysrq"; + sysrq->handle.private = sysrq; - error = input_register_handle(handle); + error = input_register_handle(&sysrq->handle); if (error) { pr_err("Failed to register input sysrq handler, error %d\n", error); goto err_free; } - error = input_open_device(handle); + error = input_open_device(&sysrq->handle); if (error) { pr_err("Failed to open input device, error %d\n", error); goto err_unregister; @@ -647,17 +723,20 @@ static int sysrq_connect(struct input_handler *handler, return 0; err_unregister: - input_unregister_handle(handle); + input_unregister_handle(&sysrq->handle); err_free: - kfree(handle); + kfree(sysrq); return error; } static void sysrq_disconnect(struct input_handle *handle) { + struct sysrq_state *sysrq = handle->private; + input_close_device(handle); + cancel_work_sync(&sysrq->reinject_work); input_unregister_handle(handle); - kfree(handle); + kfree(sysrq); } /* diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index c05c5af5aa04..35480dd57a30 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -559,6 +559,9 @@ void __tty_hangup(struct tty_struct *tty) tty_lock(); + /* some functions below drop BTM, so we need this bit */ + set_bit(TTY_HUPPING, &tty->flags); + /* inuse_filps is protected by the single tty lock, this really needs to change if we want to flush the workqueue with the lock held */ @@ -578,6 +581,10 @@ void __tty_hangup(struct tty_struct *tty) } spin_unlock(&tty_files_lock); + /* + * it drops BTM and thus races with reopen + * we protect the race by TTY_HUPPING + */ tty_ldisc_hangup(tty); read_lock(&tasklist_lock); @@ -615,7 +622,6 @@ void __tty_hangup(struct tty_struct *tty) tty->session = NULL; tty->pgrp = NULL; tty->ctrl_status = 0; - set_bit(TTY_HUPPED, &tty->flags); spin_unlock_irqrestore(&tty->ctrl_lock, flags); /* Account for the p->signal references we killed */ @@ -641,6 +647,7 @@ void __tty_hangup(struct tty_struct *tty) * can't yet guarantee all that. */ set_bit(TTY_HUPPED, &tty->flags); + clear_bit(TTY_HUPPING, &tty->flags); tty_ldisc_enable(tty); tty_unlock(); @@ -1310,7 +1317,9 @@ static int tty_reopen(struct tty_struct *tty) { struct tty_driver *driver = tty->driver; - if (test_bit(TTY_CLOSING, &tty->flags)) + if (test_bit(TTY_CLOSING, &tty->flags) || + test_bit(TTY_HUPPING, &tty->flags) || + test_bit(TTY_LDISC_CHANGING, &tty->flags)) return -EIO; if (driver->type == TTY_DRIVER_TYPE_PTY && diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index d8e96b005023..4214d58276f7 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -454,6 +454,8 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) /* BTM here locks versus a hangup event */ WARN_ON(!tty_locked()); ret = ld->ops->open(tty); + if (ret) + clear_bit(TTY_LDISC_OPEN, &tty->flags); return ret; } return 0; diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index a858d2b87b94..51fe1795d5a8 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -3,7 +3,7 @@ * * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de> * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de> - * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de> + * Copyright(C) 2006, Hans J. Koch <hjk@hansjkoch.de> * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com> * * Userspace IO diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c index a8ea2f19a0cc..a84a451159ed 100644 --- a/drivers/uio/uio_cif.c +++ b/drivers/uio/uio_cif.c @@ -1,7 +1,7 @@ /* * UIO Hilscher CIF card driver * - * (C) 2007 Hans J. Koch <hjk@linutronix.de> + * (C) 2007 Hans J. Koch <hjk@hansjkoch.de> * Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de> * * Licensed under GPL version 2 only. diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c index 5a18e9f7b836..5ffdb483b015 100644 --- a/drivers/uio/uio_netx.c +++ b/drivers/uio/uio_netx.c @@ -2,7 +2,7 @@ * UIO driver for Hilscher NetX based fieldbus cards (cifX, comX). * See http://www.hilscher.com for details. * - * (C) 2007 Hans J. Koch <hjk@linutronix.de> + * (C) 2007 Hans J. Koch <hjk@hansjkoch.de> * (C) 2008 Manuel Traut <manut@linutronix.de> * * Licensed under GPL version 2 only. diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index ea071a5b6eee..44447f54942f 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2301,7 +2301,7 @@ out: return ret; } -static DEVICE_ATTR(stat_status, S_IWUGO | S_IRUGO, read_status, reboot); +static DEVICE_ATTR(stat_status, S_IWUSR | S_IRUGO, read_status, reboot); static ssize_t read_human_status(struct device *dev, struct device_attribute *attr, char *buf) @@ -2364,8 +2364,7 @@ out: return ret; } -static DEVICE_ATTR(stat_human_status, S_IWUGO | S_IRUGO, - read_human_status, NULL); +static DEVICE_ATTR(stat_human_status, S_IRUGO, read_human_status, NULL); static ssize_t read_delin(struct device *dev, struct device_attribute *attr, char *buf) @@ -2397,7 +2396,7 @@ out: return ret; } -static DEVICE_ATTR(stat_delin, S_IWUGO | S_IRUGO, read_delin, NULL); +static DEVICE_ATTR(stat_delin, S_IRUGO, read_delin, NULL); #define UEA_ATTR(name, reset) \ \ diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 05bf5a27b5b0..989e16e4ab5c 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -951,7 +951,9 @@ static int usbatm_atm_init(struct usbatm_data *instance) * condition: callbacks we register can be executed at once, before we have * initialized the struct atm_dev. To protect against this, all callbacks * abort if atm_dev->dev_data is NULL. */ - atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL); + atm_dev = atm_dev_register(instance->driver_name, + &instance->usb_intf->dev, &usbatm_atm_devops, + -1, NULL); if (!atm_dev) { usb_err(instance, "%s: failed to register ATM device!\n", __func__); return -1; @@ -966,14 +968,6 @@ static int usbatm_atm_init(struct usbatm_data *instance) /* temp init ATM device, set to 128kbit */ atm_dev->link_rate = 128 * 1000 / 424; - ret = sysfs_create_link(&atm_dev->class_dev.kobj, - &instance->usb_intf->dev.kobj, "device"); - if (ret) { - atm_err(instance, "%s: sysfs_create_link failed: %d\n", - __func__, ret); - goto fail_sysfs; - } - if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) { atm_err(instance, "%s: atm_start failed: %d!\n", __func__, ret); goto fail; @@ -992,8 +986,6 @@ static int usbatm_atm_init(struct usbatm_data *instance) return 0; fail: - sysfs_remove_link(&atm_dev->class_dev.kobj, "device"); - fail_sysfs: instance->atm_dev = NULL; atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */ return ret; @@ -1329,7 +1321,6 @@ void usbatm_usb_disconnect(struct usb_interface *intf) /* ATM finalize */ if (instance->atm_dev) { - sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device"); atm_dev_deregister(instance->atm_dev); instance->atm_dev = NULL; } diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 9eed5b52d9de..bcc24779ba0e 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -107,11 +107,19 @@ config USB_SUSPEND If you are unsure about this, say N here. config USB_OTG - bool + bool "OTG support" depends on USB && EXPERIMENTAL depends on USB_SUSPEND default n - + help + The most notable feature of USB OTG is support for a + "Dual-Role" device, which can act as either a device + or a host. The initial role is decided by the type of + plug inserted and can be changed later when two dual + role devices talk to each other. + + Select this only if your board has Mini-AB/Micro-AB + connector. config USB_OTG_WHITELIST bool "Rely on OTG Targeted Peripherals List" diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 61800f77dac8..ced846ac4141 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1330,6 +1330,8 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, */ if (usb_endpoint_xfer_control(&urb->ep->desc)) { + if (hcd->self.uses_pio_for_control) + return ret; if (hcd->self.uses_dma) { urb->setup_dma = dma_map_single( hcd->self.controller, diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index b5e20e873cba..717ff653fa23 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -2017,7 +2017,7 @@ static int __init usba_udc_probe(struct platform_device *pdev) } } else { /* gpio_request fail so use -EINVAL for gpio_is_valid */ - ubc->vbus_pin = -EINVAL; + udc->vbus_pin = -EINVAL; } } diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 7b5cc16e4a0b..8572dad5ecbb 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1047,9 +1047,9 @@ composite_unbind(struct usb_gadget *gadget) kfree(cdev->req->buf); usb_ep_free_request(gadget->ep0, cdev->req); } + device_remove_file(&gadget->dev, &dev_attr_suspended); kfree(cdev); set_gadget_data(gadget, NULL); - device_remove_file(&gadget->dev, &dev_attr_suspended); composite = NULL; } @@ -1107,14 +1107,6 @@ static int composite_bind(struct usb_gadget *gadget) */ usb_ep_autoconfig_reset(cdev->gadget); - /* standardized runtime overrides for device ID data */ - if (idVendor) - cdev->desc.idVendor = cpu_to_le16(idVendor); - if (idProduct) - cdev->desc.idProduct = cpu_to_le16(idProduct); - if (bcdDevice) - cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); - /* composite gadget needs to assign strings for whole device (like * serial number), register function drivers, potentially update * power state and consumption, etc @@ -1126,6 +1118,14 @@ static int composite_bind(struct usb_gadget *gadget) cdev->desc = *composite->dev; cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + /* standardized runtime overrides for device ID data */ + if (idVendor) + cdev->desc.idVendor = cpu_to_le16(idVendor); + if (idProduct) + cdev->desc.idProduct = cpu_to_le16(idProduct); + if (bcdDevice) + cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); + /* stirng overrides */ if (iManufacturer || !cdev->desc.iManufacturer) { if (!iManufacturer && !composite->iManufacturer && diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 86afdc73322f..6e2599661b5b 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -1067,7 +1067,7 @@ static inline void create_debug_files (struct ehci_hcd *ehci) &debug_registers_fops)) goto file_error; - if (!debugfs_create_file("lpm", S_IRUGO|S_IWUGO, ehci->debug_dir, bus, + if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus, &debug_lpm_fops)) goto file_error; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 502a7e6fef42..e9062806d4a2 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1063,10 +1063,11 @@ rescan: tmp && tmp != qh; tmp = tmp->qh_next.qh) continue; - /* periodic qh self-unlinks on empty */ - if (!tmp) - goto nogood; - unlink_async (ehci, qh); + /* periodic qh self-unlinks on empty, and a COMPLETING qh + * may already be unlinked. + */ + if (tmp) + unlink_async(ehci, qh); /* FALL THROUGH */ case QH_STATE_UNLINK: /* wait for hw to finish? */ case QH_STATE_UNLINK_WAIT: @@ -1083,7 +1084,6 @@ idle_timeout: } /* else FALL THROUGH */ default: -nogood: /* caller was supposed to have unlinked any requests; * that's not our job. just leak this memory. */ diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index d36e4e75e08d..12f70c302b0b 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -141,6 +141,10 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci) qh_put (ehci->async); ehci->async = NULL; + if (ehci->dummy) + qh_put(ehci->dummy); + ehci->dummy = NULL; + /* DMA consistent memory and pools */ if (ehci->qtd_pool) dma_pool_destroy (ehci->qtd_pool); @@ -227,8 +231,26 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) if (ehci->periodic == NULL) { goto fail; } - for (i = 0; i < ehci->periodic_size; i++) - ehci->periodic [i] = EHCI_LIST_END(ehci); + + if (ehci->use_dummy_qh) { + struct ehci_qh_hw *hw; + ehci->dummy = ehci_qh_alloc(ehci, flags); + if (!ehci->dummy) + goto fail; + + hw = ehci->dummy->hw; + hw->hw_next = EHCI_LIST_END(ehci); + hw->hw_qtd_next = EHCI_LIST_END(ehci); + hw->hw_alt_next = EHCI_LIST_END(ehci); + hw->hw_token &= ~QTD_STS_ACTIVE; + ehci->dummy->hw = hw; + + for (i = 0; i < ehci->periodic_size; i++) + ehci->periodic[i] = ehci->dummy->qh_dma; + } else { + for (i = 0; i < ehci->periodic_size; i++) + ehci->periodic[i] = EHCI_LIST_END(ehci); + } /* software shadow of hardware table */ ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags); diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index a1e8d273103f..655f3c9f88bf 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -103,6 +103,19 @@ static int ehci_pci_setup(struct usb_hcd *hcd) if (retval) return retval; + if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) || + (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) { + /* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may + * read/write memory space which does not belong to it when + * there is NULL pointer with T-bit set to 1 in the frame list + * table. To avoid the issue, the frame list link pointer + * should always contain a valid pointer to a inactive qh. + */ + ehci->use_dummy_qh = 1; + ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI " + "dummy qh workaround\n"); + } + /* data structure init */ retval = ehci_init(hcd); if (retval) @@ -148,6 +161,18 @@ static int ehci_pci_setup(struct usb_hcd *hcd) if (pdev->revision < 0xa4) ehci->no_selective_suspend = 1; break; + + /* MCP89 chips on the MacBookAir3,1 give EPROTO when + * fetching device descriptors unless LPM is disabled. + * There are also intermittent problems enumerating + * devices with PPCD enabled. + */ + case 0x0d9d: + ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89"); + ehci->has_lpm = 0; + ehci->has_ppcd = 0; + ehci->command &= ~CMD_PPCEE; + break; } break; case PCI_VENDOR_ID_VIA: diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index a92526d6e5ae..d9f78eb26572 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -98,7 +98,14 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) */ *prev_p = *periodic_next_shadow(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); - *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); + + if (!ehci->use_dummy_qh || + *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)) + != EHCI_LIST_END(ehci)) + *hw_p = *shadow_next_periodic(ehci, &here, + Q_NEXT_TYPE(ehci, *hw_p)); + else + *hw_p = ehci->dummy->qh_dma; } /* how many of the uframe's 125 usecs are allocated? */ @@ -2335,7 +2342,11 @@ restart: * pointer for much longer, if at all. */ *q_p = q.itd->itd_next; - *hw_p = q.itd->hw_next; + if (!ehci->use_dummy_qh || + q.itd->hw_next != EHCI_LIST_END(ehci)) + *hw_p = q.itd->hw_next; + else + *hw_p = ehci->dummy->qh_dma; type = Q_NEXT_TYPE(ehci, q.itd->hw_next); wmb(); modified = itd_complete (ehci, q.itd); @@ -2368,7 +2379,11 @@ restart: * URB completion. */ *q_p = q.sitd->sitd_next; - *hw_p = q.sitd->hw_next; + if (!ehci->use_dummy_qh || + q.sitd->hw_next != EHCI_LIST_END(ehci)) + *hw_p = q.sitd->hw_next; + else + *hw_p = ehci->dummy->qh_dma; type = Q_NEXT_TYPE(ehci, q.sitd->hw_next); wmb(); modified = sitd_complete (ehci, q.sitd); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index bde823f704e9..ba8eab366b82 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -73,6 +73,7 @@ struct ehci_hcd { /* one per controller */ /* async schedule support */ struct ehci_qh *async; + struct ehci_qh *dummy; /* For AMD quirk use */ struct ehci_qh *reclaim; unsigned scanning : 1; @@ -131,6 +132,7 @@ struct ehci_hcd { /* one per controller */ unsigned need_io_watchdog:1; unsigned broken_periodic:1; unsigned fs_i_thresh:1; /* Intel iso scheduling */ + unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/ /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 6c4fb4efb4bb..43a39eb56cc6 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2683,7 +2683,7 @@ static int __devexit isp1362_remove(struct platform_device *pdev) return 0; } -static int __init isp1362_probe(struct platform_device *pdev) +static int __devinit isp1362_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct isp1362_hcd *isp1362_hcd; diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index fef5a1f9d483..5d963e350494 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -229,6 +229,13 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id) static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex, u32 __iomem *addr, u32 port_status) { + /* Don't allow the USB core to disable SuperSpeed ports. */ + if (xhci->port_array[wIndex] == 0x03) { + xhci_dbg(xhci, "Ignoring request to disable " + "SuperSpeed port.\n"); + return; + } + /* Write 1 to disable the port */ xhci_writel(xhci, port_status | PORT_PE, addr); port_status = xhci_readl(xhci, addr); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 202770676da3..1d0f45f0e7a6 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1045,7 +1045,7 @@ static inline u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci, if (udev->speed == USB_SPEED_SUPER) return ep->ss_ep_comp.wBytesPerInterval; - max_packet = ep->desc.wMaxPacketSize & 0x3ff; + max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize); max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11; /* A 0 in max burst means 1 transfer per ESIT */ return max_packet * (max_burst + 1); @@ -1135,7 +1135,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, /* Fall through */ case USB_SPEED_FULL: case USB_SPEED_LOW: - max_packet = ep->desc.wMaxPacketSize & 0x3ff; + max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize); ep_ctx->ep_info2 |= MAX_PACKET(max_packet); break; default: @@ -1443,6 +1443,13 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->dcbaa = NULL; scratchpad_free(xhci); + + xhci->num_usb2_ports = 0; + xhci->num_usb3_ports = 0; + kfree(xhci->usb2_ports); + kfree(xhci->usb3_ports); + kfree(xhci->port_array); + xhci->page_size = 0; xhci->page_shift = 0; xhci->bus_suspended = 0; @@ -1627,6 +1634,166 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci) &xhci->ir_set->erst_dequeue); } +static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, + u32 __iomem *addr, u8 major_revision) +{ + u32 temp, port_offset, port_count; + int i; + + if (major_revision > 0x03) { + xhci_warn(xhci, "Ignoring unknown port speed, " + "Ext Cap %p, revision = 0x%x\n", + addr, major_revision); + /* Ignoring port protocol we can't understand. FIXME */ + return; + } + + /* Port offset and count in the third dword, see section 7.2 */ + temp = xhci_readl(xhci, addr + 2); + port_offset = XHCI_EXT_PORT_OFF(temp); + port_count = XHCI_EXT_PORT_COUNT(temp); + xhci_dbg(xhci, "Ext Cap %p, port offset = %u, " + "count = %u, revision = 0x%x\n", + addr, port_offset, port_count, major_revision); + /* Port count includes the current port offset */ + if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) + /* WTF? "Valid values are ‘1’ to MaxPorts" */ + return; + port_offset--; + for (i = port_offset; i < (port_offset + port_count); i++) { + /* Duplicate entry. Ignore the port if the revisions differ. */ + if (xhci->port_array[i] != 0) { + xhci_warn(xhci, "Duplicate port entry, Ext Cap %p," + " port %u\n", addr, i); + xhci_warn(xhci, "Port was marked as USB %u, " + "duplicated as USB %u\n", + xhci->port_array[i], major_revision); + /* Only adjust the roothub port counts if we haven't + * found a similar duplicate. + */ + if (xhci->port_array[i] != major_revision && + xhci->port_array[i] != (u8) -1) { + if (xhci->port_array[i] == 0x03) + xhci->num_usb3_ports--; + else + xhci->num_usb2_ports--; + xhci->port_array[i] = (u8) -1; + } + /* FIXME: Should we disable the port? */ + continue; + } + xhci->port_array[i] = major_revision; + if (major_revision == 0x03) + xhci->num_usb3_ports++; + else + xhci->num_usb2_ports++; + } + /* FIXME: Should we disable ports not in the Extended Capabilities? */ +} + +/* + * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that + * specify what speeds each port is supposed to be. We can't count on the port + * speed bits in the PORTSC register being correct until a device is connected, + * but we need to set up the two fake roothubs with the correct number of USB + * 3.0 and USB 2.0 ports at host controller initialization time. + */ +static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) +{ + u32 __iomem *addr; + u32 offset; + unsigned int num_ports; + int i, port_index; + + addr = &xhci->cap_regs->hcc_params; + offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr)); + if (offset == 0) { + xhci_err(xhci, "No Extended Capability registers, " + "unable to set up roothub.\n"); + return -ENODEV; + } + + num_ports = HCS_MAX_PORTS(xhci->hcs_params1); + xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags); + if (!xhci->port_array) + return -ENOMEM; + + /* + * For whatever reason, the first capability offset is from the + * capability register base, not from the HCCPARAMS register. + * See section 5.3.6 for offset calculation. + */ + addr = &xhci->cap_regs->hc_capbase + offset; + while (1) { + u32 cap_id; + + cap_id = xhci_readl(xhci, addr); + if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL) + xhci_add_in_port(xhci, num_ports, addr, + (u8) XHCI_EXT_PORT_MAJOR(cap_id)); + offset = XHCI_EXT_CAPS_NEXT(cap_id); + if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports) + == num_ports) + break; + /* + * Once you're into the Extended Capabilities, the offset is + * always relative to the register holding the offset. + */ + addr += offset; + } + + if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) { + xhci_warn(xhci, "No ports on the roothubs?\n"); + return -ENODEV; + } + xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n", + xhci->num_usb2_ports, xhci->num_usb3_ports); + /* + * Note we could have all USB 3.0 ports, or all USB 2.0 ports. + * Not sure how the USB core will handle a hub with no ports... + */ + if (xhci->num_usb2_ports) { + xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)* + xhci->num_usb2_ports, flags); + if (!xhci->usb2_ports) + return -ENOMEM; + + port_index = 0; + for (i = 0; i < num_ports; i++) { + if (xhci->port_array[i] == 0x03 || + xhci->port_array[i] == 0 || + xhci->port_array[i] == -1) + continue; + + xhci->usb2_ports[port_index] = + &xhci->op_regs->port_status_base + + NUM_PORT_REGS*i; + xhci_dbg(xhci, "USB 2.0 port at index %u, " + "addr = %p\n", i, + xhci->usb2_ports[port_index]); + port_index++; + } + } + if (xhci->num_usb3_ports) { + xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)* + xhci->num_usb3_ports, flags); + if (!xhci->usb3_ports) + return -ENOMEM; + + port_index = 0; + for (i = 0; i < num_ports; i++) + if (xhci->port_array[i] == 0x03) { + xhci->usb3_ports[port_index] = + &xhci->op_regs->port_status_base + + NUM_PORT_REGS*i; + xhci_dbg(xhci, "USB 3.0 port at index %u, " + "addr = %p\n", i, + xhci->usb3_ports[port_index]); + port_index++; + } + } + return 0; +} int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) { @@ -1809,6 +1976,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) if (scratchpad_alloc(xhci, flags)) goto fail; + if (xhci_setup_port_arrays(xhci, flags)) + goto fail; return 0; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9f3115e729b1..df558f6f84e3 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2104,7 +2104,6 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) if (!(status & STS_EINT)) { spin_unlock(&xhci->lock); - xhci_warn(xhci, "Spurious interrupt.\n"); return IRQ_NONE; } xhci_dbg(xhci, "op reg status = %08x\n", status); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 5d7d4e951ea4..45e4a3108cc3 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -577,6 +577,65 @@ static void xhci_restore_registers(struct xhci_hcd *xhci) xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base); } +static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) +{ + u64 val_64; + + /* step 2: initialize command ring buffer */ + val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); + val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | + (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, + xhci->cmd_ring->dequeue) & + (u64) ~CMD_RING_RSVD_BITS) | + xhci->cmd_ring->cycle_state; + xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n", + (long unsigned long) val_64); + xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); +} + +/* + * The whole command ring must be cleared to zero when we suspend the host. + * + * The host doesn't save the command ring pointer in the suspend well, so we + * need to re-program it on resume. Unfortunately, the pointer must be 64-byte + * aligned, because of the reserved bits in the command ring dequeue pointer + * register. Therefore, we can't just set the dequeue pointer back in the + * middle of the ring (TRBs are 16-byte aligned). + */ +static void xhci_clear_command_ring(struct xhci_hcd *xhci) +{ + struct xhci_ring *ring; + struct xhci_segment *seg; + + ring = xhci->cmd_ring; + seg = ring->deq_seg; + do { + memset(seg->trbs, 0, SEGMENT_SIZE); + seg = seg->next; + } while (seg != ring->deq_seg); + + /* Reset the software enqueue and dequeue pointers */ + ring->deq_seg = ring->first_seg; + ring->dequeue = ring->first_seg->trbs; + ring->enq_seg = ring->deq_seg; + ring->enqueue = ring->dequeue; + + /* + * Ring is now zeroed, so the HW should look for change of ownership + * when the cycle bit is set to 1. + */ + ring->cycle_state = 1; + + /* + * Reset the hardware dequeue pointer. + * Yes, this will need to be re-written after resume, but we're paranoid + * and want to make sure the hardware doesn't access bogus memory + * because, say, the BIOS or an SMI started the host without changing + * the command ring pointers. + */ + xhci_set_cmd_ring_deq(xhci); +} + /* * Stop HC (not bus-specific) * @@ -604,6 +663,7 @@ int xhci_suspend(struct xhci_hcd *xhci) spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; } + xhci_clear_command_ring(xhci); /* step 3: save registers */ xhci_save_registers(xhci); @@ -635,7 +695,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) u32 command, temp = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - u64 val_64; int old_state, retval; old_state = hcd->state; @@ -648,15 +707,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* step 1: restore register */ xhci_restore_registers(xhci); /* step 2: initialize command ring buffer */ - val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); - val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | - (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, - xhci->cmd_ring->dequeue) & - (u64) ~CMD_RING_RSVD_BITS) | - xhci->cmd_ring->cycle_state; - xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n", - (long unsigned long) val_64); - xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); + xhci_set_cmd_ring_deq(xhci); /* step 3: restore state and start state*/ /* step 3: set CRS flag */ command = xhci_readl(xhci, &xhci->op_regs->command); @@ -714,6 +765,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) return retval; } + spin_unlock_irq(&xhci->lock); /* Re-setup MSI-X */ if (hcd->irq) free_irq(hcd->irq, hcd); @@ -736,6 +788,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) hcd->irq = pdev->irq; } + spin_lock_irq(&xhci->lock); /* step 4: set Run/Stop bit */ command = xhci_readl(xhci, &xhci->op_regs->command); command |= CMD_RUN; @@ -1496,6 +1549,15 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, cmd_completion = command->completion; cmd_status = &command->status; command->command_trb = xhci->cmd_ring->enqueue; + + /* Enqueue pointer can be left pointing to the link TRB, + * we must handle that + */ + if ((command->command_trb->link.control & TRB_TYPE_BITMASK) + == TRB_TYPE(TRB_LINK)) + command->command_trb = + xhci->cmd_ring->enq_seg->next->trbs; + list_add_tail(&command->cmd_list, &virt_dev->cmd_list); } else { in_ctx = virt_dev->in_ctx; @@ -2219,6 +2281,15 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) /* Attempt to submit the Reset Device command to the command ring */ spin_lock_irqsave(&xhci->lock, flags); reset_device_cmd->command_trb = xhci->cmd_ring->enqueue; + + /* Enqueue pointer can be left pointing to the link TRB, + * we must handle that + */ + if ((reset_device_cmd->command_trb->link.control & TRB_TYPE_BITMASK) + == TRB_TYPE(TRB_LINK)) + reset_device_cmd->command_trb = + xhci->cmd_ring->enq_seg->next->trbs; + list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list); ret = xhci_queue_reset_device(xhci, slot_id); if (ret) { diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 93d3bf4d213c..170c367112d2 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -454,6 +454,24 @@ struct xhci_doorbell_array { /** + * struct xhci_protocol_caps + * @revision: major revision, minor revision, capability ID, + * and next capability pointer. + * @name_string: Four ASCII characters to say which spec this xHC + * follows, typically "USB ". + * @port_info: Port offset, count, and protocol-defined information. + */ +struct xhci_protocol_caps { + u32 revision; + u32 name_string; + u32 port_info; +}; + +#define XHCI_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff) +#define XHCI_EXT_PORT_OFF(x) ((x) & 0xff) +#define XHCI_EXT_PORT_COUNT(x) (((x) >> 8) & 0xff) + +/** * struct xhci_container_ctx * @type: Type of context. Used to calculated offsets to contained contexts. * @size: Size of the context data @@ -621,6 +639,11 @@ struct xhci_ep_ctx { #define MAX_PACKET_MASK (0xffff << 16) #define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff) +/* Get max packet size from ep desc. Bit 10..0 specify the max packet size. + * USB2.0 spec 9.6.6. + */ +#define GET_MAX_PACKET(p) ((p) & 0x7ff) + /* tx_info bitmasks */ #define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff) #define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16) @@ -1235,6 +1258,14 @@ struct xhci_hcd { u32 suspended_ports[8]; /* which ports are suspended */ unsigned long resume_done[MAX_HC_PORTS]; + /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */ + u8 *port_array; + /* Array of pointers to USB 3.0 PORTSC registers */ + u32 __iomem **usb3_ports; + unsigned int num_usb3_ports; + /* Array of pointers to USB 2.0 PORTSC registers */ + u32 __iomem **usb2_ports; + unsigned int num_usb2_ports; }; /* For testing purposes */ diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c index 2f43c57743c9..9251773ecef4 100644 --- a/drivers/usb/misc/cypress_cy7c63.c +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -196,11 +196,9 @@ static ssize_t get_port1_handler(struct device *dev, return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1); } -static DEVICE_ATTR(port0, S_IWUGO | S_IRUGO, - get_port0_handler, set_port0_handler); +static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR, get_port0_handler, set_port0_handler); -static DEVICE_ATTR(port1, S_IWUGO | S_IRUGO, - get_port1_handler, set_port1_handler); +static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR, get_port1_handler, set_port1_handler); static int cypress_probe(struct usb_interface *interface, diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index d77aba46ae85..f63776a48e2a 100644 --- a/drivers/usb/misc/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c @@ -86,7 +86,7 @@ static ssize_t set_speed(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed); +static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR, show_speed, set_speed); static int tv_probe(struct usb_interface *interface, const struct usb_device_id *id) diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c index 63da2c3c838f..c96f51de1696 100644 --- a/drivers/usb/misc/usbled.c +++ b/drivers/usb/misc/usbled.c @@ -94,7 +94,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co change_color(led); \ return count; \ } \ -static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value); +static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value); show_set(blue); show_set(red); show_set(green); diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c index de8ef945b536..417b8f207e8b 100644 --- a/drivers/usb/misc/usbsevseg.c +++ b/drivers/usb/misc/usbsevseg.c @@ -192,7 +192,7 @@ static ssize_t set_attr_##name(struct device *dev, \ \ return count; \ } \ -static DEVICE_ATTR(name, S_IWUGO | S_IRUGO, show_attr_##name, set_attr_##name); +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_attr_##name, set_attr_##name); static ssize_t show_attr_text(struct device *dev, struct device_attribute *attr, char *buf) @@ -223,7 +223,7 @@ static ssize_t set_attr_text(struct device *dev, return count; } -static DEVICE_ATTR(text, S_IWUGO | S_IRUGO, show_attr_text, set_attr_text); +static DEVICE_ATTR(text, S_IRUGO | S_IWUSR, show_attr_text, set_attr_text); static ssize_t show_attr_decimals(struct device *dev, struct device_attribute *attr, char *buf) @@ -272,8 +272,7 @@ static ssize_t set_attr_decimals(struct device *dev, return count; } -static DEVICE_ATTR(decimals, S_IWUGO | S_IRUGO, - show_attr_decimals, set_attr_decimals); +static DEVICE_ATTR(decimals, S_IRUGO | S_IWUSR, show_attr_decimals, set_attr_decimals); static ssize_t show_attr_textmode(struct device *dev, struct device_attribute *attr, char *buf) @@ -319,8 +318,7 @@ static ssize_t set_attr_textmode(struct device *dev, return -EINVAL; } -static DEVICE_ATTR(textmode, S_IWUGO | S_IRUGO, - show_attr_textmode, set_attr_textmode); +static DEVICE_ATTR(textmode, S_IRUGO | S_IWUSR, show_attr_textmode, set_attr_textmode); MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered); diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 796e2f68f749..4ff21587ab03 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -3,7 +3,7 @@ /* * uss720.c -- USS720 USB Parport Cable. * - * Copyright (C) 1999, 2005 + * Copyright (C) 1999, 2005, 2010 * Thomas Sailer (t.sailer@alumni.ethz.ch) * * This program is free software; you can redistribute it and/or modify @@ -776,6 +776,8 @@ static const struct usb_device_id uss720_table[] = { { USB_DEVICE(0x0557, 0x2001) }, { USB_DEVICE(0x0729, 0x1284) }, { USB_DEVICE(0x1293, 0x0002) }, + { USB_DEVICE(0x1293, 0x0002) }, + { USB_DEVICE(0x050d, 0x0002) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 719c6180b31f..ac5bfd619e62 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -536,6 +536,7 @@ static const struct file_operations yurex_fops = { .open = yurex_open, .release = yurex_release, .fasync = yurex_fasync, + .llseek = default_llseek, }; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index e6669fc3b804..99beebce8550 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2116,12 +2116,15 @@ bad_config: * Otherwise, wait till the gadget driver hooks up. */ if (!is_otg_enabled(musb) && is_host_enabled(musb)) { + struct usb_hcd *hcd = musb_to_hcd(musb); + MUSB_HST_MODE(musb); musb->xceiv->default_a = 1; musb->xceiv->state = OTG_STATE_A_IDLE; status = usb_add_hcd(musb_to_hcd(musb), -1, 0); + hcd->self.uses_pio_for_control = 1; DBG(1, "%s mode, status %d, devctl %02x %c\n", "HOST", status, musb_readb(musb->mregs, MUSB_DEVCTL), diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 36cfd060dbe5..9d6ade82b9f2 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -92,6 +92,59 @@ /* ----------------------------------------------------------------------- */ +/* Maps the buffer to dma */ + +static inline void map_dma_buffer(struct musb_request *request, + struct musb *musb) +{ + if (request->request.dma == DMA_ADDR_INVALID) { + request->request.dma = dma_map_single( + musb->controller, + request->request.buf, + request->request.length, + request->tx + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + request->mapped = 1; + } else { + dma_sync_single_for_device(musb->controller, + request->request.dma, + request->request.length, + request->tx + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + request->mapped = 0; + } +} + +/* Unmap the buffer from dma and maps it back to cpu */ +static inline void unmap_dma_buffer(struct musb_request *request, + struct musb *musb) +{ + if (request->request.dma == DMA_ADDR_INVALID) { + DBG(20, "not unmapping a never mapped buffer\n"); + return; + } + if (request->mapped) { + dma_unmap_single(musb->controller, + request->request.dma, + request->request.length, + request->tx + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + request->request.dma = DMA_ADDR_INVALID; + request->mapped = 0; + } else { + dma_sync_single_for_cpu(musb->controller, + request->request.dma, + request->request.length, + request->tx + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + + } +} + /* * Immediately complete a request. * @@ -119,24 +172,8 @@ __acquires(ep->musb->lock) ep->busy = 1; spin_unlock(&musb->lock); - if (is_dma_capable()) { - if (req->mapped) { - dma_unmap_single(musb->controller, - req->request.dma, - req->request.length, - req->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->request.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } else if (req->request.dma != DMA_ADDR_INVALID) - dma_sync_single_for_cpu(musb->controller, - req->request.dma, - req->request.length, - req->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - } + if (is_dma_capable() && ep->dma) + unmap_dma_buffer(req, musb); if (request->status == 0) DBG(5, "%s done request %p, %d/%d\n", ep->end_point.name, request, @@ -395,6 +432,13 @@ static void txstate(struct musb *musb, struct musb_request *req) #endif if (!use_dma) { + /* + * Unmap the dma buffer back to cpu if dma channel + * programming fails + */ + if (is_dma_capable() && musb_ep->dma) + unmap_dma_buffer(req, musb); + musb_write_fifo(musb_ep->hw_ep, fifo_count, (u8 *) (request->buf + request->actual)); request->actual += fifo_count; @@ -713,6 +757,21 @@ static void rxstate(struct musb *musb, struct musb_request *req) return; } #endif + /* + * Unmap the dma buffer back to cpu if dma channel + * programming fails. This buffer is mapped if the + * channel allocation is successful + */ + if (is_dma_capable() && musb_ep->dma) { + unmap_dma_buffer(req, musb); + + /* + * Clear DMAENAB and AUTOCLEAR for the + * PIO mode transfer + */ + csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR); + musb_writew(epio, MUSB_RXCSR, csr); + } musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *) (request->buf + request->actual)); @@ -837,7 +896,9 @@ void musb_g_rx(struct musb *musb, u8 epnum) if (!request) return; } +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) exit: +#endif /* Analyze request */ rxstate(musb, to_musb_request(request)); } @@ -1150,26 +1211,9 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, request->epnum = musb_ep->current_epnum; request->tx = musb_ep->is_in; - if (is_dma_capable() && musb_ep->dma) { - if (request->request.dma == DMA_ADDR_INVALID) { - request->request.dma = dma_map_single( - musb->controller, - request->request.buf, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - request->mapped = 1; - } else { - dma_sync_single_for_device(musb->controller, - request->request.dma, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - request->mapped = 0; - } - } else + if (is_dma_capable() && musb_ep->dma) + map_dma_buffer(request, musb); + else request->mapped = 0; spin_lock_irqsave(&musb->lock, lockflags); @@ -1789,6 +1833,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, spin_unlock_irqrestore(&musb->lock, flags); if (is_otg_enabled(musb)) { + struct usb_hcd *hcd = musb_to_hcd(musb); + DBG(3, "OTG startup...\n"); /* REVISIT: funcall to other code, which also @@ -1803,6 +1849,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, musb->gadget_driver = NULL; musb->g.dev.driver = NULL; spin_unlock_irqrestore(&musb->lock, flags); + } else { + hcd->self.uses_pio_for_control = 1; } } } diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c index bdc3ea66be69..9fea48264fa2 100644 --- a/drivers/usb/otg/langwell_otg.c +++ b/drivers/usb/otg/langwell_otg.c @@ -1896,7 +1896,7 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr, } return count; } -static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req); +static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req); static ssize_t get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf) @@ -1942,8 +1942,7 @@ set_a_bus_drop(struct device *dev, struct device_attribute *attr, } return count; } -static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO, - get_a_bus_drop, set_a_bus_drop); +static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop, set_a_bus_drop); static ssize_t get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf) @@ -1988,7 +1987,7 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr, } return count; } -static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req); +static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req); static ssize_t set_a_clr_err(struct device *dev, struct device_attribute *attr, @@ -2012,7 +2011,7 @@ set_a_clr_err(struct device *dev, struct device_attribute *attr, } return count; } -static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err); +static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err); static struct attribute *inputs_attrs[] = { &dev_attr_a_bus_req.attr, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 76f8b3556672..2dec50013528 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -201,6 +201,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) }, + { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) }, { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) }, @@ -696,6 +697,7 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, @@ -794,6 +796,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { }, /* Optional parameter entry */ diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 263f62551197..bf0867285481 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -114,6 +114,9 @@ /* Lenz LI-USB Computer Interface. */ #define FTDI_LENZ_LIUSB_PID 0xD780 +/* Vardaan Enterprises Serial Interface VEUSB422R3 */ +#define FTDI_VARDAAN_PID 0xF070 + /* * Xsens Technologies BV products (http://www.xsens.com). */ @@ -721,6 +724,7 @@ */ #define RTSYSTEMS_VID 0x2100 /* Vendor ID */ #define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ +#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */ /* * Bayer Ascensia Contour blood glucose meter USB-converter cable. @@ -1077,6 +1081,11 @@ #define MJSG_HD_RADIO_PID 0x937C /* + * D.O.Tec products (http://www.directout.eu) + */ +#define FTDI_DOTEC_PID 0x9868 + +/* * Xverve Signalyzer tools (http://www.signalyzer.com/) */ #define XVERVE_SIGNALYZER_ST_PID 0xBCA0 diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 861223f2af6e..6954de50c0ff 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -51,6 +51,7 @@ static struct usb_driver usb_serial_driver = { .suspend = usb_serial_suspend, .resume = usb_serial_resume, .no_dynamic_id = 1, + .supports_autosuspend = 1, }; /* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead @@ -1343,6 +1344,8 @@ int usb_serial_register(struct usb_serial_driver *driver) return -ENODEV; fixup_generic(driver); + if (driver->usb_driver) + driver->usb_driver->supports_autosuspend = 1; if (!driver->description) driver->description = driver->driver.name; diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index 57fc2f532cab..ceba512f84d0 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c @@ -121,7 +121,7 @@ static ssize_t show_truinst(struct device *dev, struct device_attribute *attr, } return result; } -static DEVICE_ATTR(truinst, S_IWUGO | S_IRUGO, show_truinst, NULL); +static DEVICE_ATTR(truinst, S_IRUGO, show_truinst, NULL); int sierra_ms_init(struct us_data *us) { diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 6ccdd3dd5259..fcc1e32ce256 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -481,6 +481,13 @@ UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_MAX_SECTORS_64), +/* Reported by Vitaly Kuznetsov <vitty@altlinux.ru> */ +UNUSUAL_DEV( 0x04e8, 0x5122, 0x0000, 0x9999, + "Samsung", + "YP-CP3", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 | US_FL_BULK_IGNORE_TAG), + /* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>. * Device uses standards-violating 32-byte Bulk Command Block Wrappers and * reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011. diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 4b4da5b86ff9..f442668a1e52 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -129,8 +129,9 @@ static void handle_tx(struct vhost_net *net) size_t hdr_size; struct socket *sock; - sock = rcu_dereference_check(vq->private_data, - lockdep_is_held(&vq->mutex)); + /* TODO: check that we are running from vhost_worker? + * Not sure it's worth it, it's straight-forward enough. */ + sock = rcu_dereference_check(vq->private_data, 1); if (!sock) return; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 94701ff3a23a..159c77a5746f 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -884,6 +884,7 @@ static int log_write(void __user *log_base, int r; if (!write_length) return 0; + write_length += write_address % VHOST_PAGE_SIZE; write_address /= VHOST_PAGE_SIZE; for (;;) { u64 base = (u64)(unsigned long)log_base; @@ -897,7 +898,7 @@ static int log_write(void __user *log_base, if (write_length <= VHOST_PAGE_SIZE) break; write_length -= VHOST_PAGE_SIZE; - write_address += VHOST_PAGE_SIZE; + write_address += 1; } return r; } diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index e207810bba3c..08703299ef61 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -197,12 +197,12 @@ static int backlight_suspend(struct device *dev, pm_message_t state) { struct backlight_device *bd = to_backlight_device(dev); - if (bd->ops->options & BL_CORE_SUSPENDRESUME) { - mutex_lock(&bd->ops_lock); + mutex_lock(&bd->ops_lock); + if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) { bd->props.state |= BL_CORE_SUSPENDED; backlight_update_status(bd); - mutex_unlock(&bd->ops_lock); } + mutex_unlock(&bd->ops_lock); return 0; } @@ -211,12 +211,12 @@ static int backlight_resume(struct device *dev) { struct backlight_device *bd = to_backlight_device(dev); - if (bd->ops->options & BL_CORE_SUSPENDRESUME) { - mutex_lock(&bd->ops_lock); + mutex_lock(&bd->ops_lock); + if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) { bd->props.state &= ~BL_CORE_SUSPENDED; backlight_update_status(bd); - mutex_unlock(&bd->ops_lock); } + mutex_unlock(&bd->ops_lock); return 0; } diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index cad7d45c8bac..c265aed09e04 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -1029,10 +1029,6 @@ static int __init fb_probe(struct platform_device *device) goto err_release_pl_mem; } - ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); - if (ret) - goto err_release_pl_mem; - /* Initialize par */ da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp; @@ -1060,7 +1056,7 @@ static int __init fb_probe(struct platform_device *device) ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); if (ret) - goto err_free_irq; + goto err_release_pl_mem; da8xx_fb_info->cmap.len = par->palette_sz; /* initialize var_screeninfo */ @@ -1088,8 +1084,13 @@ static int __init fb_probe(struct platform_device *device) goto err_cpu_freq; } #endif + + ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); + if (ret) + goto irq_freq; return 0; +irq_freq: #ifdef CONFIG_CPU_FREQ err_cpu_freq: unregister_framebuffer(da8xx_fb_info); @@ -1098,9 +1099,6 @@ err_cpu_freq: err_dealloc_cmap: fb_dealloc_cmap(&da8xx_fb_info->cmap); -err_free_irq: - free_irq(par->irq, par); - err_release_pl_mem: dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base, par->p_palette_base); diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index f53b9f1d6aba..5c3960da755a 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c @@ -80,6 +80,7 @@ static const struct fb_cmap default_16_colors = { * @cmap: frame buffer colormap structure * @len: length of @cmap * @transp: boolean, 1 if there is transparency, 0 otherwise + * @flags: flags for kmalloc memory allocation * * Allocates memory for a colormap @cmap. @len is the * number of entries in the palette. @@ -88,34 +89,48 @@ static const struct fb_cmap default_16_colors = { * */ -int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp) +int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags) { - int size = len*sizeof(u16); - - if (cmap->len != len) { - fb_dealloc_cmap(cmap); - if (!len) - return 0; - if (!(cmap->red = kmalloc(size, GFP_ATOMIC))) - goto fail; - if (!(cmap->green = kmalloc(size, GFP_ATOMIC))) - goto fail; - if (!(cmap->blue = kmalloc(size, GFP_ATOMIC))) - goto fail; - if (transp) { - if (!(cmap->transp = kmalloc(size, GFP_ATOMIC))) + int size = len * sizeof(u16); + int ret = -ENOMEM; + + if (cmap->len != len) { + fb_dealloc_cmap(cmap); + if (!len) + return 0; + + cmap->red = kmalloc(size, flags); + if (!cmap->red) + goto fail; + cmap->green = kmalloc(size, flags); + if (!cmap->green) + goto fail; + cmap->blue = kmalloc(size, flags); + if (!cmap->blue) + goto fail; + if (transp) { + cmap->transp = kmalloc(size, flags); + if (!cmap->transp) + goto fail; + } else { + cmap->transp = NULL; + } + } + cmap->start = 0; + cmap->len = len; + ret = fb_copy_cmap(fb_default_cmap(len), cmap); + if (ret) goto fail; - } else - cmap->transp = NULL; - } - cmap->start = 0; - cmap->len = len; - fb_copy_cmap(fb_default_cmap(len), cmap); - return 0; + return 0; fail: - fb_dealloc_cmap(cmap); - return -ENOMEM; + fb_dealloc_cmap(cmap); + return ret; +} + +int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp) +{ + return fb_alloc_cmap_gfp(cmap, len, transp, GFP_ATOMIC); } /** @@ -250,8 +265,12 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info) int rc, size = cmap->len * sizeof(u16); struct fb_cmap umap; + if (size < 0 || size < cmap->len) + return -E2BIG; + memset(&umap, 0, sizeof(struct fb_cmap)); - rc = fb_alloc_cmap(&umap, cmap->len, cmap->transp != NULL); + rc = fb_alloc_cmap_gfp(&umap, cmap->len, cmap->transp != NULL, + GFP_KERNEL); if (rc) return rc; if (copy_from_user(umap.red, cmap->red, size) || diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h index e4c4d89b7860..be8ccb47ebe0 100644 --- a/drivers/video/geode/lxfb.h +++ b/drivers/video/geode/lxfb.h @@ -22,6 +22,7 @@ #define DC_HFILT_COUNT 0x100 #define DC_VFILT_COUNT 0x100 #define VP_COEFF_SIZE 0x1000 +#define VP_PAL_COUNT 0x100 #define OUTPUT_CRT 0x01 #define OUTPUT_PANEL 0x02 @@ -48,7 +49,8 @@ struct lxfb_par { uint64_t vp[VP_REG_COUNT]; uint64_t fp[FP_REG_COUNT]; - uint32_t pal[DC_PAL_COUNT]; + uint32_t dc_pal[DC_PAL_COUNT]; + uint32_t vp_pal[VP_PAL_COUNT]; uint32_t hcoeff[DC_HFILT_COUNT * 2]; uint32_t vcoeff[DC_VFILT_COUNT]; uint32_t vp_coeff[VP_COEFF_SIZE / 4]; diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c index bc35a95e59d4..79e9abc72b83 100644 --- a/drivers/video/geode/lxfb_ops.c +++ b/drivers/video/geode/lxfb_ops.c @@ -276,10 +276,10 @@ static void lx_graphics_enable(struct fb_info *info) write_fp(par, FP_PT1, 0); temp = FP_PT2_SCRC; - if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) temp |= FP_PT2_HSP; - if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) temp |= FP_PT2_VSP; write_fp(par, FP_PT2, temp); @@ -610,10 +610,15 @@ static void lx_save_regs(struct lxfb_par *par) memcpy(par->vp, par->vp_regs, sizeof(par->vp)); memcpy(par->fp, par->vp_regs + VP_FP_START, sizeof(par->fp)); - /* save the palette */ + /* save the display controller palette */ write_dc(par, DC_PAL_ADDRESS, 0); - for (i = 0; i < ARRAY_SIZE(par->pal); i++) - par->pal[i] = read_dc(par, DC_PAL_DATA); + for (i = 0; i < ARRAY_SIZE(par->dc_pal); i++) + par->dc_pal[i] = read_dc(par, DC_PAL_DATA); + + /* save the video processor palette */ + write_vp(par, VP_PAR, 0); + for (i = 0; i < ARRAY_SIZE(par->vp_pal); i++) + par->vp_pal[i] = read_vp(par, VP_PDR); /* save the horizontal filter coefficients */ filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL; @@ -706,8 +711,8 @@ static void lx_restore_display_ctlr(struct lxfb_par *par) /* restore the palette */ write_dc(par, DC_PAL_ADDRESS, 0); - for (i = 0; i < ARRAY_SIZE(par->pal); i++) - write_dc(par, DC_PAL_DATA, par->pal[i]); + for (i = 0; i < ARRAY_SIZE(par->dc_pal); i++) + write_dc(par, DC_PAL_DATA, par->dc_pal[i]); /* restore the horizontal filter coefficients */ filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL; @@ -751,6 +756,11 @@ static void lx_restore_video_proc(struct lxfb_par *par) } } + /* restore video processor palette */ + write_vp(par, VP_PAR, 0); + for (i = 0; i < ARRAY_SIZE(par->vp_pal); i++) + write_vp(par, VP_PDR, par->vp_pal[i]); + /* restore video coeff ram */ memcpy(par->vp_regs + VP_VCR, par->vp_coeff, sizeof(par->vp_coeff)); } diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index c3a182581c1f..7a61ba6a4850 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -902,6 +902,7 @@ const struct fb_videomode *fb_find_nearest_mode(const struct fb_videomode *mode, abs(cmode->yres - mode->yres); if (diff > d) { diff = d; + diff_refresh = abs(cmode->refresh - mode->refresh); best = cmode; } else if (diff == d) { d = abs(cmode->refresh - mode->refresh); diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 9f7c9015de3b..cb013919e9ce 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -27,6 +27,7 @@ #include <linux/clk.h> #include <linux/mutex.h> +#include <mach/dma.h> #include <mach/hardware.h> #include <mach/ipu.h> #include <mach/mx3fb.h> @@ -1420,6 +1421,9 @@ static bool chan_filter(struct dma_chan *chan, void *arg) struct device *dev; struct mx3fb_platform_data *mx3fb_pdata; + if (!imx_dma_is_ipu(chan)) + return false; + if (!rq) return false; diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig index 455c6055325d..083c8fe53e24 100644 --- a/drivers/video/omap/Kconfig +++ b/drivers/video/omap/Kconfig @@ -1,7 +1,7 @@ config FB_OMAP tristate "OMAP frame buffer support (EXPERIMENTAL)" - depends on FB && ARCH_OMAP && (OMAP2_DSS = "n") - + depends on FB && (OMAP2_DSS = "n") + depends on ARCH_OMAP1 || ARCH_OMAP2 || ARCH_OMAP3 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c index 2fd7e5271be9..9441e2eb3dee 100644 --- a/drivers/video/omap2/vram.c +++ b/drivers/video/omap2/vram.c @@ -551,7 +551,7 @@ void __init omap_vram_reserve_sdram_memblock(void) if (!size) return; - size = PAGE_ALIGN(size); + size = ALIGN(size, SZ_2M); if (paddr) { if (paddr & ~PAGE_MASK) { @@ -576,7 +576,7 @@ void __init omap_vram_reserve_sdram_memblock(void) return; } } else { - paddr = memblock_alloc(size, PAGE_SIZE); + paddr = memblock_alloc(size, SZ_2M); } memblock_free(paddr, size); diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 37419ba2c29a..778bffbbdbb7 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -860,7 +860,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info) /* Couldn't reconfigure, hopefully, can continue as before */ return; - info->fix.line_length = mode2.xres * (ch->cfg.bpp / 8); + info->fix.line_length = mode1.xres * (ch->cfg.bpp / 8); /* * fb_set_var() calls the notifier change internally, only if @@ -868,7 +868,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info) * user event, we have to call the chain ourselves. */ event.info = info; - event.data = &mode2; + event.data = &mode1; fb_notifier_call_chain(evnt, &event); } diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c index c311ad3c3687..31137adc8fba 100644 --- a/drivers/video/sis/init.c +++ b/drivers/video/sis/init.c @@ -62,11 +62,11 @@ #include "init.h" -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 #include "300vtbl.h" #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 #include "310vtbl.h" #endif @@ -78,7 +78,7 @@ /* POINTER INITIALIZATION */ /*********************************************/ -#if defined(SIS300) || defined(SIS315H) +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) static void InitCommonPointer(struct SiS_Private *SiS_Pr) { @@ -160,7 +160,7 @@ InitCommonPointer(struct SiS_Private *SiS_Pr) } #endif -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 static void InitTo300Pointer(struct SiS_Private *SiS_Pr) { @@ -237,7 +237,7 @@ InitTo300Pointer(struct SiS_Private *SiS_Pr) } #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static void InitTo310Pointer(struct SiS_Private *SiS_Pr) { @@ -321,13 +321,13 @@ bool SiSInitPtr(struct SiS_Private *SiS_Pr) { if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 InitTo300Pointer(SiS_Pr); #else return false; #endif } else { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 InitTo310Pointer(SiS_Pr); #else return false; @@ -340,9 +340,7 @@ SiSInitPtr(struct SiS_Private *SiS_Pr) /* HELPER: Get ModeID */ /*********************************************/ -#ifndef SIS_XORG_XF86 static -#endif unsigned short SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, int Depth, bool FSTN, int LCDwidth, int LCDheight) @@ -884,51 +882,51 @@ SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDispl void SiS_SetReg(SISIOADDRESS port, unsigned short index, unsigned short data) { - OutPortByte(port, index); - OutPortByte(port + 1, data); + outb((u8)index, port); + outb((u8)data, port + 1); } void SiS_SetRegByte(SISIOADDRESS port, unsigned short data) { - OutPortByte(port, data); + outb((u8)data, port); } void SiS_SetRegShort(SISIOADDRESS port, unsigned short data) { - OutPortWord(port, data); + outw((u16)data, port); } void SiS_SetRegLong(SISIOADDRESS port, unsigned int data) { - OutPortLong(port, data); + outl((u32)data, port); } unsigned char SiS_GetReg(SISIOADDRESS port, unsigned short index) { - OutPortByte(port, index); - return(InPortByte(port + 1)); + outb((u8)index, port); + return inb(port + 1); } unsigned char SiS_GetRegByte(SISIOADDRESS port) { - return(InPortByte(port)); + return inb(port); } unsigned short SiS_GetRegShort(SISIOADDRESS port) { - return(InPortWord(port)); + return inw(port); } unsigned int SiS_GetRegLong(SISIOADDRESS port) { - return(InPortLong(port)); + return inl(port); } void @@ -1089,7 +1087,7 @@ static void SiSInitPCIetc(struct SiS_Private *SiS_Pr) { switch(SiS_Pr->ChipType) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 case SIS_300: case SIS_540: case SIS_630: @@ -1108,7 +1106,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr) SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x5A); break; #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 case SIS_315H: case SIS_315: case SIS_315PRO: @@ -1152,9 +1150,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr) /* HELPER: SetLVDSetc */ /*********************************************/ -#ifdef SIS_LINUX_KERNEL static -#endif void SiSSetLVDSetc(struct SiS_Private *SiS_Pr) { @@ -1174,7 +1170,7 @@ SiSSetLVDSetc(struct SiS_Private *SiS_Pr) if((temp == 1) || (temp == 2)) return; switch(SiS_Pr->ChipType) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 case SIS_540: case SIS_630: case SIS_730: @@ -1188,7 +1184,7 @@ SiSSetLVDSetc(struct SiS_Private *SiS_Pr) } break; #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 case SIS_550: case SIS_650: case SIS_740: @@ -1420,9 +1416,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) /* HELPER: GetVBType */ /*********************************************/ -#ifdef SIS_LINUX_KERNEL static -#endif void SiS_GetVBType(struct SiS_Private *SiS_Pr) { @@ -1487,7 +1481,6 @@ SiS_GetVBType(struct SiS_Private *SiS_Pr) /* HELPER: Check RAM size */ /*********************************************/ -#ifdef SIS_LINUX_KERNEL static bool SiS_CheckMemorySize(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) @@ -1501,13 +1494,12 @@ SiS_CheckMemorySize(struct SiS_Private *SiS_Pr, unsigned short ModeNo, if(AdapterMemSize < memorysize) return false; return true; } -#endif /*********************************************/ /* HELPER: Get DRAM type */ /*********************************************/ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static unsigned char SiS_Get310DRAMType(struct SiS_Private *SiS_Pr) { @@ -1574,7 +1566,6 @@ SiS_GetMCLK(struct SiS_Private *SiS_Pr) /* HELPER: ClearBuffer */ /*********************************************/ -#ifdef SIS_LINUX_KERNEL static void SiS_ClearBuffer(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { @@ -1587,7 +1578,7 @@ SiS_ClearBuffer(struct SiS_Private *SiS_Pr, unsigned short ModeNo) if(SiS_Pr->SiS_ModeType >= ModeEGA) { if(ModeNo > 0x13) { - SiS_SetMemory(memaddr, memsize, 0); + memset_io(memaddr, 0, memsize); } else { pBuffer = (unsigned short SISIOMEMTYPE *)memaddr; for(i = 0; i < 0x4000; i++) writew(0x0000, &pBuffer[i]); @@ -1596,10 +1587,9 @@ SiS_ClearBuffer(struct SiS_Private *SiS_Pr, unsigned short ModeNo) pBuffer = (unsigned short SISIOMEMTYPE *)memaddr; for(i = 0; i < 0x4000; i++) writew(0x0720, &pBuffer[i]); } else { - SiS_SetMemory(memaddr, 0x8000, 0); + memset_io(memaddr, 0, 0x8000); } } -#endif /*********************************************/ /* HELPER: SearchModeID */ @@ -2132,7 +2122,7 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F); } -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType == XGI_20) { SiS_SetReg(SiS_Pr->SiS_P3d4,0x04,crt1data[4] - 1); if(!(temp = crt1data[5] & 0x1f)) { @@ -2215,7 +2205,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,clkb); if(SiS_Pr->ChipType >= SIS_315H) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x01); if(SiS_Pr->ChipType == XGI_20) { unsigned short mf = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); @@ -2236,7 +2226,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, /* FIFO */ /*********************************************/ -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 void SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *idx1, unsigned short *idx2) @@ -2506,11 +2496,7 @@ SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data); /* Write foreground and background queue */ -#ifdef SIS_LINUX_KERNEL templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0x50); -#else - templ = pciReadLong(0x00000000, 0x50); -#endif if(SiS_Pr->ChipType == SIS_730) { @@ -2530,13 +2516,8 @@ SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo, } -#ifdef SIS_LINUX_KERNEL sisfb_write_nbridge_pci_dword(SiS_Pr, 0x50, templ); templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0xA0); -#else - pciWriteLong(0x00000000, 0x50, templ); - templ = pciReadLong(0x00000000, 0xA0); -#endif /* GUI grant timer (PCI config 0xA3) */ if(SiS_Pr->ChipType == SIS_730) { @@ -2552,15 +2533,11 @@ SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo, } -#ifdef SIS_LINUX_KERNEL sisfb_write_nbridge_pci_dword(SiS_Pr, 0xA0, templ); -#else - pciWriteLong(0x00000000, 0xA0, templ); -#endif } -#endif /* SIS300 */ +#endif /* CONFIG_FB_SIS_300 */ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static void SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { @@ -2612,7 +2589,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, } if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(VCLK > 150) data |= 0x80; SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data); @@ -2621,7 +2598,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data); #endif } else if(SiS_Pr->ChipType < XGI_20) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(VCLK >= 166) data |= 0x0c; SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data); @@ -2630,7 +2607,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, } #endif } else { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(VCLK >= 200) data |= 0x0c; if(SiS_Pr->ChipType == XGI_20) data &= ~0x04; SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data); @@ -2675,7 +2652,7 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RRTI) { unsigned short data, infoflag = 0, modeflag, resindex; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; unsigned short data2, data3; #endif @@ -2736,7 +2713,7 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,data); } -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType >= SIS_315H) { SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xfb); } @@ -2826,7 +2803,7 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_SetVCLKState(SiS_Pr, ModeNo, RRTI, ModeIdIndex); -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->ChipType < SIS_661)) || (SiS_Pr->ChipType == XGI_40)) { if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) { @@ -2845,7 +2822,7 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, #endif } -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static void SiS_SetupDualChip(struct SiS_Private *SiS_Pr) { @@ -2999,11 +2976,6 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sho SiS_Pr->SiS_SelectCRT2Rate = 0; SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); -#ifdef SIS_XORG_XF86 - xf86DrvMsgVerb(0, X_PROBED, 4, "(init: VBType=0x%04x, VBInfo=0x%04x)\n", - SiS_Pr->SiS_VBType, SiS_Pr->SiS_VBInfo); -#endif - if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) { if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; @@ -3028,7 +3000,7 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sho } switch(SiS_Pr->ChipType) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 case SIS_300: SiS_SetCRT1FIFO_300(SiS_Pr, ModeNo, RefreshRateTableIndex); break; @@ -3039,7 +3011,7 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sho break; #endif default: -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType == XGI_20) { unsigned char sr2b = 0, sr2c = 0; switch(ModeNo) { @@ -3062,7 +3034,7 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sho SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType == XGI_40) { SiS_SetupDualChip(SiS_Pr); } @@ -3070,11 +3042,9 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sho SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex); -#ifdef SIS_LINUX_KERNEL if(SiS_Pr->SiS_flag_clearbuffer) { SiS_ClearBuffer(SiS_Pr, ModeNo); } -#endif if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA))) { SiS_WaitRetrace1(SiS_Pr); @@ -3104,7 +3074,7 @@ SiS_InitVB(struct SiS_Private *SiS_Pr) static void SiS_ResetVB(struct SiS_Private *SiS_Pr) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; unsigned short temp; @@ -3139,7 +3109,7 @@ SiS_StrangeStuff(struct SiS_Private *SiS_Pr) * which locks CRT2 in some way to CRT1 timing. Disable * this here. */ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if((IS_SIS651) || (IS_SISM650) || SiS_Pr->ChipType == SIS_340 || SiS_Pr->ChipType == XGI_40) { @@ -3160,7 +3130,7 @@ SiS_StrangeStuff(struct SiS_Private *SiS_Pr) static void SiS_Handle760(struct SiS_Private *SiS_Pr) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned int somebase; unsigned char temp1, temp2, temp3; @@ -3170,11 +3140,7 @@ SiS_Handle760(struct SiS_Private *SiS_Pr) (!(SiS_Pr->SiS_SysFlags & SF_760UMA)) ) return; -#ifdef SIS_LINUX_KERNEL somebase = sisfb_read_mio_pci_word(SiS_Pr, 0x74); -#else - somebase = pciReadWord(0x00001000, 0x74); -#endif somebase &= 0xffff; if(somebase == 0) return; @@ -3190,105 +3156,34 @@ SiS_Handle760(struct SiS_Private *SiS_Pr) temp2 = 0x0b; } -#ifdef SIS_LINUX_KERNEL sisfb_write_nbridge_pci_byte(SiS_Pr, 0x7e, temp1); sisfb_write_nbridge_pci_byte(SiS_Pr, 0x8d, temp2); -#else - pciWriteByte(0x00000000, 0x7e, temp1); - pciWriteByte(0x00000000, 0x8d, temp2); -#endif SiS_SetRegByte((somebase + 0x85), temp3); #endif } /*********************************************/ -/* X.org/XFree86: SET SCREEN PITCH */ -/*********************************************/ - -#ifdef SIS_XORG_XF86 -static void -SiS_SetPitchCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) -{ - SISPtr pSiS = SISPTR(pScrn); - unsigned short HDisplay = pSiS->scrnPitch >> 3; - - SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,(HDisplay & 0xFF)); - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,(HDisplay >> 8)); -} - -static void -SiS_SetPitchCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) -{ - SISPtr pSiS = SISPTR(pScrn); - unsigned short HDisplay = pSiS->scrnPitch2 >> 3; - - /* Unlock CRT2 */ - if(pSiS->VGAEngine == SIS_315_VGA) - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2F, 0x01); - else - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24, 0x01); - - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(HDisplay & 0xFF)); - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0xF0,(HDisplay >> 8)); -} - -static void -SiS_SetPitch(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) -{ - SISPtr pSiS = SISPTR(pScrn); - bool isslavemode = false; - - if( (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && - ( ((pSiS->VGAEngine == SIS_300_VGA) && - (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) || - ((pSiS->VGAEngine == SIS_315_VGA) && - (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) { - isslavemode = true; - } - - /* We need to set pitch for CRT1 if bridge is in slave mode, too */ - if((pSiS->VBFlags & DISPTYPE_DISP1) || (isslavemode)) { - SiS_SetPitchCRT1(SiS_Pr, pScrn); - } - /* We must not set the pitch for CRT2 if bridge is in slave mode */ - if((pSiS->VBFlags & DISPTYPE_DISP2) && (!isslavemode)) { - SiS_SetPitchCRT2(SiS_Pr, pScrn); - } -} -#endif - -/*********************************************/ /* SiSSetMode() */ /*********************************************/ -#ifdef SIS_XORG_XF86 -/* We need pScrn for setting the pitch correctly */ -bool -SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo, bool dosetpitch) -#else bool SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) -#endif { SISIOADDRESS BaseAddr = SiS_Pr->IOAddress; unsigned short RealModeNo, ModeIdIndex; unsigned char backupreg = 0; -#ifdef SIS_LINUX_KERNEL unsigned short KeepLockReg; SiS_Pr->UseCustomMode = false; SiS_Pr->CRT1UsesCustomMode = false; -#endif SiS_Pr->SiS_flag_clearbuffer = 0; if(SiS_Pr->UseCustomMode) { ModeNo = 0xfe; } else { -#ifdef SIS_LINUX_KERNEL if(!(ModeNo & 0x80)) SiS_Pr->SiS_flag_clearbuffer = 1; -#endif ModeNo &= 0x7f; } @@ -3301,13 +3196,8 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) SiS_GetSysFlags(SiS_Pr); SiS_Pr->SiS_VGAINFO = 0x11; -#if defined(SIS_XORG_XF86) && (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__)) - if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); -#endif -#ifdef SIS_LINUX_KERNEL KeepLockReg = SiS_GetReg(SiS_Pr->SiS_P3c4,0x05); -#endif SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); SiSInitPCIetc(SiS_Pr); @@ -3344,12 +3234,10 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex); SiS_SetLowModeTest(SiS_Pr, ModeNo); -#ifdef SIS_LINUX_KERNEL /* Check memory size (kernel framebuffer driver only) */ if(!SiS_CheckMemorySize(SiS_Pr, ModeNo, ModeIdIndex)) { return false; } -#endif SiS_OpenCRTC(SiS_Pr); @@ -3384,7 +3272,7 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) SiS_DisplayOn(SiS_Pr); SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { if(!(SiS_IsDualEdge(SiS_Pr))) { @@ -3396,7 +3284,7 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { if(SiS_Pr->ChipType >= SIS_315H) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(!SiS_Pr->SiS_ROMNew) { if(SiS_IsVAMode(SiS_Pr)) { SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); @@ -3424,424 +3312,16 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) } } -#ifdef SIS_XORG_XF86 - if(pScrn) { - /* SetPitch: Adapt to virtual size & position */ - if((ModeNo > 0x13) && (dosetpitch)) { - SiS_SetPitch(SiS_Pr, pScrn); - } - - /* Backup/Set ModeNo in BIOS scratch area */ - SiS_GetSetModeID(pScrn, ModeNo); - } -#endif - SiS_CloseCRTC(SiS_Pr); SiS_Handle760(SiS_Pr); -#ifdef SIS_LINUX_KERNEL /* We never lock registers in XF86 */ if(KeepLockReg != 0xA1) SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x00); -#endif return true; } -/*********************************************/ -/* X.org/XFree86: SiSBIOSSetMode() */ -/* for non-Dual-Head mode */ -/*********************************************/ - -#ifdef SIS_XORG_XF86 -bool -SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, - DisplayModePtr mode, bool IsCustom) -{ - SISPtr pSiS = SISPTR(pScrn); - unsigned short ModeNo = 0; - - SiS_Pr->UseCustomMode = false; - - if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) { - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting custom mode %dx%d\n", - SiS_Pr->CHDisplay, - (mode->Flags & V_INTERLACE ? SiS_Pr->CVDisplay * 2 : - (mode->Flags & V_DBLSCAN ? SiS_Pr->CVDisplay / 2 : - SiS_Pr->CVDisplay))); - - } else { - - /* Don't need vbflags here; checks done earlier */ - ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags); - if(!ModeNo) return false; - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo); - - } - - return(SiSSetMode(SiS_Pr, pScrn, ModeNo, true)); -} - -/*********************************************/ -/* X.org/XFree86: SiSBIOSSetModeCRT2() */ -/* for Dual-Head modes */ -/*********************************************/ - -bool -SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, - DisplayModePtr mode, bool IsCustom) -{ - SISIOADDRESS BaseAddr = SiS_Pr->IOAddress; - SISPtr pSiS = SISPTR(pScrn); -#ifdef SISDUALHEAD - SISEntPtr pSiSEnt = pSiS->entityPrivate; -#endif - unsigned short ModeIdIndex; - unsigned short ModeNo = 0; - unsigned char backupreg = 0; - - SiS_Pr->UseCustomMode = false; - - /* Remember: Custom modes for CRT2 are ONLY supported - * -) on the 30x/B/C, and - * -) if CRT2 is LCD or VGA, or CRT1 is LCDA - */ - - if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) { - - ModeNo = 0xfe; - - } else { - - ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags); - if(!ModeNo) return false; - - } - - SiSRegInit(SiS_Pr, BaseAddr); - SiSInitPtr(SiS_Pr); - SiS_GetSysFlags(SiS_Pr); -#if defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__) - SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); -#else - SiS_Pr->SiS_VGAINFO = 0x11; -#endif - - SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); - - SiSInitPCIetc(SiS_Pr); - SiSSetLVDSetc(SiS_Pr); - SiSDetermineROMUsage(SiS_Pr); - - /* Save mode info so we can set it from within SetMode for CRT1 */ -#ifdef SISDUALHEAD - if(pSiS->DualHeadMode) { - pSiSEnt->CRT2ModeNo = ModeNo; - pSiSEnt->CRT2DMode = mode; - pSiSEnt->CRT2IsCustom = IsCustom; - pSiSEnt->CRT2CR30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - pSiSEnt->CRT2CR31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31); - pSiSEnt->CRT2CR35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); - pSiSEnt->CRT2CR38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); -#if 0 - /* We can't set CRT2 mode before CRT1 mode is set - says who...? */ - if(pSiSEnt->CRT1ModeNo == -1) { - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, - "Setting CRT2 mode delayed until after setting CRT1 mode\n"); - return true; - } -#endif - pSiSEnt->CRT2ModeSet = true; - } -#endif - - if(SiS_Pr->UseCustomMode) { - - unsigned short temptemp = SiS_Pr->CVDisplay; - - if(SiS_Pr->CModeFlag & DoubleScanMode) temptemp >>= 1; - else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1; - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, - "Setting custom mode %dx%d on CRT2\n", - SiS_Pr->CHDisplay, temptemp); - - } else { - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, - "Setting standard mode 0x%x on CRT2\n", ModeNo); - - } - - SiS_UnLockCRT2(SiS_Pr); - - if(!SiS_Pr->UseCustomMode) { - if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false; - } else { - ModeIdIndex = 0; - } - - SiS_GetVBType(SiS_Pr); - - SiS_InitVB(SiS_Pr); - if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { - if(SiS_Pr->ChipType >= SIS_315H) { - SiS_ResetVB(SiS_Pr); - SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10); - SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c); - backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - } else { - backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); - } - } - - /* Get VB information (connectors, connected devices) */ - if(!SiS_Pr->UseCustomMode) { - SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 1); - } else { - /* If this is a custom mode, we don't check the modeflag for CRT2Mode */ - SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 0); - } - SiS_SetYPbPr(SiS_Pr); - SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex); - SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex); - SiS_SetLowModeTest(SiS_Pr, ModeNo); - - SiS_ResetSegmentRegisters(SiS_Pr); - - /* Set mode on CRT2 */ - if( (SiS_Pr->SiS_VBType & VB_SISVB) || - (SiS_Pr->SiS_IF_DEF_LVDS == 1) || - (SiS_Pr->SiS_IF_DEF_CH70xx != 0) || - (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) { - SiS_SetCRT2Group(SiS_Pr, ModeNo); - } - - SiS_StrangeStuff(SiS_Pr); - - SiS_DisplayOn(SiS_Pr); - SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); - - if(SiS_Pr->ChipType >= SIS_315H) { - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(!(SiS_IsDualEdge(SiS_Pr))) { - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); - } - } - } - - if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { - if(SiS_Pr->ChipType >= SIS_315H) { - if(!SiS_Pr->SiS_ROMNew) { - if(SiS_IsVAMode(SiS_Pr)) { - SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); - } else { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE); - } - } - - SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg); - - if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); - } - } else if((SiS_Pr->ChipType == SIS_630) || - (SiS_Pr->ChipType == SIS_730)) { - SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg); - } - } - - /* SetPitch: Adapt to virtual size & position */ - SiS_SetPitchCRT2(SiS_Pr, pScrn); - - SiS_Handle760(SiS_Pr); - - return true; -} - -/*********************************************/ -/* X.org/XFree86: SiSBIOSSetModeCRT1() */ -/* for Dual-Head modes */ -/*********************************************/ - -bool -SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, - DisplayModePtr mode, bool IsCustom) -{ - SISIOADDRESS BaseAddr = SiS_Pr->IOAddress; - SISPtr pSiS = SISPTR(pScrn); - unsigned short ModeIdIndex, ModeNo = 0; - unsigned char backupreg = 0; -#ifdef SISDUALHEAD - SISEntPtr pSiSEnt = pSiS->entityPrivate; - unsigned char backupcr30, backupcr31, backupcr38, backupcr35, backupp40d=0; - bool backupcustom; -#endif - - SiS_Pr->UseCustomMode = false; - - if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) { - - unsigned short temptemp = SiS_Pr->CVDisplay; - - if(SiS_Pr->CModeFlag & DoubleScanMode) temptemp >>= 1; - else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1; - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, - "Setting custom mode %dx%d on CRT1\n", - SiS_Pr->CHDisplay, temptemp); - ModeNo = 0xfe; - - } else { - - ModeNo = SiS_GetModeNumber(pScrn, mode, 0); /* don't give VBFlags */ - if(!ModeNo) return false; - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, - "Setting standard mode 0x%x on CRT1\n", ModeNo); - } - - SiSInitPtr(SiS_Pr); - SiSRegInit(SiS_Pr, BaseAddr); - SiS_GetSysFlags(SiS_Pr); -#if defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__) - SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); -#else - SiS_Pr->SiS_VGAINFO = 0x11; -#endif - - SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); - - SiSInitPCIetc(SiS_Pr); - SiSSetLVDSetc(SiS_Pr); - SiSDetermineROMUsage(SiS_Pr); - - SiS_UnLockCRT2(SiS_Pr); - - if(!SiS_Pr->UseCustomMode) { - if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false; - } else { - ModeIdIndex = 0; - } - - /* Determine VBType */ - SiS_GetVBType(SiS_Pr); - - SiS_InitVB(SiS_Pr); - if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { - if(SiS_Pr->ChipType >= SIS_315H) { - backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - } else { - backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); - } - } - - /* Get VB information (connectors, connected devices) */ - /* (We don't care if the current mode is a CRT2 mode) */ - SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 0); - SiS_SetYPbPr(SiS_Pr); - SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex); - SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex); - SiS_SetLowModeTest(SiS_Pr, ModeNo); - - SiS_OpenCRTC(SiS_Pr); - - /* Set mode on CRT1 */ - SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex); - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - SiS_SetCRT2Group(SiS_Pr, ModeNo); - } - - /* SetPitch: Adapt to virtual size & position */ - SiS_SetPitchCRT1(SiS_Pr, pScrn); - - SiS_HandleCRT1(SiS_Pr); - - SiS_StrangeStuff(SiS_Pr); - - SiS_CloseCRTC(SiS_Pr); - -#ifdef SISDUALHEAD - if(pSiS->DualHeadMode) { - pSiSEnt->CRT1ModeNo = ModeNo; - pSiSEnt->CRT1DMode = mode; - } -#endif - - if(SiS_Pr->UseCustomMode) { - SiS_Pr->CRT1UsesCustomMode = true; - SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock; - SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag; - } else { - SiS_Pr->CRT1UsesCustomMode = false; - } - - /* Reset CRT2 if changing mode on CRT1 */ -#ifdef SISDUALHEAD - if(pSiS->DualHeadMode) { - if(pSiSEnt->CRT2ModeNo != -1) { - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, - "(Re-)Setting mode for CRT2\n"); - backupcustom = SiS_Pr->UseCustomMode; - backupcr30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - backupcr31 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31); - backupcr35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); - backupcr38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - if(SiS_Pr->SiS_VBType & VB_SISVB) { - /* Backup LUT-enable */ - if(pSiSEnt->CRT2ModeSet) { - backupp40d = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0d) & 0x08; - } - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,pSiSEnt->CRT2CR30); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,pSiSEnt->CRT2CR31); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,pSiSEnt->CRT2CR35); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,pSiSEnt->CRT2CR38); - } - - SiSBIOSSetModeCRT2(SiS_Pr, pSiSEnt->pScrn_1, - pSiSEnt->CRT2DMode, pSiSEnt->CRT2IsCustom); - - SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,backupcr30); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,backupcr31); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupcr35); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupcr38); - if(SiS_Pr->SiS_VBType & VB_SISVB) { - SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d, ~0x08, backupp40d); - } - SiS_Pr->UseCustomMode = backupcustom; - } - } -#endif - - /* Warning: From here, the custom mode entries in SiS_Pr are - * possibly overwritten - */ - - SiS_DisplayOn(SiS_Pr); - SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); - - if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { - if(SiS_Pr->ChipType >= SIS_315H) { - SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg); - } else if((SiS_Pr->ChipType == SIS_630) || - (SiS_Pr->ChipType == SIS_730)) { - SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg); - } - } - - SiS_Handle760(SiS_Pr); - - /* Backup/Set ModeNo in BIOS scratch area */ - SiS_GetSetModeID(pScrn,ModeNo); - - return true; -} -#endif /* Linux_XF86 */ - #ifndef GETBITSTR #define BITMASK(h,l) (((unsigned)(1U << ((h)-(l)+1))-1)<<(l)) #define GENMASK(mask) BITMASK(1?mask,0?mask) @@ -3927,7 +3407,7 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_Pr->CVBlankStart = SiS_Pr->SiS_VGAVDE; if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 tempbx = SiS_Pr->SiS_VGAHT; if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { tempbx = SiS_Pr->PanelHT; @@ -3936,7 +3416,7 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, remaining = tempbx % 8; #endif } else { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 /* OK for LCDA, LVDS */ tempbx = SiS_Pr->PanelHT - SiS_Pr->PanelXRes; tempax = SiS_Pr->SiS_VGAHDE; /* not /2 ! */ @@ -3950,7 +3430,7 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_Pr->CHTotal = SiS_Pr->CHBlankEnd = tempbx; if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(SiS_Pr->SiS_VGAHDE == SiS_Pr->PanelXRes) { SiS_Pr->CHSyncStart = SiS_Pr->SiS_VGAHDE + ((SiS_Pr->PanelHRS + 1) & ~1); SiS_Pr->CHSyncEnd = SiS_Pr->CHSyncStart + SiS_Pr->PanelHRE; @@ -3982,7 +3462,7 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, } #endif } else { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 tempax = VGAHDE; if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { tempbx = SiS_Pr->PanelXRes; @@ -4001,7 +3481,7 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { tempax = SiS_Pr->PanelYRes; } else if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 /* Stupid hack for 640x400/320x200 */ if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { if((tempax + tempbx) == 438) tempbx += 16; @@ -4054,36 +3534,12 @@ SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, if(modeflag & DoubleScanMode) tempax |= 0x80; SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,tempax); -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "%d %d %d %d %d %d %d %d (%d %d %d %d)\n", - SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal, - SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal, - SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd); - xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", - SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1], - SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3], - SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5], - SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]); - xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", - SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9], - SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11], - SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13], - SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]); - xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]); -#endif -#endif } void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres, int yres, -#ifdef SIS_XORG_XF86 - DisplayModePtr current -#endif -#ifdef SIS_LINUX_KERNEL struct fb_var_screeninfo *var, bool writeres -#endif ) { unsigned short HRE, HBE, HRS, HBS, HDE, HT; @@ -4127,25 +3583,10 @@ SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, D = B - F - C; -#ifdef SIS_XORG_XF86 - current->HDisplay = (E * 8); - current->HSyncStart = (E * 8) + (F * 8); - current->HSyncEnd = (E * 8) + (F * 8) + (C * 8); - current->HTotal = (E * 8) + (F * 8) + (C * 8) + (D * 8); -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, - "H: A %d B %d C %d D %d E %d F %d HT %d HDE %d HRS %d HBS %d HBE %d HRE %d\n", - A, B, C, D, E, F, HT, HDE, HRS, HBS, HBE, HRE); -#else - (void)VBS; (void)HBS; (void)A; -#endif -#endif -#ifdef SIS_LINUX_KERNEL if(writeres) var->xres = xres = E * 8; var->left_margin = D * 8; var->right_margin = F * 8; var->hsync_len = C * 8; -#endif /* Vertical */ sr_data = crdata[13]; @@ -4192,30 +3633,10 @@ SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, D = B - F - C; -#ifdef SIS_XORG_XF86 - current->VDisplay = VDE + 1; - current->VSyncStart = VRS + 1; - current->VSyncEnd = ((VRS & ~0x1f) | VRE) + 1; - if(VRE <= (VRS & 0x1f)) current->VSyncEnd += 32; - current->VTotal = E + D + C + F; -#if 0 - current->VDisplay = E; - current->VSyncStart = E + D; - current->VSyncEnd = E + D + C; - current->VTotal = E + D + C + F; -#endif -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, - "V: A %d B %d C %d D %d E %d F %d VT %d VDE %d VRS %d VBS %d VBE %d VRE %d\n", - A, B, C, D, E, F, VT, VDE, VRS, VBS, VBE, VRE); -#endif -#endif -#ifdef SIS_LINUX_KERNEL if(writeres) var->yres = yres = E; var->upper_margin = D; var->lower_margin = F; var->vsync_len = C; -#endif if((xres == 320) && ((yres == 200) || (yres == 240))) { /* Terrible hack, but correct CRTC data for @@ -4224,17 +3645,9 @@ SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, * a negative D. The CRT controller does not * seem to like correcting HRE to 50) */ -#ifdef SIS_XORG_XF86 - current->HDisplay = 320; - current->HSyncStart = 328; - current->HSyncEnd = 376; - current->HTotal = 400; -#endif -#ifdef SIS_LINUX_KERNEL var->left_margin = (400 - 376); var->right_margin = (328 - 320); var->hsync_len = (376 - 328); -#endif } diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h index b96005c39c67..ee8ed3c203da 100644 --- a/drivers/video/sis/init.h +++ b/drivers/video/sis/init.h @@ -53,21 +53,8 @@ #ifndef _INIT_H_ #define _INIT_H_ -#include "osdef.h" #include "initdef.h" -#ifdef SIS_XORG_XF86 -#include "sis.h" -#define SIS_NEED_inSISREG -#define SIS_NEED_inSISREGW -#define SIS_NEED_inSISREGL -#define SIS_NEED_outSISREG -#define SIS_NEED_outSISREGW -#define SIS_NEED_outSISREGL -#include "sis_regs.h" -#endif - -#ifdef SIS_LINUX_KERNEL #include "vgatypes.h" #include "vstruct.h" #ifdef SIS_CP @@ -78,7 +65,6 @@ #include <linux/fb.h> #include "sis.h" #include <video/sisfb.h> -#endif /* Mode numbers */ static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f}; @@ -286,7 +272,7 @@ static const struct SiS_ModeResInfo_S SiS_ModeResInfo[] = { 1280, 854, 8,16} /* 0x22 */ }; -#if defined(SIS300) || defined(SIS315H) +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) static const struct SiS_StandTable_S SiS_StandTable[]= { /* 0x00: MD_0_200 */ @@ -1521,10 +1507,6 @@ static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1640x480_1_H[] = }; bool SiSInitPtr(struct SiS_Private *SiS_Pr); -#ifdef SIS_XORG_XF86 -unsigned short SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, - int Depth, bool FSTN, int LCDwith, int LCDheight); -#endif unsigned short SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, int Depth, bool FSTN, unsigned short CustomT, int LCDwith, int LCDheight, @@ -1550,17 +1532,11 @@ void SiS_SetRegOR(SISIOADDRESS Port,unsigned short Index, unsigned short DataOR void SiS_DisplayOn(struct SiS_Private *SiS_Pr); void SiS_DisplayOff(struct SiS_Private *SiS_Pr); void SiSRegInit(struct SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr); -#ifndef SIS_LINUX_KERNEL -void SiSSetLVDSetc(struct SiS_Private *SiS_Pr); -#endif void SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable); void SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable); unsigned short SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); bool SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr); -#ifndef SIS_LINUX_KERNEL -void SiS_GetVBType(struct SiS_Private *SiS_Pr); -#endif bool SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, unsigned short *ModeIdIndex); @@ -1572,37 +1548,19 @@ unsigned short SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short Mode unsigned short ModeIdIndex); unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr,unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RRTI); -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 void SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *idx1, unsigned short *idx2); unsigned short SiS_GetFIFOThresholdB300(unsigned short idx1, unsigned short idx2); unsigned short SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index); #endif void SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); -#ifdef SIS_XORG_XF86 -bool SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo, - bool dosetpitch); -bool SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, - DisplayModePtr mode, bool IsCustom); -bool SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, - DisplayModePtr mode, bool IsCustom); -bool SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, - DisplayModePtr mode, bool IsCustom); -#endif -#ifdef SIS_LINUX_KERNEL bool SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); -#endif void SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth); void SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); -#ifdef SIS_XORG_XF86 -void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres, - int yres, DisplayModePtr current); -#endif -#ifdef SIS_LINUX_KERNEL void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres, int yres, struct fb_var_screeninfo *var, bool writeres); -#endif /* From init301.c: */ extern void SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, @@ -1626,29 +1584,16 @@ extern unsigned short SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short extern bool SiS_IsVAMode(struct SiS_Private *); extern bool SiS_IsDualEdge(struct SiS_Private *); -#ifdef SIS_XORG_XF86 -/* From other modules: */ -extern unsigned short SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, - unsigned int VBFlags); -extern unsigned char SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, unsigned short offset, - unsigned char value); -extern unsigned char SiS_GetSetModeID(ScrnInfoPtr pScrn, unsigned char id); -extern unsigned short SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, - unsigned int VBFlags); -#endif - -#ifdef SIS_LINUX_KERNEL -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 extern unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg); extern void sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val); #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 extern void sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val); extern unsigned int sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg); #endif -#endif #endif diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c index da33d801c22e..9fa66fd4052a 100644 --- a/drivers/video/sis/init301.c +++ b/drivers/video/sis/init301.c @@ -75,11 +75,11 @@ #include "init301.h" -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 #include "oem300.h" #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 #include "oem310.h" #endif @@ -87,9 +87,7 @@ #define SiS_I2CDELAYSHORT 150 static unsigned short SiS_GetBIOSLCDResInfo(struct SiS_Private *SiS_Pr); -#ifdef SIS_LINUX_KERNEL static void SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); -#endif /*********************************************/ /* HELPER: Lock/Unlock CRT2 */ @@ -106,9 +104,7 @@ SiS_UnLockCRT2(struct SiS_Private *SiS_Pr) SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01); } -#ifdef SIS_LINUX_KERNEL static -#endif void SiS_LockCRT2(struct SiS_Private *SiS_Pr) { @@ -138,7 +134,7 @@ SiS_SetRegSR11ANDOR(struct SiS_Private *SiS_Pr, unsigned short DataAND, unsigned /* HELPER: Get Pointer to LCD structure */ /*********************************************/ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static unsigned char * GetLCDStructPtr661(struct SiS_Private *SiS_Pr) { @@ -404,7 +400,7 @@ SiS_SaveCRT2Info(struct SiS_Private *SiS_Pr, unsigned short ModeNo) /* HELPER: GET SOME DATA FROM BIOS ROM */ /*********************************************/ -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 static bool SiS_CR36BIOSWord23b(struct SiS_Private *SiS_Pr) { @@ -449,7 +445,7 @@ SiS_DDC2Delay(struct SiS_Private *SiS_Pr, unsigned int delaytime) SiS_GetReg(SiS_Pr->SiS_P3c4, 0x05); } -#if defined(SIS300) || defined(SIS315H) +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) static void SiS_GenericDelay(struct SiS_Private *SiS_Pr, unsigned short delay) { @@ -457,7 +453,7 @@ SiS_GenericDelay(struct SiS_Private *SiS_Pr, unsigned short delay) } #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static void SiS_LongDelay(struct SiS_Private *SiS_Pr, unsigned short delay) { @@ -467,7 +463,7 @@ SiS_LongDelay(struct SiS_Private *SiS_Pr, unsigned short delay) } #endif -#if defined(SIS300) || defined(SIS315H) +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) static void SiS_ShortDelay(struct SiS_Private *SiS_Pr, unsigned short delay) { @@ -480,14 +476,14 @@ SiS_ShortDelay(struct SiS_Private *SiS_Pr, unsigned short delay) static void SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime) { -#if defined(SIS300) || defined(SIS315H) +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; unsigned short PanelID, DelayIndex, Delay=0; #endif if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); if(SiS_Pr->SiS_VBType & VB_SISVB) { @@ -513,11 +509,11 @@ SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime) } SiS_ShortDelay(SiS_Pr, Delay); -#endif /* SIS300 */ +#endif /* CONFIG_FB_SIS_300 */ } else { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if((SiS_Pr->ChipType >= SIS_661) || (SiS_Pr->ChipType <= SIS_315PRO) || @@ -579,12 +575,12 @@ SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime) } -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ } } -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static void SiS_PanelDelayLoop(struct SiS_Private *SiS_Pr, unsigned short DelayTime, unsigned short DelayLoop) { @@ -613,7 +609,7 @@ SiS_WaitRetrace1(struct SiS_Private *SiS_Pr) while((!(SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog); } -#if defined(SIS300) || defined(SIS315H) +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) static void SiS_WaitRetrace2(struct SiS_Private *SiS_Pr, unsigned short reg) { @@ -630,7 +626,7 @@ static void SiS_WaitVBRetrace(struct SiS_Private *SiS_Pr) { if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x20)) return; } @@ -641,7 +637,7 @@ SiS_WaitVBRetrace(struct SiS_Private *SiS_Pr) } #endif } else { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x40)) { SiS_WaitRetrace1(SiS_Pr); } else { @@ -686,7 +682,7 @@ SiS_VBLongWait(struct SiS_Private *SiS_Pr) /* HELPER: MISC */ /*********************************************/ -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 static bool SiS_Is301B(struct SiS_Private *SiS_Pr) { @@ -708,7 +704,7 @@ SiS_CRT2IsLCD(struct SiS_Private *SiS_Pr) bool SiS_IsDualEdge(struct SiS_Private *SiS_Pr) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType >= SIS_315H) { if((SiS_Pr->ChipType != SIS_650) || (SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0)) { if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableDualEdge) return true; @@ -721,7 +717,7 @@ SiS_IsDualEdge(struct SiS_Private *SiS_Pr) bool SiS_IsVAMode(struct SiS_Private *SiS_Pr) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned short flag; if(SiS_Pr->ChipType >= SIS_315H) { @@ -732,7 +728,7 @@ SiS_IsVAMode(struct SiS_Private *SiS_Pr) return false; } -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static bool SiS_IsVAorLCD(struct SiS_Private *SiS_Pr) { @@ -745,7 +741,7 @@ SiS_IsVAorLCD(struct SiS_Private *SiS_Pr) static bool SiS_IsDualLink(struct SiS_Private *SiS_Pr) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType >= SIS_315H) { if((SiS_CRT2IsLCD(SiS_Pr)) || (SiS_IsVAMode(SiS_Pr))) { @@ -756,7 +752,7 @@ SiS_IsDualLink(struct SiS_Private *SiS_Pr) return false; } -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static bool SiS_TVEnabled(struct SiS_Private *SiS_Pr) { @@ -768,7 +764,7 @@ SiS_TVEnabled(struct SiS_Private *SiS_Pr) } #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static bool SiS_LCDAEnabled(struct SiS_Private *SiS_Pr) { @@ -777,7 +773,7 @@ SiS_LCDAEnabled(struct SiS_Private *SiS_Pr) } #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static bool SiS_WeHaveBacklightCtrl(struct SiS_Private *SiS_Pr) { @@ -788,7 +784,7 @@ SiS_WeHaveBacklightCtrl(struct SiS_Private *SiS_Pr) } #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static bool SiS_IsNotM650orLater(struct SiS_Private *SiS_Pr) { @@ -804,7 +800,7 @@ SiS_IsNotM650orLater(struct SiS_Private *SiS_Pr) } #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static bool SiS_IsYPbPr(struct SiS_Private *SiS_Pr) { @@ -816,7 +812,7 @@ SiS_IsYPbPr(struct SiS_Private *SiS_Pr) } #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static bool SiS_IsChScart(struct SiS_Private *SiS_Pr) { @@ -828,7 +824,7 @@ SiS_IsChScart(struct SiS_Private *SiS_Pr) } #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static bool SiS_IsTVOrYPbPrOrScart(struct SiS_Private *SiS_Pr) { @@ -848,7 +844,7 @@ SiS_IsTVOrYPbPrOrScart(struct SiS_Private *SiS_Pr) } #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static bool SiS_IsLCDOrLCDA(struct SiS_Private *SiS_Pr) { @@ -914,7 +910,7 @@ SiS_BridgeInSlavemode(struct SiS_Private *SiS_Pr) /*********************************************/ /* Setup general purpose IO for Chrontel communication */ -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 void SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo) { @@ -923,11 +919,7 @@ SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo) if(!(SiS_Pr->SiS_ChSW)) return; -#ifdef SIS_LINUX_KERNEL acpibase = sisfb_read_lpc_pci_dword(SiS_Pr, 0x74); -#else - acpibase = pciReadLong(0x00000800, 0x74); -#endif acpibase &= 0xFFFF; if(!acpibase) return; temp = SiS_GetRegShort((acpibase + 0x3c)); /* ACPI register 0x3c: GP Event 1 I/O mode select */ @@ -969,7 +961,7 @@ SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, tempax &= (DriverMode | LoadDACFlag | SetNotSimuMode | SetPALTV); tempbx |= tempax; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_VBType & VB_SISLCDA) { if(ModeNo == 0x03) { @@ -1019,7 +1011,7 @@ SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, } } -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ if(!(SiS_Pr->SiS_VBType & VB_SISVGA2)) { tempbx &= ~(SetCRT2ToRAMDAC); @@ -1154,24 +1146,16 @@ SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_Pr->SiS_VBInfo = tempbx; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(SiS_Pr->ChipType == SIS_630) { SiS_SetChrontelGPIO(SiS_Pr, SiS_Pr->SiS_VBInfo); } #endif -#ifdef SIS_LINUX_KERNEL #if 0 printk(KERN_DEBUG "sisfb: (init301: VBInfo= 0x%04x, SetFlag=0x%04x)\n", SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag); #endif -#endif -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_PROBED, "(init301: VBInfo=0x%04x, SetFlag=0x%04x)\n", - SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag); -#endif -#endif } /*********************************************/ @@ -1415,12 +1399,6 @@ SiS_SetTVMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short } SiS_Pr->SiS_VBInfo &= ~SetPALTV; - -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "(init301: TVMode %x, VBInfo %x)\n", SiS_Pr->SiS_TVMode, SiS_Pr->SiS_VBInfo); -#endif -#endif } /*********************************************/ @@ -1443,22 +1421,10 @@ SiS_GetBIOSLCDResInfo(struct SiS_Private *SiS_Pr) static void SiS_GetLCDInfoBIOS(struct SiS_Private *SiS_Pr) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned char *ROMAddr; unsigned short temp; -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "Paneldata driver: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n", - SiS_Pr->PanelHT, SiS_Pr->PanelVT, - SiS_Pr->PanelHRS, SiS_Pr->PanelHRE, - SiS_Pr->PanelVRS, SiS_Pr->PanelVRE, - SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK, - SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A, - SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B); -#endif -#endif - if((ROMAddr = GetLCDStructPtr661(SiS_Pr))) { if((temp = SISGETROMW(6)) != SiS_Pr->PanelHT) { SiS_Pr->SiS_NeedRomModeData = true; @@ -1480,18 +1446,6 @@ SiS_GetLCDInfoBIOS(struct SiS_Private *SiS_Pr) SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2C = SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_B = ROMAddr[20]; -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "Paneldata BIOS: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n", - SiS_Pr->PanelHT, SiS_Pr->PanelVT, - SiS_Pr->PanelHRS, SiS_Pr->PanelHRE, - SiS_Pr->PanelVRS, SiS_Pr->PanelVRE, - SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK, - SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A, - SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B); -#endif -#endif - } #endif } @@ -1517,13 +1471,13 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh { unsigned short temp,modeflag,resinfo=0,modexres=0,modeyres=0; bool panelcanscale = false; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; static const unsigned char SiS300SeriesLCDRes[] = { 0, 1, 2, 3, 7, 4, 5, 8, 0, 0, 10, 0, 0, 0, 0, 15 }; #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned char *myptr = NULL; #endif @@ -1562,7 +1516,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh SiS_Pr->SiS_LCDTypeInfo = (temp & 0x0F) - 1; } temp &= 0x0f; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(SiS_Pr->ChipType < SIS_315H) { /* Very old BIOSes only know 7 sizes (NetVista 2179, 1.01g) */ if(SiS_Pr->SiS_VBType & VB_SIS301) { @@ -1574,7 +1528,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh #endif /* Translate to our internal types */ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType == SIS_550) { if (temp == Panel310_1152x768) temp = Panel_320x240_2; /* Verified working */ else if(temp == Panel310_320x240_2) temp = Panel_320x240_2; @@ -1597,7 +1551,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh SiS_Pr->SiS_LCDResInfo = temp; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { SiS_Pr->SiS_LCDResInfo = Panel_Barco1366; @@ -1639,7 +1593,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD; /* Dual link, Pass 1:1 BIOS default, etc. */ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType >= SIS_661) { if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { if(temp & 0x08) SiS_Pr->SiS_LCDInfo |= LCDPass11; @@ -2076,7 +2030,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh } } -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { if(SiS_Pr->SiS_CustomT == CUT_PANEL848 || SiS_Pr->SiS_CustomT == CUT_PANEL856) { SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20; /* neg h/v sync, RGB24(D0 = 0) */ @@ -2186,17 +2140,10 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh SiS_Pr->SiS_SetFlag |= LCDVESATiming; } -#ifdef SIS_LINUX_KERNEL #if 0 printk(KERN_DEBUG "sisfb: (LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x)\n", SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo); #endif -#endif -#ifdef SIS_XORG_XF86 - xf86DrvMsgVerb(0, X_PROBED, 4, - "(init301: LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x SetFlag=0x%04x)\n", - SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo, SiS_Pr->SiS_SetFlag); -#endif } /*********************************************/ @@ -2359,7 +2306,7 @@ SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor VCLKIndex = SiS_Pr->PanelVCLKIdx315; } -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 /* Special Timing: Barco iQ Pro R series */ if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) VCLKIndex = 0x44; @@ -2410,12 +2357,6 @@ SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor } -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "VCLKIndex %d (0x%x)\n", VCLKIndex, VCLKIndex); -#endif -#endif - return VCLKIndex; } @@ -2428,10 +2369,10 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned { unsigned short i, j, modeflag, tempah=0; short tempcl; -#if defined(SIS300) || defined(SIS315H) +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) unsigned short tempbl; #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; unsigned short tempah2, tempbl2; #endif @@ -2454,7 +2395,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 /* ---- 300 series ---- */ +#ifdef CONFIG_FB_SIS_300 /* ---- 300 series ---- */ /* For 301BDH: (with LCD via LVDS) */ if(SiS_Pr->SiS_VBType & VB_NoLCD) { @@ -2477,11 +2418,11 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0xA0; -#endif /* SIS300 */ +#endif /* CONFIG_FB_SIS_300 */ } else { -#ifdef SIS315H /* ------- 315/330 series ------ */ +#ifdef CONFIG_FB_SIS_315 /* ------- 315/330 series ------ */ if(ModeNo > 0x13) { tempcl -= ModeVGA; @@ -2494,7 +2435,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0x50; -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ } @@ -2503,7 +2444,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned if(SiS_Pr->ChipType < SIS_315H) { SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah); } else { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah); } else if(SiS_Pr->SiS_VBType & VB_SISVB) { @@ -2584,7 +2525,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned if(SiS_Pr->ChipType >= SIS_315H) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 /* LVDS can only be slave in 8bpp modes */ tempah = 0x80; if((modeflag & CRT2Mode) && (SiS_Pr->SiS_ModeType > ModeVGA)) { @@ -2604,7 +2545,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned } else { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 tempah = 0; if( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) && (SiS_Pr->SiS_ModeType > ModeVGA) ) { tempah |= 0x02; @@ -2626,7 +2567,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned if(SiS_Pr->ChipType >= SIS_315H) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 /* unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); */ /* The following is nearly unpreditable and varies from machine @@ -2718,11 +2659,11 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah); } -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ } else if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f); if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) || @@ -2745,7 +2686,7 @@ SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned } else { /* LVDS */ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { @@ -2931,7 +2872,7 @@ SiS_GetCRT2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short } } -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { @@ -3036,7 +2977,7 @@ SiS_GetCRT2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short case Panel_1280x1024: tempbx = 24; break; case Panel_1400x1050: tempbx = 26; break; case Panel_1600x1200: tempbx = 28; break; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 case Panel_Barco1366: tempbx = 80; break; #endif } @@ -3053,7 +2994,7 @@ SiS_GetCRT2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempbx = 30; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { tempbx = 82; if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; @@ -3189,7 +3130,7 @@ SiS_GetCRT2DataLVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 SiS_CalcPanelLinkTiming(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); SiS_CalcLCDACRT1Timing(SiS_Pr, ModeNo, ModeIdIndex); #endif @@ -3214,7 +3155,7 @@ SiS_GetCRT2DataLVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned case 16: LVDSData = SiS_Pr->SiS_LVDS800x600Data_1; break; case 18: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1; break; case 20: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 case 80: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_1; break; case 81: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2; break; case 82: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1; break; @@ -3248,7 +3189,7 @@ SiS_GetCRT2DataLVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned (SiS_Pr->SiS_SetFlag & SetDOSMode) ) { SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { if(ResIndex < 0x08) { SiS_Pr->SiS_HDE = 1280; @@ -3270,7 +3211,7 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s unsigned short resinfo, CRT2Index, ResIndex; const struct SiS_LCDData *LCDPtr = NULL; const struct SiS_TVData *TVPtr = NULL; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 short resinfo661; #endif @@ -3283,7 +3224,7 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s } else { modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 resinfo661 = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].ROMMODEIDX661; if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_SetFlag & LCDVESATiming) && @@ -3460,7 +3401,7 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s } else if( (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) && (romptr) && (ROMAddr) ) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 SiS_Pr->SiS_RVBHCMAX = ROMAddr[romptr]; SiS_Pr->SiS_RVBHCFACT = ROMAddr[romptr+1]; SiS_Pr->SiS_VGAHT = ROMAddr[romptr+2] | ((ROMAddr[romptr+3] & 0x0f) << 8); @@ -3520,19 +3461,13 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s case Panel_1680x1050 : case Panel_1680x1050 + 32: LCDPtr = SiS_Pr->SiS_LCD1680x1050Data; break; case 100 : LCDPtr = SiS_Pr->SiS_NoScaleData; break; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 case 200 : LCDPtr = SiS310_ExtCompaq1280x1024Data; break; case 201 : LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; #endif default : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; } -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex); -#endif -#endif - SiS_Pr->SiS_RVBHCMAX = (LCDPtr+ResIndex)->RVBHCMAX; SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT; SiS_Pr->SiS_VGAHT = (LCDPtr+ResIndex)->VGAHT; @@ -3624,7 +3559,7 @@ SiS_GetLVDSDesPtr(struct SiS_Private *SiS_Pr) { const struct SiS_LVDSDes *PanelDesPtr = NULL; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { if(SiS_Pr->ChipType < SIS_315H) { @@ -3696,7 +3631,7 @@ SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { /* non-pass 1:1 only, see above */ if(SiS_Pr->SiS_VGAHDE != SiS_Pr->PanelXRes) { @@ -3771,7 +3706,7 @@ SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s } else { if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 switch(SiS_Pr->SiS_LCDResInfo) { case Panel_800x600: if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { @@ -3816,7 +3751,7 @@ SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s } #endif } else { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 switch(SiS_Pr->SiS_LCDResInfo) { case Panel_1024x768: case Panel_1280x1024: @@ -3844,7 +3779,7 @@ SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s if(SiS_Pr->ChipType < SIS_315H) { if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 320; } else { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) SiS_Pr->SiS_LCDHDES = 480; if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 804; if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 704; @@ -3866,7 +3801,7 @@ SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s /* DISABLE VIDEO BRIDGE */ /*********************************************/ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static int SiS_HandlePWD(struct SiS_Private *SiS_Pr) { @@ -3891,11 +3826,6 @@ SiS_HandlePWD(struct SiS_Private *SiS_Pr) ret = 1; } SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x27,0x7f,temp); -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, 0, "Setting PWD %x\n", temp); -#endif -#endif } #endif return ret; @@ -3909,7 +3839,7 @@ SiS_HandlePWD(struct SiS_Private *SiS_Pr) void SiS_DisableBridge(struct SiS_Private *SiS_Pr) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned short tempah, pushax=0, modenum; #endif unsigned short temp=0; @@ -3920,7 +3850,7 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr) if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 /* 300 series */ +#ifdef CONFIG_FB_SIS_300 /* 300 series */ if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { if(SiS_Pr->SiS_VBType & VB_SISLVDS) { @@ -3953,11 +3883,11 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr) } } -#endif /* SIS300 */ +#endif /* CONFIG_FB_SIS_300 */ } else { -#ifdef SIS315H /* 315 series */ +#ifdef CONFIG_FB_SIS_315 /* 315 series */ int didpwd = 0; bool custom1 = (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || @@ -4081,14 +4011,14 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr) } -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ } } else { /* ============ For 301 ================ */ if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08); SiS_PanelDelay(SiS_Pr, 3); @@ -4111,7 +4041,7 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr) SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp); } else { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); /* disable CRT2 */ if( (!(SiS_CRT2IsLCD(SiS_Pr))) || (!(SiS_CR36BIOSWord23d(SiS_Pr))) ) { @@ -4127,7 +4057,7 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr) if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 /* 300 series */ +#ifdef CONFIG_FB_SIS_300 /* 300 series */ if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { SiS_SetCH700x(SiS_Pr,0x0E,0x09); @@ -4171,11 +4101,11 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr) SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x04); } -#endif /* SIS300 */ +#endif /* CONFIG_FB_SIS_300 */ } else { -#ifdef SIS315H /* 315 series */ +#ifdef CONFIG_FB_SIS_315 /* 315 series */ if(!(SiS_IsNotM650orLater(SiS_Pr))) { /*if(SiS_Pr->ChipType < SIS_340) { */ /* XGI needs this */ @@ -4288,7 +4218,7 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr) } } -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ } /* 315 series */ @@ -4304,14 +4234,12 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr) * from outside the context of a mode switch! * MUST call getVBType before calling this */ -#ifdef SIS_LINUX_KERNEL static -#endif void SiS_EnableBridge(struct SiS_Private *SiS_Pr) { unsigned short temp=0, tempah; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned short temp1, pushax=0; bool delaylong = false; #endif @@ -4322,7 +4250,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr) if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 /* 300 series */ +#ifdef CONFIG_FB_SIS_300 /* 300 series */ if(SiS_CRT2IsLCD(SiS_Pr)) { if(SiS_Pr->SiS_VBType & VB_SISLVDS) { @@ -4385,11 +4313,11 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr) } -#endif /* SIS300 */ +#endif /* CONFIG_FB_SIS_300 */ } else { -#ifdef SIS315H /* 315 series */ +#ifdef CONFIG_FB_SIS_315 /* 315 series */ #ifdef SET_EMI unsigned char r30=0, r31=0, r32=0, r33=0, cr36=0; @@ -4688,7 +4616,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr) SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); } -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ } @@ -4739,7 +4667,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr) if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 /* 300 series */ +#ifdef CONFIG_FB_SIS_300 /* 300 series */ if(SiS_CRT2IsLCD(SiS_Pr)) { if(SiS_Pr->ChipType == SIS_730) { @@ -4783,11 +4711,11 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr) } } -#endif /* SIS300 */ +#endif /* CONFIG_FB_SIS_300 */ } else { -#ifdef SIS315H /* 315 series */ +#ifdef CONFIG_FB_SIS_315 /* 315 series */ if(!(SiS_IsNotM650orLater(SiS_Pr))) { /*if(SiS_Pr->ChipType < SIS_340) {*/ /* XGI needs this */ @@ -4881,7 +4809,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr) } } -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ } /* 310 series */ @@ -4971,7 +4899,7 @@ SiS_SetCRT2Sync(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 /* ---- 300 series --- */ +#ifdef CONFIG_FB_SIS_300 /* ---- 300 series --- */ if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { /* 630 - 301B(-DH) */ @@ -5000,11 +4928,11 @@ SiS_SetCRT2Sync(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor } -#endif /* SIS300 */ +#endif /* CONFIG_FB_SIS_300 */ } else { -#ifdef SIS315H /* ------- 315 series ------ */ +#ifdef CONFIG_FB_SIS_315 /* ------- 315 series ------ */ if(SiS_Pr->SiS_VBType & VB_SISLVDS) { /* 315 - LVDS */ @@ -5076,13 +5004,13 @@ SiS_SetCRT2Sync(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor } } -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ } } } /* Set CRT2 FIFO on 300/540/630/730 */ -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 static void SiS_SetCRT2FIFO_300(struct SiS_Private *SiS_Pr,unsigned short ModeNo) { @@ -5154,13 +5082,8 @@ SiS_SetCRT2FIFO_300(struct SiS_Private *SiS_Pr,unsigned short ModeNo) } else { -#ifdef SIS_LINUX_KERNEL pci50 = sisfb_read_nbridge_pci_dword(SiS_Pr, 0x50); pciA0 = sisfb_read_nbridge_pci_dword(SiS_Pr, 0xa0); -#else - pci50 = pciReadLong(0x00000000, 0x50); - pciA0 = pciReadLong(0x00000000, 0xA0); -#endif if(SiS_Pr->ChipType == SIS_730) { @@ -5262,7 +5185,7 @@ SiS_SetCRT2FIFO_300(struct SiS_Private *SiS_Pr,unsigned short ModeNo) #endif /* Set CRT2 FIFO on 315/330 series */ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static void SiS_SetCRT2FIFO_310(struct SiS_Private *SiS_Pr) { @@ -5420,27 +5343,6 @@ SiS_SetGroup1_301(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned sho temp = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp); /* ? */ - -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "%d %d %d %d %d %d %d %d (%d %d %d %d)\n", - SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal, - SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal, - SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd); - - xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", - SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1], - SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3], - SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5], - SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]); - xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", - SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9], - SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11], - SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13], - SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]); - xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]); -#endif -#endif } /* Setup panel link @@ -5455,17 +5357,17 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s unsigned short push2, tempax, tempbx, tempcx, temp; unsigned int tempeax = 0, tempebx, tempecx, tempvcfact = 0; bool islvds = false, issis = false, chkdclkfirst = false; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 unsigned short crt2crtc = 0; #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned short pushcx; #endif if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; #endif } else if(SiS_Pr->UseCustomMode) { @@ -5473,7 +5375,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s } else { modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; #endif } @@ -5494,7 +5396,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s } } -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { if(IS_SIS330) { SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10); @@ -5744,7 +5646,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 /* 300 series */ +#ifdef CONFIG_FB_SIS_300 /* 300 series */ tempeax = SiS_Pr->SiS_VGAVDE << 6; temp = (tempeax % (unsigned int)SiS_Pr->SiS_VDE); tempeax = tempeax / (unsigned int)SiS_Pr->SiS_VDE; @@ -5755,11 +5657,11 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s temp = (unsigned short)(tempeax & 0x00FF); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,temp); /* BPLVCFACT */ tempvcfact = temp; -#endif /* SIS300 */ +#endif /* CONFIG_FB_SIS_300 */ } else { -#ifdef SIS315H /* 315 series */ +#ifdef CONFIG_FB_SIS_315 /* 315 series */ tempeax = SiS_Pr->SiS_VGAVDE << 18; tempebx = SiS_Pr->SiS_VDE; temp = (tempeax % tempebx); @@ -5845,7 +5747,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s temp = (unsigned short)(tempecx & 0x00FF); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp); -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { if((islvds) || (SiS_Pr->SiS_VBInfo & VB_SISLVDS)) { @@ -5863,7 +5765,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s } #endif -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(SiS_Pr->SiS_IF_DEF_TRUMPION) { unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; unsigned char *trumpdata; @@ -5899,7 +5801,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s } #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) { SiS_SetReg(SiS_Pr->SiS_Part1Port,0x25,0x00); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x26,0x00); @@ -5999,7 +5901,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s SiS_SetReg(SiS_Pr->SiS_Part1Port,0x45,0x0a); } } -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ } /* Set Part 1 */ @@ -6007,12 +5909,12 @@ static void SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex) { -#if defined(SIS300) || defined(SIS315H) +#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; #endif unsigned short temp=0, tempax=0, tempbx=0, tempcx=0, bridgeadd=0; unsigned short pushbx=0, CRT1Index=0, modeflag, resinfo=0; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned short tempbl=0; #endif @@ -6038,11 +5940,11 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) { if(SiS_Pr->ChipType < SIS_315H ) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo); #endif } else { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 SiS_SetCRT2FIFO_310(SiS_Pr); #endif } @@ -6051,7 +5953,7 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short if(SiS_Pr->ChipType < SIS_315H ) { -#ifdef SIS300 /* ------------- 300 series --------------*/ +#ifdef CONFIG_FB_SIS_300 /* ------------- 300 series --------------*/ temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp); /* CRT2 Horizontal Total */ @@ -6070,11 +5972,11 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short bridgeadd = 12; -#endif /* SIS300 */ +#endif /* CONFIG_FB_SIS_300 */ } else { -#ifdef SIS315H /* ------------------- 315/330 series --------------- */ +#ifdef CONFIG_FB_SIS_315 /* ------------------- 315/330 series --------------- */ tempcx = SiS_Pr->SiS_VGAHT; /* BTVGA2HT 0x08,0x09 */ if(modeflag & HalfDCLK) { @@ -6125,7 +6027,7 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short } } -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ } /* 315/330 series */ @@ -6256,7 +6158,7 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short if(SiS_Pr->ChipType < SIS_315H) { -#ifdef SIS300 /* ---------- 300 series -------------- */ +#ifdef CONFIG_FB_SIS_300 /* ---------- 300 series -------------- */ if(SiS_Pr->SiS_VBType & VB_SISVB) { temp = 0x20; @@ -6310,11 +6212,11 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */ -#endif /* SIS300 */ +#endif /* CONFIG_FB_SIS_300 */ } else { -#ifdef SIS315H /* --------------- 315/330 series ---------------*/ +#ifdef CONFIG_FB_SIS_315 /* --------------- 315/330 series ---------------*/ if(SiS_Pr->ChipType < SIS_661) { @@ -6349,7 +6251,7 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short if(modeflag & HalfDCLK) tempax |= 0x40; SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax); -#endif /* SIS315H */ +#endif /* CONFIG_FB_SIS_315 */ } @@ -6381,7 +6283,7 @@ SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short /* SET PART 2 REGISTER GROUP */ /*********************************************/ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static unsigned char * SiS_GetGroup2CLVXPtr(struct SiS_Private *SiS_Pr, int tabletype) { @@ -6478,7 +6380,7 @@ SiS_GetCRT2Part2Ptr(struct SiS_Private *SiS_Pr,unsigned short ModeNo,unsigned sh } #endif -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 static void SiS_Group2LCDSpecial(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short crt2crtc) { @@ -6690,7 +6592,7 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short unsigned int longtemp, PhaseIndex; bool newtvphase; const unsigned char *TimingPoint; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned short resindex, CRT2Index; const struct SiS_Part2PortTbl *CRT2Part2Ptr = NULL; @@ -7069,7 +6971,7 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB); SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF); -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_GetCRT2Part2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, &CRT2Index, &resindex)) { switch(CRT2Index) { @@ -7130,12 +7032,6 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short /* Non-expanding: lcdvdes = tempcx = VT-1; lcdvdee = tempbx = VDE-1 */ -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "lcdvdes 0x%x lcdvdee 0x%x\n", tempcx, tempbx); -#endif -#endif - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,tempcx); /* lcdvdes */ SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,tempbx); /* lcdvdee */ @@ -7184,12 +7080,6 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short tempbx = SiS_Pr->CVSyncStart; } -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "lcdvrs 0x%x\n", tempbx); -#endif -#endif - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,tempbx); /* lcdvrs */ temp = (tempbx >> 4) & 0xF0; @@ -7201,15 +7091,9 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short temp |= (SiS_Pr->CVSyncEnd & 0x0f); } -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "lcdvre[3:0] 0x%x\n", (temp & 0x0f)); -#endif -#endif - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp); -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 SiS_Group2LCDSpecial(SiS_Pr, ModeNo, crt2crtc); #endif @@ -7245,12 +7129,6 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short tempax >>= 1; } -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "lcdhdee 0x%x\n", tempbx); -#endif -#endif - tempbx += bridgeoffset; SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,tempbx); /* lcdhdee */ @@ -7276,12 +7154,6 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short tempbx += bridgeoffset; } -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "lcdhrs 0x%x\n", tempbx); -#endif -#endif - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1C,tempbx); /* lcdhrs */ SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,((tempbx >> 4) & 0xf0)); @@ -7300,20 +7172,14 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short tempbx += bridgeoffset; } -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "lcdhre 0x%x\n", tempbx); -#endif -#endif - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,tempbx); /* lcdhre */ SiS_SetGroup2_Tail(SiS_Pr, ModeNo); -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 SiS_Set300Part2Regs(SiS_Pr, ModeIdIndex, RefreshRateTableIndex, ModeNo); #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 } /* CRT2-LCD from table */ #endif } @@ -7382,7 +7248,7 @@ SiS_SetGroup3(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short /* SET PART 4 REGISTER GROUP */ /*********************************************/ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 #if 0 static void SiS_ShiftXPos(struct SiS_Private *SiS_Pr, int shift) @@ -8011,7 +7877,7 @@ SiS_SetCHTVReg(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 /* Chrontel 7005 - I assume that it does not come with a 315 series chip */ @@ -8124,7 +7990,7 @@ SiS_SetCHTVReg(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short /* Chrontel 7019 - assumed that it does not come with a 300 series chip */ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 unsigned short temp; @@ -8175,7 +8041,7 @@ SiS_SetCHTVReg(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short } -#ifdef SIS315H /* ----------- 315 series only ---------- */ +#ifdef CONFIG_FB_SIS_315 /* ----------- 315 series only ---------- */ void SiS_Chrontel701xBLOn(struct SiS_Private *SiS_Pr) @@ -8657,7 +8523,7 @@ SiS_ChrontelDoSomething1(struct SiS_Private *SiS_Pr) bool SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; #endif unsigned short ModeIdIndex, RefreshRateTableIndex; @@ -8703,16 +8569,6 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo) SiS_GetLVDSDesData(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "(init301: LCDHDES 0x%03x LCDVDES 0x%03x)\n", SiS_Pr->SiS_LCDHDES, SiS_Pr->SiS_LCDVDES); - xf86DrvMsg(0, X_INFO, "(init301: HDE 0x%03x VDE 0x%03x)\n", SiS_Pr->SiS_HDE, SiS_Pr->SiS_VDE); - xf86DrvMsg(0, X_INFO, "(init301: VGAHDE 0x%03x VGAVDE 0x%03x)\n", SiS_Pr->SiS_VGAHDE, SiS_Pr->SiS_VGAVDE); - xf86DrvMsg(0, X_INFO, "(init301: HT 0x%03x VT 0x%03x)\n", SiS_Pr->SiS_HT, SiS_Pr->SiS_VT); - xf86DrvMsg(0, X_INFO, "(init301: VGAHT 0x%03x VGAVT 0x%03x)\n", SiS_Pr->SiS_VGAHT, SiS_Pr->SiS_VGAVT); -#endif -#endif - if(SiS_Pr->SiS_SetFlag & LowModeTests) { SiS_SetGroup1(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } @@ -8722,12 +8578,12 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo) if(SiS_Pr->SiS_SetFlag & LowModeTests) { SiS_SetGroup2(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 SiS_SetGroup2_C_ELV(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); #endif SiS_SetGroup3(SiS_Pr, ModeNo, ModeIdIndex); SiS_SetGroup4(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 SiS_SetGroup4_C_ELV(SiS_Pr, ModeNo, ModeIdIndex); #endif SiS_SetGroup5(SiS_Pr, ModeNo, ModeIdIndex); @@ -8758,7 +8614,7 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo) if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 SiS_SetCH701xForLCD(SiS_Pr); #endif } @@ -8771,7 +8627,7 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo) } -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 if(SiS_Pr->ChipType < SIS_315H) { if(SiS_Pr->SiS_SetFlag & LowModeTests) { if(SiS_Pr->SiS_UseOEM) { @@ -8794,7 +8650,7 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo) } #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_SetFlag & LowModeTests) { if(SiS_Pr->ChipType < SIS_661) { @@ -8873,7 +8729,7 @@ SiS_SetupDDCN(struct SiS_Private *SiS_Pr) } } -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 static unsigned char * SiS_SetTrumpBlockLoop(struct SiS_Private *SiS_Pr, unsigned char *dataptr) { @@ -8923,11 +8779,6 @@ SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr) dataptr = SiS_SetTrumpBlockLoop(SiS_Pr, dataptr); if(!dataptr) return false; } -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "Trumpion block success\n"); -#endif -#endif return true; } #endif @@ -9002,9 +8853,7 @@ SiS_SetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val) SiS_SetChReg(SiS_Pr, reg, val, 0); } -#ifdef SIS_LINUX_KERNEL static -#endif void SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val) { @@ -9091,9 +8940,7 @@ SiS_GetCH701x(struct SiS_Private *SiS_Pr, unsigned short tempbx) /* Read from Chrontel 70xx */ /* Parameter is [Register no (S7-S0)] */ -#ifdef SIS_LINUX_KERNEL static -#endif unsigned short SiS_GetCH70xx(struct SiS_Private *SiS_Pr, unsigned short tempbx) { @@ -9114,9 +8961,7 @@ SiS_SetCH70xxANDOR(struct SiS_Private *SiS_Pr, unsigned short reg, } /* Our own DDC functions */ -#ifndef SIS_XORG_XF86 static -#endif unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype, bool checkcr32, @@ -9224,12 +9069,6 @@ SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, SiS_SetupDDCN(SiS_Pr); -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "DDC Port %x Index %x Shift %d\n", - SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index, temp); -#endif -#endif return 0; } @@ -9292,11 +9131,6 @@ SiS_DoProbeDDC(struct SiS_Private *SiS_Pr) SiS_SetSwitchDDC2(SiS_Pr); if(SiS_PrepareDDC(SiS_Pr)) { SiS_SetStop(SiS_Pr); -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "Probe: Prepare failed\n"); -#endif -#endif return 0xFFFF; } mask = 0xf0; @@ -9310,11 +9144,6 @@ SiS_DoProbeDDC(struct SiS_Private *SiS_Pr) } else { failed = true; ret = 0xFFFF; -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "Probe: Read 1 failed\n"); -#endif -#endif } } if(!failed) { @@ -9324,11 +9153,6 @@ SiS_DoProbeDDC(struct SiS_Private *SiS_Pr) if(temp == value) ret = 0; else { ret = 0xFFFF; -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "Probe: Read 2 failed\n"); -#endif -#endif if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) { if(temp == 0x30) ret = 0; } @@ -9338,9 +9162,7 @@ SiS_DoProbeDDC(struct SiS_Private *SiS_Pr) return ret; } -#ifndef SIS_XORG_XF86 static -#endif unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr) { @@ -9357,9 +9179,7 @@ SiS_ProbeDDC(struct SiS_Private *SiS_Pr) return flag; } -#ifndef SIS_XORG_XF86 static -#endif unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype, unsigned char *buffer) { @@ -9606,11 +9426,6 @@ SiS_SetSCLKHigh(struct SiS_Private *SiS_Pr) temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); } while((!(temp & SiS_Pr->SiS_DDC_Clk)) && --watchdog); if (!watchdog) { -#ifdef SIS_XORG_XF86 -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "SetClkHigh failed\n"); -#endif -#endif return 0xFFFF; } SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); @@ -9641,7 +9456,7 @@ SiS_CheckACK(struct SiS_Private *SiS_Pr) /* =============== SiS 315/330 O.E.M. ================= */ -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static unsigned short GetRAMDACromptr(struct SiS_Private *SiS_Pr) @@ -10829,7 +10644,7 @@ SiS_FinalizeLCD(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor /* ================= SiS 300 O.E.M. ================== */ -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 static void SetOEMLCDData2(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex, diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h index 51d99222375d..e1fd31d0fddf 100644 --- a/drivers/video/sis/init301.h +++ b/drivers/video/sis/init301.h @@ -53,15 +53,8 @@ #ifndef _INIT301_H_ #define _INIT301_H_ -#include "osdef.h" #include "initdef.h" -#ifdef SIS_XORG_XF86 -#include "sis.h" -#include "sis_regs.h" -#endif - -#ifdef SIS_LINUX_KERNEL #include "vgatypes.h" #include "vstruct.h" #ifdef SIS_CP @@ -72,7 +65,6 @@ #include <linux/fb.h> #include "sis.h" #include <video/sisfb.h> -#endif static const unsigned char SiS_YPbPrTable[3][64] = { { @@ -237,7 +229,7 @@ static const unsigned char SiS_Part2CLVX_6[] = { /* 1080i */ 0xFF,0xFF, }; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 /* 661 et al LCD data structure (2.03.00) */ static const unsigned char SiS_LCDStruct661[] = { /* 1024x768 */ @@ -279,7 +271,7 @@ static const unsigned char SiS_LCDStruct661[] = { }; #endif -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 static unsigned char SiS300_TrumpionData[14][80] = { { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, 0x20,0x03,0x0B,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x10,0x00,0x00,0x04,0x23, @@ -356,9 +348,6 @@ static unsigned char SiS300_TrumpionData[14][80] = { #endif void SiS_UnLockCRT2(struct SiS_Private *SiS_Pr); -#ifndef SIS_LINUX_KERNEL -void SiS_LockCRT2(struct SiS_Private *SiS_Pr); -#endif void SiS_EnableCRT2(struct SiS_Private *SiS_Pr); unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); void SiS_WaitRetrace1(struct SiS_Private *SiS_Pr); @@ -375,9 +364,6 @@ unsigned short SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo unsigned short RefreshRateTableIndex); unsigned short SiS_GetResInfo(struct SiS_Private *SiS_Pr,unsigned short ModeNo,unsigned short ModeIdIndex); void SiS_DisableBridge(struct SiS_Private *SiS_Pr); -#ifndef SIS_LINUX_KERNEL -void SiS_EnableBridge(struct SiS_Private *SiS_Pr); -#endif bool SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo); void SiS_SiS30xBLOn(struct SiS_Private *SiS_Pr); void SiS_SiS30xBLOff(struct SiS_Private *SiS_Pr); @@ -386,13 +372,9 @@ void SiS_SetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned cha unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short tempax); void SiS_SetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); unsigned short SiS_GetCH701x(struct SiS_Private *SiS_Pr, unsigned short tempax); -#ifndef SIS_LINUX_KERNEL -void SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); -unsigned short SiS_GetCH70xx(struct SiS_Private *SiS_Pr, unsigned short tempax); -#endif void SiS_SetCH70xxANDOR(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char orval,unsigned short andval); -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static void SiS_Chrontel701xOn(struct SiS_Private *SiS_Pr); static void SiS_Chrontel701xOff(struct SiS_Private *SiS_Pr); static void SiS_ChrontelInitTVVSync(struct SiS_Private *SiS_Pr); @@ -401,7 +383,7 @@ void SiS_Chrontel701xBLOn(struct SiS_Private *SiS_Pr); void SiS_Chrontel701xBLOff(struct SiS_Private *SiS_Pr); #endif /* 315 */ -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 static bool SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr); void SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo); #endif @@ -412,21 +394,12 @@ unsigned short SiS_HandleDDC(struct SiS_Private *SiS_Pr, unsigned int VBFlags, i unsigned short adaptnum, unsigned short DDCdatatype, unsigned char *buffer, unsigned int VBFlags2); -#ifdef SIS_XORG_XF86 -unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, - int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype, - bool checkcr32, unsigned int VBFlags2); -unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr); -unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype, - unsigned char *buffer); -#else static unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype, bool checkcr32, unsigned int VBFlags2); static unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr); static unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype, unsigned char *buffer); -#endif static void SiS_SetSwitchDDC2(struct SiS_Private *SiS_Pr); static unsigned short SiS_SetStart(struct SiS_Private *SiS_Pr); static unsigned short SiS_SetStop(struct SiS_Private *SiS_Pr); @@ -441,13 +414,13 @@ static unsigned short SiS_PrepareDDC(struct SiS_Private *SiS_Pr); static void SiS_SendACK(struct SiS_Private *SiS_Pr, unsigned short yesno); static unsigned short SiS_DoProbeDDC(struct SiS_Private *SiS_Pr); -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 static void SiS_OEM300Setting(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefTabindex); static void SetOEMLCDData2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex,unsigned short RefTableIndex); #endif -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 static void SiS_OEM310Setting(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex, unsigned short RRTI); static void SiS_OEM661Setting(struct SiS_Private *SiS_Pr, @@ -482,15 +455,13 @@ extern void SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short M extern void SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth); extern unsigned short SiS_GetRefCRTVCLK(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide); extern unsigned short SiS_GetRefCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide); -#ifdef SIS300 +#ifdef CONFIG_FB_SIS_300 extern void SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *tempbx, unsigned short *tempcl); extern unsigned short SiS_GetFIFOThresholdB300(unsigned short tempbx, unsigned short tempcl); extern unsigned short SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index); -#ifdef SIS_LINUX_KERNEL extern unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg); extern unsigned int sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg); #endif -#endif #endif diff --git a/drivers/video/sis/initextlfb.c b/drivers/video/sis/initextlfb.c index 99c04a4855d1..9dec64da4015 100644 --- a/drivers/video/sis/initextlfb.c +++ b/drivers/video/sis/initextlfb.c @@ -25,7 +25,6 @@ * Author: Thomas Winischhofer <thomas@winischhofer.net> */ -#include "osdef.h" #include "initdef.h" #include "vgatypes.h" #include "vstruct.h" @@ -59,7 +58,7 @@ sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno, if(rateindex > 0) rateindex--; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 switch(ModeNo) { case 0x5a: ModeNo = 0x50; break; case 0x5b: ModeNo = 0x56; @@ -103,7 +102,7 @@ sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno, if(rateindex > 0) rateindex--; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 switch(ModeNo) { case 0x5a: ModeNo = 0x50; break; case 0x5b: ModeNo = 0x56; @@ -187,7 +186,7 @@ sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *ht if(rateindex > 0) rateindex--; -#ifdef SIS315H +#ifdef CONFIG_FB_SIS_315 switch(ModeNo) { case 0x5a: ModeNo = 0x50; break; case 0x5b: ModeNo = 0x56; diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h deleted file mode 100644 index 6ff8f988a1a7..000000000000 --- a/drivers/video/sis/osdef.h +++ /dev/null @@ -1,133 +0,0 @@ -/* $XFree86$ */ -/* $XdotOrg$ */ -/* - * OS depending defines - * - * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria - * - * If distributed as part of the Linux kernel, the following license terms - * apply: - * - * * 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 named License, - * * or 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 - * - * Otherwise, the following license terms apply: - * - * * Redistribution and use in source and binary forms, with or without - * * modification, are permitted provided that the following conditions - * * are met: - * * 1) Redistributions of source code must retain the above copyright - * * notice, this list of conditions and the following disclaimer. - * * 2) Redistributions in binary form must reproduce the above copyright - * * notice, this list of conditions and the following disclaimer in the - * * documentation and/or other materials provided with the distribution. - * * 3) The name of the author may not be used to endorse or promote products - * * derived from this software without specific prior written permission. - * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. - * - * Author: Thomas Winischhofer <thomas@winischhofer.net> - * Silicon Integrated Systems, Inc. (used by permission) - * - */ - -#ifndef _SIS_OSDEF_H_ -#define _SIS_OSDEF_H_ - -/* The choices are: */ -#define SIS_LINUX_KERNEL /* Linux kernel framebuffer */ -#undef SIS_XORG_XF86 /* XFree86/X.org */ - -#ifdef OutPortByte -#undef OutPortByte -#endif - -#ifdef OutPortWord -#undef OutPortWord -#endif - -#ifdef OutPortLong -#undef OutPortLong -#endif - -#ifdef InPortByte -#undef InPortByte -#endif - -#ifdef InPortWord -#undef InPortWord -#endif - -#ifdef InPortLong -#undef InPortLong -#endif - -/**********************************************************************/ -/* LINUX KERNEL */ -/**********************************************************************/ - -#ifdef SIS_LINUX_KERNEL - -#ifdef CONFIG_FB_SIS_300 -#define SIS300 -#endif - -#ifdef CONFIG_FB_SIS_315 -#define SIS315H -#endif - -#if !defined(SIS300) && !defined(SIS315H) -#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set -#warning sisfb will not work! -#endif - -#define OutPortByte(p,v) outb((u8)(v),(SISIOADDRESS)(p)) -#define OutPortWord(p,v) outw((u16)(v),(SISIOADDRESS)(p)) -#define OutPortLong(p,v) outl((u32)(v),(SISIOADDRESS)(p)) -#define InPortByte(p) inb((SISIOADDRESS)(p)) -#define InPortWord(p) inw((SISIOADDRESS)(p)) -#define InPortLong(p) inl((SISIOADDRESS)(p)) -#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset_io(MemoryAddress, value, MemorySize) - -#endif /* LINUX_KERNEL */ - -/**********************************************************************/ -/* XFree86/X.org */ -/**********************************************************************/ - -#ifdef SIS_XORG_XF86 - -#define SIS300 -#define SIS315H - -#define OutPortByte(p,v) outSISREG((IOADDRESS)(p),(CARD8)(v)) -#define OutPortWord(p,v) outSISREGW((IOADDRESS)(p),(CARD16)(v)) -#define OutPortLong(p,v) outSISREGL((IOADDRESS)(p),(CARD32)(v)) -#define InPortByte(p) inSISREG((IOADDRESS)(p)) -#define InPortWord(p) inSISREGW((IOADDRESS)(p)) -#define InPortLong(p) inSISREGL((IOADDRESS)(p)) -#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize) - -#endif /* XF86 */ - -#endif /* _OSDEF_H_ */ diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h index 7c5710e3fb56..80d89d37c414 100644 --- a/drivers/video/sis/sis.h +++ b/drivers/video/sis/sis.h @@ -24,7 +24,6 @@ #ifndef _SIS_H_ #define _SIS_H_ -#include "osdef.h" #include <video/sisfb.h> #include "vgatypes.h" diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 3dde12b0ab06..7e3370f115b6 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -60,6 +60,11 @@ #include "sis.h" #include "sis_main.h" +#if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315) +#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set +#warning sisfb will not work! +#endif + static void sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command); @@ -4114,14 +4119,6 @@ sisfb_find_rom(struct pci_dev *pdev) if(sisfb_check_rom(rom_base, ivideo)) { if((myrombase = vmalloc(65536))) { - - /* Work around bug in pci/rom.c: Folks forgot to check - * whether the size retrieved from the BIOS image eventually - * is larger than the mapped size - */ - if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize) - romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE); - memcpy_fromio(myrombase, rom_base, (romsize > 65536) ? 65536 : romsize); } @@ -4155,23 +4152,6 @@ sisfb_find_rom(struct pci_dev *pdev) } -#else - - pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp); - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, - (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE); - - rom_base = ioremap(ivideo->video_base, 65536); - if(rom_base) { - if(sisfb_check_rom(rom_base, ivideo)) { - if((myrombase = vmalloc(65536))) - memcpy_fromio(myrombase, rom_base, 65536); - } - iounmap(rom_base); - } - - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp); - #endif return myrombase; diff --git a/drivers/video/sis/vgatypes.h b/drivers/video/sis/vgatypes.h index 81a22eaabfde..12c0dfaf2518 100644 --- a/drivers/video/sis/vgatypes.h +++ b/drivers/video/sis/vgatypes.h @@ -55,21 +55,10 @@ #define SISIOMEMTYPE -#ifdef SIS_LINUX_KERNEL typedef unsigned long SISIOADDRESS; #include <linux/types.h> /* Need __iomem */ #undef SISIOMEMTYPE #define SISIOMEMTYPE __iomem -#endif - -#ifdef SIS_XORG_XF86 -#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,0,0,0) -typedef unsigned long IOADDRESS; -typedef unsigned long SISIOADDRESS; -#else -typedef IOADDRESS SISIOADDRESS; -#endif -#endif typedef enum _SIS_CHIP_TYPE { SIS_VGALegacy = 0, diff --git a/drivers/video/sis/vstruct.h b/drivers/video/sis/vstruct.h index bef4aae388d0..ea94d214dcff 100644 --- a/drivers/video/sis/vstruct.h +++ b/drivers/video/sis/vstruct.h @@ -233,24 +233,15 @@ struct SiS_Private { unsigned char ChipType; unsigned char ChipRevision; -#ifdef SIS_XORG_XF86 - PCITAG PciTag; -#endif -#ifdef SIS_LINUX_KERNEL void *ivideo; -#endif unsigned char *VirtualRomBase; bool UseROM; -#ifdef SIS_LINUX_KERNEL unsigned char SISIOMEMTYPE *VideoMemoryAddress; unsigned int VideoMemorySize; -#endif SISIOADDRESS IOAddress; SISIOADDRESS IOAddress2; /* For dual chip XGI volari */ -#ifdef SIS_LINUX_KERNEL SISIOADDRESS RelIO; -#endif SISIOADDRESS SiS_P3c4; SISIOADDRESS SiS_P3d4; SISIOADDRESS SiS_P3c0; @@ -280,9 +271,6 @@ struct SiS_Private unsigned short SiS_IF_DEF_FSTN; unsigned short SiS_SysFlags; unsigned char SiS_VGAINFO; -#ifdef SIS_XORG_XF86 - unsigned short SiS_CP1, SiS_CP2, SiS_CP3, SiS_CP4; -#endif bool SiS_UseROM; bool SiS_ROMNew; bool SiS_XGIROM; diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 3a43ebf83a49..efb35aa8309a 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -9,19 +9,19 @@ static ssize_t device_show(struct device *_d, struct device_attribute *attr, char *buf) { struct virtio_device *dev = container_of(_d,struct virtio_device,dev); - return sprintf(buf, "%hu", dev->id.device); + return sprintf(buf, "0x%04x\n", dev->id.device); } static ssize_t vendor_show(struct device *_d, struct device_attribute *attr, char *buf) { struct virtio_device *dev = container_of(_d,struct virtio_device,dev); - return sprintf(buf, "%hu", dev->id.vendor); + return sprintf(buf, "0x%04x\n", dev->id.vendor); } static ssize_t status_show(struct device *_d, struct device_attribute *attr, char *buf) { struct virtio_device *dev = container_of(_d,struct virtio_device,dev); - return sprintf(buf, "0x%08x", dev->config->get_status(dev)); + return sprintf(buf, "0x%08x\n", dev->config->get_status(dev)); } static ssize_t modalias_show(struct device *_d, struct device_attribute *attr, char *buf) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 1475ed6b575f..cc2f73e03475 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -230,9 +230,6 @@ add_head: pr_debug("Added buffer head %i to %p\n", head, vq); END_USE(vq); - /* If we're indirect, we can fit many (assuming not OOM). */ - if (vq->indirect) - return vq->num_free ? vq->vring.num : 0; return vq->num_free; } EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 4a291045ebac..a5ad77ef4266 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -558,6 +558,9 @@ config IT8712F_WDT This is the driver for the built-in watchdog timer on the IT8712F Super I/0 chipset used on many motherboards. + If the driver does not work, then make sure that the game port in + the BIOS is enabled. + To compile this driver as a module, choose M here: the module will be called it8712f_wdt. diff --git a/drivers/watchdog/bcm63xx_wdt.c b/drivers/watchdog/bcm63xx_wdt.c index a1debc89356b..3c5045a206dd 100644 --- a/drivers/watchdog/bcm63xx_wdt.c +++ b/drivers/watchdog/bcm63xx_wdt.c @@ -18,7 +18,6 @@ #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/reboot.h> #include <linux/types.h> #include <linux/uaccess.h> #include <linux/watchdog.h> @@ -220,14 +219,6 @@ static long bcm63xx_wdt_ioctl(struct file *file, unsigned int cmd, } } -static int bcm63xx_wdt_notify_sys(struct notifier_block *this, - unsigned long code, void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) - bcm63xx_wdt_pause(); - return NOTIFY_DONE; -} - static const struct file_operations bcm63xx_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -243,12 +234,8 @@ static struct miscdevice bcm63xx_wdt_miscdev = { .fops = &bcm63xx_wdt_fops, }; -static struct notifier_block bcm63xx_wdt_notifier = { - .notifier_call = bcm63xx_wdt_notify_sys, -}; - -static int bcm63xx_wdt_probe(struct platform_device *pdev) +static int __devinit bcm63xx_wdt_probe(struct platform_device *pdev) { int ret; struct resource *r; @@ -280,16 +267,10 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev) wdt_time); } - ret = register_reboot_notifier(&bcm63xx_wdt_notifier); - if (ret) { - dev_err(&pdev->dev, "failed to register reboot_notifier\n"); - goto unregister_timer; - } - ret = misc_register(&bcm63xx_wdt_miscdev); if (ret < 0) { dev_err(&pdev->dev, "failed to register watchdog device\n"); - goto unregister_reboot_notifier; + goto unregister_timer; } dev_info(&pdev->dev, " started, timer margin: %d sec\n", @@ -297,8 +278,6 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev) return 0; -unregister_reboot_notifier: - unregister_reboot_notifier(&bcm63xx_wdt_notifier); unregister_timer: bcm63xx_timer_unregister(TIMER_WDT_ID); unmap: @@ -306,25 +285,28 @@ unmap: return ret; } -static int bcm63xx_wdt_remove(struct platform_device *pdev) +static int __devexit bcm63xx_wdt_remove(struct platform_device *pdev) { if (!nowayout) bcm63xx_wdt_pause(); misc_deregister(&bcm63xx_wdt_miscdev); - - iounmap(bcm63xx_wdt_device.regs); - - unregister_reboot_notifier(&bcm63xx_wdt_notifier); bcm63xx_timer_unregister(TIMER_WDT_ID); - + iounmap(bcm63xx_wdt_device.regs); return 0; } +static void bcm63xx_wdt_shutdown(struct platform_device *pdev) +{ + bcm63xx_wdt_pause(); +} + static struct platform_driver bcm63xx_wdt = { .probe = bcm63xx_wdt_probe, - .remove = bcm63xx_wdt_remove, + .remove = __devexit_p(bcm63xx_wdt_remove), + .shutdown = bcm63xx_wdt_shutdown, .driver = { + .owner = THIS_MODULE, .name = "bcm63xx-wdt", } }; diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c index 9c21d19043a6..f6bd6f10fcec 100644 --- a/drivers/watchdog/gef_wdt.c +++ b/drivers/watchdog/gef_wdt.c @@ -30,6 +30,7 @@ #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/watchdog.h> +#include <linux/fs.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/io.h> diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index f7e90fe47b71..b8838d2c67a6 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -32,6 +32,7 @@ * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH) * document number 320066-003, 320257-008: EP80597 (IICH) * document number TBD : Cougar Point (CPT) + * document number TBD : Patsburg (PBG) */ /* @@ -146,7 +147,8 @@ enum iTCO_chipsets { TCO_CPT29, /* Cougar Point */ TCO_CPT30, /* Cougar Point */ TCO_CPT31, /* Cougar Point */ - TCO_PBG, /* Patsburg */ + TCO_PBG1, /* Patsburg */ + TCO_PBG2, /* Patsburg */ }; static struct { @@ -235,6 +237,7 @@ static struct { {"Cougar Point", 2}, {"Cougar Point", 2}, {"Patsburg", 2}, + {"Patsburg", 2}, {NULL, 0} }; @@ -350,7 +353,8 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { { ITCO_PCI_DEVICE(0x1c5d, TCO_CPT29)}, { ITCO_PCI_DEVICE(0x1c5e, TCO_CPT30)}, { ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)}, - { ITCO_PCI_DEVICE(0x1d40, TCO_PBG)}, + { ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)}, + { ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index eb8a78d77d9d..533a199e7a3f 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -8,9 +8,12 @@ obj-$(CONFIG_BLOCK) += biomerge.o obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o obj-$(CONFIG_XEN_XENCOMM) += xencomm.o obj-$(CONFIG_XEN_BALLOON) += balloon.o -obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o +obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o obj-$(CONFIG_XENFS) += xenfs/ obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o obj-$(CONFIG_XEN_DOM0) += pci.o + +xen-evtchn-y := evtchn.o + diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 500290b150bb..43f9f02c7db0 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -50,6 +50,7 @@ #include <asm/pgtable.h> #include <asm/uaccess.h> #include <asm/tlb.h> +#include <asm/e820.h> #include <asm/xen/hypervisor.h> #include <asm/xen/hypercall.h> @@ -119,7 +120,7 @@ static void scrub_page(struct page *page) } /* balloon_append: add the given page to the balloon. */ -static void balloon_append(struct page *page) +static void __balloon_append(struct page *page) { /* Lowmem is re-populated first, so highmem pages go at list tail. */ if (PageHighMem(page)) { @@ -130,7 +131,11 @@ static void balloon_append(struct page *page) list_add(&page->lru, &ballooned_pages); balloon_stats.balloon_low++; } +} +static void balloon_append(struct page *page) +{ + __balloon_append(page); totalram_pages--; } @@ -191,7 +196,7 @@ static unsigned long current_target(void) static int increase_reservation(unsigned long nr_pages) { - unsigned long pfn, i, flags; + unsigned long pfn, i; struct page *page; long rc; struct xen_memory_reservation reservation = { @@ -203,8 +208,6 @@ static int increase_reservation(unsigned long nr_pages) if (nr_pages > ARRAY_SIZE(frame_list)) nr_pages = ARRAY_SIZE(frame_list); - spin_lock_irqsave(&xen_reservation_lock, flags); - page = balloon_first_page(); for (i = 0; i < nr_pages; i++) { BUG_ON(page == NULL); @@ -247,14 +250,12 @@ static int increase_reservation(unsigned long nr_pages) balloon_stats.current_pages += rc; out: - spin_unlock_irqrestore(&xen_reservation_lock, flags); - return rc < 0 ? rc : rc != nr_pages; } static int decrease_reservation(unsigned long nr_pages) { - unsigned long pfn, i, flags; + unsigned long pfn, i; struct page *page; int need_sleep = 0; int ret; @@ -292,8 +293,6 @@ static int decrease_reservation(unsigned long nr_pages) kmap_flush_unused(); flush_tlb_all(); - spin_lock_irqsave(&xen_reservation_lock, flags); - /* No more mappings: invalidate P2M and add to balloon. */ for (i = 0; i < nr_pages; i++) { pfn = mfn_to_pfn(frame_list[i]); @@ -308,8 +307,6 @@ static int decrease_reservation(unsigned long nr_pages) balloon_stats.current_pages -= nr_pages; - spin_unlock_irqrestore(&xen_reservation_lock, flags); - return need_sleep; } @@ -395,7 +392,7 @@ static struct notifier_block xenstore_notifier; static int __init balloon_init(void) { - unsigned long pfn; + unsigned long pfn, extra_pfn_end; struct page *page; if (!xen_pv_domain()) @@ -415,11 +412,24 @@ static int __init balloon_init(void) register_balloon(&balloon_sysdev); - /* Initialise the balloon with excess memory space. */ - for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { + /* + * Initialise the balloon with excess memory space. We need + * to make sure we don't add memory which doesn't exist or + * logically exist. The E820 map can be trimmed to be smaller + * than the amount of physical memory due to the mem= command + * line parameter. And if this is a 32-bit non-HIGHMEM kernel + * on a system with memory which requires highmem to access, + * don't try to use it. + */ + extra_pfn_end = min(min(max_pfn, e820_end_of_ram_pfn()), + (unsigned long)PFN_DOWN(xen_extra_mem_start + xen_extra_mem_size)); + for (pfn = PFN_UP(xen_extra_mem_start); + pfn < extra_pfn_end; + pfn++) { page = pfn_to_page(pfn); - if (!PageReserved(page)) - balloon_append(page); + /* totalram_pages doesn't include the boot-time + balloon extension, so don't subtract from it. */ + __balloon_append(page); } target_watch.callback = watch_target; diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 321a0c8346e5..31af0ac31a98 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -105,7 +105,6 @@ struct irq_info static struct irq_info *irq_info; static int *pirq_to_irq; -static int nr_pirqs; static int *evtchn_to_irq; struct cpu_evtchn_s { @@ -278,17 +277,17 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu)); #endif - __clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq))); - __set_bit(chn, cpu_evtchn_mask(cpu)); + clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq))); + set_bit(chn, cpu_evtchn_mask(cpu)); irq_info[irq].cpu = cpu; } static void init_evtchn_cpu_bindings(void) { + int i; #ifdef CONFIG_SMP struct irq_desc *desc; - int i; /* By default all event channels notify CPU#0. */ for_each_irq_desc(i, desc) { @@ -296,7 +295,10 @@ static void init_evtchn_cpu_bindings(void) } #endif - memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s)); + for_each_possible_cpu(i) + memset(cpu_evtchn_mask(i), + (i == 0) ? ~0 : 0, sizeof(struct cpu_evtchn_s)); + } static inline void clear_evtchn(int port) @@ -382,12 +384,17 @@ static int get_nr_hw_irqs(void) return ret; } -/* callers of this function should make sure that PHYSDEVOP_get_nr_pirqs - * succeeded otherwise nr_pirqs won't hold the right value */ -static int find_unbound_pirq(void) +static int find_unbound_pirq(int type) { - int i; - for (i = nr_pirqs-1; i >= 0; i--) { + int rc, i; + struct physdev_get_free_pirq op_get_free_pirq; + op_get_free_pirq.type = type; + + rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq); + if (!rc) + return op_get_free_pirq.pirq; + + for (i = 0; i < nr_irqs; i++) { if (pirq_to_irq[i] < 0) return i; } @@ -420,7 +427,7 @@ static int find_unbound_irq(void) if (irq == start) goto no_irqs; - res = irq_alloc_desc_at(irq, 0); + res = irq_alloc_desc_at(irq, -1); if (WARN_ON(res != irq)) return -1; @@ -608,10 +615,10 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) spin_lock(&irq_mapping_update_lock); - if ((pirq > nr_pirqs) || (gsi > nr_irqs)) { + if ((pirq > nr_irqs) || (gsi > nr_irqs)) { printk(KERN_WARNING "xen_map_pirq_gsi: %s %s is incorrect!\n", - pirq > nr_pirqs ? "nr_pirqs" :"", - gsi > nr_irqs ? "nr_irqs" : ""); + pirq > nr_irqs ? "pirq" :"", + gsi > nr_irqs ? "gsi" : ""); goto out; } @@ -627,7 +634,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) if (identity_mapped_irq(gsi) || (!xen_initial_domain() && xen_pv_domain())) { irq = gsi; - irq_alloc_desc_at(irq, 0); + irq_alloc_desc_at(irq, -1); } else irq = find_unbound_irq(); @@ -661,17 +668,21 @@ out: #include <linux/msi.h> #include "../pci/msi.h" -void xen_allocate_pirq_msi(char *name, int *irq, int *pirq) +void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc) { spin_lock(&irq_mapping_update_lock); - *irq = find_unbound_irq(); - if (*irq == -1) - goto out; + if (alloc & XEN_ALLOC_IRQ) { + *irq = find_unbound_irq(); + if (*irq == -1) + goto out; + } - *pirq = find_unbound_pirq(); - if (*pirq == -1) - goto out; + if (alloc & XEN_ALLOC_PIRQ) { + *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI); + if (*pirq == -1) + goto out; + } set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, handle_level_irq, name); @@ -752,13 +763,14 @@ int xen_destroy_irq(int irq) goto out; if (xen_initial_domain()) { - unmap_irq.pirq = info->u.pirq.gsi; + unmap_irq.pirq = info->u.pirq.pirq; unmap_irq.domid = DOMID_SELF; rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); if (rc) { printk(KERN_WARNING "unmap irq failed %d\n", rc); goto out; } + pirq_to_irq[info->u.pirq.pirq] = -1; } irq_info[irq] = mk_unbound_info(); @@ -779,6 +791,11 @@ int xen_gsi_from_irq(unsigned irq) return gsi_from_irq(irq); } +int xen_irq_from_pirq(unsigned pirq) +{ + return pirq_to_irq[pirq]; +} + int bind_evtchn_to_irq(unsigned int evtchn) { int irq; @@ -1276,6 +1293,42 @@ static int retrigger_dynirq(unsigned int irq) return ret; } +static void restore_cpu_pirqs(void) +{ + int pirq, rc, irq, gsi; + struct physdev_map_pirq map_irq; + + for (pirq = 0; pirq < nr_irqs; pirq++) { + irq = pirq_to_irq[pirq]; + if (irq == -1) + continue; + + /* save/restore of PT devices doesn't work, so at this point the + * only devices present are GSI based emulated devices */ + gsi = gsi_from_irq(irq); + if (!gsi) + continue; + + map_irq.domid = DOMID_SELF; + map_irq.type = MAP_PIRQ_TYPE_GSI; + map_irq.index = gsi; + map_irq.pirq = pirq; + + rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); + if (rc) { + printk(KERN_WARNING "xen map irq failed gsi=%d irq=%d pirq=%d rc=%d\n", + gsi, irq, pirq, rc); + irq_info[irq] = mk_unbound_info(); + pirq_to_irq[pirq] = -1; + continue; + } + + printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq); + + startup_pirq(irq); + } +} + static void restore_cpu_virqs(unsigned int cpu) { struct evtchn_bind_virq bind_virq; @@ -1419,6 +1472,8 @@ void xen_irq_resume(void) unmask_evtchn(evtchn); } + + restore_cpu_pirqs(); } static struct irq_chip xen_dynamic_chip __read_mostly = { @@ -1503,26 +1558,17 @@ void xen_callback_vector(void) {} void __init xen_init_IRQ(void) { - int i, rc; - struct physdev_nr_pirqs op_nr_pirqs; + int i; cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s), GFP_KERNEL); irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); - rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_nr_pirqs, &op_nr_pirqs); - if (rc < 0) { - nr_pirqs = nr_irqs; - if (rc != -ENOSYS) - printk(KERN_WARNING "PHYSDEVOP_get_nr_pirqs returned rc=%d\n", rc); - } else { - if (xen_pv_domain() && !xen_initial_domain()) - nr_pirqs = max((int)op_nr_pirqs.nr_pirqs, nr_irqs); - else - nr_pirqs = op_nr_pirqs.nr_pirqs; - } - pirq_to_irq = kcalloc(nr_pirqs, sizeof(*pirq_to_irq), GFP_KERNEL); - for (i = 0; i < nr_pirqs; i++) + /* We are using nr_irqs as the maximum number of pirq available but + * that number is actually chosen by Xen and we don't know exactly + * what it is. Be careful choosing high pirq numbers. */ + pirq_to_irq = kcalloc(nr_irqs, sizeof(*pirq_to_irq), GFP_KERNEL); + for (i = 0; i < nr_irqs; i++) pirq_to_irq[i] = -1; evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index fec6ba3c08a8..ef11daf0cafe 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -69,20 +69,51 @@ struct per_user_data { const char *name; }; -/* Who's bound to each port? */ -static struct per_user_data *port_user[NR_EVENT_CHANNELS]; +/* + * Who's bound to each port? This is logically an array of struct + * per_user_data *, but we encode the current enabled-state in bit 0. + */ +static unsigned long *port_user; static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */ -irqreturn_t evtchn_interrupt(int irq, void *data) +static inline struct per_user_data *get_port_user(unsigned port) +{ + return (struct per_user_data *)(port_user[port] & ~1); +} + +static inline void set_port_user(unsigned port, struct per_user_data *u) +{ + port_user[port] = (unsigned long)u; +} + +static inline bool get_port_enabled(unsigned port) +{ + return port_user[port] & 1; +} + +static inline void set_port_enabled(unsigned port, bool enabled) +{ + if (enabled) + port_user[port] |= 1; + else + port_user[port] &= ~1; +} + +static irqreturn_t evtchn_interrupt(int irq, void *data) { unsigned int port = (unsigned long)data; struct per_user_data *u; spin_lock(&port_user_lock); - u = port_user[port]; + u = get_port_user(port); + + WARN(!get_port_enabled(port), + "Interrupt for port %d, but apparently not enabled; per-user %p\n", + port, u); disable_irq_nosync(irq); + set_port_enabled(port, false); if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port; @@ -92,9 +123,8 @@ irqreturn_t evtchn_interrupt(int irq, void *data) kill_fasync(&u->evtchn_async_queue, SIGIO, POLL_IN); } - } else { + } else u->ring_overflow = 1; - } spin_unlock(&port_user_lock); @@ -198,9 +228,18 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf, goto out; spin_lock_irq(&port_user_lock); - for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) - if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u)) - enable_irq(irq_from_evtchn(kbuf[i])); + + for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) { + unsigned port = kbuf[i]; + + if (port < NR_EVENT_CHANNELS && + get_port_user(port) == u && + !get_port_enabled(port)) { + set_port_enabled(port, true); + enable_irq(irq_from_evtchn(port)); + } + } + spin_unlock_irq(&port_user_lock); rc = count; @@ -222,8 +261,9 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port) * interrupt handler yet, and our caller has already * serialized bind operations.) */ - BUG_ON(port_user[port] != NULL); - port_user[port] = u; + BUG_ON(get_port_user(port) != NULL); + set_port_user(port, u); + set_port_enabled(port, true); /* start enabled */ rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, u->name, (void *)(unsigned long)port); @@ -239,10 +279,7 @@ static void evtchn_unbind_from_user(struct per_user_data *u, int port) unbind_from_irqhandler(irq, (void *)(unsigned long)port); - /* make sure we unbind the irq handler before clearing the port */ - barrier(); - - port_user[port] = NULL; + set_port_user(port, NULL); } static long evtchn_ioctl(struct file *file, @@ -333,15 +370,17 @@ static long evtchn_ioctl(struct file *file, spin_lock_irq(&port_user_lock); rc = -ENOTCONN; - if (port_user[unbind.port] != u) { + if (get_port_user(unbind.port) != u) { spin_unlock_irq(&port_user_lock); break; } - evtchn_unbind_from_user(u, unbind.port); + disable_irq(irq_from_evtchn(unbind.port)); spin_unlock_irq(&port_user_lock); + evtchn_unbind_from_user(u, unbind.port); + rc = 0; break; } @@ -355,7 +394,7 @@ static long evtchn_ioctl(struct file *file, if (notify.port >= NR_EVENT_CHANNELS) { rc = -EINVAL; - } else if (port_user[notify.port] != u) { + } else if (get_port_user(notify.port) != u) { rc = -ENOTCONN; } else { notify_remote_via_evtchn(notify.port); @@ -431,7 +470,7 @@ static int evtchn_open(struct inode *inode, struct file *filp) filp->private_data = u; - return 0; + return nonseekable_open(inode, filp);; } static int evtchn_release(struct inode *inode, struct file *filp) @@ -444,14 +483,21 @@ static int evtchn_release(struct inode *inode, struct file *filp) free_page((unsigned long)u->ring); for (i = 0; i < NR_EVENT_CHANNELS; i++) { - if (port_user[i] != u) + if (get_port_user(i) != u) continue; - evtchn_unbind_from_user(port_user[i], i); + disable_irq(irq_from_evtchn(i)); } spin_unlock_irq(&port_user_lock); + for (i = 0; i < NR_EVENT_CHANNELS; i++) { + if (get_port_user(i) != u) + continue; + + evtchn_unbind_from_user(get_port_user(i), i); + } + kfree(u->name); kfree(u); @@ -467,12 +513,12 @@ static const struct file_operations evtchn_fops = { .fasync = evtchn_fasync, .open = evtchn_open, .release = evtchn_release, - .llseek = noop_llseek, + .llseek = no_llseek, }; static struct miscdevice evtchn_miscdev = { .minor = MISC_DYNAMIC_MINOR, - .name = "evtchn", + .name = "xen/evtchn", .fops = &evtchn_fops, }; static int __init evtchn_init(void) @@ -482,8 +528,11 @@ static int __init evtchn_init(void) if (!xen_domain()) return -ENODEV; + port_user = kcalloc(NR_EVENT_CHANNELS, sizeof(*port_user), GFP_KERNEL); + if (port_user == NULL) + return -ENOMEM; + spin_lock_init(&port_user_lock); - memset(port_user, 0, sizeof(port_user)); /* Create '/dev/misc/evtchn'. */ err = misc_register(&evtchn_miscdev); @@ -499,6 +548,9 @@ static int __init evtchn_init(void) static void __exit evtchn_cleanup(void) { + kfree(port_user); + port_user = NULL; + misc_deregister(&evtchn_miscdev); } diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index ef9c7db52077..db8c4c4ac880 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -49,6 +49,7 @@ static int xen_hvm_suspend(void *data) if (!*cancelled) { xen_irq_resume(); + xen_console_resume(); xen_timer_resume(); } diff --git a/drivers/xen/xenfs/privcmd.c b/drivers/xen/xenfs/privcmd.c index 0f5d4162b22d..dbd3b16fd131 100644 --- a/drivers/xen/xenfs/privcmd.c +++ b/drivers/xen/xenfs/privcmd.c @@ -265,9 +265,7 @@ static int mmap_return_errors(void *data, void *state) xen_pfn_t *mfnp = data; struct mmap_batch_state *st = state; - put_user(*mfnp, st->user++); - - return 0; + return put_user(*mfnp, st->user++); } static struct vm_operations_struct privcmd_vm_ops; @@ -322,10 +320,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata) up_write(&mm->mmap_sem); if (state.err > 0) { - ret = 0; - state.user = m.arr; - traverse_pages(m.num, sizeof(xen_pfn_t), + ret = traverse_pages(m.num, sizeof(xen_pfn_t), &pagelist, mmap_return_errors, &state); } @@ -383,8 +379,9 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma) if (xen_feature(XENFEAT_auto_translated_physmap)) return -ENOSYS; - /* DONTCOPY is essential for Xen as copy_page_range is broken. */ - vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY; + /* DONTCOPY is essential for Xen because copy_page_range doesn't know + * how to recreate these mappings */ + vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP; vma->vm_ops = &privcmd_vm_ops; vma->vm_private_data = NULL; diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index f6339d11d59c..1aa389719846 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c @@ -12,8 +12,6 @@ #include <linux/module.h> #include <linux/fs.h> #include <linux/magic.h> -#include <linux/mm.h> -#include <linux/backing-dev.h> #include <xen/xen.h> @@ -24,28 +22,12 @@ MODULE_DESCRIPTION("Xen filesystem"); MODULE_LICENSE("GPL"); -static int xenfs_set_page_dirty(struct page *page) -{ - return !TestSetPageDirty(page); -} - -static const struct address_space_operations xenfs_aops = { - .set_page_dirty = xenfs_set_page_dirty, -}; - -static struct backing_dev_info xenfs_backing_dev_info = { - .ra_pages = 0, /* No readahead */ - .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, -}; - static struct inode *xenfs_make_inode(struct super_block *sb, int mode) { struct inode *ret = new_inode(sb); if (ret) { ret->i_mode = mode; - ret->i_mapping->a_ops = &xenfs_aops; - ret->i_mapping->backing_dev_info = &xenfs_backing_dev_info; ret->i_uid = ret->i_gid = 0; ret->i_blocks = 0; ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; @@ -121,9 +103,9 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent) return rc; } -static int xenfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static struct dentry *xenfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) { return mount_single(fs_type, flags, data, xenfs_fill_super); } @@ -137,25 +119,11 @@ static struct file_system_type xenfs_type = { static int __init xenfs_init(void) { - int err; - if (!xen_domain()) { - printk(KERN_INFO "xenfs: not registering filesystem on non-xen platform\n"); - return 0; - } - - err = register_filesystem(&xenfs_type); - if (err) { - printk(KERN_ERR "xenfs: Unable to register filesystem!\n"); - goto out; - } - - err = bdi_init(&xenfs_backing_dev_info); - if (err) - unregister_filesystem(&xenfs_type); - - out: + if (xen_domain()) + return register_filesystem(&xenfs_type); - return err; + printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); + return 0; } static void __exit xenfs_exit(void) diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index d5c1401f0031..d34896cfb19f 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -980,19 +980,11 @@ static int autofs4_root_ioctl_unlocked(struct inode *inode, struct file *filp, } } -static DEFINE_MUTEX(autofs4_ioctl_mutex); - static long autofs4_root_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - long ret; struct inode *inode = filp->f_dentry->d_inode; - - mutex_lock(&autofs4_ioctl_mutex); - ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, arg); - mutex_unlock(&autofs4_ioctl_mutex); - - return ret; + return autofs4_root_ioctl_unlocked(inode, filp, cmd, arg); } #ifdef CONFIG_COMPAT @@ -1002,13 +994,11 @@ static long autofs4_root_compat_ioctl(struct file *filp, struct inode *inode = filp->f_path.dentry->d_inode; int ret; - mutex_lock(&autofs4_ioctl_mutex); if (cmd == AUTOFS_IOC_READY || cmd == AUTOFS_IOC_FAIL) ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, arg); else ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, (unsigned long)compat_ptr(arg)); - mutex_unlock(&autofs4_ioctl_mutex); return ret; } diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 7845d1f7d1d9..b50bc4bd5c56 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -91,23 +91,10 @@ static inline int compressed_bio_size(struct btrfs_root *root, static struct bio *compressed_bio_alloc(struct block_device *bdev, u64 first_byte, gfp_t gfp_flags) { - struct bio *bio; int nr_vecs; nr_vecs = bio_get_nr_vecs(bdev); - bio = bio_alloc(gfp_flags, nr_vecs); - - if (bio == NULL && (current->flags & PF_MEMALLOC)) { - while (!bio && (nr_vecs /= 2)) - bio = bio_alloc(gfp_flags, nr_vecs); - } - - if (bio) { - bio->bi_size = 0; - bio->bi_bdev = bdev; - bio->bi_sector = first_byte >> 9; - } - return bio; + return btrfs_bio_alloc(bdev, first_byte >> 9, nr_vecs, gfp_flags); } static int check_compressed_csum(struct inode *inode, diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 8db9234f6b41..af52f6d7a4d8 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -808,9 +808,9 @@ struct btrfs_block_group_cache { int extents_thresh; int free_extents; int total_bitmaps; - int ro:1; - int dirty:1; - int iref:1; + unsigned int ro:1; + unsigned int dirty:1; + unsigned int iref:1; int disk_cache_state; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index fb827d0d7181..51d2e4de34eb 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -28,6 +28,7 @@ #include <linux/freezer.h> #include <linux/crc32c.h> #include <linux/slab.h> +#include <linux/migrate.h> #include "compat.h" #include "ctree.h" #include "disk-io.h" @@ -355,6 +356,8 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page) ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE, btrfs_header_generation(eb)); BUG_ON(ret); + WARN_ON(!btrfs_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN)); + found_start = btrfs_header_bytenr(eb); if (found_start != start) { WARN_ON(1); @@ -693,6 +696,27 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, __btree_submit_bio_done); } +#ifdef CONFIG_MIGRATION +static int btree_migratepage(struct address_space *mapping, + struct page *newpage, struct page *page) +{ + /* + * we can't safely write a btree page from here, + * we haven't done the locking hook + */ + if (PageDirty(page)) + return -EAGAIN; + /* + * Buffers may be managed in a filesystem specific way. + * We must have no buffers or drop them. + */ + if (page_has_private(page) && + !try_to_release_page(page, GFP_KERNEL)) + return -EAGAIN; + return migrate_page(mapping, newpage, page); +} +#endif + static int btree_writepage(struct page *page, struct writeback_control *wbc) { struct extent_io_tree *tree; @@ -707,8 +731,7 @@ static int btree_writepage(struct page *page, struct writeback_control *wbc) } redirty_page_for_writepage(wbc, page); - eb = btrfs_find_tree_block(root, page_offset(page), - PAGE_CACHE_SIZE); + eb = btrfs_find_tree_block(root, page_offset(page), PAGE_CACHE_SIZE); WARN_ON(!eb); was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags); @@ -799,6 +822,9 @@ static const struct address_space_operations btree_aops = { .releasepage = btree_releasepage, .invalidatepage = btree_invalidatepage, .sync_page = block_sync_page, +#ifdef CONFIG_MIGRATION + .migratepage = btree_migratepage, +#endif }; int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, @@ -981,7 +1007,10 @@ static int find_and_setup_root(struct btrfs_root *tree_root, blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), blocksize, generation); - BUG_ON(!root->node); + if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) { + free_extent_buffer(root->node); + return -EIO; + } root->commit_root = btrfs_root_node(root); return 0; } @@ -1538,10 +1567,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, GFP_NOFS); struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS); - struct btrfs_root *tree_root = kzalloc(sizeof(struct btrfs_root), - GFP_NOFS); - struct btrfs_fs_info *fs_info = kzalloc(sizeof(*fs_info), - GFP_NOFS); + struct btrfs_root *tree_root = btrfs_sb(sb); + struct btrfs_fs_info *fs_info = tree_root->fs_info; struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS); struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root), diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c index 951ef09b82f4..659f532d26a0 100644 --- a/fs/btrfs/export.c +++ b/fs/btrfs/export.c @@ -166,7 +166,7 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh, static struct dentry *btrfs_get_parent(struct dentry *child) { struct inode *dir = child->d_inode; - static struct dentry *dentry; + struct dentry *dentry; struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_path *path; struct extent_buffer *leaf; @@ -232,9 +232,85 @@ fail: return ERR_PTR(ret); } +static int btrfs_get_name(struct dentry *parent, char *name, + struct dentry *child) +{ + struct inode *inode = child->d_inode; + struct inode *dir = parent->d_inode; + struct btrfs_path *path; + struct btrfs_root *root = BTRFS_I(dir)->root; + struct btrfs_inode_ref *iref; + struct btrfs_root_ref *rref; + struct extent_buffer *leaf; + unsigned long name_ptr; + struct btrfs_key key; + int name_len; + int ret; + + if (!dir || !inode) + return -EINVAL; + + if (!S_ISDIR(dir->i_mode)) + return -EINVAL; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + path->leave_spinning = 1; + + if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) { + key.objectid = BTRFS_I(inode)->root->root_key.objectid; + key.type = BTRFS_ROOT_BACKREF_KEY; + key.offset = (u64)-1; + root = root->fs_info->tree_root; + } else { + key.objectid = inode->i_ino; + key.offset = dir->i_ino; + key.type = BTRFS_INODE_REF_KEY; + } + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) { + btrfs_free_path(path); + return ret; + } else if (ret > 0) { + if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) { + path->slots[0]--; + } else { + btrfs_free_path(path); + return -ENOENT; + } + } + leaf = path->nodes[0]; + + if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) { + rref = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_root_ref); + name_ptr = (unsigned long)(rref + 1); + name_len = btrfs_root_ref_name_len(leaf, rref); + } else { + iref = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_inode_ref); + name_ptr = (unsigned long)(iref + 1); + name_len = btrfs_inode_ref_name_len(leaf, iref); + } + + read_extent_buffer(leaf, name, name_ptr, name_len); + btrfs_free_path(path); + + /* + * have to add the null termination to make sure that reconnect_path + * gets the right len for strlen + */ + name[name_len] = '\0'; + + return 0; +} + const struct export_operations btrfs_export_ops = { .encode_fh = btrfs_encode_fh, .fh_to_dentry = btrfs_fh_to_dentry, .fh_to_parent = btrfs_fh_to_parent, .get_parent = btrfs_get_parent, + .get_name = btrfs_get_name, }; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0c097f3aec41..227e5815d838 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -429,6 +429,7 @@ err: static int cache_block_group(struct btrfs_block_group_cache *cache, struct btrfs_trans_handle *trans, + struct btrfs_root *root, int load_cache_only) { struct btrfs_fs_info *fs_info = cache->fs_info; @@ -442,9 +443,12 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, /* * We can't do the read from on-disk cache during a commit since we need - * to have the normal tree locking. + * to have the normal tree locking. Also if we are currently trying to + * allocate blocks for the tree root we can't do the fast caching since + * we likely hold important locks. */ - if (!trans->transaction->in_commit) { + if (!trans->transaction->in_commit && + (root && root != root->fs_info->tree_root)) { spin_lock(&cache->lock); if (cache->cached != BTRFS_CACHE_NO) { spin_unlock(&cache->lock); @@ -2741,6 +2745,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group, struct btrfs_root *root = block_group->fs_info->tree_root; struct inode *inode = NULL; u64 alloc_hint = 0; + int dcs = BTRFS_DC_ERROR; int num_pages = 0; int retries = 0; int ret = 0; @@ -2795,6 +2800,8 @@ again: spin_lock(&block_group->lock); if (block_group->cached != BTRFS_CACHE_FINISHED) { + /* We're not cached, don't bother trying to write stuff out */ + dcs = BTRFS_DC_WRITTEN; spin_unlock(&block_group->lock); goto out_put; } @@ -2821,6 +2828,8 @@ again: ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages, num_pages, num_pages, &alloc_hint); + if (!ret) + dcs = BTRFS_DC_SETUP; btrfs_free_reserved_data_space(inode, num_pages); out_put: iput(inode); @@ -2828,10 +2837,7 @@ out_free: btrfs_release_path(root, path); out: spin_lock(&block_group->lock); - if (ret) - block_group->disk_cache_state = BTRFS_DC_ERROR; - else - block_group->disk_cache_state = BTRFS_DC_SETUP; + block_group->disk_cache_state = dcs; spin_unlock(&block_group->lock); return ret; @@ -3037,7 +3043,13 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) { - u64 num_devices = root->fs_info->fs_devices->rw_devices; + /* + * we add in the count of missing devices because we want + * to make sure that any RAID levels on a degraded FS + * continue to be honored. + */ + u64 num_devices = root->fs_info->fs_devices->rw_devices + + root->fs_info->fs_devices->missing_devices; if (num_devices == 1) flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0); @@ -3412,7 +3424,7 @@ again: * our reservation. */ if (unused <= space_info->total_bytes) { - unused -= space_info->total_bytes; + unused = space_info->total_bytes - unused; if (unused >= num_bytes) { if (!reserved) space_info->bytes_reserved += orig_bytes; @@ -4080,7 +4092,7 @@ static int update_block_group(struct btrfs_trans_handle *trans, * space back to the block group, otherwise we will leak space. */ if (!alloc && cache->cached == BTRFS_CACHE_NO) - cache_block_group(cache, trans, 1); + cache_block_group(cache, trans, NULL, 1); byte_in_group = bytenr - cache->key.objectid; WARN_ON(byte_in_group > cache->key.offset); @@ -4930,11 +4942,31 @@ search: btrfs_get_block_group(block_group); search_start = block_group->key.objectid; + /* + * this can happen if we end up cycling through all the + * raid types, but we want to make sure we only allocate + * for the proper type. + */ + if (!block_group_bits(block_group, data)) { + u64 extra = BTRFS_BLOCK_GROUP_DUP | + BTRFS_BLOCK_GROUP_RAID1 | + BTRFS_BLOCK_GROUP_RAID10; + + /* + * if they asked for extra copies and this block group + * doesn't provide them, bail. This does allow us to + * fill raid0 from raid1. + */ + if ((data & extra) && !(block_group->flags & extra)) + goto loop; + } + have_block_group: if (unlikely(block_group->cached == BTRFS_CACHE_NO)) { u64 free_percent; - ret = cache_block_group(block_group, trans, 1); + ret = cache_block_group(block_group, trans, + orig_root, 1); if (block_group->cached == BTRFS_CACHE_FINISHED) goto have_block_group; @@ -4958,7 +4990,8 @@ have_block_group: if (loop > LOOP_CACHING_NOWAIT || (loop > LOOP_FIND_IDEAL && atomic_read(&space_info->caching_threads) < 2)) { - ret = cache_block_group(block_group, trans, 0); + ret = cache_block_group(block_group, trans, + orig_root, 0); BUG_ON(ret); } found_uncached_bg = true; @@ -5515,7 +5548,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, u64 num_bytes = ins->offset; block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid); - cache_block_group(block_group, trans, 0); + cache_block_group(block_group, trans, NULL, 0); caching_ctl = get_caching_control(block_group); if (!caching_ctl) { @@ -6300,9 +6333,13 @@ int btrfs_drop_snapshot(struct btrfs_root *root, NULL, NULL); BUG_ON(ret < 0); if (ret > 0) { - ret = btrfs_del_orphan_item(trans, tree_root, - root->root_key.objectid); - BUG_ON(ret); + /* if we fail to delete the orphan item this time + * around, it'll get picked up the next time. + * + * The most common failure here is just -ENOENT. + */ + btrfs_del_orphan_item(trans, tree_root, + root->root_key.objectid); } } @@ -7878,7 +7915,14 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags) u64 stripped = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10; - num_devices = root->fs_info->fs_devices->rw_devices; + /* + * we add in the count of missing devices because we want + * to make sure that any RAID levels on a degraded FS + * continue to be honored. + */ + num_devices = root->fs_info->fs_devices->rw_devices + + root->fs_info->fs_devices->missing_devices; + if (num_devices == 1) { stripped |= BTRFS_BLOCK_GROUP_DUP; stripped = flags & ~stripped; @@ -8247,7 +8291,6 @@ int btrfs_read_block_groups(struct btrfs_root *root) break; if (ret != 0) goto error; - leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); cache = kzalloc(sizeof(*cache), GFP_NOFS); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index eac10e3260a9..3e86b9f36507 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1828,9 +1828,9 @@ static void end_bio_extent_preparewrite(struct bio *bio, int err) bio_put(bio); } -static struct bio * -extent_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, - gfp_t gfp_flags) +struct bio * +btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, + gfp_t gfp_flags) { struct bio *bio; @@ -1919,7 +1919,7 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, else nr = bio_get_nr_vecs(bdev); - bio = extent_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH); + bio = btrfs_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH); bio_add_page(bio, page, page_size, offset); bio->bi_end_io = end_io_func; @@ -2901,21 +2901,53 @@ out: int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, __u64 start, __u64 len, get_extent_t *get_extent) { - int ret; + int ret = 0; u64 off = start; u64 max = start + len; u32 flags = 0; + u32 found_type; + u64 last; u64 disko = 0; + struct btrfs_key found_key; struct extent_map *em = NULL; struct extent_state *cached_state = NULL; + struct btrfs_path *path; + struct btrfs_file_extent_item *item; int end = 0; u64 em_start = 0, em_len = 0; unsigned long emflags; - ret = 0; + int hole = 0; if (len == 0) return -EINVAL; + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + path->leave_spinning = 1; + + ret = btrfs_lookup_file_extent(NULL, BTRFS_I(inode)->root, + path, inode->i_ino, -1, 0); + if (ret < 0) { + btrfs_free_path(path); + return ret; + } + WARN_ON(!ret); + path->slots[0]--; + item = btrfs_item_ptr(path->nodes[0], path->slots[0], + struct btrfs_file_extent_item); + btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); + found_type = btrfs_key_type(&found_key); + + /* No extents, just return */ + if (found_key.objectid != inode->i_ino || + found_type != BTRFS_EXTENT_DATA_KEY) { + btrfs_free_path(path); + return 0; + } + last = found_key.offset; + btrfs_free_path(path); + lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0, &cached_state, GFP_NOFS); em = get_extent(inode, NULL, 0, off, max - off, 0); @@ -2925,11 +2957,18 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ret = PTR_ERR(em); goto out; } + while (!end) { + hole = 0; off = em->start + em->len; if (off >= max) end = 1; + if (em->block_start == EXTENT_MAP_HOLE) { + hole = 1; + goto next; + } + em_start = em->start; em_len = em->len; @@ -2939,8 +2978,6 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, if (em->block_start == EXTENT_MAP_LAST_BYTE) { end = 1; flags |= FIEMAP_EXTENT_LAST; - } else if (em->block_start == EXTENT_MAP_HOLE) { - flags |= FIEMAP_EXTENT_UNWRITTEN; } else if (em->block_start == EXTENT_MAP_INLINE) { flags |= (FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED); @@ -2953,10 +2990,10 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) flags |= FIEMAP_EXTENT_ENCODED; +next: emflags = em->flags; free_extent_map(em); em = NULL; - if (!end) { em = get_extent(inode, NULL, 0, off, max - off, 0); if (!em) @@ -2967,15 +3004,23 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, } emflags = em->flags; } + if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) { flags |= FIEMAP_EXTENT_LAST; end = 1; } - ret = fiemap_fill_next_extent(fieinfo, em_start, disko, - em_len, flags); - if (ret) - goto out_free; + if (em_start == last) { + flags |= FIEMAP_EXTENT_LAST; + end = 1; + } + + if (!hole) { + ret = fiemap_fill_next_extent(fieinfo, em_start, disko, + em_len, flags); + if (ret) + goto out_free; + } } out_free: free_extent_map(em); @@ -3836,8 +3881,10 @@ int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page) spin_lock(&tree->buffer_lock); eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT); - if (!eb) - goto out; + if (!eb) { + spin_unlock(&tree->buffer_lock); + return ret; + } if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { ret = 0; diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 1c6d4f342ef7..4183c8178f01 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -310,4 +310,7 @@ int extent_clear_unlock_delalloc(struct inode *inode, struct extent_io_tree *tree, u64 start, u64 end, struct page *locked_page, unsigned long op); +struct bio * +btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, + gfp_t gfp_flags); #endif diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index e354c33df082..66836d85763b 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -48,30 +48,34 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, struct page **prepared_pages, struct iov_iter *i) { - size_t copied; + size_t copied = 0; int pg = 0; int offset = pos & (PAGE_CACHE_SIZE - 1); + int total_copied = 0; while (write_bytes > 0) { size_t count = min_t(size_t, PAGE_CACHE_SIZE - offset, write_bytes); struct page *page = prepared_pages[pg]; -again: - if (unlikely(iov_iter_fault_in_readable(i, count))) - return -EFAULT; - - /* Copy data from userspace to the current page */ - copied = iov_iter_copy_from_user(page, i, offset, count); + /* + * Copy data from userspace to the current page + * + * Disable pagefault to avoid recursive lock since + * the pages are already locked + */ + pagefault_disable(); + copied = iov_iter_copy_from_user_atomic(page, i, offset, count); + pagefault_enable(); /* Flush processor's dcache for this page */ flush_dcache_page(page); iov_iter_advance(i, copied); write_bytes -= copied; + total_copied += copied; + /* Return to btrfs_file_aio_write to fault page */ if (unlikely(copied == 0)) { - count = min_t(size_t, PAGE_CACHE_SIZE - offset, - iov_iter_single_seg_count(i)); - goto again; + break; } if (unlikely(copied < PAGE_CACHE_SIZE - offset)) { @@ -81,7 +85,7 @@ again: offset = 0; } } - return 0; + return total_copied; } /* @@ -854,6 +858,8 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, unsigned long last_index; int will_write; int buffered = 0; + int copied = 0; + int dirty_pages = 0; will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) || (file->f_flags & O_DIRECT)); @@ -970,7 +976,17 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, WARN_ON(num_pages > nrptrs); memset(pages, 0, sizeof(struct page *) * nrptrs); - ret = btrfs_delalloc_reserve_space(inode, write_bytes); + /* + * Fault pages before locking them in prepare_pages + * to avoid recursive lock + */ + if (unlikely(iov_iter_fault_in_readable(&i, write_bytes))) { + ret = -EFAULT; + goto out; + } + + ret = btrfs_delalloc_reserve_space(inode, + num_pages << PAGE_CACHE_SHIFT); if (ret) goto out; @@ -978,37 +994,49 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, pos, first_index, last_index, write_bytes); if (ret) { - btrfs_delalloc_release_space(inode, write_bytes); + btrfs_delalloc_release_space(inode, + num_pages << PAGE_CACHE_SHIFT); goto out; } - ret = btrfs_copy_from_user(pos, num_pages, + copied = btrfs_copy_from_user(pos, num_pages, write_bytes, pages, &i); - if (ret == 0) { + dirty_pages = (copied + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT; + + if (num_pages > dirty_pages) { + if (copied > 0) + atomic_inc( + &BTRFS_I(inode)->outstanding_extents); + btrfs_delalloc_release_space(inode, + (num_pages - dirty_pages) << + PAGE_CACHE_SHIFT); + } + + if (copied > 0) { dirty_and_release_pages(NULL, root, file, pages, - num_pages, pos, write_bytes); + dirty_pages, pos, copied); } btrfs_drop_pages(pages, num_pages); - if (ret) { - btrfs_delalloc_release_space(inode, write_bytes); - goto out; - } - if (will_write) { - filemap_fdatawrite_range(inode->i_mapping, pos, - pos + write_bytes - 1); - } else { - balance_dirty_pages_ratelimited_nr(inode->i_mapping, - num_pages); - if (num_pages < - (root->leafsize >> PAGE_CACHE_SHIFT) + 1) - btrfs_btree_balance_dirty(root, 1); - btrfs_throttle(root); + if (copied > 0) { + if (will_write) { + filemap_fdatawrite_range(inode->i_mapping, pos, + pos + copied - 1); + } else { + balance_dirty_pages_ratelimited_nr( + inode->i_mapping, + dirty_pages); + if (dirty_pages < + (root->leafsize >> PAGE_CACHE_SHIFT) + 1) + btrfs_btree_balance_dirty(root, 1); + btrfs_throttle(root); + } } - pos += write_bytes; - num_written += write_bytes; + pos += copied; + num_written += copied; cond_resched(); } @@ -1047,8 +1075,14 @@ out: if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) { trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + num_written = PTR_ERR(trans); + goto done; + } + mutex_lock(&inode->i_mutex); ret = btrfs_log_dentry_safe(trans, root, file->f_dentry); + mutex_unlock(&inode->i_mutex); if (ret == 0) { ret = btrfs_sync_log(trans, root); if (ret == 0) @@ -1067,6 +1101,7 @@ out: (start_pos + num_written - 1) >> PAGE_CACHE_SHIFT); } } +done: current->backing_dev_info = NULL; return num_written ? num_written : err; } diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 22ee0dc2e6b8..60d684266959 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -290,7 +290,7 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, (unsigned long long)BTRFS_I(inode)->generation, (unsigned long long)generation, (unsigned long long)block_group->key.objectid); - goto out; + goto free_cache; } if (!num_entries) @@ -524,6 +524,12 @@ int btrfs_write_out_cache(struct btrfs_root *root, return 0; } + node = rb_first(&block_group->free_space_offset); + if (!node) { + iput(inode); + return 0; + } + last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT; filemap_write_and_wait(inode->i_mapping); btrfs_wait_ordered_range(inode, inode->i_size & @@ -543,10 +549,6 @@ int btrfs_write_out_cache(struct btrfs_root *root, */ first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64); - node = rb_first(&block_group->free_space_offset); - if (!node) - goto out_free; - /* * Lock all pages first so we can lock the extent safely. * diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 558cac2dfa54..72f31ecb5c90 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -495,7 +495,7 @@ again: add_async_extent(async_cow, start, num_bytes, total_compressed, pages, nr_pages_ret); - if (start + num_bytes < end && start + num_bytes < actual_end) { + if (start + num_bytes < end) { start += num_bytes; pages = NULL; cond_resched(); @@ -4501,6 +4501,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, BTRFS_I(inode)->index_cnt = 2; BTRFS_I(inode)->root = root; BTRFS_I(inode)->generation = trans->transid; + inode->i_generation = BTRFS_I(inode)->generation; btrfs_set_inode_space_info(root, inode); if (mode & S_IFDIR) @@ -4622,12 +4623,12 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, } static int btrfs_add_nondir(struct btrfs_trans_handle *trans, - struct dentry *dentry, struct inode *inode, - int backref, u64 index) + struct inode *dir, struct dentry *dentry, + struct inode *inode, int backref, u64 index) { - int err = btrfs_add_link(trans, dentry->d_parent->d_inode, - inode, dentry->d_name.name, - dentry->d_name.len, backref, index); + int err = btrfs_add_link(trans, dir, inode, + dentry->d_name.name, dentry->d_name.len, + backref, index); if (!err) { d_instantiate(dentry, inode); return 0; @@ -4668,8 +4669,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, btrfs_set_trans_block_group(trans, dir); inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, - dentry->d_name.len, - dentry->d_parent->d_inode->i_ino, objectid, + dentry->d_name.len, dir->i_ino, objectid, BTRFS_I(dir)->block_group, mode, &index); err = PTR_ERR(inode); if (IS_ERR(inode)) @@ -4682,7 +4682,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, } btrfs_set_trans_block_group(trans, inode); - err = btrfs_add_nondir(trans, dentry, inode, 0, index); + err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index); if (err) drop_inode = 1; else { @@ -4730,10 +4730,8 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, btrfs_set_trans_block_group(trans, dir); inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, - dentry->d_name.len, - dentry->d_parent->d_inode->i_ino, - objectid, BTRFS_I(dir)->block_group, mode, - &index); + dentry->d_name.len, dir->i_ino, objectid, + BTRFS_I(dir)->block_group, mode, &index); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_unlock; @@ -4745,7 +4743,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, } btrfs_set_trans_block_group(trans, inode); - err = btrfs_add_nondir(trans, dentry, inode, 0, index); + err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index); if (err) drop_inode = 1; else { @@ -4787,6 +4785,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, return -EPERM; btrfs_inc_nlink(inode); + inode->i_ctime = CURRENT_TIME; err = btrfs_set_inode_index(dir, &index); if (err) @@ -4805,15 +4804,17 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, btrfs_set_trans_block_group(trans, dir); ihold(inode); - err = btrfs_add_nondir(trans, dentry, inode, 1, index); + err = btrfs_add_nondir(trans, dir, dentry, inode, 1, index); if (err) { drop_inode = 1; } else { + struct dentry *parent = dget_parent(dentry); btrfs_update_inode_block_group(trans, dir); err = btrfs_update_inode(trans, root, inode); BUG_ON(err); - btrfs_log_new_name(trans, inode, NULL, dentry->d_parent); + btrfs_log_new_name(trans, inode, NULL, parent); + dput(parent); } nr = trans->blocks_used; @@ -4853,8 +4854,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) btrfs_set_trans_block_group(trans, dir); inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, - dentry->d_name.len, - dentry->d_parent->d_inode->i_ino, objectid, + dentry->d_name.len, dir->i_ino, objectid, BTRFS_I(dir)->block_group, S_IFDIR | mode, &index); if (IS_ERR(inode)) { @@ -4877,9 +4877,8 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (err) goto out_fail; - err = btrfs_add_link(trans, dentry->d_parent->d_inode, - inode, dentry->d_name.name, - dentry->d_name.len, 0, index); + err = btrfs_add_link(trans, dir, inode, dentry->d_name.name, + dentry->d_name.len, 0, index); if (err) goto out_fail; @@ -5535,13 +5534,21 @@ struct btrfs_dio_private { u64 bytes; u32 *csums; void *private; + + /* number of bios pending for this dio */ + atomic_t pending_bios; + + /* IO errors */ + int errors; + + struct bio *orig_bio; }; static void btrfs_endio_direct_read(struct bio *bio, int err) { + struct btrfs_dio_private *dip = bio->bi_private; struct bio_vec *bvec_end = bio->bi_io_vec + bio->bi_vcnt - 1; struct bio_vec *bvec = bio->bi_io_vec; - struct btrfs_dio_private *dip = bio->bi_private; struct inode *inode = dip->inode; struct btrfs_root *root = BTRFS_I(inode)->root; u64 start; @@ -5595,15 +5602,18 @@ static void btrfs_endio_direct_write(struct bio *bio, int err) struct btrfs_trans_handle *trans; struct btrfs_ordered_extent *ordered = NULL; struct extent_state *cached_state = NULL; + u64 ordered_offset = dip->logical_offset; + u64 ordered_bytes = dip->bytes; int ret; if (err) goto out_done; - - ret = btrfs_dec_test_ordered_pending(inode, &ordered, - dip->logical_offset, dip->bytes); +again: + ret = btrfs_dec_test_first_ordered_pending(inode, &ordered, + &ordered_offset, + ordered_bytes); if (!ret) - goto out_done; + goto out_test; BUG_ON(!ordered); @@ -5663,8 +5673,20 @@ out_unlock: out: btrfs_delalloc_release_metadata(inode, ordered->len); btrfs_end_transaction(trans, root); + ordered_offset = ordered->file_offset + ordered->len; btrfs_put_ordered_extent(ordered); btrfs_put_ordered_extent(ordered); + +out_test: + /* + * our bio might span multiple ordered extents. If we haven't + * completed the accounting for the whole dio, go back and try again + */ + if (ordered_offset < dip->logical_offset + dip->bytes) { + ordered_bytes = dip->logical_offset + dip->bytes - + ordered_offset; + goto again; + } out_done: bio->bi_private = dip->private; @@ -5684,6 +5706,176 @@ static int __btrfs_submit_bio_start_direct_io(struct inode *inode, int rw, return 0; } +static void btrfs_end_dio_bio(struct bio *bio, int err) +{ + struct btrfs_dio_private *dip = bio->bi_private; + + if (err) { + printk(KERN_ERR "btrfs direct IO failed ino %lu rw %lu " + "sector %#Lx len %u err no %d\n", + dip->inode->i_ino, bio->bi_rw, + (unsigned long long)bio->bi_sector, bio->bi_size, err); + dip->errors = 1; + + /* + * before atomic variable goto zero, we must make sure + * dip->errors is perceived to be set. + */ + smp_mb__before_atomic_dec(); + } + + /* if there are more bios still pending for this dio, just exit */ + if (!atomic_dec_and_test(&dip->pending_bios)) + goto out; + + if (dip->errors) + bio_io_error(dip->orig_bio); + else { + set_bit(BIO_UPTODATE, &dip->orig_bio->bi_flags); + bio_endio(dip->orig_bio, 0); + } +out: + bio_put(bio); +} + +static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev, + u64 first_sector, gfp_t gfp_flags) +{ + int nr_vecs = bio_get_nr_vecs(bdev); + return btrfs_bio_alloc(bdev, first_sector, nr_vecs, gfp_flags); +} + +static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, + int rw, u64 file_offset, int skip_sum, + u32 *csums) +{ + int write = rw & REQ_WRITE; + struct btrfs_root *root = BTRFS_I(inode)->root; + int ret; + + bio_get(bio); + ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0); + if (ret) + goto err; + + if (write && !skip_sum) { + ret = btrfs_wq_submit_bio(root->fs_info, + inode, rw, bio, 0, 0, + file_offset, + __btrfs_submit_bio_start_direct_io, + __btrfs_submit_bio_done); + goto err; + } else if (!skip_sum) + btrfs_lookup_bio_sums_dio(root, inode, bio, + file_offset, csums); + + ret = btrfs_map_bio(root, rw, bio, 0, 1); +err: + bio_put(bio); + return ret; +} + +static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, + int skip_sum) +{ + struct inode *inode = dip->inode; + struct btrfs_root *root = BTRFS_I(inode)->root; + struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; + struct bio *bio; + struct bio *orig_bio = dip->orig_bio; + struct bio_vec *bvec = orig_bio->bi_io_vec; + u64 start_sector = orig_bio->bi_sector; + u64 file_offset = dip->logical_offset; + u64 submit_len = 0; + u64 map_length; + int nr_pages = 0; + u32 *csums = dip->csums; + int ret = 0; + + bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS); + if (!bio) + return -ENOMEM; + bio->bi_private = dip; + bio->bi_end_io = btrfs_end_dio_bio; + atomic_inc(&dip->pending_bios); + + map_length = orig_bio->bi_size; + ret = btrfs_map_block(map_tree, READ, start_sector << 9, + &map_length, NULL, 0); + if (ret) { + bio_put(bio); + return -EIO; + } + + while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) { + if (unlikely(map_length < submit_len + bvec->bv_len || + bio_add_page(bio, bvec->bv_page, bvec->bv_len, + bvec->bv_offset) < bvec->bv_len)) { + /* + * inc the count before we submit the bio so + * we know the end IO handler won't happen before + * we inc the count. Otherwise, the dip might get freed + * before we're done setting it up + */ + atomic_inc(&dip->pending_bios); + ret = __btrfs_submit_dio_bio(bio, inode, rw, + file_offset, skip_sum, + csums); + if (ret) { + bio_put(bio); + atomic_dec(&dip->pending_bios); + goto out_err; + } + + if (!skip_sum) + csums = csums + nr_pages; + start_sector += submit_len >> 9; + file_offset += submit_len; + + submit_len = 0; + nr_pages = 0; + + bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, + start_sector, GFP_NOFS); + if (!bio) + goto out_err; + bio->bi_private = dip; + bio->bi_end_io = btrfs_end_dio_bio; + + map_length = orig_bio->bi_size; + ret = btrfs_map_block(map_tree, READ, start_sector << 9, + &map_length, NULL, 0); + if (ret) { + bio_put(bio); + goto out_err; + } + } else { + submit_len += bvec->bv_len; + nr_pages ++; + bvec++; + } + } + + ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, + csums); + if (!ret) + return 0; + + bio_put(bio); +out_err: + dip->errors = 1; + /* + * before atomic variable goto zero, we must + * make sure dip->errors is perceived to be set. + */ + smp_mb__before_atomic_dec(); + if (atomic_dec_and_test(&dip->pending_bios)) + bio_io_error(dip->orig_bio); + + /* bio_end_io() will handle error, so we needn't return it */ + return 0; +} + static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode, loff_t file_offset) { @@ -5723,36 +5915,18 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode, dip->disk_bytenr = (u64)bio->bi_sector << 9; bio->bi_private = dip; + dip->errors = 0; + dip->orig_bio = bio; + atomic_set(&dip->pending_bios, 0); if (write) bio->bi_end_io = btrfs_endio_direct_write; else bio->bi_end_io = btrfs_endio_direct_read; - ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0); - if (ret) - goto out_err; - - if (write && !skip_sum) { - ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, - inode, rw, bio, 0, 0, - dip->logical_offset, - __btrfs_submit_bio_start_direct_io, - __btrfs_submit_bio_done); - if (ret) - goto out_err; + ret = btrfs_submit_direct_hook(rw, dip, skip_sum); + if (!ret) return; - } else if (!skip_sum) - btrfs_lookup_bio_sums_dio(root, inode, bio, - dip->logical_offset, dip->csums); - - ret = btrfs_map_bio(root, rw, bio, 0, 1); - if (ret) - goto out_err; - return; -out_err: - kfree(dip->csums); - kfree(dip); free_ordered: /* * If this is a write, we need to clean up the reserved space and kill @@ -5760,8 +5934,7 @@ free_ordered: */ if (write) { struct btrfs_ordered_extent *ordered; - ordered = btrfs_lookup_ordered_extent(inode, - dip->logical_offset); + ordered = btrfs_lookup_ordered_extent(inode, file_offset); if (!test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags) && !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) btrfs_free_reserved_extent(root, ordered->start, @@ -6607,8 +6780,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, BUG_ON(ret); if (old_inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) { - btrfs_log_new_name(trans, old_inode, old_dir, - new_dentry->d_parent); + struct dentry *parent = dget_parent(new_dentry); + btrfs_log_new_name(trans, old_inode, old_dir, parent); + dput(parent); btrfs_end_log_trans(root); } out_fail: @@ -6758,8 +6932,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, btrfs_set_trans_block_group(trans, dir); inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, - dentry->d_name.len, - dentry->d_parent->d_inode->i_ino, objectid, + dentry->d_name.len, dir->i_ino, objectid, BTRFS_I(dir)->block_group, S_IFLNK|S_IRWXUGO, &index); err = PTR_ERR(inode); @@ -6773,7 +6946,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, } btrfs_set_trans_block_group(trans, inode); - err = btrfs_add_nondir(trans, dentry, inode, 0, index); + err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index); if (err) drop_inode = 1; else { @@ -6844,6 +7017,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_key ins; u64 cur_offset = start; + u64 i_size; int ret = 0; bool own_trans = true; @@ -6885,11 +7059,11 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, (actual_len > inode->i_size) && (cur_offset > inode->i_size)) { if (cur_offset > actual_len) - i_size_write(inode, actual_len); + i_size = actual_len; else - i_size_write(inode, cur_offset); - i_size_write(inode, cur_offset); - btrfs_ordered_update_i_size(inode, cur_offset, NULL); + i_size = cur_offset; + i_size_write(inode, i_size); + btrfs_ordered_update_i_size(inode, i_size, NULL); } ret = btrfs_update_inode(trans, root, inode); @@ -6943,6 +7117,10 @@ static long btrfs_fallocate(struct inode *inode, int mode, btrfs_wait_ordered_range(inode, alloc_start, alloc_end - alloc_start); mutex_lock(&inode->i_mutex); + ret = inode_newsize_ok(inode, alloc_end); + if (ret) + goto out; + if (alloc_start > inode->i_size) { ret = btrfs_cont_expand(inode, alloc_start); if (ret) @@ -7139,6 +7317,7 @@ static const struct inode_operations btrfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, + .getattr = btrfs_getattr, .permission = btrfs_permission, .setxattr = btrfs_setxattr, .getxattr = btrfs_getxattr, diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 463d91b4dd3a..f87552a1d7ea 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -233,7 +233,8 @@ static noinline int create_subvol(struct btrfs_root *root, struct btrfs_inode_item *inode_item; struct extent_buffer *leaf; struct btrfs_root *new_root; - struct inode *dir = dentry->d_parent->d_inode; + struct dentry *parent = dget_parent(dentry); + struct inode *dir; int ret; int err; u64 objectid; @@ -242,8 +243,13 @@ static noinline int create_subvol(struct btrfs_root *root, ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root, 0, &objectid); - if (ret) + if (ret) { + dput(parent); return ret; + } + + dir = parent->d_inode; + /* * 1 - inode item * 2 - refs @@ -251,8 +257,10 @@ static noinline int create_subvol(struct btrfs_root *root, * 2 - dir items */ trans = btrfs_start_transaction(root, 6); - if (IS_ERR(trans)) + if (IS_ERR(trans)) { + dput(parent); return PTR_ERR(trans); + } leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0, objectid, NULL, 0, 0, 0); @@ -339,6 +347,7 @@ static noinline int create_subvol(struct btrfs_root *root, d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); fail: + dput(parent); if (async_transid) { *async_transid = trans->transid; err = btrfs_commit_transaction_async(trans, root, 1); @@ -354,6 +363,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, char *name, int namelen, u64 *async_transid) { struct inode *inode; + struct dentry *parent; struct btrfs_pending_snapshot *pending_snapshot; struct btrfs_trans_handle *trans; int ret; @@ -396,7 +406,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, btrfs_orphan_cleanup(pending_snapshot->snap); - inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); + parent = dget_parent(dentry); + inode = btrfs_lookup_dentry(parent->d_inode, dentry); + dput(parent); if (IS_ERR(inode)) { ret = PTR_ERR(inode); goto fail; @@ -935,23 +947,42 @@ out: static noinline int btrfs_ioctl_snap_create(struct file *file, void __user *arg, int subvol, - int async) + int v2) { struct btrfs_ioctl_vol_args *vol_args = NULL; - struct btrfs_ioctl_async_vol_args *async_vol_args = NULL; + struct btrfs_ioctl_vol_args_v2 *vol_args_v2 = NULL; char *name; u64 fd; - u64 transid = 0; int ret; - if (async) { - async_vol_args = memdup_user(arg, sizeof(*async_vol_args)); - if (IS_ERR(async_vol_args)) - return PTR_ERR(async_vol_args); + if (v2) { + u64 transid = 0; + u64 *ptr = NULL; + + vol_args_v2 = memdup_user(arg, sizeof(*vol_args_v2)); + if (IS_ERR(vol_args_v2)) + return PTR_ERR(vol_args_v2); + + if (vol_args_v2->flags & ~BTRFS_SUBVOL_CREATE_ASYNC) { + ret = -EINVAL; + goto out; + } + + name = vol_args_v2->name; + fd = vol_args_v2->fd; + vol_args_v2->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; + + if (vol_args_v2->flags & BTRFS_SUBVOL_CREATE_ASYNC) + ptr = &transid; + + ret = btrfs_ioctl_snap_create_transid(file, name, fd, + subvol, ptr); - name = async_vol_args->name; - fd = async_vol_args->fd; - async_vol_args->name[BTRFS_SNAPSHOT_NAME_MAX] = '\0'; + if (ret == 0 && ptr && + copy_to_user(arg + + offsetof(struct btrfs_ioctl_vol_args_v2, + transid), ptr, sizeof(*ptr))) + ret = -EFAULT; } else { vol_args = memdup_user(arg, sizeof(*vol_args)); if (IS_ERR(vol_args)) @@ -959,20 +990,13 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, name = vol_args->name; fd = vol_args->fd; vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; - } - - ret = btrfs_ioctl_snap_create_transid(file, name, fd, - subvol, &transid); - if (!ret && async) { - if (copy_to_user(arg + - offsetof(struct btrfs_ioctl_async_vol_args, - transid), &transid, sizeof(transid))) - return -EFAULT; + ret = btrfs_ioctl_snap_create_transid(file, name, fd, + subvol, NULL); } - +out: kfree(vol_args); - kfree(async_vol_args); + kfree(vol_args_v2); return ret; } @@ -1669,12 +1693,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, olen = len = src->i_size - off; /* if we extend to eof, continue to block boundary */ if (off + len == src->i_size) - len = ((src->i_size + bs-1) & ~(bs-1)) - - off; + len = ALIGN(src->i_size, bs) - off; /* verify the end result is block aligned */ - if ((off & (bs-1)) || - ((off + len) & (bs-1))) + if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) || + !IS_ALIGNED(destoff, bs)) goto out_unlock; /* do any pending delalloc/csum calc on src, one way or @@ -1874,8 +1897,8 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, * but shouldn't round up the file size */ endoff = new_key.offset + datal; - if (endoff > off+olen) - endoff = off+olen; + if (endoff > destoff+olen) + endoff = destoff+olen; if (endoff > inode->i_size) btrfs_i_size_write(inode, endoff); @@ -2235,7 +2258,7 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_getversion(file, argp); case BTRFS_IOC_SNAP_CREATE: return btrfs_ioctl_snap_create(file, argp, 0, 0); - case BTRFS_IOC_SNAP_CREATE_ASYNC: + case BTRFS_IOC_SNAP_CREATE_V2: return btrfs_ioctl_snap_create(file, argp, 0, 1); case BTRFS_IOC_SUBVOL_CREATE: return btrfs_ioctl_snap_create(file, argp, 1, 0); diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 17c99ebdf960..c344d12c646b 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h @@ -30,11 +30,15 @@ struct btrfs_ioctl_vol_args { char name[BTRFS_PATH_NAME_MAX + 1]; }; -#define BTRFS_SNAPSHOT_NAME_MAX 4079 -struct btrfs_ioctl_async_vol_args { +#define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) + +#define BTRFS_SUBVOL_NAME_MAX 4039 +struct btrfs_ioctl_vol_args_v2 { __s64 fd; __u64 transid; - char name[BTRFS_SNAPSHOT_NAME_MAX + 1]; + __u64 flags; + __u64 unused[4]; + char name[BTRFS_SUBVOL_NAME_MAX + 1]; }; #define BTRFS_INO_LOOKUP_PATH_MAX 4080 @@ -187,6 +191,6 @@ struct btrfs_ioctl_space_args { struct btrfs_ioctl_space_args) #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64) #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) -#define BTRFS_IOC_SNAP_CREATE_ASYNC _IOW(BTRFS_IOCTL_MAGIC, 23, \ - struct btrfs_ioctl_async_vol_args) +#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ + struct btrfs_ioctl_vol_args_v2) #endif diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index f4621f6deca1..ae7737e352c9 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -250,6 +250,73 @@ int btrfs_add_ordered_sum(struct inode *inode, /* * this is used to account for finished IO across a given range + * of the file. The IO may span ordered extents. If + * a given ordered_extent is completely done, 1 is returned, otherwise + * 0. + * + * test_and_set_bit on a flag in the struct btrfs_ordered_extent is used + * to make sure this function only returns 1 once for a given ordered extent. + * + * file_offset is updated to one byte past the range that is recorded as + * complete. This allows you to walk forward in the file. + */ +int btrfs_dec_test_first_ordered_pending(struct inode *inode, + struct btrfs_ordered_extent **cached, + u64 *file_offset, u64 io_size) +{ + struct btrfs_ordered_inode_tree *tree; + struct rb_node *node; + struct btrfs_ordered_extent *entry = NULL; + int ret; + u64 dec_end; + u64 dec_start; + u64 to_dec; + + tree = &BTRFS_I(inode)->ordered_tree; + spin_lock(&tree->lock); + node = tree_search(tree, *file_offset); + if (!node) { + ret = 1; + goto out; + } + + entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); + if (!offset_in_entry(entry, *file_offset)) { + ret = 1; + goto out; + } + + dec_start = max(*file_offset, entry->file_offset); + dec_end = min(*file_offset + io_size, entry->file_offset + + entry->len); + *file_offset = dec_end; + if (dec_start > dec_end) { + printk(KERN_CRIT "bad ordering dec_start %llu end %llu\n", + (unsigned long long)dec_start, + (unsigned long long)dec_end); + } + to_dec = dec_end - dec_start; + if (to_dec > entry->bytes_left) { + printk(KERN_CRIT "bad ordered accounting left %llu size %llu\n", + (unsigned long long)entry->bytes_left, + (unsigned long long)to_dec); + } + entry->bytes_left -= to_dec; + if (entry->bytes_left == 0) + ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags); + else + ret = 1; +out: + if (!ret && cached && entry) { + *cached = entry; + atomic_inc(&entry->refs); + } + spin_unlock(&tree->lock); + return ret == 0; +} + +/* + * this is used to account for finished IO across a given range * of the file. The IO should not span ordered extents. If * a given ordered_extent is completely done, 1 is returned, otherwise * 0. diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 8ac365492a3f..61dca83119dd 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -141,6 +141,9 @@ int btrfs_remove_ordered_extent(struct inode *inode, int btrfs_dec_test_ordered_pending(struct inode *inode, struct btrfs_ordered_extent **cached, u64 file_offset, u64 io_size); +int btrfs_dec_test_first_ordered_pending(struct inode *inode, + struct btrfs_ordered_extent **cached, + u64 *file_offset, u64 io_size); int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, u64 start, u64 len, u64 disk_len, int type); int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset, diff --git a/fs/btrfs/orphan.c b/fs/btrfs/orphan.c index 79cba5fbc28e..f8be250963a0 100644 --- a/fs/btrfs/orphan.c +++ b/fs/btrfs/orphan.c @@ -56,8 +56,12 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, return -ENOMEM; ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret) + if (ret < 0) goto out; + if (ret) { + ret = -ENOENT; + goto out; + } ret = btrfs_del_item(trans, root, path); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 8299a25ffc8f..883c6fa1367e 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -244,6 +244,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) case Opt_space_cache: printk(KERN_INFO "btrfs: enabling disk space caching\n"); btrfs_set_opt(info->mount_opt, SPACE_CACHE); + break; case Opt_clear_cache: printk(KERN_INFO "btrfs: force clearing of disk cache\n"); btrfs_set_opt(info->mount_opt, CLEAR_CACHE); @@ -562,12 +563,26 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs) static int btrfs_test_super(struct super_block *s, void *data) { - struct btrfs_fs_devices *test_fs_devices = data; + struct btrfs_root *test_root = data; struct btrfs_root *root = btrfs_sb(s); - return root->fs_info->fs_devices == test_fs_devices; + /* + * If this super block is going away, return false as it + * can't match as an existing super block. + */ + if (!atomic_read(&s->s_active)) + return 0; + return root->fs_info->fs_devices == test_root->fs_info->fs_devices; +} + +static int btrfs_set_super(struct super_block *s, void *data) +{ + s->s_fs_info = data; + + return set_anon_super(s, data); } + /* * Find a superblock for the given device / mount point. * @@ -581,6 +596,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, struct super_block *s; struct dentry *root; struct btrfs_fs_devices *fs_devices = NULL; + struct btrfs_root *tree_root = NULL; + struct btrfs_fs_info *fs_info = NULL; fmode_t mode = FMODE_READ; char *subvol_name = NULL; u64 subvol_objectid = 0; @@ -608,8 +625,24 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, goto error_close_devices; } + /* + * Setup a dummy root and fs_info for test/set super. This is because + * we don't actually fill this stuff out until open_ctree, but we need + * it for searching for existing supers, so this lets us do that and + * then open_ctree will properly initialize everything later. + */ + fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS); + tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS); + if (!fs_info || !tree_root) { + error = -ENOMEM; + goto error_close_devices; + } + fs_info->tree_root = tree_root; + fs_info->fs_devices = fs_devices; + tree_root->fs_info = fs_info; + bdev = fs_devices->latest_bdev; - s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices); + s = sget(fs_type, btrfs_test_super, btrfs_set_super, tree_root); if (IS_ERR(s)) goto error_s; @@ -652,9 +685,9 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, mutex_unlock(&root->d_inode->i_mutex); if (IS_ERR(new_root)) { + dput(root); deactivate_locked_super(s); error = PTR_ERR(new_root); - dput(root); goto error_free_subvol_name; } if (!new_root->d_inode) { @@ -675,6 +708,8 @@ error_s: error = PTR_ERR(s); error_close_devices: btrfs_close_devices(fs_devices); + kfree(fs_info); + kfree(tree_root); error_free_subvol_name: kfree(subvol_name); return ERR_PTR(error); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 1fffbc017bdf..f50e931fc217 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -902,6 +902,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root *root = pending->root; struct btrfs_root *parent_root; struct inode *parent_inode; + struct dentry *parent; struct dentry *dentry; struct extent_buffer *tmp; struct extent_buffer *old; @@ -941,7 +942,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, trans->block_rsv = &pending->block_rsv; dentry = pending->dentry; - parent_inode = dentry->d_parent->d_inode; + parent = dget_parent(dentry); + parent_inode = parent->d_inode; parent_root = BTRFS_I(parent_inode)->root; record_root_in_trans(trans, parent_root); @@ -989,6 +991,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, parent_inode->i_ino, index, dentry->d_name.name, dentry->d_name.len); BUG_ON(ret); + dput(parent); key.offset = (u64)-1; pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key); diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index a29f19384a27..054744ac5719 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2869,6 +2869,7 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, { int ret = 0; struct btrfs_root *root; + struct dentry *old_parent = NULL; /* * for regular files, if its inode is already on disk, we don't @@ -2910,10 +2911,13 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, if (IS_ROOT(parent)) break; - parent = parent->d_parent; + parent = dget_parent(parent); + dput(old_parent); + old_parent = parent; inode = parent->d_inode; } + dput(old_parent); out: return ret; } @@ -2945,6 +2949,7 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, { int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL; struct super_block *sb; + struct dentry *old_parent = NULL; int ret = 0; u64 last_committed = root->fs_info->last_trans_committed; @@ -3016,10 +3021,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, if (IS_ROOT(parent)) break; - parent = parent->d_parent; + parent = dget_parent(parent); + dput(old_parent); + old_parent = parent; } ret = 0; end_trans: + dput(old_parent); if (ret < 0) { BUG_ON(ret != -ENOSPC); root->fs_info->last_trans_log_full_commit = trans->transid; @@ -3039,8 +3047,13 @@ end_no_trans: int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct dentry *dentry) { - return btrfs_log_inode_parent(trans, root, dentry->d_inode, - dentry->d_parent, 0); + struct dentry *parent = dget_parent(dentry); + int ret; + + ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, 0); + dput(parent); + + return ret; } /* diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index cc04dc1445d6..6b9884507837 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -412,12 +412,16 @@ static noinline int device_list_add(const char *path, device->fs_devices = fs_devices; fs_devices->num_devices++; - } else if (strcmp(device->name, path)) { + } else if (!device->name || strcmp(device->name, path)) { name = kstrdup(path, GFP_NOFS); if (!name) return -ENOMEM; kfree(device->name); device->name = name; + if (device->missing) { + fs_devices->missing_devices--; + device->missing = 0; + } } if (found_transid > fs_devices->latest_trans) { @@ -1236,6 +1240,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) device->fs_devices->num_devices--; + if (device->missing) + root->fs_info->fs_devices->missing_devices--; + next_device = list_entry(root->fs_info->fs_devices->devices.next, struct btrfs_device, dev_list); if (device->bdev == root->fs_info->sb->s_bdev) @@ -3080,7 +3087,9 @@ static struct btrfs_device *add_missing_dev(struct btrfs_root *root, device->devid = devid; device->work.func = pending_bios_fn; device->fs_devices = fs_devices; + device->missing = 1; fs_devices->num_devices++; + fs_devices->missing_devices++; spin_lock_init(&device->io_lock); INIT_LIST_HEAD(&device->dev_alloc_list); memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE); @@ -3278,6 +3287,15 @@ static int read_one_dev(struct btrfs_root *root, device = add_missing_dev(root, devid, dev_uuid); if (!device) return -ENOMEM; + } else if (!device->missing) { + /* + * this happens when a device that was properly setup + * in the device info lists suddenly goes bad. + * device->bdev is NULL, and so we have to set + * device->missing to one here + */ + root->fs_info->fs_devices->missing_devices++; + device->missing = 1; } } diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 2b638b6e4eea..2740db49eb04 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -44,6 +44,7 @@ struct btrfs_device { int writeable; int in_fs_metadata; + int missing; spinlock_t io_lock; @@ -93,6 +94,7 @@ struct btrfs_fs_devices { u64 num_devices; u64 open_devices; u64 rw_devices; + u64 missing_devices; u64 total_rw_bytes; struct block_device *latest_bdev; diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index e9c874abc9e1..561438b6a50c 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -204,7 +204,7 @@ static int readpage_nounlock(struct file *filp, struct page *page) err = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout, page->index << PAGE_CACHE_SHIFT, &len, ci->i_truncate_seq, ci->i_truncate_size, - &page, 1); + &page, 1, 0); if (err == -ENOENT) err = 0; if (err < 0) { @@ -287,7 +287,7 @@ static int ceph_readpages(struct file *file, struct address_space *mapping, rc = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout, offset, &len, ci->i_truncate_seq, ci->i_truncate_size, - pages, nr_pages); + pages, nr_pages, 0); if (rc == -ENOENT) rc = 0; if (rc < 0) @@ -774,7 +774,7 @@ get_more_pages: snapc, do_sync, ci->i_truncate_seq, ci->i_truncate_size, - &inode->i_mtime, true, 1); + &inode->i_mtime, true, 1, 0); max_pages = req->r_num_pages; alloc_page_vec(fsc, req); diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 98ab13e2b71d..60d27bc9eb83 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1430,8 +1430,8 @@ static int try_nonblocking_invalidate(struct inode *inode) invalidating_gen == ci->i_rdcache_gen) { /* success. */ dout("try_nonblocking_invalidate %p success\n", inode); - ci->i_rdcache_gen = 0; - ci->i_rdcache_revoking = 0; + /* save any racing async invalidate some trouble */ + ci->i_rdcache_revoking = ci->i_rdcache_gen - 1; return 0; } dout("try_nonblocking_invalidate %p failed\n", inode); @@ -2273,8 +2273,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, { struct ceph_inode_info *ci = ceph_inode(inode); int mds = session->s_mds; - unsigned seq = le32_to_cpu(grant->seq); - unsigned issue_seq = le32_to_cpu(grant->issue_seq); + int seq = le32_to_cpu(grant->seq); int newcaps = le32_to_cpu(grant->caps); int issued, implemented, used, wanted, dirty; u64 size = le64_to_cpu(grant->size); @@ -2286,8 +2285,8 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, int revoked_rdcache = 0; int queue_invalidate = 0; - dout("handle_cap_grant inode %p cap %p mds%d seq %u/%u %s\n", - inode, cap, mds, seq, issue_seq, ceph_cap_string(newcaps)); + dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n", + inode, cap, mds, seq, ceph_cap_string(newcaps)); dout(" size %llu max_size %llu, i_size %llu\n", size, max_size, inode->i_size); @@ -2383,7 +2382,6 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, } cap->seq = seq; - cap->issue_seq = issue_seq; /* file layout may have changed */ ci->i_layout = grant->layout; @@ -2691,6 +2689,11 @@ static void handle_cap_import(struct ceph_mds_client *mdsc, NULL /* no caps context */); try_flush_caps(inode, session, NULL); up_read(&mdsc->snap_rwsem); + + /* make sure we re-request max_size, if necessary */ + spin_lock(&inode->i_lock); + ci->i_requested_max_size = 0; + spin_unlock(&inode->i_lock); } /* diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index e0a2dc6fcafc..d902948a90d8 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -40,7 +40,8 @@ int ceph_init_dentry(struct dentry *dentry) if (dentry->d_fsdata) return 0; - if (ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) + if (dentry->d_parent == NULL || /* nfs fh_to_dentry */ + ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) dentry->d_op = &ceph_dentry_ops; else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR) dentry->d_op = &ceph_snapdir_dentry_ops; @@ -114,8 +115,8 @@ static int __dcache_readdir(struct file *filp, spin_lock(&dcache_lock); /* start at beginning? */ - if (filp->f_pos == 2 || (last && - filp->f_pos < ceph_dentry(last)->offset)) { + if (filp->f_pos == 2 || last == NULL || + filp->f_pos < ceph_dentry(last)->offset) { if (list_empty(&parent->d_subdirs)) goto out_unlock; p = parent->d_subdirs.prev; @@ -336,7 +337,10 @@ more: if (req->r_reply_info.dir_end) { kfree(fi->last_name); fi->last_name = NULL; - fi->next_offset = 2; + if (ceph_frag_is_rightmost(frag)) + fi->next_offset = 2; + else + fi->next_offset = 0; } else { rinfo = &req->r_reply_info; err = note_last_dentry(fi, @@ -355,18 +359,22 @@ more: u64 pos = ceph_make_fpos(frag, off); struct ceph_mds_reply_inode *in = rinfo->dir_in[off - fi->offset].in; + struct ceph_vino vino; + ino_t ino; + dout("readdir off %d (%d/%d) -> %lld '%.*s' %p\n", off, off - fi->offset, rinfo->dir_nr, pos, rinfo->dir_dname_len[off - fi->offset], rinfo->dir_dname[off - fi->offset], in); BUG_ON(!in); ftype = le32_to_cpu(in->mode) >> 12; + vino.ino = le64_to_cpu(in->ino); + vino.snap = le64_to_cpu(in->snapid); + ino = ceph_vino_to_ino(vino); if (filldir(dirent, rinfo->dir_dname[off - fi->offset], rinfo->dir_dname_len[off - fi->offset], - pos, - le64_to_cpu(in->ino), - ftype) < 0) { + pos, ino, ftype) < 0) { dout("filldir stopping us...\n"); return 0; } @@ -414,6 +422,7 @@ static void reset_readdir(struct ceph_file_info *fi) fi->last_readdir = NULL; } kfree(fi->last_name); + fi->last_name = NULL; fi->next_offset = 2; /* compensate for . and .. */ if (fi->dentry) { dput(fi->dentry); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index e77c28cf3690..7d0e4a82d898 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -154,11 +154,13 @@ int ceph_open(struct inode *inode, struct file *file) } /* - * No need to block if we have any caps. Update wanted set + * No need to block if we have caps on the auth MDS (for + * write) or any MDS (for read). Update wanted set * asynchronously. */ spin_lock(&inode->i_lock); - if (__ceph_is_any_real_caps(ci)) { + if (__ceph_is_any_real_caps(ci) && + (((fmode & CEPH_FILE_MODE_WR) == 0) || ci->i_auth_cap)) { int mds_wanted = __ceph_caps_mds_wanted(ci); int issued = __ceph_caps_issued(ci, NULL); @@ -280,11 +282,13 @@ int ceph_release(struct inode *inode, struct file *file) static int striped_read(struct inode *inode, u64 off, u64 len, struct page **pages, int num_pages, - int *checkeof) + int *checkeof, bool align_to_pages, + unsigned long buf_align) { struct ceph_fs_client *fsc = ceph_inode_to_client(inode); struct ceph_inode_info *ci = ceph_inode(inode); u64 pos, this_len; + int io_align, page_align; int page_off = off & ~PAGE_CACHE_MASK; /* first byte's offset in page */ int left, pages_left; int read; @@ -300,14 +304,19 @@ static int striped_read(struct inode *inode, page_pos = pages; pages_left = num_pages; read = 0; + io_align = off & ~PAGE_MASK; more: + if (align_to_pages) + page_align = (pos - io_align + buf_align) & ~PAGE_MASK; + else + page_align = pos & ~PAGE_MASK; this_len = left; ret = ceph_osdc_readpages(&fsc->client->osdc, ceph_vino(inode), &ci->i_layout, pos, &this_len, ci->i_truncate_seq, ci->i_truncate_size, - page_pos, pages_left); + page_pos, pages_left, page_align); hit_stripe = this_len < left; was_short = ret >= 0 && ret < this_len; if (ret == -ENOENT) @@ -368,32 +377,34 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data, struct inode *inode = file->f_dentry->d_inode; struct page **pages; u64 off = *poff; - int num_pages = calc_pages_for(off, len); - int ret; + int num_pages, ret; dout("sync_read on file %p %llu~%u %s\n", file, off, len, (file->f_flags & O_DIRECT) ? "O_DIRECT" : ""); if (file->f_flags & O_DIRECT) { - pages = ceph_get_direct_page_vector(data, num_pages, off, len); - - /* - * flush any page cache pages in this range. this - * will make concurrent normal and O_DIRECT io slow, - * but it will at least behave sensibly when they are - * in sequence. - */ + num_pages = calc_pages_for((unsigned long)data, len); + pages = ceph_get_direct_page_vector(data, num_pages, true); } else { + num_pages = calc_pages_for(off, len); pages = ceph_alloc_page_vector(num_pages, GFP_NOFS); } if (IS_ERR(pages)) return PTR_ERR(pages); + /* + * flush any page cache pages in this range. this + * will make concurrent normal and sync io slow, + * but it will at least behave sensibly when they are + * in sequence. + */ ret = filemap_write_and_wait(inode->i_mapping); if (ret < 0) goto done; - ret = striped_read(inode, off, len, pages, num_pages, checkeof); + ret = striped_read(inode, off, len, pages, num_pages, checkeof, + file->f_flags & O_DIRECT, + (unsigned long)data & ~PAGE_MASK); if (ret >= 0 && (file->f_flags & O_DIRECT) == 0) ret = ceph_copy_page_vector_to_user(pages, data, off, ret); @@ -402,7 +413,7 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data, done: if (file->f_flags & O_DIRECT) - ceph_put_page_vector(pages, num_pages); + ceph_put_page_vector(pages, num_pages, true); else ceph_release_page_vector(pages, num_pages); dout("sync_read result %d\n", ret); @@ -448,6 +459,8 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, int flags; int do_sync = 0; int check_caps = 0; + int page_align, io_align; + unsigned long buf_align; int ret; struct timespec mtime = CURRENT_TIME; @@ -462,6 +475,9 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, else pos = *offset; + io_align = pos & ~PAGE_MASK; + buf_align = (unsigned long)data & ~PAGE_MASK; + ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left); if (ret < 0) return ret; @@ -486,20 +502,27 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, */ more: len = left; + if (file->f_flags & O_DIRECT) { + /* write from beginning of first page, regardless of + io alignment */ + page_align = (pos - io_align + buf_align) & ~PAGE_MASK; + num_pages = calc_pages_for((unsigned long)data, len); + } else { + page_align = pos & ~PAGE_MASK; + num_pages = calc_pages_for(pos, len); + } req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, ceph_vino(inode), pos, &len, CEPH_OSD_OP_WRITE, flags, ci->i_snap_realm->cached_context, do_sync, ci->i_truncate_seq, ci->i_truncate_size, - &mtime, false, 2); + &mtime, false, 2, page_align); if (!req) return -ENOMEM; - num_pages = calc_pages_for(pos, len); - if (file->f_flags & O_DIRECT) { - pages = ceph_get_direct_page_vector(data, num_pages, pos, len); + pages = ceph_get_direct_page_vector(data, num_pages, false); if (IS_ERR(pages)) { ret = PTR_ERR(pages); goto out; @@ -549,7 +572,7 @@ more: } if (file->f_flags & O_DIRECT) - ceph_put_page_vector(pages, num_pages); + ceph_put_page_vector(pages, num_pages, false); else if (file->f_flags & O_SYNC) ceph_release_page_vector(pages, num_pages); diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 524b80be4482..bf1286588f26 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -470,7 +470,9 @@ void ceph_fill_file_time(struct inode *inode, int issued, if (issued & (CEPH_CAP_FILE_EXCL| CEPH_CAP_FILE_WR| - CEPH_CAP_FILE_BUFFER)) { + CEPH_CAP_FILE_BUFFER| + CEPH_CAP_AUTH_EXCL| + CEPH_CAP_XATTR_EXCL)) { if (timespec_compare(ctime, &inode->i_ctime) > 0) { dout("ctime %ld.%09ld -> %ld.%09ld inc w/ cap\n", inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec, @@ -510,7 +512,7 @@ void ceph_fill_file_time(struct inode *inode, int issued, warn = 1; } } else { - /* we have no write caps; whatever the MDS says is true */ + /* we have no write|excl caps; whatever the MDS says is true */ if (ceph_seq_cmp(time_warp_seq, ci->i_time_warp_seq) >= 0) { inode->i_ctime = *ctime; inode->i_mtime = *mtime; @@ -566,12 +568,17 @@ static int fill_inode(struct inode *inode, /* * provided version will be odd if inode value is projected, - * even if stable. skip the update if we have a newer info - * (e.g., due to inode info racing form multiple MDSs), or if - * we are getting projected (unstable) inode info. + * even if stable. skip the update if we have newer stable + * info (ours>=theirs, e.g. due to racing mds replies), unless + * we are getting projected (unstable) info (in which case the + * version is odd, and we want ours>theirs). + * us them + * 2 2 skip + * 3 2 skip + * 3 3 update */ if (le64_to_cpu(info->version) > 0 && - (ci->i_version & ~1) > le64_to_cpu(info->version)) + (ci->i_version & ~1) >= le64_to_cpu(info->version)) goto no_change; issued = __ceph_caps_issued(ci, &implemented); @@ -605,7 +612,14 @@ static int fill_inode(struct inode *inode, le32_to_cpu(info->time_warp_seq), &ctime, &mtime, &atime); - ci->i_max_size = le64_to_cpu(info->max_size); + /* only update max_size on auth cap */ + if ((info->cap.flags & CEPH_CAP_FLAG_AUTH) && + ci->i_max_size != le64_to_cpu(info->max_size)) { + dout("max_size %lld -> %llu\n", ci->i_max_size, + le64_to_cpu(info->max_size)); + ci->i_max_size = le64_to_cpu(info->max_size); + } + ci->i_layout = info->layout; inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1; @@ -1054,7 +1068,8 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, ininfo = rinfo->targeti.in; vino.ino = le64_to_cpu(ininfo->ino); vino.snap = le64_to_cpu(ininfo->snapid); - if (!dn->d_inode) { + in = dn->d_inode; + if (!in) { in = ceph_get_inode(sb, vino); if (IS_ERR(in)) { pr_err("fill_trace bad get_inode " @@ -1385,11 +1400,8 @@ static void ceph_invalidate_work(struct work_struct *work) spin_lock(&inode->i_lock); dout("invalidate_pages %p gen %d revoking %d\n", inode, ci->i_rdcache_gen, ci->i_rdcache_revoking); - if (ci->i_rdcache_gen == 0 || - ci->i_rdcache_revoking != ci->i_rdcache_gen) { - BUG_ON(ci->i_rdcache_revoking > ci->i_rdcache_gen); + if (ci->i_rdcache_revoking != ci->i_rdcache_gen) { /* nevermind! */ - ci->i_rdcache_revoking = 0; spin_unlock(&inode->i_lock); goto out; } @@ -1399,15 +1411,16 @@ static void ceph_invalidate_work(struct work_struct *work) ceph_invalidate_nondirty_pages(inode->i_mapping); spin_lock(&inode->i_lock); - if (orig_gen == ci->i_rdcache_gen) { + if (orig_gen == ci->i_rdcache_gen && + orig_gen == ci->i_rdcache_revoking) { dout("invalidate_pages %p gen %d successful\n", inode, ci->i_rdcache_gen); - ci->i_rdcache_gen = 0; - ci->i_rdcache_revoking = 0; + ci->i_rdcache_revoking--; check = 1; } else { - dout("invalidate_pages %p gen %d raced, gen now %d\n", - inode, orig_gen, ci->i_rdcache_gen); + dout("invalidate_pages %p gen %d raced, now %d revoking %d\n", + inode, orig_gen, ci->i_rdcache_gen, + ci->i_rdcache_revoking); } spin_unlock(&inode->i_lock); @@ -1738,7 +1751,7 @@ int ceph_do_getattr(struct inode *inode, int mask) return 0; } - dout("do_getattr inode %p mask %s\n", inode, ceph_cap_string(mask)); + dout("do_getattr inode %p mask %s mode 0%o\n", inode, ceph_cap_string(mask), inode->i_mode); if (ceph_caps_issued_mask(ceph_inode(inode), mask, 1)) return 0; diff --git a/fs/ceph/ioctl.h b/fs/ceph/ioctl.h index a6ce54e94eb5..52e8fd74d450 100644 --- a/fs/ceph/ioctl.h +++ b/fs/ceph/ioctl.h @@ -4,7 +4,7 @@ #include <linux/ioctl.h> #include <linux/types.h> -#define CEPH_IOCTL_MAGIC 0x98 +#define CEPH_IOCTL_MAGIC 0x97 /* just use u64 to align sanely on all archs */ struct ceph_ioctl_layout { diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 40abde93c345..476b329867d4 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -11,40 +11,68 @@ * Implement fcntl and flock locking functions. */ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, - u64 pid, u64 pid_ns, - int cmd, u64 start, u64 length, u8 wait) + int cmd, u8 wait, struct file_lock *fl) { struct inode *inode = file->f_dentry->d_inode; struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; struct ceph_mds_request *req; int err; + u64 length = 0; req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS); if (IS_ERR(req)) return PTR_ERR(req); req->r_inode = igrab(inode); + /* mds requires start and length rather than start and end */ + if (LLONG_MAX == fl->fl_end) + length = 0; + else + length = fl->fl_end - fl->fl_start + 1; + dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, " "length: %llu, wait: %d, type`: %d", (int)lock_type, - (int)operation, pid, start, length, wait, cmd); + (int)operation, (u64)fl->fl_pid, fl->fl_start, + length, wait, fl->fl_type); + req->r_args.filelock_change.rule = lock_type; req->r_args.filelock_change.type = cmd; - req->r_args.filelock_change.pid = cpu_to_le64(pid); + req->r_args.filelock_change.pid = cpu_to_le64((u64)fl->fl_pid); /* This should be adjusted, but I'm not sure if namespaces actually get id numbers*/ req->r_args.filelock_change.pid_namespace = - cpu_to_le64((u64)pid_ns); - req->r_args.filelock_change.start = cpu_to_le64(start); + cpu_to_le64((u64)(unsigned long)fl->fl_nspid); + req->r_args.filelock_change.start = cpu_to_le64(fl->fl_start); req->r_args.filelock_change.length = cpu_to_le64(length); req->r_args.filelock_change.wait = wait; err = ceph_mdsc_do_request(mdsc, inode, req); + + if ( operation == CEPH_MDS_OP_GETFILELOCK){ + fl->fl_pid = le64_to_cpu(req->r_reply_info.filelock_reply->pid); + if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type) + fl->fl_type = F_RDLCK; + else if (CEPH_LOCK_EXCL == req->r_reply_info.filelock_reply->type) + fl->fl_type = F_WRLCK; + else + fl->fl_type = F_UNLCK; + + fl->fl_start = le64_to_cpu(req->r_reply_info.filelock_reply->start); + length = le64_to_cpu(req->r_reply_info.filelock_reply->start) + + le64_to_cpu(req->r_reply_info.filelock_reply->length); + if (length >= 1) + fl->fl_end = length -1; + else + fl->fl_end = 0; + + } ceph_mdsc_put_request(req); dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, " - "length: %llu, wait: %d, type`: %d err code %d", (int)lock_type, - (int)operation, pid, start, length, wait, cmd, err); + "length: %llu, wait: %d, type`: %d, err code %d", (int)lock_type, + (int)operation, (u64)fl->fl_pid, fl->fl_start, + length, wait, fl->fl_type, err); return err; } @@ -54,7 +82,6 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, */ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) { - u64 length; u8 lock_cmd; int err; u8 wait = 0; @@ -76,29 +103,20 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) else lock_cmd = CEPH_LOCK_UNLOCK; - if (LLONG_MAX == fl->fl_end) - length = 0; - else - length = fl->fl_end - fl->fl_start + 1; - - err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, - (u64)fl->fl_pid, - (u64)(unsigned long)fl->fl_nspid, - lock_cmd, fl->fl_start, - length, wait); + err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, lock_cmd, wait, fl); if (!err) { - dout("mds locked, locking locally"); - err = posix_lock_file(file, fl, NULL); - if (err && (CEPH_MDS_OP_SETFILELOCK == op)) { - /* undo! This should only happen if the kernel detects - * local deadlock. */ - ceph_lock_message(CEPH_LOCK_FCNTL, op, file, - (u64)fl->fl_pid, - (u64)(unsigned long)fl->fl_nspid, - CEPH_LOCK_UNLOCK, fl->fl_start, - length, 0); - dout("got %d on posix_lock_file, undid lock", err); + if ( op != CEPH_MDS_OP_GETFILELOCK ){ + dout("mds locked, locking locally"); + err = posix_lock_file(file, fl, NULL); + if (err && (CEPH_MDS_OP_SETFILELOCK == op)) { + /* undo! This should only happen if the kernel detects + * local deadlock. */ + ceph_lock_message(CEPH_LOCK_FCNTL, op, file, + CEPH_LOCK_UNLOCK, 0, fl); + dout("got %d on posix_lock_file, undid lock", err); + } } + } else { dout("mds returned error code %d", err); } @@ -107,7 +125,6 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) int ceph_flock(struct file *file, int cmd, struct file_lock *fl) { - u64 length; u8 lock_cmd; int err; u8 wait = 1; @@ -127,26 +144,15 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) lock_cmd = CEPH_LOCK_EXCL; else lock_cmd = CEPH_LOCK_UNLOCK; - /* mds requires start and length rather than start and end */ - if (LLONG_MAX == fl->fl_end) - length = 0; - else - length = fl->fl_end - fl->fl_start + 1; err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, - file, (u64)fl->fl_pid, - (u64)(unsigned long)fl->fl_nspid, - lock_cmd, fl->fl_start, - length, wait); + file, lock_cmd, wait, fl); if (!err) { err = flock_lock_file_wait(file, fl); if (err) { ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, - file, (u64)fl->fl_pid, - (u64)(unsigned long)fl->fl_nspid, - CEPH_LOCK_UNLOCK, fl->fl_start, - length, 0); + file, CEPH_LOCK_UNLOCK, 0, fl); dout("got %d on flock_lock_file_wait, undid lock", err); } } else { diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 7799cac2b629..38800eaa81d0 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -202,6 +202,38 @@ out_bad: } /* + * parse fcntl F_GETLK results + */ +static int parse_reply_info_filelock(void **p, void *end, + struct ceph_mds_reply_info_parsed *info) +{ + if (*p + sizeof(*info->filelock_reply) > end) + goto bad; + + info->filelock_reply = *p; + *p += sizeof(*info->filelock_reply); + + if (unlikely(*p != end)) + goto bad; + return 0; + +bad: + return -EIO; +} + +/* + * parse extra results + */ +static int parse_reply_info_extra(void **p, void *end, + struct ceph_mds_reply_info_parsed *info) +{ + if (info->head->op == CEPH_MDS_OP_GETFILELOCK) + return parse_reply_info_filelock(p, end, info); + else + return parse_reply_info_dir(p, end, info); +} + +/* * parse entire mds reply */ static int parse_reply_info(struct ceph_msg *msg, @@ -223,10 +255,10 @@ static int parse_reply_info(struct ceph_msg *msg, goto out_bad; } - /* dir content */ + /* extra */ ceph_decode_32_safe(&p, end, len, bad); if (len > 0) { - err = parse_reply_info_dir(&p, p+len, info); + err = parse_reply_info_extra(&p, p+len, info); if (err < 0) goto out_bad; } @@ -528,6 +560,9 @@ static void __register_request(struct ceph_mds_client *mdsc, ceph_mdsc_get_request(req); __insert_request(mdsc, req); + req->r_uid = current_fsuid(); + req->r_gid = current_fsgid(); + if (dir) { struct ceph_inode_info *ci = ceph_inode(dir); @@ -1587,8 +1622,8 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, head->mdsmap_epoch = cpu_to_le32(mdsc->mdsmap->m_epoch); head->op = cpu_to_le32(req->r_op); - head->caller_uid = cpu_to_le32(current_fsuid()); - head->caller_gid = cpu_to_le32(current_fsgid()); + head->caller_uid = cpu_to_le32(req->r_uid); + head->caller_gid = cpu_to_le32(req->r_gid); head->args = req->r_args; ceph_encode_filepath(&p, end, ino1, path1); @@ -2071,7 +2106,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) mutex_lock(&session->s_mutex); if (err < 0) { - pr_err("mdsc_handle_reply got corrupt reply mds%d\n", mds); + pr_err("mdsc_handle_reply got corrupt reply mds%d(tid:%lld)\n", mds, tid); ceph_msg_dump(msg); goto out_err; } @@ -2091,7 +2126,8 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) mutex_lock(&req->r_fill_mutex); err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session); if (err == 0) { - if (result == 0 && rinfo->dir_nr) + if (result == 0 && req->r_op != CEPH_MDS_OP_GETFILELOCK && + rinfo->dir_nr) ceph_readdir_prepopulate(req, req->r_session); ceph_unreserve_caps(mdsc, &req->r_caps_reservation); } diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index d66d63c72355..aabe563b54db 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -42,26 +42,37 @@ struct ceph_mds_reply_info_in { }; /* - * parsed info about an mds reply, including information about the - * target inode and/or its parent directory and dentry, and directory - * contents (for readdir results). + * parsed info about an mds reply, including information about + * either: 1) the target inode and/or its parent directory and dentry, + * and directory contents (for readdir results), or + * 2) the file range lock info (for fcntl F_GETLK results). */ struct ceph_mds_reply_info_parsed { struct ceph_mds_reply_head *head; + /* trace */ struct ceph_mds_reply_info_in diri, targeti; struct ceph_mds_reply_dirfrag *dirfrag; char *dname; u32 dname_len; struct ceph_mds_reply_lease *dlease; - struct ceph_mds_reply_dirfrag *dir_dir; - int dir_nr; - char **dir_dname; - u32 *dir_dname_len; - struct ceph_mds_reply_lease **dir_dlease; - struct ceph_mds_reply_info_in *dir_in; - u8 dir_complete, dir_end; + /* extra */ + union { + /* for fcntl F_GETLK results */ + struct ceph_filelock *filelock_reply; + + /* for readdir results */ + struct { + struct ceph_mds_reply_dirfrag *dir_dir; + int dir_nr; + char **dir_dname; + u32 *dir_dname_len; + struct ceph_mds_reply_lease **dir_dlease; + struct ceph_mds_reply_info_in *dir_in; + u8 dir_complete, dir_end; + }; + }; /* encoded blob describing snapshot contexts for certain operations (e.g., open) */ @@ -170,6 +181,8 @@ struct ceph_mds_request { union ceph_mds_request_args r_args; int r_fmode; /* file mode, if expecting cap */ + uid_t r_uid; + gid_t r_gid; /* for choosing which mds to send this request to */ int r_direct_mode; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 1886294e12f7..7f01728a4657 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -293,9 +293,7 @@ struct ceph_inode_info { int i_rd_ref, i_rdcache_ref, i_wr_ref; int i_wrbuffer_ref, i_wrbuffer_ref_head; u32 i_shared_gen; /* increment each time we get FILE_SHARED */ - u32 i_rdcache_gen; /* we increment this each time we get - FILE_CACHE. If it's non-zero, we - _may_ have cached pages. */ + u32 i_rdcache_gen; /* incremented each time we get FILE_CACHE. */ u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */ struct list_head i_unsafe_writes; /* uncommitted sync writes */ diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 0ed213970ced..ee45648b0d1a 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -4,6 +4,7 @@ config CIFS select NLS select CRYPTO select CRYPTO_MD5 + select CRYPTO_HMAC select CRYPTO_ARC4 help This is the client VFS module for the Common Internet File System @@ -143,6 +144,13 @@ config CIFS_FSCACHE to be cached locally on disk through the general filesystem cache manager. If unsure, say N. +config CIFS_ACL + bool "Provide CIFS ACL support (EXPERIMENTAL)" + depends on EXPERIMENTAL && CIFS_XATTR + help + Allows to fetch CIFS/NTFS ACL from the server. The DACL blob + is handed over to the application/caller. + config CIFS_EXPERIMENTAL bool "CIFS Experimental Features (EXPERIMENTAL)" depends on CIFS && EXPERIMENTAL diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index adefa60a9bdc..43b19dd39191 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -6,7 +6,9 @@ obj-$(CONFIG_CIFS) += cifs.o cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \ md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ - readdir.o ioctl.o sess.o export.o cifsacl.o + readdir.o ioctl.o sess.o export.o + +cifs-$(CONFIG_CIFS_ACL) += cifsacl.o cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o diff --git a/fs/cifs/README b/fs/cifs/README index ee68d1036544..46af99ab3614 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -337,6 +337,15 @@ A partial list of the supported mount options follows: wsize default write size (default 57344) maximum wsize currently allowed by CIFS is 57344 (fourteen 4096 byte pages) + actimeo=n attribute cache timeout in seconds (default 1 second). + After this timeout, the cifs client requests fresh attribute + information from the server. This option allows to tune the + attribute cache timeout to suit the workload needs. Shorter + timeouts mean better the cache coherency, but increased number + of calls to the server. Longer timeouts mean reduced number + of calls to the server at the expense of less stricter cache + coherency checks (i.e. incorrect attribute cache for a short + period of time). rw mount the network share read-write (note that the server may still consider the share read-only) ro mount network share read-only diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index e9a393c9c2ca..7852cd677051 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -48,6 +48,7 @@ struct cifs_sb_info { struct nls_table *local_nls; unsigned int rsize; unsigned int wsize; + unsigned long actimeo; /* attribute cache timeout (jiffies) */ atomic_t active; uid_t mnt_uid; gid_t mnt_gid; diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index c9b4792ae825..a437ec391a01 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -30,8 +30,6 @@ #include "cifs_debug.h" -#ifdef CONFIG_CIFS_EXPERIMENTAL - static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, @@ -560,7 +558,7 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) - return NULL; + return ERR_CAST(tlink); xid = GetXid(); rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen); @@ -568,7 +566,9 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, cifs_put_tlink(tlink); - cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); + cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen); + if (rc) + return ERR_PTR(rc); return pntsd; } @@ -583,7 +583,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) - return NULL; + return ERR_CAST(tlink); tcon = tlink_tcon(tlink); xid = GetXid(); @@ -591,23 +591,22 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - if (rc) { - cERROR(1, "Unable to open file to get ACL"); - goto out; + if (!rc) { + rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); + CIFSSMBClose(xid, tcon, fid); } - rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); - cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); - - CIFSSMBClose(xid, tcon, fid); - out: cifs_put_tlink(tlink); FreeXid(xid); + + cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen); + if (rc) + return ERR_PTR(rc); return pntsd; } /* Retrieve an ACL from the server */ -static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, +struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, struct inode *inode, const char *path, u32 *pacllen) { @@ -695,7 +694,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, } /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ -void +int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, struct inode *inode, const char *path, const __u16 *pfid) { @@ -711,17 +710,21 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen); /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ - if (pntsd) + if (IS_ERR(pntsd)) { + rc = PTR_ERR(pntsd); + cERROR(1, "%s: error %d getting sec desc", __func__, rc); + } else { rc = parse_sec_desc(pntsd, acllen, fattr); - if (rc) - cFYI(1, "parse sec desc failed rc = %d", rc); + kfree(pntsd); + if (rc) + cERROR(1, "parse sec desc failed rc = %d", rc); + } - kfree(pntsd); - return; + return rc; } /* Convert mode bits to an ACL so we can update the ACL on the server */ -int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) +int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode) { int rc = 0; __u32 secdesclen = 0; @@ -736,7 +739,10 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) /* Add three ACEs for owner, group, everyone getting rid of other ACEs as chmod disables ACEs and set the security descriptor */ - if (pntsd) { + if (IS_ERR(pntsd)) { + rc = PTR_ERR(pntsd); + cERROR(1, "%s: error %d getting sec desc", __func__, rc); + } else { /* allocate memory for the smb header, set security descriptor request security descriptor parameters, and secuirty descriptor itself */ @@ -766,4 +772,3 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) return rc; } -#endif /* CONFIG_CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 6c8096cf5155..c4ae7d036563 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -74,11 +74,7 @@ struct cifs_wksid { char sidname[SIDNAMELENGTH]; } __attribute__((packed)); -#ifdef CONFIG_CIFS_EXPERIMENTAL - extern int match_sid(struct cifs_sid *); extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *); -#endif /* CONFIG_CIFS_EXPERIMENTAL */ - #endif /* _CIFSACL_H */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 9c3789762ab7..3936aa7f2c22 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -458,9 +458,13 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) seq_printf(s, ",acl"); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) seq_printf(s, ",mfsymlinks"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) + seq_printf(s, ",fsc"); seq_printf(s, ",rsize=%d", cifs_sb->rsize); seq_printf(s, ",wsize=%d", cifs_sb->wsize); + /* convert actimeo and display it in seconds */ + seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ); return 0; } @@ -933,7 +937,6 @@ init_cifs(void) GlobalCurrentXid = 0; GlobalTotalActiveXid = 0; GlobalMaxActiveXid = 0; - memset(Local_System_Name, 0, 15); spin_lock_init(&cifs_tcp_ses_lock); spin_lock_init(&cifs_file_list_lock); spin_lock_init(&GlobalMid_Lock); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b577bf0a1bb3..7136c0c3e2f9 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -45,6 +45,16 @@ #define CIFS_MIN_RCV_POOL 4 /* + * default attribute cache timeout (jiffies) + */ +#define CIFS_DEF_ACTIMEO (1 * HZ) + +/* + * max attribute cache timeout (jiffies) - 2^30 + */ +#define CIFS_MAX_ACTIMEO (1 << 30) + +/* * MAX_REQ is the maximum number of requests that WE will send * on one socket concurrently. It also matches the most common * value of max multiplex returned by servers. We may @@ -746,8 +756,6 @@ GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */ /* on midQ entries */ -GLOBAL_EXTERN char Local_System_Name[15]; - /* * Global counters, updated atomically */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7ed69b6b5fe6..e6d1481b16c1 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -54,7 +54,8 @@ do { \ __func__, curr_xid, (int)rc); \ } while (0) extern char *build_path_from_dentry(struct dentry *); -extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb); +extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, + struct cifsTconInfo *tcon); extern char *build_wildcard_path_from_dentry(struct dentry *direntry); extern char *cifs_compose_mount_options(const char *sb_mountdata, const char *fullpath, const struct dfs_info3_param *ref, @@ -79,9 +80,7 @@ extern bool is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); -#ifdef CONFIG_CIFS_EXPERIMENTAL extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); -#endif extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, @@ -130,10 +129,12 @@ extern int cifs_get_file_info_unix(struct file *filp); extern int cifs_get_inode_info_unix(struct inode **pinode, const unsigned char *search_path, struct super_block *sb, int xid); -extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, +extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, struct inode *inode, const char *path, const __u16 *pfid); -extern int mode_to_acl(struct inode *inode, const char *path, __u64); +extern int mode_to_cifs_acl(struct inode *inode, const char *path, __u64); +extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, + const char *, u32 *); extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, const char *); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2f2632b6df5a..67acfb3acad2 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2478,95 +2478,6 @@ querySymLinkRetry: } #ifdef CONFIG_CIFS_EXPERIMENTAL -/* Initialize NT TRANSACT SMB into small smb request buffer. - This assumes that all NT TRANSACTS that we init here have - total parm and data under about 400 bytes (to fit in small cifs - buffer size), which is the case so far, it easily fits. NB: - Setup words themselves and ByteCount - MaxSetupCount (size of returned setup area) and - MaxParameterCount (returned parms size) must be set by caller */ -static int -smb_init_nttransact(const __u16 sub_command, const int setup_count, - const int parm_len, struct cifsTconInfo *tcon, - void **ret_buf) -{ - int rc; - __u32 temp_offset; - struct smb_com_ntransact_req *pSMB; - - rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, - (void **)&pSMB); - if (rc) - return rc; - *ret_buf = (void *)pSMB; - pSMB->Reserved = 0; - pSMB->TotalParameterCount = cpu_to_le32(parm_len); - pSMB->TotalDataCount = 0; - pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); - pSMB->ParameterCount = pSMB->TotalParameterCount; - pSMB->DataCount = pSMB->TotalDataCount; - temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + - (setup_count * 2) - 4 /* for rfc1001 length itself */; - pSMB->ParameterOffset = cpu_to_le32(temp_offset); - pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); - pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ - pSMB->SubCommand = cpu_to_le16(sub_command); - return 0; -} - -static int -validate_ntransact(char *buf, char **ppparm, char **ppdata, - __u32 *pparmlen, __u32 *pdatalen) -{ - char *end_of_smb; - __u32 data_count, data_offset, parm_count, parm_offset; - struct smb_com_ntransact_rsp *pSMBr; - - *pdatalen = 0; - *pparmlen = 0; - - if (buf == NULL) - return -EINVAL; - - pSMBr = (struct smb_com_ntransact_rsp *)buf; - - /* ByteCount was converted from little endian in SendReceive */ - end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + - (char *)&pSMBr->ByteCount; - - data_offset = le32_to_cpu(pSMBr->DataOffset); - data_count = le32_to_cpu(pSMBr->DataCount); - parm_offset = le32_to_cpu(pSMBr->ParameterOffset); - parm_count = le32_to_cpu(pSMBr->ParameterCount); - - *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; - *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; - - /* should we also check that parm and data areas do not overlap? */ - if (*ppparm > end_of_smb) { - cFYI(1, "parms start after end of smb"); - return -EINVAL; - } else if (parm_count + *ppparm > end_of_smb) { - cFYI(1, "parm end after end of smb"); - return -EINVAL; - } else if (*ppdata > end_of_smb) { - cFYI(1, "data starts after end of smb"); - return -EINVAL; - } else if (data_count + *ppdata > end_of_smb) { - cFYI(1, "data %p + count %d (%p) past smb end %p start %p", - *ppdata, data_count, (data_count + *ppdata), - end_of_smb, pSMBr); - return -EINVAL; - } else if (parm_count + data_count > pSMBr->ByteCount) { - cFYI(1, "parm count and data count larger than SMB"); - return -EINVAL; - } - *pdatalen = data_count; - *pparmlen = parm_count; - return 0; -} - int CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, @@ -3056,7 +2967,97 @@ GetExtAttrOut: #endif /* CONFIG_POSIX */ -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CONFIG_CIFS_ACL +/* + * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that + * all NT TRANSACTS that we init here have total parm and data under about 400 + * bytes (to fit in small cifs buffer size), which is the case so far, it + * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of + * returned setup area) and MaxParameterCount (returned parms size) must be set + * by caller + */ +static int +smb_init_nttransact(const __u16 sub_command, const int setup_count, + const int parm_len, struct cifsTconInfo *tcon, + void **ret_buf) +{ + int rc; + __u32 temp_offset; + struct smb_com_ntransact_req *pSMB; + + rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, + (void **)&pSMB); + if (rc) + return rc; + *ret_buf = (void *)pSMB; + pSMB->Reserved = 0; + pSMB->TotalParameterCount = cpu_to_le32(parm_len); + pSMB->TotalDataCount = 0; + pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - + MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->DataCount = pSMB->TotalDataCount; + temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + + (setup_count * 2) - 4 /* for rfc1001 length itself */; + pSMB->ParameterOffset = cpu_to_le32(temp_offset); + pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); + pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ + pSMB->SubCommand = cpu_to_le16(sub_command); + return 0; +} + +static int +validate_ntransact(char *buf, char **ppparm, char **ppdata, + __u32 *pparmlen, __u32 *pdatalen) +{ + char *end_of_smb; + __u32 data_count, data_offset, parm_count, parm_offset; + struct smb_com_ntransact_rsp *pSMBr; + + *pdatalen = 0; + *pparmlen = 0; + + if (buf == NULL) + return -EINVAL; + + pSMBr = (struct smb_com_ntransact_rsp *)buf; + + /* ByteCount was converted from little endian in SendReceive */ + end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + + (char *)&pSMBr->ByteCount; + + data_offset = le32_to_cpu(pSMBr->DataOffset); + data_count = le32_to_cpu(pSMBr->DataCount); + parm_offset = le32_to_cpu(pSMBr->ParameterOffset); + parm_count = le32_to_cpu(pSMBr->ParameterCount); + + *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; + *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; + + /* should we also check that parm and data areas do not overlap? */ + if (*ppparm > end_of_smb) { + cFYI(1, "parms start after end of smb"); + return -EINVAL; + } else if (parm_count + *ppparm > end_of_smb) { + cFYI(1, "parm end after end of smb"); + return -EINVAL; + } else if (*ppdata > end_of_smb) { + cFYI(1, "data starts after end of smb"); + return -EINVAL; + } else if (data_count + *ppdata > end_of_smb) { + cFYI(1, "data %p + count %d (%p) past smb end %p start %p", + *ppdata, data_count, (data_count + *ppdata), + end_of_smb, pSMBr); + return -EINVAL; + } else if (parm_count + data_count > pSMBr->ByteCount) { + cFYI(1, "parm count and data count larger than SMB"); + return -EINVAL; + } + *pdatalen = data_count; + *pparmlen = parm_count; + return 0; +} + /* Get Security Descriptor (by handle) from remote server for a file or dir */ int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, @@ -3214,7 +3215,7 @@ setCifsAclRetry: return (rc); } -#endif /* CONFIG_CIFS_EXPERIMENTAL */ +#endif /* CONFIG_CIFS_ACL */ /* Legacy Query Path Information call for lookup to old servers such as Win9x/WinME */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 251a17c03545..cc1a8604a790 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -105,6 +105,7 @@ struct smb_vol { unsigned int wsize; bool sockopt_tcp_nodelay:1; unsigned short int port; + unsigned long actimeo; /* attribute cache timeout (jiffies) */ char *prepath; struct sockaddr_storage srcaddr; /* allow binding to a local IP */ struct nls_table *local_nls; @@ -806,23 +807,20 @@ cifs_parse_mount_options(char *options, const char *devname, short int override_gid = -1; bool uid_specified = false; bool gid_specified = false; + char *nodename = utsname()->nodename; separator[0] = ','; separator[1] = 0; - if (Local_System_Name[0] != 0) - memcpy(vol->source_rfc1001_name, Local_System_Name, 15); - else { - char *nodename = utsname()->nodename; - int n = strnlen(nodename, 15); - memset(vol->source_rfc1001_name, 0x20, 15); - for (i = 0; i < n; i++) { - /* does not have to be perfect mapping since field is - informational, only used for servers that do not support - port 445 and it can be overridden at mount time */ - vol->source_rfc1001_name[i] = toupper(nodename[i]); - } - } + /* + * does not have to be perfect mapping since field is + * informational, only used for servers that do not support + * port 445 and it can be overridden at mount time + */ + memset(vol->source_rfc1001_name, 0x20, 15); + for (i = 0; i < strnlen(nodename, 15); i++) + vol->source_rfc1001_name[i] = toupper(nodename[i]); + vol->source_rfc1001_name[15] = 0; /* null target name indicates to use *SMBSERVR default called name if we end up sending RFC1001 session initialize */ @@ -840,6 +838,8 @@ cifs_parse_mount_options(char *options, const char *devname, /* default to using server inode numbers where available */ vol->server_ino = 1; + vol->actimeo = CIFS_DEF_ACTIMEO; + if (!options) return 1; @@ -1214,6 +1214,16 @@ cifs_parse_mount_options(char *options, const char *devname, printk(KERN_WARNING "CIFS: server net" "biosname longer than 15 truncated.\n"); } + } else if (strnicmp(data, "actimeo", 7) == 0) { + if (value && *value) { + vol->actimeo = HZ * simple_strtoul(value, + &value, 0); + if (vol->actimeo > CIFS_MAX_ACTIMEO) { + cERROR(1, "CIFS: attribute cache" + "timeout too large"); + return 1; + } + } } else if (strnicmp(data, "credentials", 4) == 0) { /* ignore */ } else if (strnicmp(data, "version", 3) == 0) { @@ -1352,6 +1362,11 @@ cifs_parse_mount_options(char *options, const char *devname, "supported. Instead set " "/proc/fs/cifs/LookupCacheEnabled to 0\n"); } else if (strnicmp(data, "fsc", 3) == 0) { +#ifndef CONFIG_CIFS_FSCACHE + cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE" + "kernel config option set"); + return 1; +#endif vol->fsc = true; } else if (strnicmp(data, "mfsymlinks", 10) == 0) { vol->mfsymlinks = true; @@ -2566,6 +2581,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, cFYI(1, "file mode: 0x%x dir mode: 0x%x", cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); + cifs_sb->actimeo = pvolume_info->actimeo; + if (pvolume_info->noperm) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; if (pvolume_info->setuids) @@ -2816,13 +2833,13 @@ remote_path_check: /* check if a whole path (including prepath) is not remote */ if (!rc && cifs_sb->prepathlen && tcon) { /* build_path_to_root works only when we have a valid tcon */ - full_path = cifs_build_path_to_root(cifs_sb); + full_path = cifs_build_path_to_root(cifs_sb, tcon); if (full_path == NULL) { rc = -ENOMEM; goto mount_fail_check; } rc = is_path_accessible(xid, tcon, cifs_sb, full_path); - if (rc != -EREMOTE) { + if (rc != 0 && rc != -EREMOTE) { kfree(full_path); goto mount_fail_check; } diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index 0eb87026cad3..548f06230a6d 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c @@ -66,7 +66,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) /* Search for server name delimiter */ sep = memchr(hostname, '\\', len); if (sep) - len = sep - unc; + len = sep - hostname; else cFYI(1, "%s: probably server name is whole unc: %s", __func__, unc); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 06c3e83fa387..5a28660ca2b5 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1108,7 +1108,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, return total_written; } -#ifdef CONFIG_CIFS_EXPERIMENTAL struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only) { @@ -1142,7 +1141,6 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, spin_unlock(&cifs_file_list_lock); return NULL; } -#endif struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only) @@ -2271,8 +2269,10 @@ void cifs_oplock_break_get(struct cifsFileInfo *cfile) void cifs_oplock_break_put(struct cifsFileInfo *cfile) { + struct super_block *sb = cfile->dentry->d_sb; + cifsFileInfo_put(cfile); - cifs_sb_deactive(cfile->dentry->d_sb); + cifs_sb_deactive(sb); } const struct address_space_operations cifs_addr_ops = { diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index a2ad94efcfe6..297a43d0ff7f 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -2,7 +2,7 @@ * fs/cifs/fscache.c - CIFS filesystem cache interface * * Copyright (c) 2010 Novell, Inc. - * Author(s): Suresh Jayaraman (sjayaraman@suse.de> + * Author(s): Suresh Jayaraman <sjayaraman@suse.de> * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -67,10 +67,12 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode) if (cifsi->fscache) return; - cifsi->fscache = fscache_acquire_cookie(tcon->fscache, + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) { + cifsi->fscache = fscache_acquire_cookie(tcon->fscache, &cifs_fscache_inode_object_def, cifsi); - cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache, + cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache, cifsi->fscache); + } } void cifs_fscache_release_inode_cookie(struct inode *inode) @@ -101,10 +103,8 @@ void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) { if ((filp->f_flags & O_ACCMODE) != O_RDONLY) cifs_fscache_disable_inode_cookie(inode); - else { + else cifs_fscache_enable_inode_cookie(inode); - cFYI(1, "CIFS: fscache inode cookie set"); - } } void cifs_fscache_reset_inode_cookie(struct inode *inode) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ef3a55bf86b6..589f3e3f6e00 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -686,13 +686,18 @@ int cifs_get_inode_info(struct inode **pinode, cFYI(1, "cifs_sfu_type failed: %d", tmprc); } -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CONFIG_CIFS_ACL /* fill in 0777 bits from ACL */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { - cFYI(1, "Getting mode bits from ACL"); - cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid); + rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, + pfid); + if (rc) { + cFYI(1, "%s: Getting ACL failed with error: %d", + __func__, rc); + goto cgii_exit; + } } -#endif +#endif /* CONFIG_CIFS_ACL */ /* fill in remaining high mode bits e.g. SUID, VTX */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) @@ -723,12 +728,12 @@ static const struct inode_operations cifs_ipc_inode_ops = { .lookup = cifs_lookup, }; -char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) +char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, + struct cifsTconInfo *tcon) { int pplen = cifs_sb->prepathlen; int dfsplen; char *full_path = NULL; - struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); /* if no prefix path, simply set path to the root of share to "" */ if (pplen == 0) { @@ -870,7 +875,7 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) char *full_path; struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); - full_path = cifs_build_path_to_root(cifs_sb); + full_path = cifs_build_path_to_root(cifs_sb, tcon); if (full_path == NULL) return ERR_PTR(-ENOMEM); @@ -881,8 +886,10 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid, NULL); - if (!inode) - return ERR_PTR(rc); + if (!inode) { + inode = ERR_PTR(rc); + goto out; + } #ifdef CONFIG_CIFS_FSCACHE /* populate tcon->resource_id */ @@ -898,13 +905,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) inode->i_uid = cifs_sb->mnt_uid; inode->i_gid = cifs_sb->mnt_gid; } else if (rc) { - kfree(full_path); - _FreeXid(xid); iget_failed(inode); - return ERR_PTR(rc); + inode = ERR_PTR(rc); } - +out: kfree(full_path); /* can not call macro FreeXid here since in a void func * TODO: This is no longer true @@ -1648,6 +1653,7 @@ static bool cifs_inode_needs_reval(struct inode *inode) { struct cifsInodeInfo *cifs_i = CIFS_I(inode); + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); if (cifs_i->clientCanCacheRead) return false; @@ -1658,19 +1664,21 @@ cifs_inode_needs_reval(struct inode *inode) if (cifs_i->time == 0) return true; - /* FIXME: the actimeo should be tunable */ - if (time_after_eq(jiffies, cifs_i->time + HZ)) + if (!time_in_range(jiffies, cifs_i->time, + cifs_i->time + cifs_sb->actimeo)) return true; /* hardlinked files w/ noserverino get "special" treatment */ - if (!(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && S_ISREG(inode->i_mode) && inode->i_nlink != 1) return true; return false; } -/* check invalid_mapping flag and zap the cache if it's set */ +/* + * Zap the cache. Called when invalid_mapping flag is set. + */ static void cifs_invalidate_mapping(struct inode *inode) { @@ -2114,11 +2122,16 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) if (attrs->ia_valid & ATTR_MODE) { rc = 0; -#ifdef CONFIG_CIFS_EXPERIMENTAL - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) - rc = mode_to_acl(inode, full_path, mode); - else -#endif +#ifdef CONFIG_CIFS_ACL + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { + rc = mode_to_cifs_acl(inode, full_path, mode); + if (rc) { + cFYI(1, "%s: Setting ACL failed with error: %d", + __func__, rc); + goto cifs_setattr_exit; + } + } else +#endif /* CONFIG_CIFS_ACL */ if (((mode & S_IWUGO) == 0) && (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index ef7bb7b50f58..a73eb9f4bdaf 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -226,26 +226,29 @@ static int initiate_cifs_search(const int xid, struct file *file) char *full_path = NULL; struct cifsFileInfo *cifsFile; struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - struct tcon_link *tlink; + struct tcon_link *tlink = NULL; struct cifsTconInfo *pTcon; - tlink = cifs_sb_tlink(cifs_sb); - if (IS_ERR(tlink)) - return PTR_ERR(tlink); - pTcon = tlink_tcon(tlink); - - if (file->private_data == NULL) - file->private_data = - kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); if (file->private_data == NULL) { - rc = -ENOMEM; - goto error_exit; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + + cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); + if (cifsFile == NULL) { + rc = -ENOMEM; + goto error_exit; + } + file->private_data = cifsFile; + cifsFile->tlink = cifs_get_tlink(tlink); + pTcon = tlink_tcon(tlink); + } else { + cifsFile = file->private_data; + pTcon = tlink_tcon(cifsFile->tlink); } - cifsFile = file->private_data; cifsFile->invalidHandle = true; cifsFile->srch_inf.endOfSearch = false; - cifsFile->tlink = cifs_get_tlink(tlink); full_path = build_path_from_dentry(file->f_path.dentry); if (full_path == NULL) { @@ -756,18 +759,6 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, ino, fattr.cf_dtype); - /* - * we can not return filldir errors to the caller since they are - * "normal" when the stat blocksize is too small - we return remapped - * error instead - * - * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above - * case already. Why should we be clobbering other errors from it? - */ - if (rc) { - cFYI(1, "filldir rc = %d", rc); - rc = -EOVERFLOW; - } dput(tmp_dentry); return rc; } diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index a264b744bb41..eae2a1491608 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -30,10 +30,11 @@ #define MAX_EA_VALUE_SIZE 65535 #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib" +#define CIFS_XATTR_CIFS_ACL "system.cifs_acl" #define CIFS_XATTR_USER_PREFIX "user." #define CIFS_XATTR_SYSTEM_PREFIX "system." #define CIFS_XATTR_OS2_PREFIX "os2." -#define CIFS_XATTR_SECURITY_PREFIX ".security" +#define CIFS_XATTR_SECURITY_PREFIX "security." #define CIFS_XATTR_TRUSTED_PREFIX "trusted." #define XATTR_TRUSTED_PREFIX_LEN 8 #define XATTR_SECURITY_PREFIX_LEN 9 @@ -277,29 +278,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); -#ifdef CONFIG_CIFS_EXPERIMENTAL - else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { - __u16 fid; - int oplock = 0; - struct cifs_ntsd *pacl = NULL; - __u32 buflen = 0; - if (experimEnabled) - rc = CIFSSMBOpen(xid, pTcon, full_path, - FILE_OPEN, GENERIC_READ, 0, &fid, - &oplock, NULL, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - /* else rc is EOPNOTSUPP from above */ - - if (rc == 0) { - rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, &pacl, - &buflen); - CIFSSMBClose(xid, pTcon, fid); - } - } -#endif /* EXPERIMENTAL */ #else - cFYI(1, "query POSIX ACL not supported yet"); + cFYI(1, "Query POSIX ACL not supported yet"); #endif /* CONFIG_CIFS_POSIX */ } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT, strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { @@ -311,8 +291,33 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); #else - cFYI(1, "query POSIX default ACL not supported yet"); -#endif + cFYI(1, "Query POSIX default ACL not supported yet"); +#endif /* CONFIG_CIFS_POSIX */ + } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, + strlen(CIFS_XATTR_CIFS_ACL)) == 0) { +#ifdef CONFIG_CIFS_ACL + u32 acllen; + struct cifs_ntsd *pacl; + + pacl = get_cifs_acl(cifs_sb, direntry->d_inode, + full_path, &acllen); + if (IS_ERR(pacl)) { + rc = PTR_ERR(pacl); + cERROR(1, "%s: error %zd getting sec desc", + __func__, rc); + } else { + if (ea_value) { + if (acllen > buf_size) + acllen = -ERANGE; + else + memcpy(ea_value, pacl, acllen); + } + rc = acllen; + kfree(pacl); + } +#else + cFYI(1, "Query CIFS ACL not supported yet"); +#endif /* CONFIG_CIFS_ACL */ } else if (strncmp(ea_name, CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) { cFYI(1, "Trusted xattr namespace not supported yet"); diff --git a/fs/compat.c b/fs/compat.c index c580c322fa6b..eb1740ac8c0a 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1350,6 +1350,10 @@ static int compat_count(compat_uptr_t __user *argv, int max) argv++; if (i++ >= max) return -E2BIG; + + if (fatal_signal_pending(current)) + return -ERESTARTNOHAND; + cond_resched(); } } return i; @@ -1391,6 +1395,12 @@ static int compat_copy_strings(int argc, compat_uptr_t __user *argv, while (len > 0) { int offset, bytes_to_copy; + if (fatal_signal_pending(current)) { + ret = -ERESTARTNOHAND; + goto out; + } + cond_resched(); + offset = pos % PAGE_SIZE; if (offset == 0) offset = PAGE_SIZE; @@ -1407,18 +1417,8 @@ static int compat_copy_strings(int argc, compat_uptr_t __user *argv, if (!kmapped_page || kpos != (pos & PAGE_MASK)) { struct page *page; -#ifdef CONFIG_STACK_GROWSUP - ret = expand_stack_downwards(bprm->vma, pos); - if (ret < 0) { - /* We've exceed the stack rlimit. */ - ret = -E2BIG; - goto out; - } -#endif - ret = get_user_pages(current, bprm->mm, pos, - 1, 1, 1, &page, NULL); - if (ret <= 0) { - /* We've exceed the stack rlimit. */ + page = get_arg_page(bprm, pos, 1); + if (!page) { ret = -E2BIG; goto out; } @@ -1539,8 +1539,10 @@ int compat_do_execve(char * filename, return retval; out: - if (bprm->mm) + if (bprm->mm) { + acct_arg_size(bprm, 0); mmput(bprm->mm); + } out_file: if (bprm->file) { diff --git a/fs/exec.c b/fs/exec.c index 99d33a1371e9..c62efcb959c7 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -164,7 +164,26 @@ out: #ifdef CONFIG_MMU -static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, +void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) +{ + struct mm_struct *mm = current->mm; + long diff = (long)(pages - bprm->vma_pages); + + if (!mm || !diff) + return; + + bprm->vma_pages = pages; + +#ifdef SPLIT_RSS_COUNTING + add_mm_counter(mm, MM_ANONPAGES, diff); +#else + spin_lock(&mm->page_table_lock); + add_mm_counter(mm, MM_ANONPAGES, diff); + spin_unlock(&mm->page_table_lock); +#endif +} + +struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, int write) { struct page *page; @@ -186,6 +205,8 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start; struct rlimit *rlim; + acct_arg_size(bprm, size / PAGE_SIZE); + /* * We've historically supported up to 32 pages (ARG_MAX) * of argument strings even with small stacks @@ -254,6 +275,11 @@ static int __bprm_mm_init(struct linux_binprm *bprm) vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP; vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); INIT_LIST_HEAD(&vma->anon_vma_chain); + + err = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); + if (err) + goto err; + err = insert_vm_struct(mm, vma); if (err) goto err; @@ -276,7 +302,11 @@ static bool valid_arg_len(struct linux_binprm *bprm, long len) #else -static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, +void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) +{ +} + +struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, int write) { struct page *page; @@ -1003,6 +1033,7 @@ int flush_old_exec(struct linux_binprm * bprm) /* * Release all of the old mmap stuff */ + acct_arg_size(bprm, 0); retval = exec_mmap(bprm->mm); if (retval) goto out; @@ -1426,8 +1457,10 @@ int do_execve(const char * filename, return retval; out: - if (bprm->mm) - mmput (bprm->mm); + if (bprm->mm) { + acct_arg_size(bprm, 0); + mmput(bprm->mm); + } out_file: if (bprm->file) { diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 6a5edea2d70b..94ce3d7a1c4b 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -910,6 +910,7 @@ struct ext4_inode_info { #define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */ #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */ #define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */ +#define EXT4_MOUNT_MBLK_IO_SUBMIT 0x4000000 /* multi-block io submits */ #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index bdbe69902207..e659597b690b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2125,9 +2125,12 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd, */ if (unlikely(journal_data && PageChecked(page))) err = __ext4_journalled_writepage(page, len); - else + else if (test_opt(inode->i_sb, MBLK_IO_SUBMIT)) err = ext4_bio_write_page(&io_submit, page, len, mpd->wbc); + else + err = block_write_full_page(page, + noalloc_get_block_write, mpd->wbc); if (!err) mpd->pages_written++; diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index bf5ae883b1bd..eb3bc2fe647e 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -331,6 +331,30 @@ mext_out: return err; } + case FITRIM: + { + struct super_block *sb = inode->i_sb; + struct fstrim_range range; + int ret = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&range, (struct fstrim_range *)arg, + sizeof(range))) + return -EFAULT; + + ret = ext4_trim_fs(sb, &range); + if (ret < 0) + return ret; + + if (copy_to_user((struct fstrim_range *)arg, &range, + sizeof(range))) + return -EFAULT; + + return 0; + } + default: return -ENOTTY; } diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 92203b8a099f..dc40e75cba88 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -872,7 +872,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, if (namelen > EXT4_NAME_LEN) return NULL; if ((namelen <= 2) && (name[0] == '.') && - (name[1] == '.' || name[1] == '0')) { + (name[1] == '.' || name[1] == '\0')) { /* * "." or ".." will only be in the first block * NFS may look up ".."; "." should be handled by the VFS diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 7f5451cd1d38..beacce11ac50 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -237,8 +237,6 @@ static void ext4_end_bio(struct bio *bio, int error) } while (bh != head); } - put_io_page(io_end->pages[i]); - /* * If this is a partial write which happened to make * all buffers uptodate then we can optimize away a @@ -248,6 +246,8 @@ static void ext4_end_bio(struct bio *bio, int error) */ if (!partial_write) SetPageUptodate(page); + + put_io_page(io_end->pages[i]); } io_end->num_io_pages = 0; inode = io_end->inode; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 61182fe6254e..fb15c9c0be74 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1026,6 +1026,8 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) !(def_mount_opts & EXT4_DEFM_NODELALLOC)) seq_puts(seq, ",nodelalloc"); + if (test_opt(sb, MBLK_IO_SUBMIT)) + seq_puts(seq, ",mblk_io_submit"); if (sbi->s_stripe) seq_printf(seq, ",stripe=%lu", sbi->s_stripe); /* @@ -1197,7 +1199,6 @@ static const struct super_operations ext4_sops = { .quota_write = ext4_quota_write, #endif .bdev_try_to_free_page = bdev_try_to_free_page, - .trim_fs = ext4_trim_fs }; static const struct super_operations ext4_nojournal_sops = { @@ -1240,8 +1241,8 @@ enum { Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota, Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, Opt_resize, Opt_usrquota, Opt_grpquota, Opt_i_version, - Opt_stripe, Opt_delalloc, Opt_nodelalloc, - Opt_block_validity, Opt_noblock_validity, + Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit, + Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity, Opt_inode_readahead_blks, Opt_journal_ioprio, Opt_dioread_nolock, Opt_dioread_lock, Opt_discard, Opt_nodiscard, @@ -1305,6 +1306,8 @@ static const match_table_t tokens = { {Opt_resize, "resize"}, {Opt_delalloc, "delalloc"}, {Opt_nodelalloc, "nodelalloc"}, + {Opt_mblk_io_submit, "mblk_io_submit"}, + {Opt_nomblk_io_submit, "nomblk_io_submit"}, {Opt_block_validity, "block_validity"}, {Opt_noblock_validity, "noblock_validity"}, {Opt_inode_readahead_blks, "inode_readahead_blks=%u"}, @@ -1726,6 +1729,12 @@ set_qf_format: case Opt_nodelalloc: clear_opt(sbi->s_mount_opt, DELALLOC); break; + case Opt_mblk_io_submit: + set_opt(sbi->s_mount_opt, MBLK_IO_SUBMIT); + break; + case Opt_nomblk_io_submit: + clear_opt(sbi->s_mount_opt, MBLK_IO_SUBMIT); + break; case Opt_stripe: if (match_int(&args[0], &option)) return 0; @@ -2799,9 +2808,6 @@ static void ext4_clear_request_list(void) struct ext4_li_request *elr; mutex_lock(&ext4_li_info->li_list_mtx); - if (list_empty(&ext4_li_info->li_request_list)) - return; - list_for_each_safe(pos, n, &ext4_li_info->li_request_list) { elr = list_entry(pos, struct ext4_li_request, lr_request); @@ -3268,13 +3274,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) * Test whether we have more sectors than will fit in sector_t, * and whether the max offset is addressable by the page cache. */ - ret = generic_check_addressable(sb->s_blocksize_bits, + err = generic_check_addressable(sb->s_blocksize_bits, ext4_blocks_count(es)); - if (ret) { + if (err) { ext4_msg(sb, KERN_ERR, "filesystem" " too large to mount safely on this system"); if (sizeof(sector_t) < 8) ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled"); + ret = err; goto failed_mount; } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c8224587123f..8b984a2cebbd 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/module.h> +#include <linux/compat.h> static const struct file_operations fuse_direct_io_file_operations; @@ -134,6 +135,7 @@ EXPORT_SYMBOL_GPL(fuse_do_open); void fuse_finish_open(struct inode *inode, struct file *file) { struct fuse_file *ff = file->private_data; + struct fuse_conn *fc = get_fuse_conn(inode); if (ff->open_flags & FOPEN_DIRECT_IO) file->f_op = &fuse_direct_io_file_operations; @@ -141,6 +143,15 @@ void fuse_finish_open(struct inode *inode, struct file *file) invalidate_inode_pages2(inode->i_mapping); if (ff->open_flags & FOPEN_NONSEEKABLE) nonseekable_open(inode, file); + if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) { + struct fuse_inode *fi = get_fuse_inode(inode); + + spin_lock(&fc->lock); + fi->attr_version = ++fc->attr_version; + i_size_write(inode, 0); + spin_unlock(&fc->lock); + fuse_invalidate_attr(inode); + } } int fuse_open_common(struct inode *inode, struct file *file, bool isdir) @@ -1618,6 +1629,58 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov, } /* + * CUSE servers compiled on 32bit broke on 64bit kernels because the + * ABI was defined to be 'struct iovec' which is different on 32bit + * and 64bit. Fortunately we can determine which structure the server + * used from the size of the reply. + */ +static int fuse_copy_ioctl_iovec(struct iovec *dst, void *src, + size_t transferred, unsigned count, + bool is_compat) +{ +#ifdef CONFIG_COMPAT + if (count * sizeof(struct compat_iovec) == transferred) { + struct compat_iovec *ciov = src; + unsigned i; + + /* + * With this interface a 32bit server cannot support + * non-compat (i.e. ones coming from 64bit apps) ioctl + * requests + */ + if (!is_compat) + return -EINVAL; + + for (i = 0; i < count; i++) { + dst[i].iov_base = compat_ptr(ciov[i].iov_base); + dst[i].iov_len = ciov[i].iov_len; + } + return 0; + } +#endif + + if (count * sizeof(struct iovec) != transferred) + return -EIO; + + memcpy(dst, src, transferred); + return 0; +} + +/* Make sure iov_length() won't overflow */ +static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count) +{ + size_t n; + u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT; + + for (n = 0; n < count; n++) { + if (iov->iov_len > (size_t) max) + return -ENOMEM; + max -= iov->iov_len; + } + return 0; +} + +/* * For ioctls, there is no generic way to determine how much memory * needs to be read and/or written. Furthermore, ioctls are allowed * to dereference the passed pointer, so the parameter requires deep @@ -1798,18 +1861,25 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV) goto out; - err = -EIO; - if ((in_iovs + out_iovs) * sizeof(struct iovec) != transferred) - goto out; - - /* okay, copy in iovs and retry */ vaddr = kmap_atomic(pages[0], KM_USER0); - memcpy(page_address(iov_page), vaddr, transferred); + err = fuse_copy_ioctl_iovec(page_address(iov_page), vaddr, + transferred, in_iovs + out_iovs, + (flags & FUSE_IOCTL_COMPAT) != 0); kunmap_atomic(vaddr, KM_USER0); + if (err) + goto out; in_iov = page_address(iov_page); out_iov = in_iov + in_iovs; + err = fuse_verify_ioctl_iov(in_iov, in_iovs); + if (err) + goto out; + + err = fuse_verify_ioctl_iov(out_iov, out_iovs); + if (err) + goto out; + goto retry; } diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 58a9b9998b42..f606baf9ba72 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -631,6 +631,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, struct fs_disk_quota *fdq) { struct inode *inode = &ip->i_inode; + struct gfs2_sbd *sdp = GFS2_SB(inode); struct address_space *mapping = inode->i_mapping; unsigned long index = loc >> PAGE_CACHE_SHIFT; unsigned offset = loc & (PAGE_CACHE_SIZE - 1); @@ -658,11 +659,11 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, qd->qd_qb.qb_value = qp->qu_value; if (fdq) { if (fdq->d_fieldmask & FS_DQ_BSOFT) { - qp->qu_warn = cpu_to_be64(fdq->d_blk_softlimit); + qp->qu_warn = cpu_to_be64(fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift); qd->qd_qb.qb_warn = qp->qu_warn; } if (fdq->d_fieldmask & FS_DQ_BHARD) { - qp->qu_limit = cpu_to_be64(fdq->d_blk_hardlimit); + qp->qu_limit = cpu_to_be64(fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift); qd->qd_qb.qb_limit = qp->qu_limit; } } @@ -1497,9 +1498,9 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id, fdq->d_version = FS_DQUOT_VERSION; fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA; fdq->d_id = id; - fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit); - fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn); - fdq->d_bcount = be64_to_cpu(qlvb->qb_value); + fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift; + fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift; + fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift; gfs2_glock_dq_uninit(&q_gh); out: @@ -1566,10 +1567,10 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id, /* If nothing has changed, this is a no-op */ if ((fdq->d_fieldmask & FS_DQ_BSOFT) && - (fdq->d_blk_softlimit == be64_to_cpu(qd->qd_qb.qb_warn))) + ((fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_warn))) fdq->d_fieldmask ^= FS_DQ_BSOFT; if ((fdq->d_fieldmask & FS_DQ_BHARD) && - (fdq->d_blk_hardlimit == be64_to_cpu(qd->qd_qb.qb_limit))) + ((fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_limit))) fdq->d_fieldmask ^= FS_DQ_BHARD; if (fdq->d_fieldmask == 0) goto out_i; diff --git a/fs/ioctl.c b/fs/ioctl.c index 4f46752ce4f9..d6cc16476620 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -529,41 +529,6 @@ static int ioctl_fsthaw(struct file *filp) return thaw_super(sb); } -static int ioctl_fstrim(struct file *filp, void __user *argp) -{ - struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; - struct fstrim_range range; - int ret = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - /* If filesystem doesn't support trim feature, return. */ - if (sb->s_op->trim_fs == NULL) - return -EOPNOTSUPP; - - /* If a blockdevice-backed filesystem isn't specified, return EINVAL. */ - if (sb->s_bdev == NULL) - return -EINVAL; - - if (argp == NULL) { - range.start = 0; - range.len = ULLONG_MAX; - range.minlen = 0; - } else if (copy_from_user(&range, argp, sizeof(range))) - return -EFAULT; - - ret = sb->s_op->trim_fs(sb, &range); - if (ret < 0) - return ret; - - if ((argp != NULL) && - (copy_to_user(argp, &range, sizeof(range)))) - return -EFAULT; - - return 0; -} - /* * When you add any new common ioctls to the switches above and below * please update compat_sys_ioctl() too. @@ -614,10 +579,6 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, error = ioctl_fsthaw(filp); break; - case FITRIM: - error = ioctl_fstrim(filp, argp); - break; - case FS_IOC_FIEMAP: return ioctl_fiemap(filp, arg); diff --git a/fs/ioprio.c b/fs/ioprio.c index 2f7d05c89922..7da2a06508e5 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -103,22 +103,15 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio) } ret = -ESRCH; - /* - * We want IOPRIO_WHO_PGRP/IOPRIO_WHO_USER to be "atomic", - * so we can't use rcu_read_lock(). See re-copy of ->ioprio - * in copy_process(). - */ - read_lock(&tasklist_lock); + rcu_read_lock(); switch (which) { case IOPRIO_WHO_PROCESS: - rcu_read_lock(); if (!who) p = current; else p = find_task_by_vpid(who); if (p) ret = set_task_ioprio(p, ioprio); - rcu_read_unlock(); break; case IOPRIO_WHO_PGRP: if (!who) @@ -141,12 +134,7 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio) break; do_each_thread(g, p) { - int match; - - rcu_read_lock(); - match = __task_cred(p)->uid == who; - rcu_read_unlock(); - if (!match) + if (__task_cred(p)->uid != who) continue; ret = set_task_ioprio(p, ioprio); if (ret) @@ -160,7 +148,7 @@ free_uid: ret = -EINVAL; } - read_unlock(&tasklist_lock); + rcu_read_unlock(); return ret; } @@ -204,17 +192,15 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who) int ret = -ESRCH; int tmpio; - read_lock(&tasklist_lock); + rcu_read_lock(); switch (which) { case IOPRIO_WHO_PROCESS: - rcu_read_lock(); if (!who) p = current; else p = find_task_by_vpid(who); if (p) ret = get_task_ioprio(p); - rcu_read_unlock(); break; case IOPRIO_WHO_PGRP: if (!who) @@ -241,12 +227,7 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who) break; do_each_thread(g, p) { - int match; - - rcu_read_lock(); - match = __task_cred(p)->uid == user->uid; - rcu_read_unlock(); - if (!match) + if (__task_cred(p)->uid != user->uid) continue; tmpio = get_task_ioprio(p); if (tmpio < 0) @@ -264,6 +245,6 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who) ret = -EINVAL; } - read_unlock(&tasklist_lock); + rcu_read_unlock(); return ret; } diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index c590d155c095..f837ba953529 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -899,6 +899,14 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev, /* journal descriptor can store up to n blocks -bzzz */ journal->j_blocksize = blocksize; + journal->j_dev = bdev; + journal->j_fs_dev = fs_dev; + journal->j_blk_offset = start; + journal->j_maxlen = len; + bdevname(journal->j_dev, journal->j_devname); + p = journal->j_devname; + while ((p = strchr(p, '/'))) + *p = '!'; jbd2_stats_proc_init(journal); n = journal->j_blocksize / sizeof(journal_block_tag_t); journal->j_wbufsize = n; @@ -908,14 +916,6 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev, __func__); goto out_err; } - journal->j_dev = bdev; - journal->j_fs_dev = fs_dev; - journal->j_blk_offset = start; - journal->j_maxlen = len; - bdevname(journal->j_dev, journal->j_devname); - p = journal->j_devname; - while ((p = strchr(p, '/'))) - *p = '!'; bh = __getblk(journal->j_dev, start, journal->j_blocksize); if (!bh) { diff --git a/fs/namei.c b/fs/namei.c index 5362af9b7372..4ff7ca530533 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1748,6 +1748,9 @@ struct file *do_filp_open(int dfd, const char *pathname, if (!(open_flag & O_CREAT)) mode = 0; + /* Must never be set by userspace */ + open_flag &= ~FMODE_NONOTIFY; + /* * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only * check for O_DSYNC if the need any syncing at all we enforce it's diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 662df2a5fad5..996dd8989a91 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -57,7 +57,7 @@ static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); static int nfs_fsync_dir(struct file *, int); static loff_t nfs_llseek_dir(struct file *, loff_t, int); -static int nfs_readdir_clear_array(struct page*, gfp_t); +static void nfs_readdir_clear_array(struct page*); const struct file_operations nfs_dir_operations = { .llseek = nfs_llseek_dir, @@ -83,8 +83,8 @@ const struct inode_operations nfs_dir_inode_operations = { .setattr = nfs_setattr, }; -const struct address_space_operations nfs_dir_addr_space_ops = { - .releasepage = nfs_readdir_clear_array, +const struct address_space_operations nfs_dir_aops = { + .freepage = nfs_readdir_clear_array, }; #ifdef CONFIG_NFS_V3 @@ -162,6 +162,7 @@ struct nfs_cache_array_entry { u64 cookie; u64 ino; struct qstr string; + unsigned char d_type; }; struct nfs_cache_array { @@ -171,14 +172,13 @@ struct nfs_cache_array { struct nfs_cache_array_entry array[0]; }; -#define MAX_READDIR_ARRAY ((PAGE_SIZE - sizeof(struct nfs_cache_array)) / sizeof(struct nfs_cache_array_entry)) - typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); typedef struct { struct file *file; struct page *page; unsigned long page_index; u64 *dir_cookie; + u64 last_cookie; loff_t current_index; decode_dirent_t decode; @@ -214,17 +214,15 @@ void nfs_readdir_release_array(struct page *page) * we are freeing strings created by nfs_add_to_readdir_array() */ static -int nfs_readdir_clear_array(struct page *page, gfp_t mask) +void nfs_readdir_clear_array(struct page *page) { - struct nfs_cache_array *array = nfs_readdir_get_array(page); + struct nfs_cache_array *array; int i; - if (IS_ERR(array)) - return PTR_ERR(array); + array = kmap_atomic(page, KM_USER0); for (i = 0; i < array->size; i++) kfree(array->array[i].string.name); - nfs_readdir_release_array(page); - return 0; + kunmap_atomic(array, KM_USER0); } /* @@ -257,19 +255,23 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page) if (IS_ERR(array)) return PTR_ERR(array); + + cache_entry = &array->array[array->size]; + + /* Check that this entry lies within the page bounds */ ret = -ENOSPC; - if (array->size >= MAX_READDIR_ARRAY) + if ((char *)&cache_entry[1] - (char *)page_address(page) > PAGE_SIZE) goto out; - cache_entry = &array->array[array->size]; cache_entry->cookie = entry->prev_cookie; cache_entry->ino = entry->ino; + cache_entry->d_type = entry->d_type; ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len); if (ret) goto out; array->last_cookie = entry->cookie; array->size++; - if (entry->eof == 1) + if (entry->eof != 0) array->eof_index = array->size; out: nfs_readdir_release_array(page); @@ -309,15 +311,14 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des for (i = 0; i < array->size; i++) { if (array->array[i].cookie == *desc->dir_cookie) { desc->cache_entry_index = i; - status = 0; - goto out; + return 0; } } - if (i == array->eof_index) { - desc->eof = 1; + if (array->eof_index >= 0) { status = -EBADCOOKIE; + if (*desc->dir_cookie == array->last_cookie) + desc->eof = 1; } -out: return status; } @@ -325,10 +326,7 @@ static int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) { struct nfs_cache_array *array; - int status = -EBADCOOKIE; - - if (desc->dir_cookie == NULL) - goto out; + int status; array = nfs_readdir_get_array(desc->page); if (IS_ERR(array)) { @@ -341,6 +339,10 @@ int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) else status = nfs_readdir_search_for_cookie(array, desc); + if (status == -EAGAIN) { + desc->last_cookie = array->last_cookie; + desc->page_index++; + } nfs_readdir_release_array(desc->page); out: return status; @@ -392,13 +394,9 @@ int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct x static int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) { - struct nfs_inode *node; if (dentry->d_inode == NULL) goto different; - node = NFS_I(dentry->d_inode); - if (node->fh.size != entry->fh->size) - goto different; - if (strncmp(node->fh.data, entry->fh->data, node->fh.size) != 0) + if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0) goto different; return 1; different: @@ -466,8 +464,9 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en struct xdr_stream stream; struct xdr_buf buf; __be32 *ptr = xdr_page; - int status; struct nfs_cache_array *array; + unsigned int count = 0; + int status; buf.head->iov_base = xdr_page; buf.head->iov_len = buflen; @@ -488,7 +487,9 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en break; } - if (desc->plus == 1) + count++; + + if (desc->plus != 0) nfs_prime_dcache(desc->file->f_path.dentry, entry); status = nfs_readdir_add_to_array(entry, page); @@ -496,13 +497,14 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en break; } while (!entry->eof); - if (status == -EBADCOOKIE && entry->eof) { + if (count == 0 || (status == -EBADCOOKIE && entry->eof != 0)) { array = nfs_readdir_get_array(page); if (!IS_ERR(array)) { array->eof_index = array->size; status = 0; nfs_readdir_release_array(page); - } + } else + status = PTR_ERR(array); } return status; } @@ -560,7 +562,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, unsigned int array_size = ARRAY_SIZE(pages); entry.prev_cookie = 0; - entry.cookie = *desc->dir_cookie; + entry.cookie = desc->last_cookie; entry.eof = 0; entry.fh = nfs_alloc_fhandle(); entry.fattr = nfs_alloc_fattr(); @@ -633,6 +635,8 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page) static void cache_page_release(nfs_readdir_descriptor_t *desc) { + if (!desc->page->mapping) + nfs_readdir_clear_array(desc->page); page_cache_release(desc->page); desc->page = NULL; } @@ -657,9 +661,8 @@ int find_cache_page(nfs_readdir_descriptor_t *desc) return PTR_ERR(desc->page); res = nfs_readdir_search_array(desc); - if (res == 0) - return 0; - cache_page_release(desc); + if (res != 0) + cache_page_release(desc); return res; } @@ -669,22 +672,16 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) { int res; - if (desc->page_index == 0) + if (desc->page_index == 0) { desc->current_index = 0; - while (1) { - res = find_cache_page(desc); - if (res != -EAGAIN) - break; - desc->page_index++; + desc->last_cookie = 0; } + do { + res = find_cache_page(desc); + } while (res == -EAGAIN); return res; } -static inline unsigned int dt_type(struct inode *inode) -{ - return (inode->i_mode >> 12) & 15; -} - /* * Once we've found the start of the dirent within a page: fill 'er up... */ @@ -696,35 +693,35 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, int i = 0; int res = 0; struct nfs_cache_array *array = NULL; - unsigned int d_type = DT_UNKNOWN; - struct dentry *dentry = NULL; array = nfs_readdir_get_array(desc->page); - if (IS_ERR(array)) - return PTR_ERR(array); + if (IS_ERR(array)) { + res = PTR_ERR(array); + goto out; + } for (i = desc->cache_entry_index; i < array->size; i++) { - d_type = DT_UNKNOWN; + struct nfs_cache_array_entry *ent; - res = filldir(dirent, array->array[i].string.name, - array->array[i].string.len, file->f_pos, - nfs_compat_user_ino64(array->array[i].ino), d_type); - if (res < 0) + ent = &array->array[i]; + if (filldir(dirent, ent->string.name, ent->string.len, + file->f_pos, nfs_compat_user_ino64(ent->ino), + ent->d_type) < 0) { + desc->eof = 1; break; + } file->f_pos++; - desc->cache_entry_index = i; if (i < (array->size-1)) *desc->dir_cookie = array->array[i+1].cookie; else *desc->dir_cookie = array->last_cookie; } - if (i == array->eof_index) + if (array->eof_index >= 0) desc->eof = 1; nfs_readdir_release_array(desc->page); +out: cache_page_release(desc); - if (dentry != NULL) - dput(dentry); dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (unsigned long long)*desc->dir_cookie, res); return res; @@ -759,13 +756,14 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, goto out; } - if (nfs_readdir_xdr_to_array(desc, page, inode) == -1) { - status = -EIO; - goto out_release; - } - desc->page_index = 0; + desc->last_cookie = *desc->dir_cookie; desc->page = page; + + status = nfs_readdir_xdr_to_array(desc, page, inode); + if (status < 0) + goto out_release; + status = nfs_do_filldir(desc, dirent, filldir); out: @@ -787,7 +785,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) struct inode *inode = dentry->d_inode; nfs_readdir_descriptor_t my_desc, *desc = &my_desc; - int res = -ENOMEM; + int res; dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", dentry->d_parent->d_name.name, dentry->d_name.name, @@ -812,18 +810,18 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) if (res < 0) goto out; - while (desc->eof != 1) { + do { res = readdir_search_pagecache(desc); if (res == -EBADCOOKIE) { + res = 0; /* This means either end of directory */ if (*desc->dir_cookie && desc->eof == 0) { /* Or that the server has 'lost' a cookie */ res = uncached_readdir(desc, dirent, filldir); - if (res >= 0) + if (res == 0) continue; } - res = 0; break; } if (res == -ETOOSMALL && desc->plus) { @@ -838,11 +836,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) break; res = nfs_do_filldir(desc, dirent, filldir); - if (res < 0) { - res = 0; + if (res < 0) break; - } - } + } while (!desc->eof); out: nfs_unblock_sillyrename(dentry); if (res > 0) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 84d3c8b90206..e6ace0d93c71 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -867,7 +867,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, goto out; nfs_alloc_commit_data(dreq); - if (dreq->commit_data == NULL || count < wsize) + if (dreq->commit_data == NULL || count <= wsize) sync = NFS_FILE_SYNC; dreq->inode = inode; diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 60677f9f1311..7bf029ef4084 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -693,6 +693,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) { struct inode *inode = filp->f_mapping->host; int status = 0; + unsigned int saved_type = fl->fl_type; /* Try local locking first */ posix_test_lock(filp, fl); @@ -700,6 +701,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) /* found a conflict */ goto out; } + fl->fl_type = saved_type; if (nfs_have_delegation(inode, FMODE_READ)) goto out_noconflict; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 314f57164602..e67e31c73416 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -289,6 +289,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) } else if (S_ISDIR(inode->i_mode)) { inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; inode->i_fop = &nfs_dir_operations; + inode->i_data.a_ops = &nfs_dir_aops; if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)) set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); /* Deal with crossing mountpoints */ diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index db08ff3ff454..e6356b750b77 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -362,6 +362,15 @@ unsigned int nfs_page_length(struct page *page) } /* + * Convert a umode to a dirent->d_type + */ +static inline +unsigned char nfs_umode_to_dtype(umode_t mode) +{ + return (mode >> 12) & 15; +} + +/* * Determine the number of pages in an array of length 'len' and * with a base offset of 'base' */ diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index eceafe74f473..4f981f1f6689 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -505,13 +505,13 @@ static struct rpc_procinfo mnt3_procedures[] = { static struct rpc_version mnt_version1 = { .number = 1, - .nrprocs = 2, + .nrprocs = ARRAY_SIZE(mnt_procedures), .procs = mnt_procedures, }; static struct rpc_version mnt_version3 = { .number = 3, - .nrprocs = 2, + .nrprocs = ARRAY_SIZE(mnt3_procedures), .procs = mnt3_procedures, }; diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 2563f765c9b4..5914a1911c95 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -485,6 +485,8 @@ nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_se entry->prev_cookie = entry->cookie; entry->cookie = ntohl(*p++); + entry->d_type = DT_UNKNOWN; + p = xdr_inline_peek(xdr, 8); if (p != NULL) entry->eof = !p[0] && p[1]; @@ -495,7 +497,7 @@ nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_se out_overflow: print_overflow_msg(__func__, xdr); - return ERR_PTR(-EIO); + return ERR_PTR(-EAGAIN); } /* diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 748dc91a4a14..f6cc60f06dac 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -622,11 +622,13 @@ nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_s entry->prev_cookie = entry->cookie; p = xdr_decode_hyper(p, &entry->cookie); + entry->d_type = DT_UNKNOWN; if (plus) { entry->fattr->valid = 0; p = xdr_decode_post_op_attr_stream(xdr, entry->fattr); if (IS_ERR(p)) goto out_overflow_exit; + entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); /* In fact, a post_op_fh3: */ p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) @@ -656,7 +658,7 @@ nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_s out_overflow: print_overflow_msg(__func__, xdr); out_overflow_exit: - return ERR_PTR(-EIO); + return ERR_PTR(-EAGAIN); } /* diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6a653ffd8e4e..4435e5e1f904 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3361,6 +3361,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) ret = nfs_revalidate_inode(server, inode); if (ret < 0) return ret; + if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) + nfs_zap_acl_cache(inode); ret = nfs4_read_cached_acl(inode, buf, buflen); if (ret != -ENOENT) return ret; @@ -3389,6 +3391,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl nfs_inode_return_delegation(inode); buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); ret = nfs4_call_sync(server, &msg, &arg, &res, 1); + /* + * Acl update can result in inode attribute update. + * so mark the attribute cache invalid. + */ + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR; + spin_unlock(&inode->i_lock); nfs_access_zap_cache(inode); nfs_zap_acl_cache(inode); return ret; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index b7a204ff6fe1..9f1826b012e6 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -6208,6 +6208,10 @@ __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) entry->ino = entry->fattr->fileid; + entry->d_type = DT_UNKNOWN; + if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE) + entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); + if (verify_attr_len(xdr, p, len) < 0) goto out_overflow; @@ -6221,7 +6225,7 @@ __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, out_overflow: print_overflow_msg(__func__, xdr); - return ERR_PTR(-EIO); + return ERR_PTR(-EAGAIN); } /* diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 137b549e63db..b68536cc9046 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -115,7 +115,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) { if (!nfs_lock_request_dontget(req)) return 0; - if (req->wb_page != NULL) + if (test_bit(PG_MAPPED, &req->wb_flags)) radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); return 1; } @@ -125,7 +125,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) */ void nfs_clear_page_tag_locked(struct nfs_page *req) { - if (req->wb_page != NULL) { + if (test_bit(PG_MAPPED, &req->wb_flags)) { struct inode *inode = req->wb_context->path.dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); diff --git a/fs/nfs/read.c b/fs/nfs/read.c index e4b62c6f5a6e..aedcaa7f291f 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -152,7 +152,6 @@ static void nfs_readpage_release(struct nfs_page *req) (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); - nfs_clear_request(req); nfs_release_request(req); } diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 3c045044fca2..4100630c9a5b 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1069,12 +1069,10 @@ static int nfs_parse_mount_options(char *raw, mnt->flags |= NFS_MOUNT_VER3; mnt->version = 3; break; -#ifdef CONFIG_NFS_V4 case Opt_v4: mnt->flags &= ~NFS_MOUNT_VER3; mnt->version = 4; break; -#endif case Opt_udp: mnt->flags &= ~NFS_MOUNT_TCP; mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; @@ -1286,12 +1284,10 @@ static int nfs_parse_mount_options(char *raw, mnt->flags |= NFS_MOUNT_VER3; mnt->version = 3; break; -#ifdef CONFIG_NFS_V4 case NFS4_VERSION: mnt->flags &= ~NFS_MOUNT_VER3; mnt->version = 4; break; -#endif default: goto out_invalid_value; } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 4c14c17a5276..10d648ea128b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -390,6 +390,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) if (nfs_have_delegation(inode, FMODE_WRITE)) nfsi->change_attr++; } + set_bit(PG_MAPPED, &req->wb_flags); SetPagePrivate(req->wb_page); set_page_private(req->wb_page, (unsigned long)req); nfsi->npages++; @@ -415,6 +416,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) spin_lock(&inode->i_lock); set_page_private(req->wb_page, 0); ClearPagePrivate(req->wb_page); + clear_bit(PG_MAPPED, &req->wb_flags); radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); nfsi->npages--; if (!nfsi->npages) { @@ -422,7 +424,6 @@ static void nfs_inode_remove_request(struct nfs_page *req) iput(inode); } else spin_unlock(&inode->i_lock); - nfs_clear_request(req); nfs_release_request(req); } diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 2a533a0af2a9..7e84a852cdae 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -260,9 +260,11 @@ void fill_post_wcc(struct svc_fh *fhp) err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, &fhp->fh_post_attr); fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; - if (err) + if (err) { fhp->fh_post_saved = 0; - else + /* Grab the ctime anyway - set_change_info might use it */ + fhp->fh_post_attr.ctime = fhp->fh_dentry->d_inode->i_ctime; + } else fhp->fh_post_saved = 1; } diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 4d476ff08ae6..60fce3dc5cb5 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -484,18 +484,17 @@ static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp) static inline void set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) { - BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved); - cinfo->atomic = 1; + BUG_ON(!fhp->fh_pre_saved); + cinfo->atomic = fhp->fh_post_saved; cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode); - if (cinfo->change_supported) { - cinfo->before_change = fhp->fh_pre_change; - cinfo->after_change = fhp->fh_post_change; - } else { - cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; - cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; - cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; - cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; - } + + cinfo->before_change = fhp->fh_pre_change; + cinfo->after_change = fhp->fh_post_change; + cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; + cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; + cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; + cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; + } int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index 49c844dab33a..59e5fe742f7b 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c @@ -335,7 +335,7 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr) * the device at this point. * * To prevent nilfs_dat_translate() from returning the - * uncommited block number, this makes a copy of the entry + * uncommitted block number, this makes a copy of the entry * buffer and redirects nilfs_dat_translate() to the copy. */ if (!buffer_nilfs_redirected(entry_bh)) { diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index 33ad25ddd5c4..caf9a6a3fb54 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c @@ -176,7 +176,6 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh) int nilfs_init_gcinode(struct inode *inode) { struct nilfs_inode_info *ii = NILFS_I(inode); - struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; inode->i_mode = S_IFREG; mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); @@ -186,14 +185,6 @@ int nilfs_init_gcinode(struct inode *inode) ii->i_flags = 0; nilfs_bmap_init_gc(ii->i_bmap); - /* - * Add the inode to GC inode list. Garbage Collection - * is serialized and no two processes manipulate the - * list simultaneously. - */ - igrab(inode); - list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes); - return 0; } diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 3e90f86d5bfe..b185e937a335 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -337,6 +337,7 @@ static int nilfs_ioctl_move_blocks(struct super_block *sb, struct nilfs_argv *argv, void *buf) { size_t nmembs = argv->v_nmembs; + struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs; struct inode *inode; struct nilfs_vdesc *vdesc; struct buffer_head *bh, *n; @@ -349,10 +350,21 @@ static int nilfs_ioctl_move_blocks(struct super_block *sb, ino = vdesc->vd_ino; cno = vdesc->vd_cno; inode = nilfs_iget_for_gc(sb, ino, cno); - if (unlikely(inode == NULL)) { - ret = -ENOMEM; + if (IS_ERR(inode)) { + ret = PTR_ERR(inode); goto failed; } + if (list_empty(&NILFS_I(inode)->i_dirty)) { + /* + * Add the inode to GC inode list. Garbage Collection + * is serialized and no two processes manipulate the + * list simultaneously. + */ + igrab(inode); + list_add(&NILFS_I(inode)->i_dirty, + &nilfs->ns_gc_inodes); + } + do { ret = nilfs_ioctl_move_inode_block(inode, vdesc, &buffers); diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index b04f88eed09e..f35794b97e8e 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -92,7 +92,11 @@ static int fanotify_get_response_from_access(struct fsnotify_group *group, pr_debug("%s: group=%p event=%p\n", __func__, group, event); - wait_event(group->fanotify_data.access_waitq, event->response); + wait_event(group->fanotify_data.access_waitq, event->response || + atomic_read(&group->fanotify_data.bypass_perm)); + + if (!event->response) /* bypass_perm set */ + return 0; /* userspace responded, convert to something usable */ spin_lock(&event->lock); diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 063224812b7e..8b61220cffc5 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -106,20 +106,29 @@ static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event) return client_fd; } -static ssize_t fill_event_metadata(struct fsnotify_group *group, +static int fill_event_metadata(struct fsnotify_group *group, struct fanotify_event_metadata *metadata, struct fsnotify_event *event) { + int ret = 0; + pr_debug("%s: group=%p metadata=%p event=%p\n", __func__, group, metadata, event); metadata->event_len = FAN_EVENT_METADATA_LEN; + metadata->metadata_len = FAN_EVENT_METADATA_LEN; metadata->vers = FANOTIFY_METADATA_VERSION; metadata->mask = event->mask & FAN_ALL_OUTGOING_EVENTS; metadata->pid = pid_vnr(event->tgid); - metadata->fd = create_fd(group, event); + if (unlikely(event->mask & FAN_Q_OVERFLOW)) + metadata->fd = FAN_NOFD; + else { + metadata->fd = create_fd(group, event); + if (metadata->fd < 0) + ret = metadata->fd; + } - return metadata->fd; + return ret; } #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS @@ -200,7 +209,7 @@ static int prepare_for_access_response(struct fsnotify_group *group, mutex_lock(&group->fanotify_data.access_mutex); - if (group->fanotify_data.bypass_perm) { + if (atomic_read(&group->fanotify_data.bypass_perm)) { mutex_unlock(&group->fanotify_data.access_mutex); kmem_cache_free(fanotify_response_event_cache, re); event->response = FAN_ALLOW; @@ -257,24 +266,34 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, pr_debug("%s: group=%p event=%p\n", __func__, group, event); - fd = fill_event_metadata(group, &fanotify_event_metadata, event); - if (fd < 0) - return fd; + ret = fill_event_metadata(group, &fanotify_event_metadata, event); + if (ret < 0) + goto out; + fd = fanotify_event_metadata.fd; ret = prepare_for_access_response(group, event, fd); if (ret) goto out_close_fd; ret = -EFAULT; - if (copy_to_user(buf, &fanotify_event_metadata, FAN_EVENT_METADATA_LEN)) + if (copy_to_user(buf, &fanotify_event_metadata, + fanotify_event_metadata.event_len)) goto out_kill_access_response; - return FAN_EVENT_METADATA_LEN; + return fanotify_event_metadata.event_len; out_kill_access_response: remove_access_response(group, event, fd); out_close_fd: - sys_close(fd); + if (fd != FAN_NOFD) + sys_close(fd); +out: +#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS + if (event->mask & FAN_ALL_PERM_EVENTS) { + event->response = FAN_DENY; + wake_up(&group->fanotify_data.access_waitq); + } +#endif return ret; } @@ -382,7 +401,7 @@ static int fanotify_release(struct inode *ignored, struct file *file) mutex_lock(&group->fanotify_data.access_mutex); - group->fanotify_data.bypass_perm = true; + atomic_inc(&group->fanotify_data.bypass_perm); list_for_each_entry_safe(re, lre, &group->fanotify_data.access_list, list) { pr_debug("%s: found group=%p re=%p event=%p\n", __func__, group, @@ -586,11 +605,10 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, { struct fsnotify_mark *fsn_mark; __u32 added; + int ret = 0; fsn_mark = fsnotify_find_vfsmount_mark(group, mnt); if (!fsn_mark) { - int ret; - if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks) return -ENOSPC; @@ -600,17 +618,16 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, fsnotify_init_mark(fsn_mark, fanotify_free_mark); ret = fsnotify_add_mark(fsn_mark, group, NULL, mnt, 0); - if (ret) { - fanotify_free_mark(fsn_mark); - return ret; - } + if (ret) + goto err; } added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); - fsnotify_put_mark(fsn_mark); + if (added & ~mnt->mnt_fsnotify_mask) fsnotify_recalc_vfsmount_mask(mnt); - - return 0; +err: + fsnotify_put_mark(fsn_mark); + return ret; } static int fanotify_add_inode_mark(struct fsnotify_group *group, @@ -619,6 +636,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, { struct fsnotify_mark *fsn_mark; __u32 added; + int ret = 0; pr_debug("%s: group=%p inode=%p\n", __func__, group, inode); @@ -634,8 +652,6 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, fsn_mark = fsnotify_find_inode_mark(group, inode); if (!fsn_mark) { - int ret; - if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks) return -ENOSPC; @@ -645,16 +661,16 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, fsnotify_init_mark(fsn_mark, fanotify_free_mark); ret = fsnotify_add_mark(fsn_mark, group, inode, NULL, 0); - if (ret) { - fanotify_free_mark(fsn_mark); - return ret; - } + if (ret) + goto err; } added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); - fsnotify_put_mark(fsn_mark); + if (added & ~inode->i_fsnotify_mask) fsnotify_recalc_inode_mask(inode); - return 0; +err: + fsnotify_put_mark(fsn_mark); + return ret; } /* fanotify syscalls */ @@ -687,8 +703,10 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ group = fsnotify_alloc_group(&fanotify_fsnotify_ops); - if (IS_ERR(group)) + if (IS_ERR(group)) { + free_uid(user); return PTR_ERR(group); + } group->fanotify_data.user = user; atomic_inc(&user->fanotify_listeners); @@ -698,6 +716,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) mutex_init(&group->fanotify_data.access_mutex); init_waitqueue_head(&group->fanotify_data.access_waitq); INIT_LIST_HEAD(&group->fanotify_data.access_list); + atomic_set(&group->fanotify_data.bypass_perm, 0); #endif switch (flags & FAN_ALL_CLASS_BITS) { case FAN_CLASS_NOTIF: @@ -764,8 +783,10 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags, if (flags & ~FAN_ALL_MARK_FLAGS) return -EINVAL; switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { - case FAN_MARK_ADD: + case FAN_MARK_ADD: /* fallthrough */ case FAN_MARK_REMOVE: + if (!mask) + return -EINVAL; case FAN_MARK_FLUSH: break; default: diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 444c305a468c..4cd5d5d78f9f 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -752,6 +752,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags) if (ret >= 0) return ret; + fsnotify_put_group(group); atomic_dec(&user->inotify_devs); out_free_uid: free_uid(user); diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 52c7557f3e25..9f26ac9be2a4 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -1964,8 +1964,10 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g if (reg == NULL) return ERR_PTR(-ENOMEM); - if (strlen(name) > O2HB_MAX_REGION_NAME_LEN) - return ERR_PTR(-ENAMETOOLONG); + if (strlen(name) > O2HB_MAX_REGION_NAME_LEN) { + ret = -ENAMETOOLONG; + goto free; + } spin_lock(&o2hb_live_lock); reg->hr_region_num = 0; @@ -1974,7 +1976,8 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g O2NM_MAX_REGIONS); if (reg->hr_region_num >= O2NM_MAX_REGIONS) { spin_unlock(&o2hb_live_lock); - return ERR_PTR(-EFBIG); + ret = -EFBIG; + goto free; } set_bit(reg->hr_region_num, o2hb_region_bitmap); } @@ -1986,10 +1989,13 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g ret = o2hb_debug_region_init(reg, o2hb_debug_dir); if (ret) { config_item_put(®->hr_item); - return ERR_PTR(ret); + goto free; } return ®->hr_item; +free: + kfree(reg); + return ERR_PTR(ret); } static void o2hb_heartbeat_group_drop_item(struct config_group *group, diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index edaded48e7e9..895532ac4d98 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c @@ -476,7 +476,6 @@ static void ocfs2_dentry_iput(struct dentry *dentry, struct inode *inode) out: iput(inode); - ocfs2_dentry_attach_gen(dentry); } /* diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 58a93b953735..cc2aaa96cfe5 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -959,7 +959,7 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, r += O2HB_MAX_REGION_NAME_LEN; } - local = kmalloc(sizeof(qr->qr_regions), GFP_KERNEL); + local = kmalloc(sizeof(qr->qr_regions), GFP_ATOMIC); if (!local) { status = -ENOMEM; goto bail; diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 1efea3615589..70dd3b1798f1 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -159,9 +159,9 @@ struct ocfs2_lock_res { char l_name[OCFS2_LOCK_ID_MAX_LEN]; unsigned int l_ro_holders; unsigned int l_ex_holders; - char l_level; - char l_requested; - char l_blocking; + signed char l_level; + signed char l_requested; + signed char l_blocking; /* Data packed - type enum ocfs2_lock_type */ unsigned char l_type; diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index 252e7c82f929..a5ebe421195f 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c @@ -190,7 +190,7 @@ static struct ocfs2_live_connection *ocfs2_connection_find(const char *name) return c; } - return c; + return NULL; } /* diff --git a/fs/pipe.c b/fs/pipe.c index a8012a955720..04629f36e397 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1199,12 +1199,24 @@ int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf, return ret; } +/* + * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same + * location, so checking ->i_pipe is not enough to verify that this is a + * pipe. + */ +struct pipe_inode_info *get_pipe_info(struct file *file) +{ + struct inode *i = file->f_path.dentry->d_inode; + + return S_ISFIFO(i->i_mode) ? i->i_pipe : NULL; +} + long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) { struct pipe_inode_info *pipe; long ret; - pipe = file->f_path.dentry->d_inode->i_pipe; + pipe = get_pipe_info(file); if (!pipe) return -EBADF; diff --git a/fs/proc/base.c b/fs/proc/base.c index f3d02ca461ec..182845147fe4 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1574,7 +1574,7 @@ static int do_proc_readlink(struct path *path, char __user *buffer, int buflen) if (!tmp) return -ENOMEM; - pathname = d_path_with_unreachable(path, tmp, PAGE_SIZE); + pathname = d_path(path, tmp, PAGE_SIZE); len = PTR_ERR(pathname); if (IS_ERR(pathname)) goto out; diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index da6b01d70f01..c126c83b9a45 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -706,6 +706,7 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, * skip over unmapped regions. */ #define PAGEMAP_WALK_SIZE (PMD_SIZE) +#define PAGEMAP_WALK_MASK (PMD_MASK) static ssize_t pagemap_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -776,7 +777,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, unsigned long end; pm.pos = 0; - end = start_vaddr + PAGEMAP_WALK_SIZE; + end = (start_vaddr + PAGEMAP_WALK_SIZE) & PAGEMAP_WALK_MASK; /* overflow ? */ if (end < start_vaddr || end > end_vaddr) end = end_vaddr; diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index bd9763e76bae..79265fdc317a 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c @@ -183,12 +183,11 @@ int reiserfs_unpack(struct inode *inode, struct file *filp) return 0; } - /* we need to make sure nobody is changing the file size beneath - ** us - */ - reiserfs_mutex_lock_safe(&inode->i_mutex, inode->i_sb); depth = reiserfs_write_lock_once(inode->i_sb); + /* we need to make sure nobody is changing the file size beneath us */ + reiserfs_mutex_lock_safe(&inode->i_mutex, inode->i_sb); + write_from = inode->i_size & (blocksize - 1); /* if we are on a block boundary, we are already unpacked. */ if (write_from == 0) { diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index 536d697a8a28..90d2fcb67a31 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -472,7 +472,9 @@ int reiserfs_acl_chmod(struct inode *inode) struct reiserfs_transaction_handle th; size_t size = reiserfs_xattr_nblocks(inode, reiserfs_acl_size(clone->a_count)); - reiserfs_write_lock(inode->i_sb); + int depth; + + depth = reiserfs_write_lock_once(inode->i_sb); error = journal_begin(&th, inode->i_sb, size * 2); if (!error) { int error2; @@ -482,7 +484,7 @@ int reiserfs_acl_chmod(struct inode *inode) if (error2) error = error2; } - reiserfs_write_unlock(inode->i_sb); + reiserfs_write_unlock_once(inode->i_sb, depth); } posix_acl_release(clone); return error; diff --git a/fs/splice.c b/fs/splice.c index 8f1dfaecc8f0..ce2f02579e35 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1311,18 +1311,6 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe, struct pipe_inode_info *opipe, size_t len, unsigned int flags); -/* - * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same - * location, so checking ->i_pipe is not enough to verify that this is a - * pipe. - */ -static inline struct pipe_inode_info *pipe_info(struct inode *inode) -{ - if (S_ISFIFO(inode->i_mode)) - return inode->i_pipe; - - return NULL; -} /* * Determine where to splice to/from. @@ -1336,8 +1324,8 @@ static long do_splice(struct file *in, loff_t __user *off_in, loff_t offset, *off; long ret; - ipipe = pipe_info(in->f_path.dentry->d_inode); - opipe = pipe_info(out->f_path.dentry->d_inode); + ipipe = get_pipe_info(in); + opipe = get_pipe_info(out); if (ipipe && opipe) { if (off_in || off_out) @@ -1555,7 +1543,7 @@ static long vmsplice_to_user(struct file *file, const struct iovec __user *iov, int error; long ret; - pipe = pipe_info(file->f_path.dentry->d_inode); + pipe = get_pipe_info(file); if (!pipe) return -EBADF; @@ -1642,7 +1630,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, }; long ret; - pipe = pipe_info(file->f_path.dentry->d_inode); + pipe = get_pipe_info(file); if (!pipe) return -EBADF; @@ -2022,8 +2010,8 @@ static int link_pipe(struct pipe_inode_info *ipipe, static long do_tee(struct file *in, struct file *out, size_t len, unsigned int flags) { - struct pipe_inode_info *ipipe = pipe_info(in->f_path.dentry->d_inode); - struct pipe_inode_info *opipe = pipe_info(out->f_path.dentry->d_inode); + struct pipe_inode_info *ipipe = get_pipe_info(in); + struct pipe_inode_info *opipe = get_pipe_info(out); int ret = -EINVAL; /* diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 7d287afccde5..691f61223ed6 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -934,7 +934,6 @@ xfs_aops_discard_page( struct xfs_inode *ip = XFS_I(inode); struct buffer_head *bh, *head; loff_t offset = page_offset(page); - ssize_t len = 1 << inode->i_blkbits; if (!xfs_is_delayed_page(page, IO_DELAY)) goto out_invalidate; @@ -949,58 +948,14 @@ xfs_aops_discard_page( xfs_ilock(ip, XFS_ILOCK_EXCL); bh = head = page_buffers(page); do { - int done; - xfs_fileoff_t offset_fsb; - xfs_bmbt_irec_t imap; - int nimaps = 1; int error; - xfs_fsblock_t firstblock; - xfs_bmap_free_t flist; + xfs_fileoff_t start_fsb; if (!buffer_delay(bh)) goto next_buffer; - offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset); - - /* - * Map the range first and check that it is a delalloc extent - * before trying to unmap the range. Otherwise we will be - * trying to remove a real extent (which requires a - * transaction) or a hole, which is probably a bad idea... - */ - error = xfs_bmapi(NULL, ip, offset_fsb, 1, - XFS_BMAPI_ENTIRE, NULL, 0, &imap, - &nimaps, NULL); - - if (error) { - /* something screwed, just bail */ - if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { - xfs_fs_cmn_err(CE_ALERT, ip->i_mount, - "page discard failed delalloc mapping lookup."); - } - break; - } - if (!nimaps) { - /* nothing there */ - goto next_buffer; - } - if (imap.br_startblock != DELAYSTARTBLOCK) { - /* been converted, ignore */ - goto next_buffer; - } - WARN_ON(imap.br_blockcount == 0); - - /* - * Note: while we initialise the firstblock/flist pair, they - * should never be used because blocks should never be - * allocated or freed for a delalloc extent and hence we need - * don't cancel or finish them after the xfs_bunmapi() call. - */ - xfs_bmap_init(&flist, &firstblock); - error = xfs_bunmapi(NULL, ip, offset_fsb, 1, 0, 1, &firstblock, - &flist, &done); - - ASSERT(!flist.xbf_count && !flist.xbf_first); + start_fsb = XFS_B_TO_FSBT(ip->i_mount, offset); + error = xfs_bmap_punch_delalloc_range(ip, start_fsb, 1); if (error) { /* something screwed, just bail */ if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { @@ -1010,7 +965,7 @@ xfs_aops_discard_page( break; } next_buffer: - offset += len; + offset += 1 << inode->i_blkbits; } while ((bh = bh->b_this_page) != head); @@ -1505,11 +1460,42 @@ xfs_vm_write_failed( struct inode *inode = mapping->host; if (to > inode->i_size) { - struct iattr ia = { - .ia_valid = ATTR_SIZE | ATTR_FORCE, - .ia_size = inode->i_size, - }; - xfs_setattr(XFS_I(inode), &ia, XFS_ATTR_NOLOCK); + /* + * punch out the delalloc blocks we have already allocated. We + * don't call xfs_setattr() to do this as we may be in the + * middle of a multi-iovec write and so the vfs inode->i_size + * will not match the xfs ip->i_size and so it will zero too + * much. Hence we jus truncate the page cache to zero what is + * necessary and punch the delalloc blocks directly. + */ + struct xfs_inode *ip = XFS_I(inode); + xfs_fileoff_t start_fsb; + xfs_fileoff_t end_fsb; + int error; + + truncate_pagecache(inode, to, inode->i_size); + + /* + * Check if there are any blocks that are outside of i_size + * that need to be trimmed back. + */ + start_fsb = XFS_B_TO_FSB(ip->i_mount, inode->i_size) + 1; + end_fsb = XFS_B_TO_FSB(ip->i_mount, to); + if (end_fsb <= start_fsb) + return; + + xfs_ilock(ip, XFS_ILOCK_EXCL); + error = xfs_bmap_punch_delalloc_range(ip, start_fsb, + end_fsb - start_fsb); + if (error) { + /* something screwed, just bail */ + if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { + xfs_fs_cmn_err(CE_ALERT, ip->i_mount, + "xfs_vm_write_failed: unable to clean up ino %lld", + ip->i_ino); + } + } + xfs_iunlock(ip, XFS_ILOCK_EXCL); } } diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index aa1d353def29..4c5deb6e9e31 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -488,29 +488,16 @@ found: spin_unlock(&pag->pag_buf_lock); xfs_perag_put(pag); - /* Attempt to get the semaphore without sleeping, - * if this does not work then we need to drop the - * spinlock and do a hard attempt on the semaphore. - */ - if (down_trylock(&bp->b_sema)) { + if (xfs_buf_cond_lock(bp)) { + /* failed, so wait for the lock if requested. */ if (!(flags & XBF_TRYLOCK)) { - /* wait for buffer ownership */ xfs_buf_lock(bp); XFS_STATS_INC(xb_get_locked_waited); } else { - /* We asked for a trylock and failed, no need - * to look at file offset and length here, we - * know that this buffer at least overlaps our - * buffer and is locked, therefore our buffer - * either does not exist, or is this buffer. - */ xfs_buf_rele(bp); XFS_STATS_INC(xb_busy_locked); return NULL; } - } else { - /* trylock worked */ - XB_SET_OWNER(bp); } if (bp->b_flags & XBF_STALE) { @@ -876,10 +863,18 @@ xfs_buf_rele( */ /* - * Locks a buffer object, if it is not already locked. - * Note that this in no way locks the underlying pages, so it is only - * useful for synchronizing concurrent use of buffer objects, not for - * synchronizing independent access to the underlying pages. + * Locks a buffer object, if it is not already locked. Note that this in + * no way locks the underlying pages, so it is only useful for + * synchronizing concurrent use of buffer objects, not for synchronizing + * independent access to the underlying pages. + * + * If we come across a stale, pinned, locked buffer, we know that we are + * being asked to lock a buffer that has been reallocated. Because it is + * pinned, we know that the log has not been pushed to disk and hence it + * will still be locked. Rather than continuing to have trylock attempts + * fail until someone else pushes the log, push it ourselves before + * returning. This means that the xfsaild will not get stuck trying + * to push on stale inode buffers. */ int xfs_buf_cond_lock( @@ -890,6 +885,8 @@ xfs_buf_cond_lock( locked = down_trylock(&bp->b_sema) == 0; if (locked) XB_SET_OWNER(bp); + else if (atomic_read(&bp->b_pin_count) && (bp->b_flags & XBF_STALE)) + xfs_log_force(bp->b_target->bt_mount, 0); trace_xfs_buf_cond_lock(bp, _RET_IP_); return locked ? 0 : -EBUSY; diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 8abd12e32e13..4111cd3966c7 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -5471,8 +5471,13 @@ xfs_getbmap( if (error) goto out_unlock_iolock; } - - ASSERT(ip->i_delayed_blks == 0); + /* + * even after flushing the inode, there can still be delalloc + * blocks on the inode beyond EOF due to speculative + * preallocation. These are not removed until the release + * function is called or the inode is inactivated. Hence we + * cannot assert here that ip->i_delayed_blks == 0. + */ } lock = xfs_ilock_map_shared(ip); @@ -6070,3 +6075,79 @@ xfs_bmap_disk_count_leaves( *count += xfs_bmbt_disk_get_blockcount(frp); } } + +/* + * dead simple method of punching delalyed allocation blocks from a range in + * the inode. Walks a block at a time so will be slow, but is only executed in + * rare error cases so the overhead is not critical. This will alays punch out + * both the start and end blocks, even if the ranges only partially overlap + * them, so it is up to the caller to ensure that partial blocks are not + * passed in. + */ +int +xfs_bmap_punch_delalloc_range( + struct xfs_inode *ip, + xfs_fileoff_t start_fsb, + xfs_fileoff_t length) +{ + xfs_fileoff_t remaining = length; + int error = 0; + + ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + + do { + int done; + xfs_bmbt_irec_t imap; + int nimaps = 1; + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + + /* + * Map the range first and check that it is a delalloc extent + * before trying to unmap the range. Otherwise we will be + * trying to remove a real extent (which requires a + * transaction) or a hole, which is probably a bad idea... + */ + error = xfs_bmapi(NULL, ip, start_fsb, 1, + XFS_BMAPI_ENTIRE, NULL, 0, &imap, + &nimaps, NULL); + + if (error) { + /* something screwed, just bail */ + if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { + xfs_fs_cmn_err(CE_ALERT, ip->i_mount, + "Failed delalloc mapping lookup ino %lld fsb %lld.", + ip->i_ino, start_fsb); + } + break; + } + if (!nimaps) { + /* nothing there */ + goto next_block; + } + if (imap.br_startblock != DELAYSTARTBLOCK) { + /* been converted, ignore */ + goto next_block; + } + WARN_ON(imap.br_blockcount == 0); + + /* + * Note: while we initialise the firstblock/flist pair, they + * should never be used because blocks should never be + * allocated or freed for a delalloc extent and hence we need + * don't cancel or finish them after the xfs_bunmapi() call. + */ + xfs_bmap_init(&flist, &firstblock); + error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock, + &flist, &done); + if (error) + break; + + ASSERT(!flist.xbf_count && !flist.xbf_first); +next_block: + start_fsb++; + remaining--; + } while(remaining > 0); + + return error; +} diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index 71ec9b6ecdfc..3651191daea1 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h @@ -394,6 +394,11 @@ xfs_bmap_count_blocks( int whichfork, int *count); +int +xfs_bmap_punch_delalloc_range( + struct xfs_inode *ip, + xfs_fileoff_t start_fsb, + xfs_fileoff_t length); #endif /* __KERNEL__ */ #endif /* __XFS_BMAP_H__ */ diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 3b9582c60a22..e60490bc00a6 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c @@ -377,6 +377,19 @@ xfs_swap_extents( ip->i_d.di_format = tip->i_d.di_format; tip->i_d.di_format = tmp; + /* + * The extents in the source inode could still contain speculative + * preallocation beyond EOF (e.g. the file is open but not modified + * while defrag is in progress). In that case, we need to copy over the + * number of delalloc blocks the data fork in the source inode is + * tracking beyond EOF so that when the fork is truncated away when the + * temporary inode is unlinked we don't underrun the i_delayed_blks + * counter on that inode. + */ + ASSERT(tip->i_delayed_blks == 0); + tip->i_delayed_blks = ip->i_delayed_blks; + ip->i_delayed_blks = 0; + ilf_fields = XFS_ILOG_CORE; switch(ip->i_d.di_format) { diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c index ed9990267661..c78cc6a3d87c 100644 --- a/fs/xfs/xfs_error.c +++ b/fs/xfs/xfs_error.c @@ -58,6 +58,7 @@ xfs_error_trap(int e) int xfs_etest[XFS_NUM_INJECT_ERROR]; int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR]; char * xfs_etest_fsname[XFS_NUM_INJECT_ERROR]; +int xfs_error_test_active; int xfs_error_test(int error_tag, int *fsidp, char *expression, @@ -108,6 +109,7 @@ xfs_errortag_add(int error_tag, xfs_mount_t *mp) len = strlen(mp->m_fsname); xfs_etest_fsname[i] = kmem_alloc(len + 1, KM_SLEEP); strcpy(xfs_etest_fsname[i], mp->m_fsname); + xfs_error_test_active++; return 0; } } @@ -137,6 +139,7 @@ xfs_errortag_clearall(xfs_mount_t *mp, int loud) xfs_etest_fsid[i] = 0LL; kmem_free(xfs_etest_fsname[i]); xfs_etest_fsname[i] = NULL; + xfs_error_test_active--; } } diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h index c2c1a072bb82..f338847f80b8 100644 --- a/fs/xfs/xfs_error.h +++ b/fs/xfs/xfs_error.h @@ -127,13 +127,14 @@ extern void xfs_corruption_error(const char *tag, int level, #define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT #ifdef DEBUG +extern int xfs_error_test_active; extern int xfs_error_test(int, int *, char *, int, char *, unsigned long); #define XFS_NUM_INJECT_ERROR 10 #define XFS_TEST_ERROR(expr, mp, tag, rf) \ - ((expr) || \ + ((expr) || (xfs_error_test_active && \ xfs_error_test((tag), (mp)->m_fixedfsid, "expr", __LINE__, __FILE__, \ - (rf))) + (rf)))) extern int xfs_errortag_add(int error_tag, xfs_mount_t *mp); extern int xfs_errortag_clearall(xfs_mount_t *mp, int loud); diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index c7ac020705df..7c8d30c453c3 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -657,18 +657,37 @@ xfs_inode_item_unlock( } /* - * This is called to find out where the oldest active copy of the - * inode log item in the on disk log resides now that the last log - * write of it completed at the given lsn. Since we always re-log - * all dirty data in an inode, the latest copy in the on disk log - * is the only one that matters. Therefore, simply return the - * given lsn. + * This is called to find out where the oldest active copy of the inode log + * item in the on disk log resides now that the last log write of it completed + * at the given lsn. Since we always re-log all dirty data in an inode, the + * latest copy in the on disk log is the only one that matters. Therefore, + * simply return the given lsn. + * + * If the inode has been marked stale because the cluster is being freed, we + * don't want to (re-)insert this inode into the AIL. There is a race condition + * where the cluster buffer may be unpinned before the inode is inserted into + * the AIL during transaction committed processing. If the buffer is unpinned + * before the inode item has been committed and inserted, then it is possible + * for the buffer to be written and IO completions before the inode is inserted + * into the AIL. In that case, we'd be inserting a clean, stale inode into the + * AIL which will never get removed. It will, however, get reclaimed which + * triggers an assert in xfs_inode_free() complaining about freein an inode + * still in the AIL. + * + * To avoid this, return a lower LSN than the one passed in so that the + * transaction committed code will not move the inode forward in the AIL but + * will still unpin it properly. */ STATIC xfs_lsn_t xfs_inode_item_committed( struct xfs_log_item *lip, xfs_lsn_t lsn) { + struct xfs_inode_log_item *iip = INODE_ITEM(lip); + struct xfs_inode *ip = iip->ili_inode; + + if (xfs_iflags_test(ip, XFS_ISTALE)) + return lsn - 1; return lsn; } diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index d2af0a8381a6..77a59891734e 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c @@ -297,6 +297,7 @@ xfs_rename( * it and some incremental backup programs won't work without it. */ xfs_trans_ichgtime(tp, src_ip, XFS_ICHGTIME_CHG); + xfs_trans_log_inode(tp, src_ip, XFS_ILOG_CORE); /* * Adjust the link count on src_dp. This is necessary when diff --git a/include/acpi/video.h b/include/acpi/video.h index 551793c9b6e8..0e98e679d3a7 100644 --- a/include/acpi/video.h +++ b/include/acpi/video.h @@ -1,6 +1,10 @@ #ifndef __ACPI_VIDEO_H #define __ACPI_VIDEO_H +#include <linux/errno.h> /* for ENODEV */ + +struct acpi_device; + #define ACPI_VIDEO_DISPLAY_CRT 1 #define ACPI_VIDEO_DISPLAY_TV 2 #define ACPI_VIDEO_DISPLAY_DVI 3 @@ -26,4 +30,3 @@ static inline int acpi_video_get_edid(struct acpi_device *device, int type, #endif #endif - diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index 8c641bed9bbd..a2776e2807a4 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -287,6 +287,8 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_EXECBUF2 9 #define I915_PARAM_HAS_BSD 10 #define I915_PARAM_HAS_BLT 11 +#define I915_PARAM_HAS_RELAXED_FENCING 12 +#define I915_PARAM_HAS_COHERENT_RINGS 13 typedef struct drm_i915_getparam { int param; diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h index 01a714119506..bc5590b1a1ac 100644 --- a/include/drm/nouveau_drm.h +++ b/include/drm/nouveau_drm.h @@ -80,6 +80,7 @@ struct drm_nouveau_gpuobj_free { #define NOUVEAU_GETPARAM_VM_VRAM_BASE 12 #define NOUVEAU_GETPARAM_GRAPH_UNITS 13 #define NOUVEAU_GETPARAM_PTIMER_TIME 14 +#define NOUVEAU_GETPARAM_HAS_BO_USAGE 15 struct drm_nouveau_getparam { uint64_t param; uint64_t value; @@ -95,6 +96,12 @@ struct drm_nouveau_setparam { #define NOUVEAU_GEM_DOMAIN_GART (1 << 2) #define NOUVEAU_GEM_DOMAIN_MAPPABLE (1 << 3) +#define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00 +#define NOUVEAU_GEM_TILE_16BPP 0x00000001 +#define NOUVEAU_GEM_TILE_32BPP 0x00000002 +#define NOUVEAU_GEM_TILE_ZETA 0x00000004 +#define NOUVEAU_GEM_TILE_NONCONTIG 0x00000008 + struct drm_nouveau_gem_info { uint32_t handle; uint32_t domain; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 050a7bccb836..67c91b4418b0 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -219,7 +219,7 @@ static inline int acpi_video_display_switch_support(void) extern int acpi_blacklisted(void); extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d); -extern int acpi_osi_setup(char *str); +extern void acpi_osi_setup(char *str); #ifdef CONFIG_ACPI_NUMA int acpi_get_pxm(acpi_handle handle); diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index a8e4e832cdbb..475f8c42c0e9 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h @@ -427,8 +427,10 @@ extern rwlock_t vcc_sklist_lock; #define ATM_SKB(skb) (((struct atm_skb_data *) (skb)->cb)) -struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, - int number,unsigned long *flags); /* number == -1: pick first available */ +struct atm_dev *atm_dev_register(const char *type, struct device *parent, + const struct atmdev_ops *ops, + int number, /* -1 == pick first available */ + unsigned long *flags); struct atm_dev *atm_dev_lookup(int number); void atm_dev_deregister(struct atm_dev *dev); diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index a065612fc928..64a7114a9394 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -29,6 +29,7 @@ struct linux_binprm{ char buf[BINPRM_BUF_SIZE]; #ifdef CONFIG_MMU struct vm_area_struct *vma; + unsigned long vma_pages; #else # define MAX_ARG_PAGES 32 struct page *page[MAX_ARG_PAGES]; @@ -59,6 +60,10 @@ struct linux_binprm{ unsigned long loader, exec; }; +extern void acct_arg_size(struct linux_binprm *bprm, unsigned long pages); +extern struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, + int write); + #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0 #define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index aae86fd10c4f..36ab42c9bb99 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -250,7 +250,7 @@ struct queue_limits { unsigned char misaligned; unsigned char discard_misaligned; - unsigned char no_cluster; + unsigned char cluster; signed char discard_zeroes_data; }; @@ -380,7 +380,6 @@ struct request_queue #endif }; -#define QUEUE_FLAG_CLUSTER 0 /* cluster several segments into 1 */ #define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */ #define QUEUE_FLAG_STOPPED 2 /* queue is stopped */ #define QUEUE_FLAG_SYNCFULL 3 /* read queue has been filled */ @@ -403,7 +402,6 @@ struct request_queue #define QUEUE_FLAG_SECDISCARD 19 /* supports SECDISCARD */ #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ - (1 << QUEUE_FLAG_CLUSTER) | \ (1 << QUEUE_FLAG_STACKABLE) | \ (1 << QUEUE_FLAG_SAME_COMP) | \ (1 << QUEUE_FLAG_ADD_RANDOM)) @@ -510,6 +508,11 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define rq_data_dir(rq) ((rq)->cmd_flags & 1) +static inline unsigned int blk_queue_cluster(struct request_queue *q) +{ + return q->limits.cluster; +} + /* * We regard a request as sync, if either a read or a sync write */ @@ -805,6 +808,7 @@ extern struct request_queue *blk_init_allocated_queue(struct request_queue *, extern void blk_cleanup_queue(struct request_queue *); extern void blk_queue_make_request(struct request_queue *, make_request_fn *); extern void blk_queue_bounce_limit(struct request_queue *, u64); +extern void blk_limits_max_hw_sectors(struct queue_limits *, unsigned int); extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int); extern void blk_queue_max_segments(struct request_queue *, unsigned short); extern void blk_queue_max_segment_size(struct request_queue *, unsigned int); diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index 266ab9291232..499dfe982a0e 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h @@ -105,6 +105,8 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat, #define alloc_bootmem(x) \ __alloc_bootmem(x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS)) +#define alloc_bootmem_align(x, align) \ + __alloc_bootmem(x, align, __pa(MAX_DMA_ADDRESS)) #define alloc_bootmem_nopanic(x) \ __alloc_bootmem_nopanic(x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS)) #define alloc_bootmem_pages(x) \ diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index f22b2e941686..72c72bfccb88 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -227,9 +227,10 @@ extern int ceph_open_session(struct ceph_client *client); extern void ceph_release_page_vector(struct page **pages, int num_pages); extern struct page **ceph_get_direct_page_vector(const char __user *data, - int num_pages, - loff_t off, size_t len); -extern void ceph_put_page_vector(struct page **pages, int num_pages); + int num_pages, + bool write_page); +extern void ceph_put_page_vector(struct page **pages, int num_pages, + bool dirty); extern void ceph_release_page_vector(struct page **pages, int num_pages); extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags); extern int ceph_copy_user_to_page_vector(struct page **pages, diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 5956d62c3057..a108b425fee2 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -82,6 +82,7 @@ struct ceph_msg { struct ceph_buffer *middle; struct page **pages; /* data payload. NOT OWNER. */ unsigned nr_pages; /* size of page array */ + unsigned page_alignment; /* io offset in first page */ struct ceph_pagelist *pagelist; /* instead of pages */ struct list_head list_head; struct kref kref; diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h index 6c91fb032c39..a1af29648fb5 100644 --- a/include/linux/ceph/osd_client.h +++ b/include/linux/ceph/osd_client.h @@ -79,6 +79,7 @@ struct ceph_osd_request { struct ceph_file_layout r_file_layout; struct ceph_snap_context *r_snapc; /* snap context for writes */ unsigned r_num_pages; /* size of page array (follows) */ + unsigned r_page_alignment; /* io offset in first page */ struct page **r_pages; /* pages for data payload */ int r_pages_from_pool; int r_own_pages; /* if true, i own page list */ @@ -194,7 +195,8 @@ extern struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *, int do_sync, u32 truncate_seq, u64 truncate_size, struct timespec *mtime, - bool use_mempool, int num_reply); + bool use_mempool, int num_reply, + int page_align); static inline void ceph_osdc_get_request(struct ceph_osd_request *req) { @@ -218,7 +220,8 @@ extern int ceph_osdc_readpages(struct ceph_osd_client *osdc, struct ceph_file_layout *layout, u64 off, u64 *plen, u32 truncate_seq, u64 truncate_size, - struct page **pages, int nr_pages); + struct page **pages, int nr_pages, + int page_align); extern int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino, diff --git a/include/linux/cnt32_to_63.h b/include/linux/cnt32_to_63.h index 7605fdd1eb65..e3d8bf26e5eb 100644 --- a/include/linux/cnt32_to_63.h +++ b/include/linux/cnt32_to_63.h @@ -61,13 +61,31 @@ union cnt32_to_63 { * * 2) this code must not be preempted for a duration longer than the * 32-bit counter half period minus the longest period between two - * calls to this code. + * calls to this code; * * Those requirements ensure proper update to the state bit in memory. * This is usually not a problem in practice, but if it is then a kernel * timer should be scheduled to manage for this code to be executed often * enough. * + * And finally: + * + * 3) the cnt_lo argument must be seen as a globally incrementing value, + * meaning that it should be a direct reference to the counter data which + * can be evaluated according to a specific ordering within the macro, + * and not the result of a previous evaluation stored in a variable. + * + * For example, this is wrong: + * + * u32 partial = get_hw_count(); + * u64 full = cnt32_to_63(partial); + * return full; + * + * This is fine: + * + * u64 full = cnt32_to_63(get_hw_count()); + * return full; + * * Note that the top bit (bit 63) in the returned value should be considered * as garbage. It is not cleared here because callers are likely to use a * multiplier on the returned value which can get rid of the top bit diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 4823af64e9db..5f09323ee880 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -10,11 +10,6 @@ * * CPUs are exported via sysfs in the class/cpu/devices/ * directory. - * - * Per-cpu interfaces can be implemented using a struct device_interface. - * See the following for how to do this: - * - drivers/base/intf.c - * - Documentation/driver-model/interface.txt */ #ifndef _LINUX_CPU_H_ #define _LINUX_CPU_H_ diff --git a/include/linux/dmar.h b/include/linux/dmar.h index a7d9dc21391d..7b776d71d36d 100644 --- a/include/linux/dmar.h +++ b/include/linux/dmar.h @@ -175,10 +175,21 @@ static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev) return 0; } -#define enable_intr_remapping(mode) (-1) -#define disable_intr_remapping() (0) -#define reenable_intr_remapping(mode) (0) #define intr_remapping_enabled (0) + +static inline int enable_intr_remapping(int eim) +{ + return -1; +} + +static inline void disable_intr_remapping(void) +{ +} + +static inline int reenable_intr_remapping(int eim) +{ + return 0; +} #endif /* Can't use the common MSI interrupt functions diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h index 0f0121467fc4..6c6133f76e16 100644 --- a/include/linux/fanotify.h +++ b/include/linux/fanotify.h @@ -83,11 +83,13 @@ FAN_ALL_PERM_EVENTS |\ FAN_Q_OVERFLOW) -#define FANOTIFY_METADATA_VERSION 2 +#define FANOTIFY_METADATA_VERSION 3 struct fanotify_event_metadata { __u32 event_len; - __u32 vers; + __u8 vers; + __u8 reserved; + __u16 metadata_len; __aligned_u64 mask; __s32 fd; __s32 pid; @@ -96,11 +98,13 @@ struct fanotify_event_metadata { struct fanotify_response { __s32 fd; __u32 response; -} __attribute__ ((packed)); +}; /* Legit userspace responses to a _PERM event */ #define FAN_ALLOW 0x01 #define FAN_DENY 0x02 +/* No fd set in event */ +#define FAN_NOFD -1 /* Helper functions to deal with fanotify_event_metadata buffers */ #define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata)) diff --git a/include/linux/fb.h b/include/linux/fb.h index e154a79b8322..68ba85a00c06 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -1124,6 +1124,7 @@ extern const struct fb_videomode *fb_find_best_display(const struct fb_monspecs /* drivers/video/fbcmap.c */ extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp); +extern int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags); extern void fb_dealloc_cmap(struct fb_cmap *cmap); extern int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to); extern int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to); diff --git a/include/linux/fs.h b/include/linux/fs.h index 334d68a17108..090f0eacde29 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -34,9 +34,9 @@ #define SEEK_MAX SEEK_END struct fstrim_range { - uint64_t start; - uint64_t len; - uint64_t minlen; + __u64 start; + __u64 len; + __u64 minlen; }; /* And dynamically-tunable limits and defaults: */ @@ -602,6 +602,7 @@ struct address_space_operations { sector_t (*bmap)(struct address_space *, sector_t); void (*invalidatepage) (struct page *, unsigned long); int (*releasepage) (struct page *, gfp_t); + void (*freepage)(struct page *); ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov, loff_t offset, unsigned long nr_segs); int (*get_xip_mem)(struct address_space *, pgoff_t, int, @@ -1612,7 +1613,6 @@ struct super_operations { ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); #endif int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t); - int (*trim_fs) (struct super_block *, struct fstrim_range *); }; /* diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 5c185fa27089..b10bcdeaef76 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -235,9 +235,6 @@ static inline void fsnotify_open(struct file *file) if (S_ISDIR(inode->i_mode)) mask |= FS_ISDIR; - /* FMODE_NONOTIFY must never be set from user */ - file->f_mode &= ~FMODE_NONOTIFY; - fsnotify_parent(path, NULL, mask); fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); } diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 0a68f924f06f..7380763595d3 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -166,7 +166,7 @@ struct fsnotify_group { struct mutex access_mutex; struct list_head access_list; wait_queue_head_t access_waitq; - bool bypass_perm; /* protected by access_mutex */ + atomic_t bypass_perm; #endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */ int f_flags; unsigned int max_marks; diff --git a/include/linux/gfp.h b/include/linux/gfp.h index e8713d55360a..f54adfcbec9c 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -360,7 +360,7 @@ void drain_local_pages(void *dummy); extern gfp_t gfp_allowed_mask; -extern void set_gfp_allowed_mask(gfp_t mask); -extern gfp_t clear_gfp_allowed_mask(gfp_t mask); +extern void pm_restrict_gfp_mask(void); +extern void pm_restore_gfp_mask(void); #endif /* __LINUX_GFP_H */ diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index ce73a30113b4..dd1a56fbe924 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -16,6 +16,8 @@ struct gpio_keys_button { struct gpio_keys_platform_data { struct gpio_keys_button *buttons; int nbuttons; + unsigned int poll_interval; /* polling interval in msecs - + for polling driver only */ unsigned int rep:1; /* enable input subsystem auto repeat */ int (*enable)(struct device *dev); void (*disable)(struct device *dev); diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 714da7e5d10c..32f9fd6619b4 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -94,6 +94,7 @@ #define in_nmi() (preempt_count() & NMI_MASK) #if defined(CONFIG_PREEMPT) && defined(CONFIG_BKL) +# include <linux/sched.h> # define PREEMPT_INATOMIC_BASE (current->lock_depth >= 0) #else # define PREEMPT_INATOMIC_BASE 0 diff --git a/include/linux/hw_breakpoint.h b/include/linux/hw_breakpoint.h index a2d6ea49ec56..d1e55fed2c7d 100644 --- a/include/linux/hw_breakpoint.h +++ b/include/linux/hw_breakpoint.h @@ -33,6 +33,8 @@ enum bp_type_idx { #ifdef CONFIG_HAVE_HW_BREAKPOINT +extern int __init init_hw_breakpoint(void); + static inline void hw_breakpoint_init(struct perf_event_attr *attr) { memset(attr, 0, sizeof(*attr)); @@ -108,6 +110,8 @@ static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp) #else /* !CONFIG_HAVE_HW_BREAKPOINT */ +static inline int __init init_hw_breakpoint(void) { return 0; } + static inline struct perf_event * register_user_hw_breakpoint(struct perf_event_attr *attr, perf_overflow_handler_t triggered, diff --git a/include/linux/input.h b/include/linux/input.h index 6ef44465db8d..9777668883be 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -47,6 +47,25 @@ struct input_id { __u16 version; }; +/** + * struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls + * @value: latest reported value for the axis. + * @minimum: specifies minimum value for the axis. + * @maximum: specifies maximum value for the axis. + * @fuzz: specifies fuzz value that is used to filter noise from + * the event stream. + * @flat: values that are within this value will be discarded by + * joydev interface and reported as 0 instead. + * @resolution: specifies resolution for the values reported for + * the axis. + * + * Note that input core does not clamp reported values to the + * [minimum, maximum] limits, such task is left to userspace. + * + * Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in + * units per millimeter (units/mm), resolution for rotational axes + * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian. + */ struct input_absinfo { __s32 value; __s32 minimum; @@ -85,8 +104,10 @@ struct input_keymap_entry { #define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */ #define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */ -#define EVIOCGKEYCODE _IOR('E', 0x04, struct input_keymap_entry) /* get keycode */ -#define EVIOCSKEYCODE _IOW('E', 0x04, struct input_keymap_entry) /* set keycode */ +#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */ +#define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry) +#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */ +#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry) #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ #define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ @@ -624,6 +645,10 @@ struct input_keymap_entry { #define KEY_CAMERA_FOCUS 0x210 #define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */ +#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */ +#define KEY_TOUCHPAD_ON 0x213 +#define KEY_TOUCHPAD_OFF 0x214 + #define BTN_TRIGGER_HAPPY 0x2c0 #define BTN_TRIGGER_HAPPY1 0x2c0 #define BTN_TRIGGER_HAPPY2 0x2c1 @@ -1130,7 +1155,7 @@ struct input_mt_slot { * of tracked contacts * @mtsize: number of MT slots the device uses * @slot: MT slot currently being transmitted - * @absinfo: array of &struct absinfo elements holding information + * @absinfo: array of &struct input_absinfo elements holding information * about absolute axes (current value, min, max, flat, fuzz, * resolution) * @key: reflects current state of device's keys/buttons diff --git a/include/linux/ioport.h b/include/linux/ioport.h index d377ea815d45..e9bb22cba764 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -112,7 +112,6 @@ struct resource_list { /* PC/ISA/whatever - the normal PC address spaces: IO and memory */ extern struct resource ioport_resource; extern struct resource iomem_resource; -extern int resource_alloc_from_bottom; extern struct resource *request_resource_conflict(struct resource *root, struct resource *new); extern int request_resource(struct resource *root, struct resource *new); @@ -124,6 +123,7 @@ extern void reserve_region_with_split(struct resource *root, extern struct resource *insert_resource_conflict(struct resource *parent, struct resource *new); extern int insert_resource(struct resource *parent, struct resource *new); extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new); +extern void arch_remove_reservations(struct resource *avail); extern int allocate_resource(struct resource *root, struct resource *new, resource_size_t size, resource_size_t min, resource_size_t max, resource_size_t align, diff --git a/include/linux/marvell_phy.h b/include/linux/marvell_phy.h index 1ff81b51b656..dd3c34ebca9a 100644 --- a/include/linux/marvell_phy.h +++ b/include/linux/marvell_phy.h @@ -11,6 +11,7 @@ #define MARVELL_PHY_ID_88E1118 0x01410e10 #define MARVELL_PHY_ID_88E1121R 0x01410cb0 #define MARVELL_PHY_ID_88E1145 0x01410cd0 +#define MARVELL_PHY_ID_88E1149R 0x01410e50 #define MARVELL_PHY_ID_88E1240 0x01410e30 #define MARVELL_PHY_ID_88E1318S 0x01410e90 diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 4307231bd22f..31c237a00c48 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -161,6 +161,9 @@ extern void register_page_bootmem_info_node(struct pglist_data *pgdat); extern void put_page_bootmem(struct page *page); #endif +void lock_memory_hotplug(void); +void unlock_memory_hotplug(void); + #else /* ! CONFIG_MEMORY_HOTPLUG */ /* * Stub functions for when hotplug is off @@ -192,6 +195,9 @@ static inline void register_page_bootmem_info_node(struct pglist_data *pgdat) { } +static inline void lock_memory_hotplug(void) {} +static inline void unlock_memory_hotplug(void) {} + #endif /* ! CONFIG_MEMORY_HOTPLUG */ #ifdef CONFIG_MEMORY_HOTREMOVE diff --git a/include/linux/mfd/wm8350/audio.h b/include/linux/mfd/wm8350/audio.h index a95141eafce3..bd581c6fa085 100644 --- a/include/linux/mfd/wm8350/audio.h +++ b/include/linux/mfd/wm8350/audio.h @@ -522,9 +522,6 @@ #define WM8350_MCLK_SEL_PLL_32K 3 #define WM8350_MCLK_SEL_MCLK 5 -#define WM8350_MCLK_DIR_OUT 0 -#define WM8350_MCLK_DIR_IN 1 - /* clock divider id's */ #define WM8350_ADC_CLKDIV 0 #define WM8350_DAC_CLKDIV 1 diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h index 5c51f367c061..add8a1b8bcf0 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h @@ -29,7 +29,7 @@ struct wm8994_ldo_pdata { #define WM8994_CONFIGURE_GPIO 0x8000 #define WM8994_DRC_REGS 5 -#define WM8994_EQ_REGS 19 +#define WM8994_EQ_REGS 20 /** * DRC configurations are specified with a label and a set of register diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 6d87f68ce4b6..30f6fad99a58 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -168,6 +168,7 @@ struct mmc_host { /* DDR mode at 1.8V */ #define MMC_CAP_1_2V_DDR (1 << 12) /* can support */ /* DDR mode at 1.2V */ +#define MMC_CAP_POWER_OFF_CARD (1 << 13) /* Can power off after boot */ mmc_pm_flag_t pm_caps; /* supported pm features */ diff --git a/include/linux/module.h b/include/linux/module.h index b29e7458b966..7575bbbdf2a2 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -517,7 +517,7 @@ static inline void __module_get(struct module *module) #define symbol_put_addr(p) do { } while(0) #endif /* CONFIG_MODULE_UNLOAD */ -int use_module(struct module *a, struct module *b); +int ref_module(struct module *a, struct module *b); /* This is a #define so the string doesn't get put in every .o file */ #define module_name(mod) \ diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index c66fdb7d6998..29d504d5d1c3 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -401,6 +401,7 @@ extern const struct inode_operations nfs3_file_inode_operations; #endif /* CONFIG_NFS_V3 */ extern const struct file_operations nfs_file_operations; extern const struct address_space_operations nfs_file_aops; +extern const struct address_space_operations nfs_dir_aops; static inline struct nfs_open_context *nfs_file_open_context(struct file *filp) { diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index f8b60e7f4c44..d55cee73f634 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -29,6 +29,7 @@ */ enum { PG_BUSY = 0, + PG_MAPPED, PG_CLEAN, PG_NEED_COMMIT, PG_NEED_RESCHED, diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index ba6cc8f223c9..80f07198a31a 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -483,6 +483,7 @@ struct nfs_entry { int eof; struct nfs_fh * fh; struct nfs_fattr * fattr; + unsigned char d_type; }; /* diff --git a/include/linux/node.h b/include/linux/node.h index 06292dac3eab..1466945cc9ef 100644 --- a/include/linux/node.h +++ b/include/linux/node.h @@ -10,11 +10,6 @@ * * Nodes are exported via driverfs in the class/node/devices/ * directory. - * - * Per-node interfaces can be implemented using a struct device_interface. - * See the following for how to do this: - * - drivers/base/intf.c - * - Documentation/driver-model/interface.txt */ #ifndef _LINUX_NODE_H_ #define _LINUX_NODE_H_ diff --git a/include/linux/page_cgroup.h b/include/linux/page_cgroup.h index 5bb13b3db84d..b02195dfc1b0 100644 --- a/include/linux/page_cgroup.h +++ b/include/linux/page_cgroup.h @@ -59,8 +59,6 @@ static inline void ClearPageCgroup##uname(struct page_cgroup *pc) \ static inline int TestClearPageCgroup##uname(struct page_cgroup *pc) \ { return test_and_clear_bit(PCG_##lname, &pc->flags); } -TESTPCGFLAG(Locked, LOCK) - /* Cache flag is set only once (at allocation) */ TESTPCGFLAG(Cache, CACHE) CLEARPCGFLAG(Cache, CACHE) @@ -104,6 +102,11 @@ static inline void unlock_page_cgroup(struct page_cgroup *pc) bit_spin_unlock(PCG_LOCK, &pc->flags); } +static inline int page_is_cgroup_locked(struct page_cgroup *pc) +{ + return bit_spin_is_locked(PCG_LOCK, &pc->flags); +} + #else /* CONFIG_CGROUP_MEM_RES_CTLR */ struct page_cgroup; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c6bcfe93b9ca..cb845c16ad7d 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2047,6 +2047,7 @@ #define PCI_DEVICE_ID_AFAVLAB_P030 0x2182 #define PCI_SUBDEVICE_ID_AFAVLAB_P061 0x2150 +#define PCI_VENDOR_ID_BCM_GVC 0x14a4 #define PCI_VENDOR_ID_BROADCOM 0x14e4 #define PCI_DEVICE_ID_TIGON3_5752 0x1600 #define PCI_DEVICE_ID_TIGON3_5752M 0x1601 @@ -2441,6 +2442,7 @@ #define PCI_DEVICE_ID_INTEL_MFD_SDIO2 0x0822 #define PCI_DEVICE_ID_INTEL_MFD_EMMC0 0x0823 #define PCI_DEVICE_ID_INTEL_MFD_EMMC1 0x0824 +#define PCI_DEVICE_ID_INTEL_MRST_SD2 0x084F #define PCI_DEVICE_ID_INTEL_I960 0x0960 #define PCI_DEVICE_ID_INTEL_I960RM 0x0962 #define PCI_DEVICE_ID_INTEL_8257X_SOL 0x1062 diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 40150f345982..4f1279e105ee 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -850,6 +850,7 @@ struct perf_event_context { int nr_active; int is_active; int nr_stat; + int rotate_disable; atomic_t refcount; struct task_struct *task; @@ -886,6 +887,7 @@ struct perf_cpu_context { int exclusive; struct list_head rotation_list; int jiffies_interval; + struct pmu *active_pmu; }; struct perf_output_handle { @@ -908,20 +910,6 @@ extern int perf_num_counters(void); extern const char *perf_pmu_name(void); extern void __perf_event_task_sched_in(struct task_struct *task); extern void __perf_event_task_sched_out(struct task_struct *task, struct task_struct *next); - -extern atomic_t perf_task_events; - -static inline void perf_event_task_sched_in(struct task_struct *task) -{ - COND_STMT(&perf_task_events, __perf_event_task_sched_in(task)); -} - -static inline -void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next) -{ - COND_STMT(&perf_task_events, __perf_event_task_sched_out(task, next)); -} - extern int perf_event_init_task(struct task_struct *child); extern void perf_event_exit_task(struct task_struct *child); extern void perf_event_free_task(struct task_struct *task); @@ -1030,6 +1018,21 @@ have_event: __perf_sw_event(event_id, nr, nmi, regs, addr); } +extern atomic_t perf_task_events; + +static inline void perf_event_task_sched_in(struct task_struct *task) +{ + COND_STMT(&perf_task_events, __perf_event_task_sched_in(task)); +} + +static inline +void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next) +{ + perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0); + + COND_STMT(&perf_task_events, __perf_event_task_sched_out(task, next)); +} + extern void perf_event_mmap(struct vm_area_struct *vma); extern struct perf_guest_info_callbacks *perf_guest_cbs; extern int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks); diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index 445796945ac9..bb27d7ec2fb9 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -160,5 +160,6 @@ void generic_pipe_buf_release(struct pipe_inode_info *, struct pipe_buffer *); /* for F_SETPIPE_SZ and F_GETPIPE_SZ */ long pipe_fcntl(struct file *, unsigned int, unsigned long arg); +struct pipe_inode_info *get_pipe_info(struct file *file); #endif diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 3ec2358f8692..d19f1cca7f74 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -77,7 +77,8 @@ static inline void device_set_run_wake(struct device *dev, bool enable) static inline bool pm_runtime_suspended(struct device *dev) { - return dev->power.runtime_status == RPM_SUSPENDED; + return dev->power.runtime_status == RPM_SUSPENDED + && !dev->power.disable_depth; } static inline void pm_runtime_mark_last_busy(struct device *dev) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index d42f274418b8..bbad657a3725 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -6,7 +6,6 @@ #include <linux/if_link.h> #include <linux/if_addr.h> #include <linux/neighbour.h> -#include <linux/netdevice.h> /* rtnetlink families. Values up to 127 are reserved for real address * families, values above 128 may be used arbitrarily. @@ -606,6 +605,7 @@ struct tcamsg { #ifdef __KERNEL__ #include <linux/mutex.h> +#include <linux/netdevice.h> static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str) { diff --git a/include/linux/sched.h b/include/linux/sched.h index 2c79e921a68b..223874538b33 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -143,7 +143,7 @@ extern unsigned long nr_iowait_cpu(int cpu); extern unsigned long this_cpu_load(void); -extern void calc_global_load(void); +extern void calc_global_load(unsigned long ticks); extern unsigned long get_parent_ip(unsigned long addr); diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h index cea0c38e7a63..9a52f72527dc 100644 --- a/include/linux/sh_clk.h +++ b/include/linux/sh_clk.h @@ -19,11 +19,13 @@ struct clk_mapping { }; struct clk_ops { +#ifdef CONFIG_SH_CLK_CPG_LEGACY void (*init)(struct clk *clk); +#endif int (*enable)(struct clk *clk); void (*disable)(struct clk *clk); unsigned long (*recalc)(struct clk *clk); - int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id); + int (*set_rate)(struct clk *clk, unsigned long rate); int (*set_parent)(struct clk *clk, struct clk *parent); long (*round_rate)(struct clk *clk, unsigned long rate); }; @@ -67,36 +69,6 @@ int clk_register(struct clk *); void clk_unregister(struct clk *); void clk_enable_init_clocks(void); -/** - * clk_set_rate_ex - set the clock rate for a clock source, with additional parameter - * @clk: clock source - * @rate: desired clock rate in Hz - * @algo_id: algorithm id to be passed down to ops->set_rate - * - * Returns success (0) or negative errno. - */ -int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id); - -enum clk_sh_algo_id { - NO_CHANGE = 0, - - IUS_N1_N1, - IUS_322, - IUS_522, - IUS_N11, - - SB_N1, - - SB3_N1, - SB3_32, - SB3_43, - SB3_54, - - BP_N1, - - IP_N1, -}; - struct clk_div_mult_table { unsigned int *divisors; unsigned int nr_divisors; diff --git a/include/linux/snmp.h b/include/linux/snmp.h index ebb0c80ffd6e..12b2b18e50c1 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -230,6 +230,7 @@ enum LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */ LINUX_MIB_TCPDEFERACCEPTDROP, LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */ + LINUX_MIB_TCPTIMEWAITOVERFLOW, /* TCPTimeWaitOverflow */ __LINUX_MIB_MAX }; diff --git a/include/linux/ssb/ssb_driver_gige.h b/include/linux/ssb/ssb_driver_gige.h index 942e38736901..eba52a100533 100644 --- a/include/linux/ssb/ssb_driver_gige.h +++ b/include/linux/ssb/ssb_driver_gige.h @@ -96,16 +96,21 @@ static inline bool ssb_gige_must_flush_posted_writes(struct pci_dev *pdev) return 0; } -extern char * nvram_get(const char *name); +#ifdef CONFIG_BCM47XX +#include <asm/mach-bcm47xx/nvram.h> /* Get the device MAC address */ static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr) { -#ifdef CONFIG_BCM47XX - char *res = nvram_get("et0macaddr"); - if (res) - memcpy(macaddr, res, 6); -#endif + char buf[20]; + if (nvram_getenv("et0macaddr", buf, sizeof(buf)) < 0) + return; + nvram_parse_macaddr(buf, macaddr); } +#else +static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr) +{ +} +#endif extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, struct pci_dev *pdev); diff --git a/include/linux/tty.h b/include/linux/tty.h index 032d79ff1d9d..54e4eaaa0561 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -366,6 +366,7 @@ struct tty_file_private { #define TTY_HUPPED 18 /* Post driver->hangup() */ #define TTY_FLUSHING 19 /* Flushing to ldisc in progress */ #define TTY_FLUSHPENDING 20 /* Queued buffer flush pending */ +#define TTY_HUPPING 21 /* ->hangup() in progress */ #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h index d6188e5a52df..665517c05eaf 100644 --- a/include/linux/uio_driver.h +++ b/include/linux/uio_driver.h @@ -3,7 +3,7 @@ * * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de> * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de> - * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de> + * Copyright(C) 2006, Hans J. Koch <hjk@hansjkoch.de> * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com> * * Userspace IO driver. diff --git a/include/linux/usb.h b/include/linux/usb.h index 24300d8a1bc1..a28eb2592577 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -313,6 +313,10 @@ struct usb_bus { int busnum; /* Bus number (in order of reg) */ const char *bus_name; /* stable id (PCI slot_name etc) */ u8 uses_dma; /* Does the host controller use DMA? */ + u8 uses_pio_for_control; /* + * Does the host controller use PIO + * for control transfers? + */ u8 otg_port; /* 0, or number of OTG/HNP port */ unsigned is_b_host:1; /* true during some HNP roleswitches */ unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */ diff --git a/include/linux/video_output.h b/include/linux/video_output.h index 2fb46bc9340d..ed5cdeb3604d 100644 --- a/include/linux/video_output.h +++ b/include/linux/video_output.h @@ -23,6 +23,7 @@ #ifndef _LINUX_VIDEO_OUTPUT_H #define _LINUX_VIDEO_OUTPUT_H #include <linux/device.h> +#include <linux/err.h> struct output_device; struct output_properties { int (*set_state)(struct output_device *); @@ -34,9 +35,23 @@ struct output_device { struct device dev; }; #define to_output_device(obj) container_of(obj, struct output_device, dev) +#if defined(CONFIG_VIDEO_OUTPUT_CONTROL) || defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE) struct output_device *video_output_register(const char *name, struct device *dev, void *devdata, struct output_properties *op); void video_output_unregister(struct output_device *dev); +#else +static struct output_device *video_output_register(const char *name, + struct device *dev, + void *devdata, + struct output_properties *op) +{ + return ERR_PTR(-ENODEV); +} +static void video_output_unregister(struct output_device *dev) +{ + return; +} +#endif #endif diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index a03dcf62ca9d..44b54f619ac6 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -7,8 +7,6 @@ struct vm_area_struct; /* vma defining user mapping in mm_types.h */ -extern bool vmap_lazy_unmap; - /* bits in flags of vmalloc's vm_struct below */ #define VM_IOREMAP 0x00000001 /* ioremap() and friends */ #define VM_ALLOC 0x00000002 /* vmalloc() */ diff --git a/include/media/saa7146.h b/include/media/saa7146.h index 7a9f76ecbbbd..ac7ce00f39cf 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h @@ -161,7 +161,7 @@ extern struct list_head saa7146_devices; extern struct mutex saa7146_devices_lock; int saa7146_register_extension(struct saa7146_extension*); int saa7146_unregister_extension(struct saa7146_extension*); -struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc); +struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc); int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt); void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt); int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length ); diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 41dd480e45f1..239125af3ea3 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -137,31 +137,27 @@ struct v4l2_subdev_ops; /* Load an i2c module and return an initialized v4l2_subdev struct. - Only call request_module if module_name != NULL. The client_type argument is the name of the chip that's on the adapter. */ struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, - const char *module_name, const char *client_type, + struct i2c_adapter *adapter, const char *client_type, int irq, void *platform_data, u8 addr, const unsigned short *probe_addrs); /* Load an i2c module and return an initialized v4l2_subdev struct. - Only call request_module if module_name != NULL. The client_type argument is the name of the chip that's on the adapter. */ static inline struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, - const char *module_name, const char *client_type, + struct i2c_adapter *adapter, const char *client_type, u8 addr, const unsigned short *probe_addrs) { - return v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, module_name, - client_type, 0, NULL, addr, probe_addrs); + return v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, client_type, 0, NULL, + addr, probe_addrs); } struct i2c_board_info; struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, const char *module_name, - struct i2c_board_info *info, const unsigned short *probe_addrs); + struct i2c_adapter *adapter, struct i2c_board_info *info, + const unsigned short *probe_addrs); /* Initialize an v4l2_subdev with data from an i2c_client struct */ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index 6648036b728d..b16f307d471a 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -51,6 +51,8 @@ struct v4l2_device { unsigned int notification, void *arg); /* The control handler. May be NULL. */ struct v4l2_ctrl_handler *ctrl_handler; + /* BKL replacement mutex. Temporary solution only. */ + struct mutex ioctl_lock; }; /* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev. diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 90c9e2872f27..18e5c3f67580 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -10,6 +10,7 @@ extern void unix_inflight(struct file *fp); extern void unix_notinflight(struct file *fp); extern void unix_gc(void); extern void wait_for_unix_gc(void); +extern struct sock *unix_get_socket(struct file *filp); #define UNIX_HASH_SIZE 256 @@ -56,6 +57,7 @@ struct unix_sock { spinlock_t lock; unsigned int gc_candidate : 1; unsigned int gc_maybe_cycle : 1; + unsigned char recursion_level; struct socket_wq peer_wq; }; #define unix_sk(__sk) ((struct unix_sock *)__sk) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2a7936d7851d..97b8b7c9b63c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1355,7 +1355,7 @@ enum wiphy_flags { WIPHY_FLAG_4ADDR_AP = BIT(5), WIPHY_FLAG_4ADDR_STATION = BIT(6), WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), - WIPHY_FLAG_IBSS_RSN = BIT(7), + WIPHY_FLAG_IBSS_RSN = BIT(8), }; struct mac_address { diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 55590ab16b3e..6beb1ffc2b7f 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -303,7 +303,7 @@ static inline void neigh_confirm(struct neighbour *neigh) static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) { - unsigned long now = ACCESS_ONCE(jiffies); + unsigned long now = jiffies; if (neigh->used != now) neigh->used = now; diff --git a/include/net/sock.h b/include/net/sock.h index a6338d039857..659d968d95c5 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1155,6 +1155,8 @@ extern void sk_common_release(struct sock *sk); /* Initialise core socket variables */ extern void sock_init_data(struct socket *sock, struct sock *sk); +extern void sk_filter_release_rcu(struct rcu_head *rcu); + /** * sk_filter_release - release a socket filter * @fp: filter to remove @@ -1165,7 +1167,7 @@ extern void sock_init_data(struct socket *sock, struct sock *sk); static inline void sk_filter_release(struct sk_filter *fp) { if (atomic_dec_and_test(&fp->refcnt)) - kfree(fp); + call_rcu_bh(&fp->rcu, sk_filter_release_rcu); } static inline void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp) diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index fa60cbda90a4..d79894192ae3 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h @@ -85,7 +85,9 @@ * ACK_MD (FSI2) * CKG1 (FSI) * - * err: return value < 0 + * err : return value < 0 + * no change : return value == 0 + * change xMD : return value > 0 * * 0x-00000AB * @@ -111,7 +113,7 @@ struct sh_fsi_platform_info { unsigned long porta_flags; unsigned long portb_flags; - int (*set_rate)(int is_porta, int rate); /* for master mode */ + int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); }; #endif /* __SOUND_FSI_H */ diff --git a/include/video/da8xx-fb.h b/include/video/da8xx-fb.h index 6316cdabf73f..89d43b3d4cb9 100644 --- a/include/video/da8xx-fb.h +++ b/include/video/da8xx-fb.h @@ -99,7 +99,6 @@ struct lcd_sync_arg { #define FBIPUT_COLOR _IOW('F', 6, int) #define FBIPUT_HSYNC _IOW('F', 9, int) #define FBIPUT_VSYNC _IOW('F', 10, int) -#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) #endif /* ifndef DA8XX_FB_H */ diff --git a/include/xen/events.h b/include/xen/events.h index 646dd17d3aa4..00f53ddcc062 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -76,7 +76,9 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name); #ifdef CONFIG_PCI_MSI /* Allocate an irq and a pirq to be used with MSIs. */ -void xen_allocate_pirq_msi(char *name, int *irq, int *pirq); +#define XEN_ALLOC_PIRQ (1 << 0) +#define XEN_ALLOC_IRQ (1 << 1) +void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_mask); int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type); #endif @@ -89,4 +91,7 @@ int xen_vector_from_irq(unsigned pirq); /* Return gsi allocated to pirq */ int xen_gsi_from_irq(unsigned pirq); +/* Return irq from pirq */ +int xen_irq_from_pirq(unsigned pirq); + #endif /* _XEN_EVENTS_H */ diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h index e8cbf431c8cc..75271b9a8f61 100644 --- a/include/xen/interface/io/ring.h +++ b/include/xen/interface/io/ring.h @@ -24,8 +24,15 @@ typedef unsigned int RING_IDX; * A ring contains as many entries as will fit, rounded down to the nearest * power of two (so we can mask with (size-1) to loop around). */ -#define __RING_SIZE(_s, _sz) \ - (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0]))) +#define __CONST_RING_SIZE(_s, _sz) \ + (__RD32(((_sz) - offsetof(struct _s##_sring, ring)) / \ + sizeof(((struct _s##_sring *)0)->ring[0]))) + +/* + * The same for passing in an actual pointer instead of a name tag. + */ +#define __RING_SIZE(_s, _sz) \ + (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0]))) /* * Macros to make the correct C datatypes for a new kind of ring. diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h index d7a6c13bde69..eac3ce153719 100644 --- a/include/xen/interface/memory.h +++ b/include/xen/interface/memory.h @@ -141,6 +141,19 @@ struct xen_machphys_mfn_list { DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list); /* + * Returns the location in virtual address space of the machine_to_phys + * mapping table. Architectures which do not have a m2p table, or which do not + * map it by default into guest address space, do not implement this command. + * arg == addr of xen_machphys_mapping_t. + */ +#define XENMEM_machphys_mapping 12 +struct xen_machphys_mapping { + unsigned long v_start, v_end; /* Start and end virtual addresses. */ + unsigned long max_mfn; /* Maximum MFN that can be looked up. */ +}; +DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mapping_t); + +/* * Sets the GPFN at which a particular page appears in the specified guest's * pseudophysical address space. * arg == addr of xen_add_to_physmap_t. diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h index 2b2c66c3df00..534cac89a77d 100644 --- a/include/xen/interface/physdev.h +++ b/include/xen/interface/physdev.h @@ -188,6 +188,16 @@ struct physdev_nr_pirqs { uint32_t nr_pirqs; }; +/* type is MAP_PIRQ_TYPE_GSI or MAP_PIRQ_TYPE_MSI + * the hypercall returns a free pirq */ +#define PHYSDEVOP_get_free_pirq 23 +struct physdev_get_free_pirq { + /* IN */ + int type; + /* OUT */ + uint32_t pirq; +}; + /* * Notify that some PIRQ-bound event channels have been unmasked. * ** This command is obsolete since interface version 0x00030202 and is ** diff --git a/include/xen/page.h b/include/xen/page.h index eaf85fab1263..0be36b976f4b 100644 --- a/include/xen/page.h +++ b/include/xen/page.h @@ -1 +1,8 @@ +#ifndef _XEN_PAGE_H +#define _XEN_PAGE_H + #include <asm/xen/page.h> + +extern phys_addr_t xen_extra_mem_start, xen_extra_mem_size; + +#endif /* _XEN_PAGE_H */ diff --git a/include/xen/privcmd.h b/include/xen/privcmd.h index b42cdfd92fee..17857fb4d550 100644 --- a/include/xen/privcmd.h +++ b/include/xen/privcmd.h @@ -34,13 +34,10 @@ #define __LINUX_PUBLIC_PRIVCMD_H__ #include <linux/types.h> +#include <linux/compiler.h> typedef unsigned long xen_pfn_t; -#ifndef __user -#define __user -#endif - struct privcmd_hypercall { __u64 op; __u64 arg[5]; diff --git a/init/Kconfig b/init/Kconfig index 88c10468db46..c9728992a776 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -613,6 +613,19 @@ config CGROUP_MEM_RES_CTLR_SWAP if boot option "noswapaccount" is set, swap will not be accounted. Now, memory usage of swap_cgroup is 2 bytes per entry. If swap page size is 4096bytes, 512k per 1Gbytes of swap. +config CGROUP_MEM_RES_CTLR_SWAP_ENABLED + bool "Memory Resource Controller Swap Extension enabled by default" + depends on CGROUP_MEM_RES_CTLR_SWAP + default y + help + Memory Resource Controller Swap Extension comes with its price in + a bigger memory consumption. General purpose distribution kernels + which want to enable the feautre but keep it disabled by default + and let the user enable it by swapaccount boot command line + parameter should have this option unselected. + For those who want to have the feature enabled by default should + select this option (if, for some reason, they need to disable it + then noswapaccount does the trick). menuconfig CGROUP_SCHED bool "Group CPU scheduler" diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 37755d621924..a6e729766821 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -82,7 +82,7 @@ static kdbtab_t kdb_base_commands[50]; #define for_each_kdbcmd(cmd, num) \ for ((cmd) = kdb_base_commands, (num) = 0; \ num < kdb_max_commands; \ - num == KDB_BASE_CMD_MAX ? cmd = kdb_commands : cmd++, num++) + num++, num == KDB_BASE_CMD_MAX ? cmd = kdb_commands : cmd++) typedef struct _kdbmsg { int km_diag; /* kdb diagnostic */ @@ -646,7 +646,7 @@ static int kdb_defcmd2(const char *cmdstr, const char *argv0) } if (!s->usable) return KDB_NOTIMP; - s->command = kmalloc((s->count + 1) * sizeof(*(s->command)), GFP_KDB); + s->command = kzalloc((s->count + 1) * sizeof(*(s->command)), GFP_KDB); if (!s->command) { kdb_printf("Could not allocate new kdb_defcmd table for %s\n", cmdstr); @@ -2361,7 +2361,7 @@ static int kdb_pid(int argc, const char **argv) */ static int kdb_ll(int argc, const char **argv) { - int diag; + int diag = 0; unsigned long addr; long offset = 0; unsigned long va; @@ -2400,20 +2400,21 @@ static int kdb_ll(int argc, const char **argv) char buf[80]; if (KDB_FLAG(CMD_INTERRUPT)) - return 0; + goto out; sprintf(buf, "%s " kdb_machreg_fmt "\n", command, va); diag = kdb_parse(buf); if (diag) - return diag; + goto out; addr = va + linkoffset; if (kdb_getword(&va, addr, sizeof(va))) - return 0; + goto out; } - kfree(command); - return 0; +out: + kfree(command); + return diag; } static int kdb_kgdb(int argc, const char **argv) @@ -2739,13 +2740,13 @@ int kdb_register_repeat(char *cmd, } if (kdb_commands) { memcpy(new, kdb_commands, - kdb_max_commands * sizeof(*new)); + (kdb_max_commands - KDB_BASE_CMD_MAX) * sizeof(*new)); kfree(kdb_commands); } memset(new + kdb_max_commands, 0, kdb_command_extend * sizeof(*new)); kdb_commands = new; - kp = kdb_commands + kdb_max_commands; + kp = kdb_commands + kdb_max_commands - KDB_BASE_CMD_MAX; kdb_max_commands += kdb_command_extend; } diff --git a/kernel/exit.c b/kernel/exit.c index 21aa7b3001fb..676149a4ac5f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -914,6 +914,15 @@ NORET_TYPE void do_exit(long code) if (unlikely(!tsk->pid)) panic("Attempted to kill the idle task!"); + /* + * If do_exit is called because this processes oopsed, it's possible + * that get_fs() was left as KERNEL_DS, so reset it to USER_DS before + * continuing. Amongst other possible reasons, this is to prevent + * mm_release()->clear_child_tid() from writing to a user-controlled + * kernel address. + */ + set_fs(USER_DS); + tracehook_report_exit(&code); validate_creds_for_do_exit(tsk); diff --git a/kernel/fork.c b/kernel/fork.c index 3b159c5991b7..5447dc7defa9 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -273,6 +273,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) setup_thread_stack(tsk, orig); clear_user_return_notifier(tsk); + clear_tsk_need_resched(tsk); stackend = end_of_stack(tsk); *stackend = STACK_END_MAGIC; /* for overflow detection */ diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c index 2c9120f0afca..e5325825aeb6 100644 --- a/kernel/hw_breakpoint.c +++ b/kernel/hw_breakpoint.c @@ -620,7 +620,7 @@ static struct pmu perf_breakpoint = { .read = hw_breakpoint_pmu_read, }; -static int __init init_hw_breakpoint(void) +int __init init_hw_breakpoint(void) { unsigned int **task_bp_pinned; int cpu, err_cpu; @@ -655,6 +655,5 @@ static int __init init_hw_breakpoint(void) return -ENOMEM; } -core_initcall(init_hw_breakpoint); diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 01b1d3a88983..6c8a2a9f8a7b 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -214,7 +214,7 @@ static int irq_spurious_proc_show(struct seq_file *m, void *v) static int irq_spurious_proc_open(struct inode *inode, struct file *file) { - return single_open(file, irq_spurious_proc_show, NULL); + return single_open(file, irq_spurious_proc_show, PDE(inode)->data); } static const struct file_operations irq_spurious_proc_fops = { diff --git a/kernel/irq_work.c b/kernel/irq_work.c index f16763ff8481..90f881904bb1 100644 --- a/kernel/irq_work.c +++ b/kernel/irq_work.c @@ -145,7 +145,9 @@ void irq_work_run(void) * Clear the BUSY bit and return to the free state if * no-one else claimed it meanwhile. */ - cmpxchg(&entry->next, next_flags(NULL, IRQ_WORK_BUSY), NULL); + (void)cmpxchg(&entry->next, + next_flags(NULL, IRQ_WORK_BUSY), + NULL); } } EXPORT_SYMBOL_GPL(irq_work_run); diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index a8db2570f99a..6f6d091b5757 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -546,7 +546,7 @@ static const struct file_operations kallsyms_operations = { static int __init kallsyms_init(void) { - proc_create("kallsyms", 0400, NULL, &kallsyms_operations); + proc_create("kallsyms", 0444, NULL, &kallsyms_operations); return 0; } device_initcall(kallsyms_init); diff --git a/kernel/module.c b/kernel/module.c index 437a74a7524a..d190664f25ff 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2326,6 +2326,18 @@ static void find_module_sections(struct module *mod, struct load_info *info) kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) * mod->num_trace_events, GFP_KERNEL); #endif +#ifdef CONFIG_TRACING + mod->trace_bprintk_fmt_start = section_objs(info, "__trace_printk_fmt", + sizeof(*mod->trace_bprintk_fmt_start), + &mod->num_trace_bprintk_fmt); + /* + * This section contains pointers to allocated objects in the trace + * code and not scanning it leads to false positives. + */ + kmemleak_scan_area(mod->trace_bprintk_fmt_start, + sizeof(*mod->trace_bprintk_fmt_start) * + mod->num_trace_bprintk_fmt, GFP_KERNEL); +#endif #ifdef CONFIG_FTRACE_MCOUNT_RECORD /* sechdrs[0].sh_size is always zero */ mod->ftrace_callsites = section_objs(info, "__mcount_loc", diff --git a/kernel/perf_event.c b/kernel/perf_event.c index cb6c0d2af68f..2870feee81dd 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -31,6 +31,7 @@ #include <linux/kernel_stat.h> #include <linux/perf_event.h> #include <linux/ftrace_event.h> +#include <linux/hw_breakpoint.h> #include <asm/irq_regs.h> @@ -1286,8 +1287,6 @@ void __perf_event_task_sched_out(struct task_struct *task, { int ctxn; - perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0); - for_each_task_context_nr(ctxn) perf_event_context_sched_out(task, ctxn, next); } @@ -1621,8 +1620,12 @@ static void rotate_ctx(struct perf_event_context *ctx) { raw_spin_lock(&ctx->lock); - /* Rotate the first entry last of non-pinned groups */ - list_rotate_left(&ctx->flexible_groups); + /* + * Rotate the first entry last of non-pinned groups. Rotation might be + * disabled by the inheritance code. + */ + if (!ctx->rotate_disable) + list_rotate_left(&ctx->flexible_groups); raw_spin_unlock(&ctx->lock); } @@ -2234,11 +2237,6 @@ int perf_event_release_kernel(struct perf_event *event) raw_spin_unlock_irq(&ctx->lock); mutex_unlock(&ctx->mutex); - mutex_lock(&event->owner->perf_event_mutex); - list_del_init(&event->owner_entry); - mutex_unlock(&event->owner->perf_event_mutex); - put_task_struct(event->owner); - free_event(event); return 0; @@ -2251,9 +2249,43 @@ EXPORT_SYMBOL_GPL(perf_event_release_kernel); static int perf_release(struct inode *inode, struct file *file) { struct perf_event *event = file->private_data; + struct task_struct *owner; file->private_data = NULL; + rcu_read_lock(); + owner = ACCESS_ONCE(event->owner); + /* + * Matches the smp_wmb() in perf_event_exit_task(). If we observe + * !owner it means the list deletion is complete and we can indeed + * free this event, otherwise we need to serialize on + * owner->perf_event_mutex. + */ + smp_read_barrier_depends(); + if (owner) { + /* + * Since delayed_put_task_struct() also drops the last + * task reference we can safely take a new reference + * while holding the rcu_read_lock(). + */ + get_task_struct(owner); + } + rcu_read_unlock(); + + if (owner) { + mutex_lock(&owner->perf_event_mutex); + /* + * We have to re-check the event->owner field, if it is cleared + * we raced with perf_event_exit_task(), acquiring the mutex + * ensured they're done, and we can proceed with freeing the + * event. + */ + if (event->owner) + list_del_init(&event->owner_entry); + mutex_unlock(&owner->perf_event_mutex); + put_task_struct(owner); + } + return perf_event_release_kernel(event); } @@ -3792,6 +3824,8 @@ static void perf_event_task_event(struct perf_task_event *task_event) rcu_read_lock(); list_for_each_entry_rcu(pmu, &pmus, entry) { cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); + if (cpuctx->active_pmu != pmu) + goto next; perf_event_task_ctx(&cpuctx->ctx, task_event); ctx = task_event->task_ctx; @@ -3927,6 +3961,8 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) rcu_read_lock(); list_for_each_entry_rcu(pmu, &pmus, entry) { cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); + if (cpuctx->active_pmu != pmu) + goto next; perf_event_comm_ctx(&cpuctx->ctx, comm_event); ctxn = pmu->task_ctx_nr; @@ -4112,6 +4148,8 @@ got_name: rcu_read_lock(); list_for_each_entry_rcu(pmu, &pmus, entry) { cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); + if (cpuctx->active_pmu != pmu) + goto next; perf_event_mmap_ctx(&cpuctx->ctx, mmap_event, vma->vm_flags & VM_EXEC); @@ -4681,7 +4719,7 @@ static int perf_swevent_init(struct perf_event *event) break; } - if (event_id > PERF_COUNT_SW_MAX) + if (event_id >= PERF_COUNT_SW_MAX) return -ENOENT; if (!event->parent) { @@ -5113,20 +5151,36 @@ static void *find_pmu_context(int ctxn) return NULL; } -static void free_pmu_context(void * __percpu cpu_context) +static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu) { - struct pmu *pmu; + int cpu; + + for_each_possible_cpu(cpu) { + struct perf_cpu_context *cpuctx; + + cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); + + if (cpuctx->active_pmu == old_pmu) + cpuctx->active_pmu = pmu; + } +} + +static void free_pmu_context(struct pmu *pmu) +{ + struct pmu *i; mutex_lock(&pmus_lock); /* * Like a real lame refcount. */ - list_for_each_entry(pmu, &pmus, entry) { - if (pmu->pmu_cpu_context == cpu_context) + list_for_each_entry(i, &pmus, entry) { + if (i->pmu_cpu_context == pmu->pmu_cpu_context) { + update_pmu_context(i, pmu); goto out; + } } - free_percpu(cpu_context); + free_percpu(pmu->pmu_cpu_context); out: mutex_unlock(&pmus_lock); } @@ -5158,6 +5212,7 @@ int perf_pmu_register(struct pmu *pmu) cpuctx->ctx.pmu = pmu; cpuctx->jiffies_interval = 1; INIT_LIST_HEAD(&cpuctx->rotation_list); + cpuctx->active_pmu = pmu; } got_cpu_context: @@ -5209,7 +5264,7 @@ void perf_pmu_unregister(struct pmu *pmu) synchronize_rcu(); free_percpu(pmu->pmu_disable_count); - free_pmu_context(pmu->pmu_cpu_context); + free_pmu_context(pmu); } struct pmu *perf_init_event(struct perf_event *event) @@ -5677,7 +5732,7 @@ SYSCALL_DEFINE5(perf_event_open, mutex_unlock(&ctx->mutex); event->owner = current; - get_task_struct(current); + mutex_lock(¤t->perf_event_mutex); list_add_tail(&event->owner_entry, ¤t->perf_event_list); mutex_unlock(¤t->perf_event_mutex); @@ -5745,12 +5800,6 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, ++ctx->generation; mutex_unlock(&ctx->mutex); - event->owner = current; - get_task_struct(current); - mutex_lock(¤t->perf_event_mutex); - list_add_tail(&event->owner_entry, ¤t->perf_event_list); - mutex_unlock(¤t->perf_event_mutex); - return event; err_free: @@ -5901,8 +5950,24 @@ again: */ void perf_event_exit_task(struct task_struct *child) { + struct perf_event *event, *tmp; int ctxn; + mutex_lock(&child->perf_event_mutex); + list_for_each_entry_safe(event, tmp, &child->perf_event_list, + owner_entry) { + list_del_init(&event->owner_entry); + + /* + * Ensure the list deletion is visible before we clear + * the owner, closes a race against perf_release() where + * we need to serialize on the owner->perf_event_mutex. + */ + smp_wmb(); + event->owner = NULL; + } + mutex_unlock(&child->perf_event_mutex); + for_each_task_context_nr(ctxn) perf_event_exit_task_context(child, ctxn); } @@ -6122,6 +6187,7 @@ int perf_event_init_context(struct task_struct *child, int ctxn) struct perf_event *event; struct task_struct *parent = current; int inherited_all = 1; + unsigned long flags; int ret = 0; child->perf_event_ctxp[ctxn] = NULL; @@ -6162,6 +6228,15 @@ int perf_event_init_context(struct task_struct *child, int ctxn) break; } + /* + * We can't hold ctx->lock when iterating the ->flexible_group list due + * to allocations, but we need to prevent rotation because + * rotate_ctx() will change the list from interrupt context. + */ + raw_spin_lock_irqsave(&parent_ctx->lock, flags); + parent_ctx->rotate_disable = 1; + raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); + list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) { ret = inherit_task_group(event, parent, parent_ctx, child, ctxn, &inherited_all); @@ -6169,6 +6244,10 @@ int perf_event_init_context(struct task_struct *child, int ctxn) break; } + raw_spin_lock_irqsave(&parent_ctx->lock, flags); + parent_ctx->rotate_disable = 0; + raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); + child_ctx = child->perf_event_ctxp[ctxn]; if (child_ctx && inherited_all) { @@ -6321,6 +6400,8 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) void __init perf_event_init(void) { + int ret; + perf_event_init_all_cpus(); init_srcu_struct(&pmus_srcu); perf_pmu_register(&perf_swevent); @@ -6328,4 +6409,7 @@ void __init perf_event_init(void) perf_pmu_register(&perf_task_clock); perf_tp_register(); perf_cpu_notifier(perf_cpu_notify); + + ret = init_hw_breakpoint(); + WARN(ret, "hw_breakpoint initialization failed with: %d", ret); } diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 6842eeba5879..05bb7173850e 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -37,13 +37,13 @@ static int check_clock(const clockid_t which_clock) if (pid == 0) return 0; - read_lock(&tasklist_lock); + rcu_read_lock(); p = find_task_by_vpid(pid); if (!p || !(CPUCLOCK_PERTHREAD(which_clock) ? - same_thread_group(p, current) : thread_group_leader(p))) { + same_thread_group(p, current) : has_group_leader_pid(p))) { error = -EINVAL; } - read_unlock(&tasklist_lock); + rcu_read_unlock(); return error; } @@ -390,7 +390,7 @@ int posix_cpu_timer_create(struct k_itimer *new_timer) INIT_LIST_HEAD(&new_timer->it.cpu.entry); - read_lock(&tasklist_lock); + rcu_read_lock(); if (CPUCLOCK_PERTHREAD(new_timer->it_clock)) { if (pid == 0) { p = current; @@ -404,7 +404,7 @@ int posix_cpu_timer_create(struct k_itimer *new_timer) p = current->group_leader; } else { p = find_task_by_vpid(pid); - if (p && !thread_group_leader(p)) + if (p && !has_group_leader_pid(p)) p = NULL; } } @@ -414,7 +414,7 @@ int posix_cpu_timer_create(struct k_itimer *new_timer) } else { ret = -EINVAL; } - read_unlock(&tasklist_lock); + rcu_read_unlock(); return ret; } diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 657272e91d0a..048d0b514831 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -327,7 +327,6 @@ static int create_image(int platform_mode) int hibernation_snapshot(int platform_mode) { int error; - gfp_t saved_mask; error = platform_begin(platform_mode); if (error) @@ -339,7 +338,7 @@ int hibernation_snapshot(int platform_mode) goto Close; suspend_console(); - saved_mask = clear_gfp_allowed_mask(GFP_IOFS); + pm_restrict_gfp_mask(); error = dpm_suspend_start(PMSG_FREEZE); if (error) goto Recover_platform; @@ -348,7 +347,10 @@ int hibernation_snapshot(int platform_mode) goto Recover_platform; error = create_image(platform_mode); - /* Control returns here after successful restore */ + /* + * Control returns here (1) after the image has been created or the + * image creation has failed and (2) after a successful restore. + */ Resume_devices: /* We may need to release the preallocated image pages here. */ @@ -357,7 +359,10 @@ int hibernation_snapshot(int platform_mode) dpm_resume_end(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); - set_gfp_allowed_mask(saved_mask); + + if (error || !in_suspend) + pm_restore_gfp_mask(); + resume_console(); Close: platform_end(platform_mode); @@ -452,17 +457,16 @@ static int resume_target_kernel(bool platform_mode) int hibernation_restore(int platform_mode) { int error; - gfp_t saved_mask; pm_prepare_console(); suspend_console(); - saved_mask = clear_gfp_allowed_mask(GFP_IOFS); + pm_restrict_gfp_mask(); error = dpm_suspend_start(PMSG_QUIESCE); if (!error) { error = resume_target_kernel(platform_mode); dpm_resume_end(PMSG_RECOVER); } - set_gfp_allowed_mask(saved_mask); + pm_restore_gfp_mask(); resume_console(); pm_restore_console(); return error; @@ -476,7 +480,6 @@ int hibernation_restore(int platform_mode) int hibernation_platform_enter(void) { int error; - gfp_t saved_mask; if (!hibernation_ops) return -ENOSYS; @@ -492,7 +495,6 @@ int hibernation_platform_enter(void) entering_platform_hibernation = true; suspend_console(); - saved_mask = clear_gfp_allowed_mask(GFP_IOFS); error = dpm_suspend_start(PMSG_HIBERNATE); if (error) { if (hibernation_ops->recover) @@ -536,7 +538,6 @@ int hibernation_platform_enter(void) Resume_devices: entering_platform_hibernation = false; dpm_resume_end(PMSG_RESTORE); - set_gfp_allowed_mask(saved_mask); resume_console(); Close: @@ -646,6 +647,7 @@ int hibernate(void) swsusp_free(); if (!error) power_down(); + pm_restore_gfp_mask(); } else { pr_debug("PM: Image restored successfully.\n"); } diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 7335952ee473..ecf770509d0d 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -197,7 +197,6 @@ static int suspend_enter(suspend_state_t state) int suspend_devices_and_enter(suspend_state_t state) { int error; - gfp_t saved_mask; if (!suspend_ops) return -ENOSYS; @@ -208,7 +207,7 @@ int suspend_devices_and_enter(suspend_state_t state) goto Close; } suspend_console(); - saved_mask = clear_gfp_allowed_mask(GFP_IOFS); + pm_restrict_gfp_mask(); suspend_test_start(); error = dpm_suspend_start(PMSG_SUSPEND); if (error) { @@ -225,7 +224,7 @@ int suspend_devices_and_enter(suspend_state_t state) suspend_test_start(); dpm_resume_end(PMSG_RESUME); suspend_test_finish("resume devices"); - set_gfp_allowed_mask(saved_mask); + pm_restore_gfp_mask(); resume_console(); Close: if (suspend_ops->end) diff --git a/kernel/power/swap.c b/kernel/power/swap.c index a0e4a86ccf94..8c7e4832b9be 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -6,6 +6,7 @@ * * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz> * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl> + * Copyright (C) 2010 Bojan Smojver <bojan@rexursive.com> * * This file is released under the GPLv2. * @@ -29,7 +30,7 @@ #include "power.h" -#define HIBERNATE_SIG "LINHIB0001" +#define HIBERNATE_SIG "S1SUSPEND" /* * The swap map is a data structure used for keeping track of each page @@ -753,30 +754,43 @@ static int load_image_lzo(struct swap_map_handle *handle, { unsigned int m; int error = 0; + struct bio *bio; struct timeval start; struct timeval stop; unsigned nr_pages; - size_t off, unc_len, cmp_len; - unsigned char *unc, *cmp, *page; + size_t i, off, unc_len, cmp_len; + unsigned char *unc, *cmp, *page[LZO_CMP_PAGES]; - page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); - if (!page) { - printk(KERN_ERR "PM: Failed to allocate LZO page\n"); - return -ENOMEM; + for (i = 0; i < LZO_CMP_PAGES; i++) { + page[i] = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); + if (!page[i]) { + printk(KERN_ERR "PM: Failed to allocate LZO page\n"); + + while (i) + free_page((unsigned long)page[--i]); + + return -ENOMEM; + } } unc = vmalloc(LZO_UNC_SIZE); if (!unc) { printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n"); - free_page((unsigned long)page); + + for (i = 0; i < LZO_CMP_PAGES; i++) + free_page((unsigned long)page[i]); + return -ENOMEM; } cmp = vmalloc(LZO_CMP_SIZE); if (!cmp) { printk(KERN_ERR "PM: Failed to allocate LZO compressed\n"); + vfree(unc); - free_page((unsigned long)page); + for (i = 0; i < LZO_CMP_PAGES; i++) + free_page((unsigned long)page[i]); + return -ENOMEM; } @@ -787,6 +801,7 @@ static int load_image_lzo(struct swap_map_handle *handle, if (!m) m = 1; nr_pages = 0; + bio = NULL; do_gettimeofday(&start); error = snapshot_write_next(snapshot); @@ -794,11 +809,11 @@ static int load_image_lzo(struct swap_map_handle *handle, goto out_finish; for (;;) { - error = swap_read_page(handle, page, NULL); /* sync */ + error = swap_read_page(handle, page[0], NULL); /* sync */ if (error) break; - cmp_len = *(size_t *)page; + cmp_len = *(size_t *)page[0]; if (unlikely(!cmp_len || cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) { printk(KERN_ERR "PM: Invalid LZO compressed length\n"); @@ -806,13 +821,20 @@ static int load_image_lzo(struct swap_map_handle *handle, break; } - memcpy(cmp, page, PAGE_SIZE); - for (off = PAGE_SIZE; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) { - error = swap_read_page(handle, page, NULL); /* sync */ + for (off = PAGE_SIZE, i = 1; + off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) { + error = swap_read_page(handle, page[i], &bio); if (error) goto out_finish; + } - memcpy(cmp + off, page, PAGE_SIZE); + error = hib_wait_on_bio_chain(&bio); /* need all data now */ + if (error) + goto out_finish; + + for (off = 0, i = 0; + off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) { + memcpy(cmp + off, page[i], PAGE_SIZE); } unc_len = LZO_UNC_SIZE; @@ -857,7 +879,8 @@ out_finish: vfree(cmp); vfree(unc); - free_page((unsigned long)page); + for (i = 0; i < LZO_CMP_PAGES; i++) + free_page((unsigned long)page[i]); return error; } diff --git a/kernel/power/user.c b/kernel/power/user.c index e819e17877ca..c36c3b9e8a84 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -137,7 +137,7 @@ static int snapshot_release(struct inode *inode, struct file *filp) free_all_swap_pages(data->swap); if (data->frozen) thaw_processes(); - pm_notifier_call_chain(data->mode == O_WRONLY ? + pm_notifier_call_chain(data->mode == O_RDONLY ? PM_POST_HIBERNATION : PM_POST_RESTORE); atomic_inc(&snapshot_device_available); @@ -263,6 +263,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, case SNAPSHOT_UNFREEZE: if (!data->frozen || data->ready) break; + pm_restore_gfp_mask(); thaw_processes(); usermodehelper_enable(); data->frozen = 0; @@ -275,6 +276,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, error = -EPERM; break; } + pm_restore_gfp_mask(); error = hibernation_snapshot(data->platform_support); if (!error) error = put_user(in_suspend, (int __user *)arg); diff --git a/kernel/printk.c b/kernel/printk.c index 9a2264fc42ca..a23315dc4498 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -1082,13 +1082,15 @@ void printk_tick(void) int printk_needs_cpu(int cpu) { + if (unlikely(cpu_is_offline(cpu))) + printk_tick(); return per_cpu(printk_pending, cpu); } void wake_up_klogd(void) { if (waitqueue_active(&log_wait)) - __raw_get_cpu_var(printk_pending) = 1; + this_cpu_write(printk_pending, 1); } /** diff --git a/kernel/resource.c b/kernel/resource.c index 9fad33efd0db..798e2fae2a06 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -40,23 +40,6 @@ EXPORT_SYMBOL(iomem_resource); static DEFINE_RWLOCK(resource_lock); -/* - * By default, we allocate free space bottom-up. The architecture can request - * top-down by clearing this flag. The user can override the architecture's - * choice with the "resource_alloc_from_bottom" kernel boot option, but that - * should only be a debugging tool. - */ -int resource_alloc_from_bottom = 1; - -static __init int setup_alloc_from_bottom(char *s) -{ - printk(KERN_INFO - "resource: allocating from bottom-up; please report a bug\n"); - resource_alloc_from_bottom = 1; - return 0; -} -early_param("resource_alloc_from_bottom", setup_alloc_from_bottom); - static void *r_next(struct seq_file *m, void *v, loff_t *pos) { struct resource *p = v; @@ -374,6 +357,10 @@ int __weak page_is_ram(unsigned long pfn) return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1; } +void __weak arch_remove_reservations(struct resource *avail) +{ +} + static resource_size_t simple_align_resource(void *data, const struct resource *avail, resource_size_t size, @@ -397,74 +384,7 @@ static bool resource_contains(struct resource *res1, struct resource *res2) } /* - * Find the resource before "child" in the sibling list of "root" children. - */ -static struct resource *find_sibling_prev(struct resource *root, struct resource *child) -{ - struct resource *this; - - for (this = root->child; this; this = this->sibling) - if (this->sibling == child) - return this; - - return NULL; -} - -/* * Find empty slot in the resource tree given range and alignment. - * This version allocates from the end of the root resource first. - */ -static int find_resource_from_top(struct resource *root, struct resource *new, - resource_size_t size, resource_size_t min, - resource_size_t max, resource_size_t align, - resource_size_t (*alignf)(void *, - const struct resource *, - resource_size_t, - resource_size_t), - void *alignf_data) -{ - struct resource *this; - struct resource tmp, avail, alloc; - - tmp.start = root->end; - tmp.end = root->end; - - this = find_sibling_prev(root, NULL); - for (;;) { - if (this) { - if (this->end < root->end) - tmp.start = this->end + 1; - } else - tmp.start = root->start; - - resource_clip(&tmp, min, max); - - /* Check for overflow after ALIGN() */ - avail = *new; - avail.start = ALIGN(tmp.start, align); - avail.end = tmp.end; - if (avail.start >= tmp.start) { - alloc.start = alignf(alignf_data, &avail, size, align); - alloc.end = alloc.start + size - 1; - if (resource_contains(&avail, &alloc)) { - new->start = alloc.start; - new->end = alloc.end; - return 0; - } - } - - if (!this || this->start == root->start) - break; - - tmp.end = this->start - 1; - this = find_sibling_prev(root, this); - } - return -EBUSY; -} - -/* - * Find empty slot in the resource tree given range and alignment. - * This version allocates from the beginning of the root resource first. */ static int find_resource(struct resource *root, struct resource *new, resource_size_t size, resource_size_t min, @@ -478,23 +398,24 @@ static int find_resource(struct resource *root, struct resource *new, struct resource *this = root->child; struct resource tmp = *new, avail, alloc; + tmp.flags = new->flags; tmp.start = root->start; /* - * Skip past an allocated resource that starts at 0, since the - * assignment of this->start - 1 to tmp->end below would cause an - * underflow. + * Skip past an allocated resource that starts at 0, since the assignment + * of this->start - 1 to tmp->end below would cause an underflow. */ if (this && this->start == 0) { tmp.start = this->end + 1; this = this->sibling; } - for (;;) { + for(;;) { if (this) tmp.end = this->start - 1; else tmp.end = root->end; resource_clip(&tmp, min, max); + arch_remove_reservations(&tmp); /* Check for overflow after ALIGN() */ avail = *new; @@ -509,10 +430,8 @@ static int find_resource(struct resource *root, struct resource *new, return 0; } } - if (!this) break; - tmp.start = this->end + 1; this = this->sibling; } @@ -545,10 +464,7 @@ int allocate_resource(struct resource *root, struct resource *new, alignf = simple_align_resource; write_lock(&resource_lock); - if (resource_alloc_from_bottom) - err = find_resource(root, new, size, min, max, align, alignf, alignf_data); - else - err = find_resource_from_top(root, new, size, min, max, align, alignf, alignf_data); + err = find_resource(root, new, size, min, max, align, alignf, alignf_data); if (err >= 0 && __request_resource(root, new)) err = -EBUSY; write_unlock(&resource_lock); diff --git a/kernel/sched.c b/kernel/sched.c index dc91a4d09ac3..297d1a0eedb0 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -636,22 +636,18 @@ static inline struct task_group *task_group(struct task_struct *p) #endif /* CONFIG_CGROUP_SCHED */ -static u64 irq_time_cpu(int cpu); -static void sched_irq_time_avg_update(struct rq *rq, u64 irq_time); +static void update_rq_clock_task(struct rq *rq, s64 delta); -inline void update_rq_clock(struct rq *rq) +static void update_rq_clock(struct rq *rq) { - if (!rq->skip_clock_update) { - int cpu = cpu_of(rq); - u64 irq_time; + s64 delta; - rq->clock = sched_clock_cpu(cpu); - irq_time = irq_time_cpu(cpu); - if (rq->clock - irq_time > rq->clock_task) - rq->clock_task = rq->clock - irq_time; + if (rq->skip_clock_update) + return; - sched_irq_time_avg_update(rq, irq_time); - } + delta = sched_clock_cpu(cpu_of(rq)) - rq->clock; + rq->clock += delta; + update_rq_clock_task(rq, delta); } /* @@ -1924,10 +1920,9 @@ static void deactivate_task(struct rq *rq, struct task_struct *p, int flags) * They are read and saved off onto struct rq in update_rq_clock(). * This may result in other CPU reading this CPU's irq time and can * race with irq/account_system_vtime on this CPU. We would either get old - * or new value (or semi updated value on 32 bit) with a side effect of - * accounting a slice of irq time to wrong task when irq is in progress - * while we read rq->clock. That is a worthy compromise in place of having - * locks on each irq in account_system_time. + * or new value with a side effect of accounting a slice of irq time to wrong + * task when irq is in progress while we read rq->clock. That is a worthy + * compromise in place of having locks on each irq in account_system_time. */ static DEFINE_PER_CPU(u64, cpu_hardirq_time); static DEFINE_PER_CPU(u64, cpu_softirq_time); @@ -1945,19 +1940,58 @@ void disable_sched_clock_irqtime(void) sched_clock_irqtime = 0; } -static u64 irq_time_cpu(int cpu) +#ifndef CONFIG_64BIT +static DEFINE_PER_CPU(seqcount_t, irq_time_seq); + +static inline void irq_time_write_begin(void) { - if (!sched_clock_irqtime) - return 0; + __this_cpu_inc(irq_time_seq.sequence); + smp_wmb(); +} + +static inline void irq_time_write_end(void) +{ + smp_wmb(); + __this_cpu_inc(irq_time_seq.sequence); +} + +static inline u64 irq_time_read(int cpu) +{ + u64 irq_time; + unsigned seq; + do { + seq = read_seqcount_begin(&per_cpu(irq_time_seq, cpu)); + irq_time = per_cpu(cpu_softirq_time, cpu) + + per_cpu(cpu_hardirq_time, cpu); + } while (read_seqcount_retry(&per_cpu(irq_time_seq, cpu), seq)); + + return irq_time; +} +#else /* CONFIG_64BIT */ +static inline void irq_time_write_begin(void) +{ +} + +static inline void irq_time_write_end(void) +{ +} + +static inline u64 irq_time_read(int cpu) +{ return per_cpu(cpu_softirq_time, cpu) + per_cpu(cpu_hardirq_time, cpu); } +#endif /* CONFIG_64BIT */ +/* + * Called before incrementing preempt_count on {soft,}irq_enter + * and before decrementing preempt_count on {soft,}irq_exit. + */ void account_system_vtime(struct task_struct *curr) { unsigned long flags; + s64 delta; int cpu; - u64 now, delta; if (!sched_clock_irqtime) return; @@ -1965,9 +1999,10 @@ void account_system_vtime(struct task_struct *curr) local_irq_save(flags); cpu = smp_processor_id(); - now = sched_clock_cpu(cpu); - delta = now - per_cpu(irq_start_time, cpu); - per_cpu(irq_start_time, cpu) = now; + delta = sched_clock_cpu(cpu) - __this_cpu_read(irq_start_time); + __this_cpu_add(irq_start_time, delta); + + irq_time_write_begin(); /* * We do not account for softirq time from ksoftirqd here. * We want to continue accounting softirq time to ksoftirqd thread @@ -1975,33 +2010,55 @@ void account_system_vtime(struct task_struct *curr) * that do not consume any time, but still wants to run. */ if (hardirq_count()) - per_cpu(cpu_hardirq_time, cpu) += delta; + __this_cpu_add(cpu_hardirq_time, delta); else if (in_serving_softirq() && !(curr->flags & PF_KSOFTIRQD)) - per_cpu(cpu_softirq_time, cpu) += delta; + __this_cpu_add(cpu_softirq_time, delta); + irq_time_write_end(); local_irq_restore(flags); } EXPORT_SYMBOL_GPL(account_system_vtime); -static void sched_irq_time_avg_update(struct rq *rq, u64 curr_irq_time) +static void update_rq_clock_task(struct rq *rq, s64 delta) { - if (sched_clock_irqtime && sched_feat(NONIRQ_POWER)) { - u64 delta_irq = curr_irq_time - rq->prev_irq_time; - rq->prev_irq_time = curr_irq_time; - sched_rt_avg_update(rq, delta_irq); - } + s64 irq_delta; + + irq_delta = irq_time_read(cpu_of(rq)) - rq->prev_irq_time; + + /* + * Since irq_time is only updated on {soft,}irq_exit, we might run into + * this case when a previous update_rq_clock() happened inside a + * {soft,}irq region. + * + * When this happens, we stop ->clock_task and only update the + * prev_irq_time stamp to account for the part that fit, so that a next + * update will consume the rest. This ensures ->clock_task is + * monotonic. + * + * It does however cause some slight miss-attribution of {soft,}irq + * time, a more accurate solution would be to update the irq_time using + * the current rq->clock timestamp, except that would require using + * atomic ops. + */ + if (irq_delta > delta) + irq_delta = delta; + + rq->prev_irq_time += irq_delta; + delta -= irq_delta; + rq->clock_task += delta; + + if (irq_delta && sched_feat(NONIRQ_POWER)) + sched_rt_avg_update(rq, irq_delta); } -#else +#else /* CONFIG_IRQ_TIME_ACCOUNTING */ -static u64 irq_time_cpu(int cpu) +static void update_rq_clock_task(struct rq *rq, s64 delta) { - return 0; + rq->clock_task += delta; } -static void sched_irq_time_avg_update(struct rq *rq, u64 curr_irq_time) { } - -#endif +#endif /* CONFIG_IRQ_TIME_ACCOUNTING */ #include "sched_idletask.c" #include "sched_fair.c" @@ -2129,7 +2186,7 @@ static void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags) * A queue event has occurred, and we're going to schedule. In * this case, we can save a useless back to back clock update. */ - if (test_tsk_need_resched(rq->curr)) + if (rq->curr->se.on_rq && test_tsk_need_resched(rq->curr)) rq->skip_clock_update = 1; } @@ -3119,6 +3176,15 @@ static long calc_load_fold_active(struct rq *this_rq) return delta; } +static unsigned long +calc_load(unsigned long load, unsigned long exp, unsigned long active) +{ + load *= exp; + load += active * (FIXED_1 - exp); + load += 1UL << (FSHIFT - 1); + return load >> FSHIFT; +} + #ifdef CONFIG_NO_HZ /* * For NO_HZ we delay the active fold to the next LOAD_FREQ update. @@ -3148,6 +3214,128 @@ static long calc_load_fold_idle(void) return delta; } + +/** + * fixed_power_int - compute: x^n, in O(log n) time + * + * @x: base of the power + * @frac_bits: fractional bits of @x + * @n: power to raise @x to. + * + * By exploiting the relation between the definition of the natural power + * function: x^n := x*x*...*x (x multiplied by itself for n times), and + * the binary encoding of numbers used by computers: n := \Sum n_i * 2^i, + * (where: n_i \elem {0, 1}, the binary vector representing n), + * we find: x^n := x^(\Sum n_i * 2^i) := \Prod x^(n_i * 2^i), which is + * of course trivially computable in O(log_2 n), the length of our binary + * vector. + */ +static unsigned long +fixed_power_int(unsigned long x, unsigned int frac_bits, unsigned int n) +{ + unsigned long result = 1UL << frac_bits; + + if (n) for (;;) { + if (n & 1) { + result *= x; + result += 1UL << (frac_bits - 1); + result >>= frac_bits; + } + n >>= 1; + if (!n) + break; + x *= x; + x += 1UL << (frac_bits - 1); + x >>= frac_bits; + } + + return result; +} + +/* + * a1 = a0 * e + a * (1 - e) + * + * a2 = a1 * e + a * (1 - e) + * = (a0 * e + a * (1 - e)) * e + a * (1 - e) + * = a0 * e^2 + a * (1 - e) * (1 + e) + * + * a3 = a2 * e + a * (1 - e) + * = (a0 * e^2 + a * (1 - e) * (1 + e)) * e + a * (1 - e) + * = a0 * e^3 + a * (1 - e) * (1 + e + e^2) + * + * ... + * + * an = a0 * e^n + a * (1 - e) * (1 + e + ... + e^n-1) [1] + * = a0 * e^n + a * (1 - e) * (1 - e^n)/(1 - e) + * = a0 * e^n + a * (1 - e^n) + * + * [1] application of the geometric series: + * + * n 1 - x^(n+1) + * S_n := \Sum x^i = ------------- + * i=0 1 - x + */ +static unsigned long +calc_load_n(unsigned long load, unsigned long exp, + unsigned long active, unsigned int n) +{ + + return calc_load(load, fixed_power_int(exp, FSHIFT, n), active); +} + +/* + * NO_HZ can leave us missing all per-cpu ticks calling + * calc_load_account_active(), but since an idle CPU folds its delta into + * calc_load_tasks_idle per calc_load_account_idle(), all we need to do is fold + * in the pending idle delta if our idle period crossed a load cycle boundary. + * + * Once we've updated the global active value, we need to apply the exponential + * weights adjusted to the number of cycles missed. + */ +static void calc_global_nohz(unsigned long ticks) +{ + long delta, active, n; + + if (time_before(jiffies, calc_load_update)) + return; + + /* + * If we crossed a calc_load_update boundary, make sure to fold + * any pending idle changes, the respective CPUs might have + * missed the tick driven calc_load_account_active() update + * due to NO_HZ. + */ + delta = calc_load_fold_idle(); + if (delta) + atomic_long_add(delta, &calc_load_tasks); + + /* + * If we were idle for multiple load cycles, apply them. + */ + if (ticks >= LOAD_FREQ) { + n = ticks / LOAD_FREQ; + + active = atomic_long_read(&calc_load_tasks); + active = active > 0 ? active * FIXED_1 : 0; + + avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n); + avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n); + avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n); + + calc_load_update += n * LOAD_FREQ; + } + + /* + * Its possible the remainder of the above division also crosses + * a LOAD_FREQ period, the regular check in calc_global_load() + * which comes after this will take care of that. + * + * Consider us being 11 ticks before a cycle completion, and us + * sleeping for 4*LOAD_FREQ + 22 ticks, then the above code will + * age us 4 cycles, and the test in calc_global_load() will + * pick up the final one. + */ +} #else static void calc_load_account_idle(struct rq *this_rq) { @@ -3157,6 +3345,10 @@ static inline long calc_load_fold_idle(void) { return 0; } + +static void calc_global_nohz(unsigned long ticks) +{ +} #endif /** @@ -3174,24 +3366,17 @@ void get_avenrun(unsigned long *loads, unsigned long offset, int shift) loads[2] = (avenrun[2] + offset) << shift; } -static unsigned long -calc_load(unsigned long load, unsigned long exp, unsigned long active) -{ - load *= exp; - load += active * (FIXED_1 - exp); - return load >> FSHIFT; -} - /* * calc_load - update the avenrun load estimates 10 ticks after the * CPUs have updated calc_load_tasks. */ -void calc_global_load(void) +void calc_global_load(unsigned long ticks) { - unsigned long upd = calc_load_update + 10; long active; - if (time_before(jiffies, upd)) + calc_global_nohz(ticks); + + if (time_before(jiffies, calc_load_update + 10)) return; active = atomic_long_read(&calc_load_tasks); @@ -3845,7 +4030,6 @@ static void put_prev_task(struct rq *rq, struct task_struct *prev) { if (prev->se.on_rq) update_rq_clock(rq); - rq->skip_clock_update = 0; prev->sched_class->put_prev_task(rq, prev); } @@ -3903,7 +4087,6 @@ need_resched_nonpreemptible: hrtick_clear(rq); raw_spin_lock_irq(&rq->lock); - clear_tsk_need_resched(prev); switch_count = &prev->nivcsw; if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { @@ -3935,6 +4118,8 @@ need_resched_nonpreemptible: put_prev_task(rq, prev); next = pick_next_task(rq); + clear_tsk_need_resched(prev); + rq->skip_clock_update = 0; if (likely(prev != next)) { sched_info_switch(prev, next); diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 52ab113d8bb9..00ebd7686676 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1758,10 +1758,6 @@ static void pull_task(struct rq *src_rq, struct task_struct *p, set_task_cpu(p, this_cpu); activate_task(this_rq, p, 0); check_preempt_curr(this_rq, p, 0); - - /* re-arm NEWIDLE balancing when moving tasks */ - src_rq->avg_idle = this_rq->avg_idle = 2*sysctl_sched_migration_cost; - this_rq->idle_stamp = 0; } /* @@ -3219,8 +3215,10 @@ static void idle_balance(int this_cpu, struct rq *this_rq) interval = msecs_to_jiffies(sd->balance_interval); if (time_after(next_balance, sd->last_balance + interval)) next_balance = sd->last_balance + interval; - if (pulled_task) + if (pulled_task) { + this_rq->idle_stamp = 0; break; + } } raw_spin_lock(&this_rq->lock); diff --git a/kernel/timer.c b/kernel/timer.c index 68a9ae7679b7..353b9227c2ec 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1252,6 +1252,12 @@ unsigned long get_next_timer_interrupt(unsigned long now) struct tvec_base *base = __get_cpu_var(tvec_bases); unsigned long expires; + /* + * Pretend that there is no timer pending if the cpu is offline. + * Possible pending timers will be migrated later to an active cpu. + */ + if (cpu_is_offline(smp_processor_id())) + return now + NEXT_TIMER_MAX_DELTA; spin_lock(&base->lock); if (time_before_eq(base->next_timer, base->timer_jiffies)) base->next_timer = __next_timer_interrupt(base); @@ -1319,7 +1325,7 @@ void do_timer(unsigned long ticks) { jiffies_64 += ticks; update_wall_time(); - calc_global_load(); + calc_global_load(ticks); } #ifdef __ARCH_WANT_SYS_ALARM diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 042084157980..f8cf959bad45 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1283,6 +1283,8 @@ void trace_dump_stack(void) __ftrace_trace_stack(global_trace.buffer, flags, 3, preempt_count()); } +static DEFINE_PER_CPU(int, user_stack_count); + void ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc) { @@ -1301,6 +1303,18 @@ ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc) if (unlikely(in_nmi())) return; + /* + * prevent recursion, since the user stack tracing may + * trigger other kernel events. + */ + preempt_disable(); + if (__this_cpu_read(user_stack_count)) + goto out; + + __this_cpu_inc(user_stack_count); + + + event = trace_buffer_lock_reserve(buffer, TRACE_USER_STACK, sizeof(*entry), flags, pc); if (!event) @@ -1318,6 +1332,11 @@ ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc) save_stack_trace_user(&trace); if (!filter_check_discard(call, entry, buffer, event)) ring_buffer_unlock_commit(buffer, event); + + __this_cpu_dec(user_stack_count); + + out: + preempt_enable(); } #ifdef UNUSED @@ -2319,11 +2338,19 @@ tracing_write_stub(struct file *filp, const char __user *ubuf, return count; } +static loff_t tracing_seek(struct file *file, loff_t offset, int origin) +{ + if (file->f_mode & FMODE_READ) + return seq_lseek(file, offset, origin); + else + return 0; +} + static const struct file_operations tracing_fops = { .open = tracing_open, .read = seq_read, .write = tracing_write_stub, - .llseek = seq_lseek, + .llseek = tracing_seek, .release = tracing_release, }; diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 90db1bd1a978..e785b0f2aea5 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -661,7 +661,7 @@ void wq_worker_waking_up(struct task_struct *task, unsigned int cpu) { struct worker *worker = kthread_data(task); - if (likely(!(worker->flags & WORKER_NOT_RUNNING))) + if (!(worker->flags & WORKER_NOT_RUNNING)) atomic_inc(get_gcwq_nr_running(cpu)); } @@ -687,7 +687,7 @@ struct task_struct *wq_worker_sleeping(struct task_struct *task, struct global_cwq *gcwq = get_gcwq(cpu); atomic_t *nr_running = get_gcwq_nr_running(cpu); - if (unlikely(worker->flags & WORKER_NOT_RUNNING)) + if (worker->flags & WORKER_NOT_RUNNING) return NULL; /* this can only happen on the local cpu */ @@ -3692,7 +3692,8 @@ static int __init init_workqueues(void) system_nrt_wq = alloc_workqueue("events_nrt", WQ_NON_REENTRANT, 0); system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, WQ_UNBOUND_MAX_ACTIVE); - BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq); + BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq || + !system_unbound_wq); return 0; } early_initcall(init_workqueues); diff --git a/lib/debug_locks.c b/lib/debug_locks.c index 5bf0020b9248..b1c177307677 100644 --- a/lib/debug_locks.c +++ b/lib/debug_locks.c @@ -8,7 +8,6 @@ * * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> */ -#include <linux/kernel.h> #include <linux/rwsem.h> #include <linux/mutex.h> #include <linux/module.h> @@ -39,7 +38,6 @@ int debug_locks_off(void) { if (__debug_locks_off()) { if (!debug_locks_silent) { - oops_in_progress = 1; console_verbose(); return 1; } diff --git a/mm/filemap.c b/mm/filemap.c index ea89840fc65f..6b9aee20f242 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -143,13 +143,18 @@ void __remove_from_page_cache(struct page *page) void remove_from_page_cache(struct page *page) { struct address_space *mapping = page->mapping; + void (*freepage)(struct page *); BUG_ON(!PageLocked(page)); + freepage = mapping->a_ops->freepage; spin_lock_irq(&mapping->tree_lock); __remove_from_page_cache(page); spin_unlock_irq(&mapping->tree_lock); mem_cgroup_uncharge_cache_page(page); + + if (freepage) + freepage(page); } EXPORT_SYMBOL(remove_from_page_cache); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index c4a3558589ab..85855240933d 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2738,7 +2738,8 @@ out_page_table_lock: unlock_page(pagecache_page); put_page(pagecache_page); } - unlock_page(page); + if (page != pagecache_page) + unlock_page(page); out_mutex: mutex_unlock(&hugetlb_instantiation_mutex); @@ -1724,8 +1724,13 @@ static int ksm_memory_callback(struct notifier_block *self, /* * Keep it very simple for now: just lock out ksmd and * MADV_UNMERGEABLE while any memory is going offline. + * mutex_lock_nested() is necessary because lockdep was alarmed + * that here we take ksm_thread_mutex inside notifier chain + * mutex, and later take notifier chain mutex inside + * ksm_thread_mutex to unlock it. But that's safe because both + * are inside mem_hotplug_mutex. */ - mutex_lock(&ksm_thread_mutex); + mutex_lock_nested(&ksm_thread_mutex, SINGLE_DEPTH_NESTING); break; case MEM_OFFLINE: diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 2efa8ea07ff7..7a22b4129211 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -61,7 +61,14 @@ struct mem_cgroup *root_mem_cgroup __read_mostly; #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP /* Turned on only when memory cgroup is enabled && really_do_swap_account = 1 */ int do_swap_account __read_mostly; -static int really_do_swap_account __initdata = 1; /* for remember boot option*/ + +/* for remember boot option*/ +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED +static int really_do_swap_account __initdata = 1; +#else +static int really_do_swap_account __initdata = 0; +#endif + #else #define do_swap_account (0) #endif @@ -278,13 +285,14 @@ enum move_type { /* "mc" and its members are protected by cgroup_mutex */ static struct move_charge_struct { - spinlock_t lock; /* for from, to, moving_task */ + spinlock_t lock; /* for from, to */ struct mem_cgroup *from; struct mem_cgroup *to; unsigned long precharge; unsigned long moved_charge; unsigned long moved_swap; struct task_struct *moving_task; /* a task moving charges */ + struct mm_struct *mm; wait_queue_head_t waitq; /* a waitq for other context */ } mc = { .lock = __SPIN_LOCK_UNLOCKED(mc.lock), @@ -2152,7 +2160,7 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc, { VM_BUG_ON(from == to); VM_BUG_ON(PageLRU(pc->page)); - VM_BUG_ON(!PageCgroupLocked(pc)); + VM_BUG_ON(!page_is_cgroup_locked(pc)); VM_BUG_ON(!PageCgroupUsed(pc)); VM_BUG_ON(pc->mem_cgroup != from); @@ -4631,7 +4639,7 @@ static unsigned long mem_cgroup_count_precharge(struct mm_struct *mm) unsigned long precharge; struct vm_area_struct *vma; - down_read(&mm->mmap_sem); + /* We've already held the mmap_sem */ for (vma = mm->mmap; vma; vma = vma->vm_next) { struct mm_walk mem_cgroup_count_precharge_walk = { .pmd_entry = mem_cgroup_count_precharge_pte_range, @@ -4643,7 +4651,6 @@ static unsigned long mem_cgroup_count_precharge(struct mm_struct *mm) walk_page_range(vma->vm_start, vma->vm_end, &mem_cgroup_count_precharge_walk); } - up_read(&mm->mmap_sem); precharge = mc.precharge; mc.precharge = 0; @@ -4694,11 +4701,16 @@ static void mem_cgroup_clear_mc(void) mc.moved_swap = 0; } + if (mc.mm) { + up_read(&mc.mm->mmap_sem); + mmput(mc.mm); + } spin_lock(&mc.lock); mc.from = NULL; mc.to = NULL; - mc.moving_task = NULL; spin_unlock(&mc.lock); + mc.moving_task = NULL; + mc.mm = NULL; mem_cgroup_end_move(from); memcg_oom_recover(from); memcg_oom_recover(to); @@ -4724,12 +4736,21 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss, return 0; /* We move charges only when we move a owner of the mm */ if (mm->owner == p) { + /* + * We do all the move charge works under one mmap_sem to + * avoid deadlock with down_write(&mmap_sem) + * -> try_charge() -> if (mc.moving_task) -> sleep. + */ + down_read(&mm->mmap_sem); + VM_BUG_ON(mc.from); VM_BUG_ON(mc.to); VM_BUG_ON(mc.precharge); VM_BUG_ON(mc.moved_charge); VM_BUG_ON(mc.moved_swap); VM_BUG_ON(mc.moving_task); + VM_BUG_ON(mc.mm); + mem_cgroup_start_move(from); spin_lock(&mc.lock); mc.from = from; @@ -4737,14 +4758,16 @@ static int mem_cgroup_can_attach(struct cgroup_subsys *ss, mc.precharge = 0; mc.moved_charge = 0; mc.moved_swap = 0; - mc.moving_task = current; spin_unlock(&mc.lock); + mc.moving_task = current; + mc.mm = mm; ret = mem_cgroup_precharge_mc(mm); if (ret) mem_cgroup_clear_mc(); - } - mmput(mm); + /* We call up_read() and mmput() in clear_mc(). */ + } else + mmput(mm); } return ret; } @@ -4832,7 +4855,7 @@ static void mem_cgroup_move_charge(struct mm_struct *mm) struct vm_area_struct *vma; lru_add_drain_all(); - down_read(&mm->mmap_sem); + /* We've already held the mmap_sem */ for (vma = mm->mmap; vma; vma = vma->vm_next) { int ret; struct mm_walk mem_cgroup_move_charge_walk = { @@ -4851,7 +4874,6 @@ static void mem_cgroup_move_charge(struct mm_struct *mm) */ break; } - up_read(&mm->mmap_sem); } static void mem_cgroup_move_task(struct cgroup_subsys *ss, @@ -4860,17 +4882,11 @@ static void mem_cgroup_move_task(struct cgroup_subsys *ss, struct task_struct *p, bool threadgroup) { - struct mm_struct *mm; - - if (!mc.to) + if (!mc.mm) /* no need to move charge */ return; - mm = get_task_mm(p); - if (mm) { - mem_cgroup_move_charge(mm); - mmput(mm); - } + mem_cgroup_move_charge(mc.mm); mem_cgroup_clear_mc(); } #else /* !CONFIG_MMU */ @@ -4911,10 +4927,20 @@ struct cgroup_subsys mem_cgroup_subsys = { }; #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP +static int __init enable_swap_account(char *s) +{ + /* consider enabled if no parameter or 1 is given */ + if (!s || !strcmp(s, "1")) + really_do_swap_account = 1; + else if (!strcmp(s, "0")) + really_do_swap_account = 0; + return 1; +} +__setup("swapaccount", enable_swap_account); static int __init disable_swap_account(char *s) { - really_do_swap_account = 0; + enable_swap_account("0"); return 1; } __setup("noswapaccount", disable_swap_account); diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 124324134ff6..46ab2c044b0e 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -51,6 +51,7 @@ #include <linux/slab.h> #include <linux/swapops.h> #include <linux/hugetlb.h> +#include <linux/memory_hotplug.h> #include "internal.h" int sysctl_memory_failure_early_kill __read_mostly = 0; @@ -1230,11 +1231,10 @@ static int get_any_page(struct page *p, unsigned long pfn, int flags) return 1; /* - * The lock_system_sleep prevents a race with memory hotplug, - * because the isolation assumes there's only a single user. + * The lock_memory_hotplug prevents a race with memory hotplug. * This is a big hammer, a better would be nicer. */ - lock_system_sleep(); + lock_memory_hotplug(); /* * Isolate the page, so that it doesn't get reallocated if it @@ -1264,7 +1264,7 @@ static int get_any_page(struct page *p, unsigned long pfn, int flags) ret = 1; } unset_migratetype_isolate(p); - unlock_system_sleep(); + unlock_memory_hotplug(); return ret; } diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 9260314a221e..2c6523af5473 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -34,6 +34,23 @@ #include "internal.h" +DEFINE_MUTEX(mem_hotplug_mutex); + +void lock_memory_hotplug(void) +{ + mutex_lock(&mem_hotplug_mutex); + + /* for exclusive hibernation if CONFIG_HIBERNATION=y */ + lock_system_sleep(); +} + +void unlock_memory_hotplug(void) +{ + unlock_system_sleep(); + mutex_unlock(&mem_hotplug_mutex); +} + + /* add this memory to iomem resource */ static struct resource *register_memory_resource(u64 start, u64 size) { @@ -493,7 +510,7 @@ int mem_online_node(int nid) pg_data_t *pgdat; int ret; - lock_system_sleep(); + lock_memory_hotplug(); pgdat = hotadd_new_pgdat(nid, 0); if (pgdat) { ret = -ENOMEM; @@ -504,7 +521,7 @@ int mem_online_node(int nid) BUG_ON(ret); out: - unlock_system_sleep(); + unlock_memory_hotplug(); return ret; } @@ -516,7 +533,7 @@ int __ref add_memory(int nid, u64 start, u64 size) struct resource *res; int ret; - lock_system_sleep(); + lock_memory_hotplug(); res = register_memory_resource(start, size); ret = -EEXIST; @@ -563,7 +580,7 @@ error: release_memory_resource(res); out: - unlock_system_sleep(); + unlock_memory_hotplug(); return ret; } EXPORT_SYMBOL_GPL(add_memory); @@ -791,7 +808,7 @@ static int offline_pages(unsigned long start_pfn, if (!test_pages_in_a_zone(start_pfn, end_pfn)) return -EINVAL; - lock_system_sleep(); + lock_memory_hotplug(); zone = page_zone(pfn_to_page(start_pfn)); node = zone_to_nid(zone); @@ -880,7 +897,7 @@ repeat: writeback_set_ratelimit(); memory_notify(MEM_OFFLINE, &arg); - unlock_system_sleep(); + unlock_memory_hotplug(); return 0; failed_removal: @@ -891,7 +908,7 @@ failed_removal: undo_isolate_page_range(start_pfn, end_pfn); out: - unlock_system_sleep(); + unlock_memory_hotplug(); return ret; } diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 4a57f135b76e..11ff260fb282 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1307,15 +1307,18 @@ SYSCALL_DEFINE4(migrate_pages, pid_t, pid, unsigned long, maxnode, goto out; /* Find the mm_struct */ + rcu_read_lock(); read_lock(&tasklist_lock); task = pid ? find_task_by_vpid(pid) : current; if (!task) { read_unlock(&tasklist_lock); + rcu_read_unlock(); err = -ESRCH; goto out; } mm = get_task_mm(task); read_unlock(&tasklist_lock); + rcu_read_unlock(); err = -EINVAL; if (!mm) diff --git a/mm/mmap.c b/mm/mmap.c index b179abb1474a..50a4aa0255a0 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2462,6 +2462,7 @@ int install_special_mapping(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long vm_flags, struct page **pages) { + int ret; struct vm_area_struct *vma; vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); @@ -2479,16 +2480,23 @@ int install_special_mapping(struct mm_struct *mm, vma->vm_ops = &special_mapping_vmops; vma->vm_private_data = pages; - if (unlikely(insert_vm_struct(mm, vma))) { - kmem_cache_free(vm_area_cachep, vma); - return -ENOMEM; - } + ret = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); + if (ret) + goto out; + + ret = insert_vm_struct(mm, vma); + if (ret) + goto out; mm->total_vm += len >> PAGE_SHIFT; perf_event_mmap(vma); return 0; + +out: + kmem_cache_free(vm_area_cachep, vma); + return ret; } static DEFINE_MUTEX(mm_all_locks_mutex); diff --git a/mm/nommu.c b/mm/nommu.c index 3613517c7592..27a9ac588516 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1717,6 +1717,7 @@ void exit_mmap(struct mm_struct *mm) mm->mmap = vma->vm_next; delete_vma_from_mm(vma); delete_vma(mm, vma); + cond_resched(); } kleave(""); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 07a654486f75..ff7e15872398 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -104,19 +104,24 @@ gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK; * only be modified with pm_mutex held, unless the suspend/hibernate code is * guaranteed not to run in parallel with that modification). */ -void set_gfp_allowed_mask(gfp_t mask) + +static gfp_t saved_gfp_mask; + +void pm_restore_gfp_mask(void) { WARN_ON(!mutex_is_locked(&pm_mutex)); - gfp_allowed_mask = mask; + if (saved_gfp_mask) { + gfp_allowed_mask = saved_gfp_mask; + saved_gfp_mask = 0; + } } -gfp_t clear_gfp_allowed_mask(gfp_t mask) +void pm_restrict_gfp_mask(void) { - gfp_t ret = gfp_allowed_mask; - WARN_ON(!mutex_is_locked(&pm_mutex)); - gfp_allowed_mask &= ~mask; - return ret; + WARN_ON(saved_gfp_mask); + saved_gfp_mask = gfp_allowed_mask; + gfp_allowed_mask &= ~GFP_IOFS; } #endif /* CONFIG_PM_SLEEP */ @@ -3008,14 +3013,6 @@ static __init_refok int __build_all_zonelists(void *data) build_zonelist_cache(pgdat); } -#ifdef CONFIG_MEMORY_HOTPLUG - /* Setup real pagesets for the new zone */ - if (data) { - struct zone *zone = data; - setup_zone_pageset(zone); - } -#endif - /* * Initialize the boot_pagesets that are going to be used * for bootstrapping processors. The real pagesets for @@ -3064,7 +3061,11 @@ void build_all_zonelists(void *data) } else { /* we have to stop all cpus to guarantee there is no user of zonelist */ - stop_machine(__build_all_zonelists, data, NULL); +#ifdef CONFIG_MEMORY_HOTPLUG + if (data) + setup_zone_pageset((struct zone *)data); +#endif + stop_machine(__build_all_zonelists, NULL, NULL); /* cpuset refresh routine should be here */ } vm_total_pages = nr_free_pagecache_pages(); diff --git a/mm/pagewalk.c b/mm/pagewalk.c index 8b1a2ce21ee5..38cc58b8b2b0 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c @@ -139,7 +139,6 @@ int walk_page_range(unsigned long addr, unsigned long end, pgd_t *pgd; unsigned long next; int err = 0; - struct vm_area_struct *vma; if (addr >= end) return err; @@ -149,15 +148,17 @@ int walk_page_range(unsigned long addr, unsigned long end, pgd = pgd_offset(walk->mm, addr); do { + struct vm_area_struct *uninitialized_var(vma); + next = pgd_addr_end(addr, end); +#ifdef CONFIG_HUGETLB_PAGE /* * handle hugetlb vma individually because pagetable walk for * the hugetlb page is dependent on the architecture and * we can't handled it in the same manner as non-huge pages. */ vma = find_vma(walk->mm, addr); -#ifdef CONFIG_HUGETLB_PAGE if (vma && is_vm_hugetlb_page(vma)) { if (vma->vm_end < next) next = vma->vm_end; diff --git a/mm/slub.c b/mm/slub.c index 981fb730aa04..bec0e355fbad 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -3401,13 +3401,13 @@ static int validate_slab(struct kmem_cache *s, struct page *page, for_each_free_object(p, s, page->freelist) { set_bit(slab_index(p, s, addr), map); - if (!check_object(s, page, p, 0)) + if (!check_object(s, page, p, SLUB_RED_INACTIVE)) return 0; } for_each_object(p, s, addr, page->objects) if (!test_bit(slab_index(p, s, addr), map)) - if (!check_object(s, page, p, 1)) + if (!check_object(s, page, p, SLUB_RED_ACTIVE)) return 0; return 1; } diff --git a/mm/truncate.c b/mm/truncate.c index ba887bff48c5..3c2d5ddfa0d4 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -390,6 +390,10 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page) __remove_from_page_cache(page); spin_unlock_irq(&mapping->tree_lock); mem_cgroup_uncharge_cache_page(page); + + if (mapping->a_ops->freepage) + mapping->a_ops->freepage(page); + page_cache_release(page); /* pagecache ref */ return 1; failed: diff --git a/mm/vmalloc.c b/mm/vmalloc.c index a3d66b3dc5cb..eb5cc7d00c5a 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -31,8 +31,6 @@ #include <asm/tlbflush.h> #include <asm/shmparam.h> -bool vmap_lazy_unmap __read_mostly = true; - /*** Page table manipulation functions ***/ static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end) @@ -503,9 +501,6 @@ static unsigned long lazy_max_pages(void) { unsigned int log; - if (!vmap_lazy_unmap) - return 0; - log = fls(num_online_cpus()); return log * (32UL * 1024 * 1024 / PAGE_SIZE); @@ -566,7 +561,6 @@ static void __purge_vmap_area_lazy(unsigned long *start, unsigned long *end, if (va->va_end > *end) *end = va->va_end; nr += (va->va_end - va->va_start) >> PAGE_SHIFT; - unmap_vmap_area(va); list_add_tail(&va->purge_list, &valist); va->flags |= VM_LAZY_FREEING; va->flags &= ~VM_LAZY_FREE; @@ -611,10 +605,11 @@ static void purge_vmap_area_lazy(void) } /* - * Free and unmap a vmap area, caller ensuring flush_cache_vunmap had been - * called for the correct range previously. + * Free a vmap area, caller ensuring that the area has been unmapped + * and flush_cache_vunmap had been called for the correct range + * previously. */ -static void free_unmap_vmap_area_noflush(struct vmap_area *va) +static void free_vmap_area_noflush(struct vmap_area *va) { va->flags |= VM_LAZY_FREE; atomic_add((va->va_end - va->va_start) >> PAGE_SHIFT, &vmap_lazy_nr); @@ -623,6 +618,16 @@ static void free_unmap_vmap_area_noflush(struct vmap_area *va) } /* + * Free and unmap a vmap area, caller ensuring flush_cache_vunmap had been + * called for the correct range previously. + */ +static void free_unmap_vmap_area_noflush(struct vmap_area *va) +{ + unmap_vmap_area(va); + free_vmap_area_noflush(va); +} + +/* * Free and unmap a vmap area */ static void free_unmap_vmap_area(struct vmap_area *va) @@ -798,7 +803,7 @@ static void free_vmap_block(struct vmap_block *vb) spin_unlock(&vmap_block_tree_lock); BUG_ON(tmp != vb); - free_unmap_vmap_area_noflush(vb->va); + free_vmap_area_noflush(vb->va); call_rcu(&vb->rcu_head, rcu_free_vb); } @@ -936,6 +941,8 @@ static void vb_free(const void *addr, unsigned long size) rcu_read_unlock(); BUG_ON(!vb); + vunmap_page_range((unsigned long)addr, (unsigned long)addr + size); + spin_lock(&vb->lock); BUG_ON(bitmap_allocate_region(vb->dirty_map, offset >> PAGE_SHIFT, order)); @@ -988,7 +995,6 @@ void vm_unmap_aliases(void) s = vb->va->va_start + (i << PAGE_SHIFT); e = vb->va->va_start + (j << PAGE_SHIFT); - vunmap_page_range(s, e); flush = 1; if (s < start) diff --git a/mm/vmscan.c b/mm/vmscan.c index d31d7ce52c0e..9ca587c69274 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -494,9 +494,16 @@ static int __remove_mapping(struct address_space *mapping, struct page *page) spin_unlock_irq(&mapping->tree_lock); swapcache_free(swap, page); } else { + void (*freepage)(struct page *); + + freepage = mapping->a_ops->freepage; + __remove_from_page_cache(page); spin_unlock_irq(&mapping->tree_lock); mem_cgroup_uncharge_cache_page(page); + + if (freepage != NULL) + freepage(page); } return 1; diff --git a/mm/vmstat.c b/mm/vmstat.c index 42eac4d33216..8f62f17ee1c7 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -750,8 +750,6 @@ static const char * const vmstat_text[] = { "nr_shmem", "nr_dirtied", "nr_written", - "nr_dirty_threshold", - "nr_dirty_background_threshold", #ifdef CONFIG_NUMA "numa_hit", @@ -761,6 +759,8 @@ static const char * const vmstat_text[] = { "numa_local", "numa_other", #endif + "nr_dirty_threshold", + "nr_dirty_background_threshold", #ifdef CONFIG_VM_EVENT_COUNTERS "pgpgin", diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c index 799c631f0fed..f7fa67c78766 100644 --- a/net/atm/atm_sysfs.c +++ b/net/atm/atm_sysfs.c @@ -143,12 +143,13 @@ static struct class atm_class = { .dev_uevent = atm_uevent, }; -int atm_register_sysfs(struct atm_dev *adev) +int atm_register_sysfs(struct atm_dev *adev, struct device *parent) { struct device *cdev = &adev->class_dev; int i, j, err; cdev->class = &atm_class; + cdev->parent = parent; dev_set_drvdata(cdev, adev); dev_set_name(cdev, "%s%d", adev->type, adev->number); diff --git a/net/atm/resources.c b/net/atm/resources.c index d29e58261511..23f45ce6f351 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -74,8 +74,9 @@ struct atm_dev *atm_dev_lookup(int number) } EXPORT_SYMBOL(atm_dev_lookup); -struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, - int number, unsigned long *flags) +struct atm_dev *atm_dev_register(const char *type, struct device *parent, + const struct atmdev_ops *ops, int number, + unsigned long *flags) { struct atm_dev *dev, *inuse; @@ -115,7 +116,7 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, goto out_fail; } - if (atm_register_sysfs(dev) < 0) { + if (atm_register_sysfs(dev, parent) < 0) { pr_err("atm_register_sysfs failed for dev %s\n", type); atm_proc_dev_deregister(dev); goto out_fail; diff --git a/net/atm/resources.h b/net/atm/resources.h index 126fb1840dfb..521431e30507 100644 --- a/net/atm/resources.h +++ b/net/atm/resources.h @@ -42,6 +42,6 @@ static inline void atm_proc_dev_deregister(struct atm_dev *dev) #endif /* CONFIG_PROC_FS */ -int atm_register_sysfs(struct atm_dev *adev); +int atm_register_sysfs(struct atm_dev *adev, struct device *parent); void atm_unregister_sysfs(struct atm_dev *adev); #endif diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index d0927d1fdada..66b9e5c0523a 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -882,7 +882,7 @@ static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) int lm = 0; if (type != SCO_LINK && type != ESCO_LINK) - return 0; + return -EINVAL; BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); @@ -908,7 +908,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status) BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) - return 0; + return -EINVAL; if (!status) { struct sco_conn *conn; @@ -927,7 +927,7 @@ static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) BT_DBG("hcon %p reason %d", hcon, reason); if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) - return 0; + return -EINVAL; sco_conn_del(hcon, bt_err(reason)); diff --git a/net/ceph/Makefile b/net/ceph/Makefile index aab1cabb8035..5f19415ec9c0 100644 --- a/net/ceph/Makefile +++ b/net/ceph/Makefile @@ -1,9 +1,6 @@ # # Makefile for CEPH filesystem. # - -ifneq ($(KERNELRELEASE),) - obj-$(CONFIG_CEPH_LIB) += libceph.o libceph-objs := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \ @@ -16,22 +13,3 @@ libceph-objs := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \ ceph_fs.o ceph_strings.o ceph_hash.o \ pagevec.o -else -#Otherwise we were called directly from the command -# line; invoke the kernel build system. - -KERNELDIR ?= /lib/modules/$(shell uname -r)/build -PWD := $(shell pwd) - -default: all - -all: - $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_LIB=m modules - -modules_install: - $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_LIB=m modules_install - -clean: - $(MAKE) -C $(KERNELDIR) M=$(PWD) clean - -endif diff --git a/net/ceph/buffer.c b/net/ceph/buffer.c index 53d8abfa25d5..bf3e6a13c215 100644 --- a/net/ceph/buffer.c +++ b/net/ceph/buffer.c @@ -19,7 +19,7 @@ struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp) if (b->vec.iov_base) { b->is_vmalloc = false; } else { - b->vec.iov_base = __vmalloc(len, gfp, PAGE_KERNEL); + b->vec.iov_base = __vmalloc(len, gfp | __GFP_HIGHMEM, PAGE_KERNEL); if (!b->vec.iov_base) { kfree(b); return NULL; diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 0e8157ee5d43..b6ff4a1519ab 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -97,11 +97,9 @@ struct workqueue_struct *ceph_msgr_wq; int ceph_msgr_init(void) { ceph_msgr_wq = create_workqueue("ceph-msgr"); - if (IS_ERR(ceph_msgr_wq)) { - int ret = PTR_ERR(ceph_msgr_wq); - pr_err("msgr_init failed to create workqueue: %d\n", ret); - ceph_msgr_wq = NULL; - return ret; + if (!ceph_msgr_wq) { + pr_err("msgr_init failed to create workqueue\n"); + return -ENOMEM; } return 0; } @@ -540,8 +538,7 @@ static void prepare_write_message(struct ceph_connection *con) /* initialize page iterator */ con->out_msg_pos.page = 0; if (m->pages) - con->out_msg_pos.page_pos = - le16_to_cpu(m->hdr.data_off) & ~PAGE_MASK; + con->out_msg_pos.page_pos = m->page_alignment; else con->out_msg_pos.page_pos = 0; con->out_msg_pos.data_pos = 0; @@ -1491,7 +1488,7 @@ static int read_partial_message(struct ceph_connection *con) struct ceph_msg *m = con->in_msg; int ret; int to, left; - unsigned front_len, middle_len, data_len, data_off; + unsigned front_len, middle_len, data_len; int datacrc = con->msgr->nocrc; int skip; u64 seq; @@ -1527,19 +1524,17 @@ static int read_partial_message(struct ceph_connection *con) data_len = le32_to_cpu(con->in_hdr.data_len); if (data_len > CEPH_MSG_MAX_DATA_LEN) return -EIO; - data_off = le16_to_cpu(con->in_hdr.data_off); /* verify seq# */ seq = le64_to_cpu(con->in_hdr.seq); if ((s64)seq - (s64)con->in_seq < 1) { - pr_info("skipping %s%lld %s seq %lld, expected %lld\n", + pr_info("skipping %s%lld %s seq %lld expected %lld\n", ENTITY_NAME(con->peer_name), ceph_pr_addr(&con->peer_addr.in_addr), seq, con->in_seq + 1); con->in_base_pos = -front_len - middle_len - data_len - sizeof(m->footer); con->in_tag = CEPH_MSGR_TAG_READY; - con->in_seq++; return 0; } else if ((s64)seq - (s64)con->in_seq > 1) { pr_err("read_partial_message bad seq %lld expected %lld\n", @@ -1576,7 +1571,7 @@ static int read_partial_message(struct ceph_connection *con) con->in_msg_pos.page = 0; if (m->pages) - con->in_msg_pos.page_pos = data_off & ~PAGE_MASK; + con->in_msg_pos.page_pos = m->page_alignment; else con->in_msg_pos.page_pos = 0; con->in_msg_pos.data_pos = 0; @@ -2301,6 +2296,7 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags) /* data */ m->nr_pages = 0; + m->page_alignment = 0; m->pages = NULL; m->pagelist = NULL; m->bio = NULL; @@ -2370,6 +2366,7 @@ static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con, type, front_len); return NULL; } + msg->page_alignment = le16_to_cpu(hdr->data_off); } memcpy(&msg->hdr, &con->in_hdr, sizeof(con->in_hdr)); diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 79391994b3ed..3e20a122ffa2 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -71,6 +71,7 @@ void ceph_calc_raw_layout(struct ceph_osd_client *osdc, op->extent.length = objlen; } req->r_num_pages = calc_pages_for(off, *plen); + req->r_page_alignment = off & ~PAGE_MASK; if (op->op == CEPH_OSD_OP_WRITE) op->payload_len = *plen; @@ -390,6 +391,8 @@ void ceph_osdc_build_request(struct ceph_osd_request *req, req->r_request->hdr.data_len = cpu_to_le32(data_len); } + req->r_request->page_alignment = req->r_page_alignment; + BUG_ON(p > msg->front.iov_base + msg->front.iov_len); msg_size = p - msg->front.iov_base; msg->front.iov_len = msg_size; @@ -419,7 +422,8 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, u32 truncate_seq, u64 truncate_size, struct timespec *mtime, - bool use_mempool, int num_reply) + bool use_mempool, int num_reply, + int page_align) { struct ceph_osd_req_op ops[3]; struct ceph_osd_request *req; @@ -447,6 +451,10 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, calc_layout(osdc, vino, layout, off, plen, req, ops); req->r_file_layout = *layout; /* keep a copy */ + /* in case it differs from natural alignment that calc_layout + filled in for us */ + req->r_page_alignment = page_align; + ceph_osdc_build_request(req, off, plen, ops, snapc, mtime, @@ -1489,7 +1497,7 @@ int ceph_osdc_readpages(struct ceph_osd_client *osdc, struct ceph_vino vino, struct ceph_file_layout *layout, u64 off, u64 *plen, u32 truncate_seq, u64 truncate_size, - struct page **pages, int num_pages) + struct page **pages, int num_pages, int page_align) { struct ceph_osd_request *req; int rc = 0; @@ -1499,15 +1507,15 @@ int ceph_osdc_readpages(struct ceph_osd_client *osdc, req = ceph_osdc_new_request(osdc, layout, vino, off, plen, CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ, NULL, 0, truncate_seq, truncate_size, NULL, - false, 1); + false, 1, page_align); if (!req) return -ENOMEM; /* it may be a short read due to an object boundary */ req->r_pages = pages; - dout("readpages final extent is %llu~%llu (%d pages)\n", - off, *plen, req->r_num_pages); + dout("readpages final extent is %llu~%llu (%d pages align %d)\n", + off, *plen, req->r_num_pages, page_align); rc = ceph_osdc_start_request(osdc, req, false); if (!rc) @@ -1533,6 +1541,7 @@ int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino, { struct ceph_osd_request *req; int rc = 0; + int page_align = off & ~PAGE_MASK; BUG_ON(vino.snap != CEPH_NOSNAP); req = ceph_osdc_new_request(osdc, layout, vino, off, &len, @@ -1541,7 +1550,7 @@ int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino, CEPH_OSD_FLAG_WRITE, snapc, do_sync, truncate_seq, truncate_size, mtime, - nofail, 1); + nofail, 1, page_align); if (!req) return -ENOMEM; @@ -1638,8 +1647,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, m = ceph_msg_get(req->r_reply); if (data_len > 0) { - unsigned data_off = le16_to_cpu(hdr->data_off); - int want = calc_pages_for(data_off & ~PAGE_MASK, data_len); + int want = calc_pages_for(req->r_page_alignment, data_len); if (unlikely(req->r_num_pages < want)) { pr_warning("tid %lld reply %d > expected %d pages\n", @@ -1651,6 +1659,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, } m->pages = req->r_pages; m->nr_pages = req->r_num_pages; + m->page_alignment = req->r_page_alignment; #ifdef CONFIG_BLOCK m->bio = req->r_bio; #endif diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c index 54caf0687155..1a040e64c69f 100644 --- a/net/ceph/pagevec.c +++ b/net/ceph/pagevec.c @@ -13,8 +13,7 @@ * build a vector of user pages */ struct page **ceph_get_direct_page_vector(const char __user *data, - int num_pages, - loff_t off, size_t len) + int num_pages, bool write_page) { struct page **pages; int rc; @@ -25,24 +24,27 @@ struct page **ceph_get_direct_page_vector(const char __user *data, down_read(¤t->mm->mmap_sem); rc = get_user_pages(current, current->mm, (unsigned long)data, - num_pages, 0, 0, pages, NULL); + num_pages, write_page, 0, pages, NULL); up_read(¤t->mm->mmap_sem); - if (rc < 0) + if (rc < num_pages) goto fail; return pages; fail: - kfree(pages); + ceph_put_page_vector(pages, rc > 0 ? rc : 0, false); return ERR_PTR(rc); } EXPORT_SYMBOL(ceph_get_direct_page_vector); -void ceph_put_page_vector(struct page **pages, int num_pages) +void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty) { int i; - for (i = 0; i < num_pages; i++) + for (i = 0; i < num_pages; i++) { + if (dirty) + set_page_dirty_lock(pages[i]); put_page(pages[i]); + } kfree(pages); } EXPORT_SYMBOL(ceph_put_page_vector); diff --git a/net/core/filter.c b/net/core/filter.c index 23e9b2a6b4c8..ae21a0d3c4a2 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -589,23 +589,16 @@ int sk_chk_filter(struct sock_filter *filter, int flen) EXPORT_SYMBOL(sk_chk_filter); /** - * sk_filter_rcu_release: Release a socket filter by rcu_head + * sk_filter_release_rcu - Release a socket filter by rcu_head * @rcu: rcu_head that contains the sk_filter to free */ -static void sk_filter_rcu_release(struct rcu_head *rcu) +void sk_filter_release_rcu(struct rcu_head *rcu) { struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); - sk_filter_release(fp); -} - -static void sk_filter_delayed_uncharge(struct sock *sk, struct sk_filter *fp) -{ - unsigned int size = sk_filter_len(fp); - - atomic_sub(size, &sk->sk_omem_alloc); - call_rcu_bh(&fp->rcu, sk_filter_rcu_release); + kfree(fp); } +EXPORT_SYMBOL(sk_filter_release_rcu); /** * sk_attach_filter - attach a socket filter @@ -649,7 +642,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) rcu_assign_pointer(sk->sk_filter, fp); if (old_fp) - sk_filter_delayed_uncharge(sk, old_fp); + sk_filter_uncharge(sk, old_fp); return 0; } EXPORT_SYMBOL_GPL(sk_attach_filter); @@ -663,7 +656,7 @@ int sk_detach_filter(struct sock *sk) sock_owned_by_user(sk)); if (filter) { rcu_assign_pointer(sk->sk_filter, NULL); - sk_filter_delayed_uncharge(sk, filter); + sk_filter_uncharge(sk, filter); ret = 0; } return ret; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index a5ff5a89f376..7f902cad10f8 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -712,15 +712,21 @@ static void rx_queue_release(struct kobject *kobj) map = rcu_dereference_raw(queue->rps_map); - if (map) + if (map) { + RCU_INIT_POINTER(queue->rps_map, NULL); call_rcu(&map->rcu, rps_map_release); + } flow_table = rcu_dereference_raw(queue->rps_flow_table); - if (flow_table) + if (flow_table) { + RCU_INIT_POINTER(queue->rps_flow_table, NULL); call_rcu(&flow_table->rcu, rps_dev_flow_table_release); + } if (atomic_dec_and_test(&first->count)) kfree(first); + else + memset(kobj, 0, sizeof(*kobj)); } static struct kobj_type rx_queue_ktype = { diff --git a/net/core/request_sock.c b/net/core/request_sock.c index 7552495aff7a..fceeb37d7161 100644 --- a/net/core/request_sock.c +++ b/net/core/request_sock.c @@ -45,9 +45,7 @@ int reqsk_queue_alloc(struct request_sock_queue *queue, nr_table_entries = roundup_pow_of_two(nr_table_entries + 1); lopt_size += nr_table_entries * sizeof(struct request_sock *); if (lopt_size > PAGE_SIZE) - lopt = __vmalloc(lopt_size, - GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, - PAGE_KERNEL); + lopt = vzalloc(lopt_size); else lopt = kzalloc(lopt_size, GFP_KERNEL); if (lopt == NULL) diff --git a/net/core/timestamping.c b/net/core/timestamping.c index 0ae6c22da85b..c19bb4ee405e 100644 --- a/net/core/timestamping.c +++ b/net/core/timestamping.c @@ -96,11 +96,13 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb) struct phy_device *phydev; unsigned int type; - skb_push(skb, ETH_HLEN); + if (skb_headroom(skb) < ETH_HLEN) + return false; + __skb_push(skb, ETH_HLEN); type = classify(skb); - skb_pull(skb, ETH_HLEN); + __skb_pull(skb, ETH_HLEN); switch (type) { case PTP_CLASS_V1_IPV4: diff --git a/net/dccp/input.c b/net/dccp/input.c index 265985370fa1..e424a09e83f6 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -239,7 +239,8 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) dccp_update_gsr(sk, seqno); if (dh->dccph_type != DCCP_PKT_SYNC && - (ackno != DCCP_PKT_WITHOUT_ACK_SEQ)) + ackno != DCCP_PKT_WITHOUT_ACK_SEQ && + after48(ackno, dp->dccps_gar)) dp->dccps_gar = ackno; } else { unsigned long now = jiffies; diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index a76b78de679f..6f97268ed85f 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -1556,6 +1556,8 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us if (r_len > sizeof(struct linkinfo_dn)) r_len = sizeof(struct linkinfo_dn); + memset(&link, 0, sizeof(link)); + switch(sock->state) { case SS_CONNECTING: link.idn_linkstate = LL_CONNECTING; diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index f8c1ae4b41f0..15dcc1a586b4 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -31,6 +31,7 @@ #include <linux/skbuff.h> #include <linux/udp.h> #include <linux/slab.h> +#include <linux/vmalloc.h> #include <net/sock.h> #include <net/inet_common.h> #include <linux/stat.h> @@ -276,12 +277,12 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, #endif #ifdef CONFIG_ECONET_AUNUDP struct msghdr udpmsg; - struct iovec iov[msg->msg_iovlen+1]; + struct iovec iov[2]; struct aunhdr ah; struct sockaddr_in udpdest; __kernel_size_t size; - int i; mm_segment_t oldfs; + char *userbuf; #endif /* @@ -297,23 +298,14 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, mutex_lock(&econet_mutex); - if (saddr == NULL) { - struct econet_sock *eo = ec_sk(sk); - - addr.station = eo->station; - addr.net = eo->net; - port = eo->port; - cb = eo->cb; - } else { - if (msg->msg_namelen < sizeof(struct sockaddr_ec)) { - mutex_unlock(&econet_mutex); - return -EINVAL; - } - addr.station = saddr->addr.station; - addr.net = saddr->addr.net; - port = saddr->port; - cb = saddr->cb; - } + if (saddr == NULL || msg->msg_namelen < sizeof(struct sockaddr_ec)) { + mutex_unlock(&econet_mutex); + return -EINVAL; + } + addr.station = saddr->addr.station; + addr.net = saddr->addr.net; + port = saddr->port; + cb = saddr->cb; /* Look for a device with the right network number. */ dev = net2dev_map[addr.net]; @@ -328,17 +320,17 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, } } - if (len + 15 > dev->mtu) { - mutex_unlock(&econet_mutex); - return -EMSGSIZE; - } - if (dev->type == ARPHRD_ECONET) { /* Real hardware Econet. We're not worthy etc. */ #ifdef CONFIG_ECONET_NATIVE unsigned short proto = 0; int res; + if (len + 15 > dev->mtu) { + mutex_unlock(&econet_mutex); + return -EMSGSIZE; + } + dev_hold(dev); skb = sock_alloc_send_skb(sk, len+LL_ALLOCATED_SPACE(dev), @@ -351,7 +343,6 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, eb = (struct ec_cb *)&skb->cb; - /* BUG: saddr may be NULL */ eb->cookie = saddr->cookie; eb->sec = *saddr; eb->sent = ec_tx_done; @@ -415,6 +406,11 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, return -ENETDOWN; /* No socket - can't send */ } + if (len > 32768) { + err = -E2BIG; + goto error; + } + /* Make up a UDP datagram and hand it off to some higher intellect. */ memset(&udpdest, 0, sizeof(udpdest)); @@ -446,36 +442,26 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, /* tack our header on the front of the iovec */ size = sizeof(struct aunhdr); - /* - * XXX: that is b0rken. We can't mix userland and kernel pointers - * in iovec, since on a lot of platforms copy_from_user() will - * *not* work with the kernel and userland ones at the same time, - * regardless of what we do with set_fs(). And we are talking about - * econet-over-ethernet here, so "it's only ARM anyway" doesn't - * apply. Any suggestions on fixing that code? -- AV - */ iov[0].iov_base = (void *)&ah; iov[0].iov_len = size; - for (i = 0; i < msg->msg_iovlen; i++) { - void __user *base = msg->msg_iov[i].iov_base; - size_t iov_len = msg->msg_iov[i].iov_len; - /* Check it now since we switch to KERNEL_DS later. */ - if (!access_ok(VERIFY_READ, base, iov_len)) { - mutex_unlock(&econet_mutex); - return -EFAULT; - } - iov[i+1].iov_base = base; - iov[i+1].iov_len = iov_len; - size += iov_len; + + userbuf = vmalloc(len); + if (userbuf == NULL) { + err = -ENOMEM; + goto error; } + iov[1].iov_base = userbuf; + iov[1].iov_len = len; + err = memcpy_fromiovec(userbuf, msg->msg_iov, len); + if (err) + goto error_free_buf; + /* Get a skbuff (no data, just holds our cb information) */ if ((skb = sock_alloc_send_skb(sk, 0, msg->msg_flags & MSG_DONTWAIT, - &err)) == NULL) { - mutex_unlock(&econet_mutex); - return err; - } + &err)) == NULL) + goto error_free_buf; eb = (struct ec_cb *)&skb->cb; @@ -491,7 +477,7 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, udpmsg.msg_name = (void *)&udpdest; udpmsg.msg_namelen = sizeof(udpdest); udpmsg.msg_iov = &iov[0]; - udpmsg.msg_iovlen = msg->msg_iovlen + 1; + udpmsg.msg_iovlen = 2; udpmsg.msg_control = NULL; udpmsg.msg_controllen = 0; udpmsg.msg_flags=0; @@ -499,9 +485,13 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, oldfs = get_fs(); set_fs(KERNEL_DS); /* More privs :-) */ err = sock_sendmsg(udpsock, &udpmsg, size); set_fs(oldfs); + +error_free_buf: + vfree(userbuf); #else err = -EPROTOTYPE; #endif + error: mutex_unlock(&econet_mutex); return err; @@ -671,6 +661,11 @@ static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void __user *arg) err = 0; switch (cmd) { case SIOCSIFADDR: + if (!capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + edev = dev->ec_ptr; if (edev == NULL) { /* Magic up a new one. */ @@ -856,9 +851,13 @@ static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len) { struct iphdr *ip = ip_hdr(skb); unsigned char stn = ntohl(ip->saddr) & 0xff; + struct dst_entry *dst = skb_dst(skb); + struct ec_device *edev = NULL; struct sock *sk = NULL; struct sk_buff *newskb; - struct ec_device *edev = skb->dev->ec_ptr; + + if (dst) + edev = dst->dev->ec_ptr; if (! edev) goto bad; diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 200eb538fbb3..0f280348e0fd 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -365,7 +365,7 @@ static struct tnode *tnode_alloc(size_t size) if (size <= PAGE_SIZE) return kzalloc(size, GFP_KERNEL); else - return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); + return vzalloc(size); } static void __tnode_vfree(struct work_struct *arg) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 96bc7f9475a3..e5d1a44bcbdf 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -569,6 +569,9 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) /* No need to clone since we're just using its address. */ rt2 = rt; + if (!fl.nl_u.ip4_u.saddr) + fl.nl_u.ip4_u.saddr = rt->rt_src; + err = xfrm_lookup(net, (struct dst_entry **)&rt, &fl, NULL, 0); switch (err) { case 0: diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 1b344f30b463..3c0369a3a663 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -133,8 +133,7 @@ int __inet_inherit_port(struct sock *sk, struct sock *child) } } } - sk_add_bind_node(child, &tb->owners); - inet_csk(child)->icsk_bind_hash = tb; + inet_bind_hash(child, tb, port); spin_unlock(&head->lock); return 0; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 1b48eb1ed453..b14ec7d03b6e 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -253,6 +253,7 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPMinTTLDrop", LINUX_MIB_TCPMINTTLDROP), SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP), SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER), + SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index e91911d7aae2..1b4ec21497a4 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -26,6 +26,8 @@ static int zero; static int tcp_retr1_max = 255; static int ip_local_port_range_min[] = { 1, 1 }; static int ip_local_port_range_max[] = { 65535, 65535 }; +static int tcp_adv_win_scale_min = -31; +static int tcp_adv_win_scale_max = 31; /* Update system visible IP port range */ static void set_local_port_range(int range[2]) @@ -426,7 +428,9 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_adv_win_scale, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = &tcp_adv_win_scale_min, + .extra2 = &tcp_adv_win_scale_max, }, { .procname = "tcp_tw_reuse", diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 081419969485..f15c36a706ec 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2246,7 +2246,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, /* Values greater than interface MTU won't take effect. However * at the point when this call is done we typically don't yet * know which interface is going to be used */ - if (val < 64 || val > MAX_TCP_WINDOW) { + if (val < TCP_MIN_MSS || val > MAX_TCP_WINDOW) { err = -EINVAL; break; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 69ccbc1dde9c..e13da6de1fc7 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2043,7 +2043,9 @@ get_req: } get_sk: sk_nulls_for_each_from(sk, node) { - if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) { + if (!net_eq(sock_net(sk), net)) + continue; + if (sk->sk_family == st->family) { cur = sk; goto out; } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 43cf901d7659..a66735f75963 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -347,7 +347,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) * socket up. We've got bigger problems than * non-graceful socket closings. */ - LIMIT_NETDEBUG(KERN_INFO "TCP: time wait bucket table overflow\n"); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPTIMEWAITOVERFLOW); } tcp_update_metrics(sk); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 05b1ecf36763..61c2463e2753 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -231,11 +231,10 @@ void tcp_select_initial_window(int __space, __u32 mss, /* when initializing use the value from init_rcv_wnd * rather than the default from above */ - if (init_rcv_wnd && - (*rcv_wnd > init_rcv_wnd * mss)) - *rcv_wnd = init_rcv_wnd * mss; - else if (*rcv_wnd > init_cwnd * mss) - *rcv_wnd = init_cwnd * mss; + if (init_rcv_wnd) + *rcv_wnd = min(*rcv_wnd, init_rcv_wnd * mss); + else + *rcv_wnd = min(*rcv_wnd, init_cwnd * mss); } /* Set the clamp no higher than max representable value */ @@ -386,27 +385,30 @@ struct tcp_out_options { */ static u8 tcp_cookie_size_check(u8 desired) { - if (desired > 0) { + int cookie_size; + + if (desired > 0) /* previously specified */ return desired; - } - if (sysctl_tcp_cookie_size <= 0) { + + cookie_size = ACCESS_ONCE(sysctl_tcp_cookie_size); + if (cookie_size <= 0) /* no default specified */ return 0; - } - if (sysctl_tcp_cookie_size <= TCP_COOKIE_MIN) { + + if (cookie_size <= TCP_COOKIE_MIN) /* value too small, specify minimum */ return TCP_COOKIE_MIN; - } - if (sysctl_tcp_cookie_size >= TCP_COOKIE_MAX) { + + if (cookie_size >= TCP_COOKIE_MAX) /* value too large, specify maximum */ return TCP_COOKIE_MAX; - } - if (0x1 & sysctl_tcp_cookie_size) { + + if (cookie_size & 1) /* 8-bit multiple, illegal, fix it */ - return (u8)(sysctl_tcp_cookie_size + 0x1); - } - return (u8)sysctl_tcp_cookie_size; + cookie_size++; + + return (u8)cookie_size; } /* Write previously computed TCP options to the packet. @@ -1513,6 +1515,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb) struct tcp_sock *tp = tcp_sk(sk); const struct inet_connection_sock *icsk = inet_csk(sk); u32 send_win, cong_win, limit, in_flight; + int win_divisor; if (TCP_SKB_CB(skb)->flags & TCPHDR_FIN) goto send_now; @@ -1544,13 +1547,14 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb) if ((skb != tcp_write_queue_tail(sk)) && (limit >= skb->len)) goto send_now; - if (sysctl_tcp_tso_win_divisor) { + win_divisor = ACCESS_ONCE(sysctl_tcp_tso_win_divisor); + if (win_divisor) { u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache); /* If at least some fraction of a window is available, * just use it. */ - chunk /= sysctl_tcp_tso_win_divisor; + chunk /= win_divisor; if (limit >= chunk) goto send_now; } else { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index b41ce0f0d514..93b7a933a775 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -98,7 +98,11 @@ #endif #define INFINITY_LIFE_TIME 0xFFFFFFFF -#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b))) + +static inline u32 cstamp_delta(unsigned long cstamp) +{ + return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; +} #define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1) #define ADDRCONF_TIMER_FUZZ (HZ / 4) @@ -2754,13 +2758,13 @@ static int addrconf_ifdown(struct net_device *dev, int how) ifa->state = INET6_IFADDR_STATE_DEAD; spin_unlock_bh(&ifa->state_lock); - if (state == INET6_IFADDR_STATE_DEAD) { - in6_ifa_put(ifa); - } else { + if (state != INET6_IFADDR_STATE_DEAD) { __ipv6_ifa_notify(RTM_DELADDR, ifa); atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); } + + in6_ifa_put(ifa); write_lock_bh(&idev->lock); } } @@ -3444,10 +3448,8 @@ static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, { struct ifa_cacheinfo ci; - ci.cstamp = (u32)(TIME_DELTA(cstamp, INITIAL_JIFFIES) / HZ * 100 - + TIME_DELTA(cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); - ci.tstamp = (u32)(TIME_DELTA(tstamp, INITIAL_JIFFIES) / HZ * 100 - + TIME_DELTA(tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); + ci.cstamp = cstamp_delta(cstamp); + ci.tstamp = cstamp_delta(tstamp); ci.ifa_prefered = preferred; ci.ifa_valid = valid; @@ -3798,8 +3800,10 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_AUTOCONF] = cnf->autoconf; array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits; array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits; - array[DEVCONF_RTR_SOLICIT_INTERVAL] = cnf->rtr_solicit_interval; - array[DEVCONF_RTR_SOLICIT_DELAY] = cnf->rtr_solicit_delay; + array[DEVCONF_RTR_SOLICIT_INTERVAL] = + jiffies_to_msecs(cnf->rtr_solicit_interval); + array[DEVCONF_RTR_SOLICIT_DELAY] = + jiffies_to_msecs(cnf->rtr_solicit_delay); array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version; #ifdef CONFIG_IPV6_PRIVACY array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr; @@ -3813,7 +3817,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; #ifdef CONFIG_IPV6_ROUTER_PREF array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref; - array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval; + array[DEVCONF_RTR_PROBE_INTERVAL] = + jiffies_to_msecs(cnf->rtr_probe_interval); #ifdef CONFIG_IPV6_ROUTE_INFO array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; #endif @@ -3929,10 +3934,9 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); ci.max_reasm_len = IPV6_MAXPLEN; - ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100 - + TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); - ci.reachable_time = idev->nd_parms->reachable_time; - ci.retrans_time = idev->nd_parms->retrans_time; + ci.tstamp = cstamp_delta(idev->tstamp); + ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); + ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time); NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); @@ -4017,11 +4021,11 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev) kfree_skb(skb); goto errout; } - rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); + rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFINFO, NULL, GFP_ATOMIC); return; errout: if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); + rtnl_set_sk_err(net, RTNLGRP_IPV6_IFINFO, err); } static inline size_t inet6_prefix_nlmsg_size(void) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 2a59610c2a58..70e891a20fb9 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1175,6 +1175,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) sizeof (struct ipv6hdr); dev->mtu = rt->rt6i_dev->mtu - sizeof (struct ipv6hdr); + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) + dev->mtu-=8; if (dev->mtu < IPV6_MIN_MTU) dev->mtu = IPV6_MIN_MTU; @@ -1363,12 +1365,17 @@ static const struct net_device_ops ip6_tnl_netdev_ops = { static void ip6_tnl_dev_setup(struct net_device *dev) { + struct ip6_tnl *t; + dev->netdev_ops = &ip6_tnl_netdev_ops; dev->destructor = ip6_dev_free; dev->type = ARPHRD_TUNNEL6; dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr); dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr); + t = netdev_priv(dev); + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) + dev->mtu-=8; dev->flags |= IFF_NOARP; dev->addr_len = sizeof(struct in6_addr); dev->features |= NETIF_F_NETNS_LOCAL; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d6bfaec3bbbf..8c4d00c7cd2b 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -606,8 +606,9 @@ static int ipip6_rcv(struct sk_buff *skb) return 0; } - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); + /* no tunnel matched, let upstream know, ipsec may handle it */ rcu_read_unlock(); + return 1; out: kfree_skb(skb); return 0; diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 285761e77d90..f6054f9ccbe3 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -550,22 +550,30 @@ EXPORT_SYMBOL(irttp_close_tsap); */ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) { + int ret; + IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); IRDA_ASSERT(skb != NULL, return -1;); IRDA_DEBUG(4, "%s()\n", __func__); + /* Take shortcut on zero byte packets */ + if (skb->len == 0) { + ret = 0; + goto err; + } + /* Check that nothing bad happens */ - if ((skb->len == 0) || (!self->connected)) { - IRDA_DEBUG(1, "%s(), No data, or not connected\n", - __func__); + if (!self->connected) { + IRDA_WARNING("%s(), Not connected\n", __func__); + ret = -ENOTCONN; goto err; } if (skb->len > self->max_seg_size) { - IRDA_DEBUG(1, "%s(), UData is too large for IrLAP!\n", - __func__); + IRDA_ERROR("%s(), UData is too large for IrLAP!\n", __func__); + ret = -EMSGSIZE; goto err; } @@ -576,7 +584,7 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) err: dev_kfree_skb(skb); - return -1; + return ret; } EXPORT_SYMBOL(irttp_udata_request); @@ -599,9 +607,15 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__, skb_queue_len(&self->tx_queue)); + /* Take shortcut on zero byte packets */ + if (skb->len == 0) { + ret = 0; + goto err; + } + /* Check that nothing bad happens */ - if ((skb->len == 0) || (!self->connected)) { - IRDA_WARNING("%s: No data, or not connected\n", __func__); + if (!self->connected) { + IRDA_WARNING("%s: Not connected\n", __func__); ret = -ENOTCONN; goto err; } diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 0bf6a59545ab..522e219f3558 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -674,4 +674,8 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); MODULE_DESCRIPTION("L2TP over IP"); MODULE_VERSION("1.0"); -MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, SOCK_DGRAM, IPPROTO_L2TP); + +/* Use the value of SOCK_DGRAM (2) directory, because __stringify does't like + * enums + */ +MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 2, IPPROTO_L2TP); diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 582612998211..e35dbe55f520 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -317,8 +317,9 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) goto out; rc = -ENODEV; rtnl_lock(); + rcu_read_lock(); if (sk->sk_bound_dev_if) { - llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); + llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); if (llc->dev) { if (!addr->sllc_arphrd) addr->sllc_arphrd = llc->dev->type; @@ -329,13 +330,13 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) !llc_mac_match(addr->sllc_mac, llc->dev->dev_addr)) { rc = -EINVAL; - dev_put(llc->dev); llc->dev = NULL; } } } else llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, addr->sllc_mac); + rcu_read_unlock(); rtnl_unlock(); if (!llc->dev) goto out; diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 4d6f8653ec88..8e8ea9cb7093 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -92,7 +92,7 @@ config MAC80211_MESH config MAC80211_LEDS bool "Enable LED triggers" depends on MAC80211 - select NEW_LEDS + depends on LEDS_CLASS select LEDS_TRIGGERS ---help--- This option enables a few LED triggers for different diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 902b03ee8f60..54fb4a0e76f0 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2247,6 +2247,10 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) break; case cpu_to_le16(IEEE80211_STYPE_DEAUTH): case cpu_to_le16(IEEE80211_STYPE_DISASSOC): + if (is_multicast_ether_addr(mgmt->da) && + !is_broadcast_ether_addr(mgmt->da)) + return RX_DROP_MONITOR; + /* process only for station */ if (sdata->vif.type != NL80211_IFTYPE_STATION) return RX_DROP_MONITOR; @@ -2741,6 +2745,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) return; + goto out; } } @@ -2780,6 +2785,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, return; } + out: dev_kfree_skb(skb); } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 96c594309506..7a637b80a62e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1587,7 +1587,12 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, list) { if (!ieee80211_sdata_running(tmp_sdata)) continue; - if (tmp_sdata->vif.type != NL80211_IFTYPE_AP) + if (tmp_sdata->vif.type == + NL80211_IFTYPE_MONITOR || + tmp_sdata->vif.type == + NL80211_IFTYPE_AP_VLAN || + tmp_sdata->vif.type == + NL80211_IFTYPE_WDS) continue; if (compare_ether_addr(tmp_sdata->vif.addr, hdr->addr2) == 0) { @@ -1732,15 +1737,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, int nh_pos, h_pos; struct sta_info *sta = NULL; u32 sta_flags = 0; + struct sk_buff *tmp_skb; if (unlikely(skb->len < ETH_HLEN)) { ret = NETDEV_TX_OK; goto fail; } - nh_pos = skb_network_header(skb) - skb->data; - h_pos = skb_transport_header(skb) - skb->data; - /* convert Ethernet header to proper 802.11 header (based on * operation mode) */ ethertype = (skb->data[12] << 8) | skb->data[13]; @@ -1913,6 +1916,20 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } + /* + * If the skb is shared we need to obtain our own copy. + */ + if (skb_shared(skb)) { + tmp_skb = skb; + skb = skb_copy(skb, GFP_ATOMIC); + kfree_skb(tmp_skb); + + if (!skb) { + ret = NETDEV_TX_OK; + goto fail; + } + } + hdr.frame_control = fc; hdr.duration_id = 0; hdr.seq_ctrl = 0; @@ -1931,6 +1948,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, encaps_len = 0; } + nh_pos = skb_network_header(skb) - skb->data; + h_pos = skb_transport_header(skb) - skb->data; + skb_pull(skb, skip_header_bytes); nh_pos -= skip_header_bytes; h_pos -= skip_header_bytes; diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig index a22dac227055..70bd1d0774c6 100644 --- a/net/netfilter/ipvs/Kconfig +++ b/net/netfilter/ipvs/Kconfig @@ -4,6 +4,7 @@ menuconfig IP_VS tristate "IP virtual server support" depends on NET && INET && NETFILTER + depends on (NF_CONNTRACK || NF_CONNTRACK=n) ---help--- IP Virtual Server support will let you build a high-performance virtual server based on cluster of two or more real servers. This diff --git a/net/rds/rdma.c b/net/rds/rdma.c index 8920f2a83327..4e37c1cbe8b2 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -567,7 +567,7 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, goto out; } - if (args->nr_local > (u64)UINT_MAX) { + if (args->nr_local > UIO_MAXIOV) { ret = -EMSGSIZE; goto out; } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6bd554323a34..0b9ee34ad35c 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2932,6 +2932,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva struct sctp_association *asoc = NULL; struct sctp_setpeerprim prim; struct sctp_chunk *chunk; + struct sctp_af *af; int err; sp = sctp_sk(sk); @@ -2959,6 +2960,13 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva if (!sctp_state(asoc, ESTABLISHED)) return -ENOTCONN; + af = sctp_get_af_specific(prim.sspp_addr.ss_family); + if (!af) + return -EINVAL; + + if (!af->addr_valid((union sctp_addr *)&prim.sspp_addr, sp, NULL)) + return -EADDRNOTAVAIL; + if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr)) return -EADDRNOTAVAIL; diff --git a/net/socket.c b/net/socket.c index 3ca2fd9e3720..088fb3fd45e0 100644 --- a/net/socket.c +++ b/net/socket.c @@ -732,6 +732,21 @@ static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, return ret; } +/** + * kernel_recvmsg - Receive a message from a socket (kernel space) + * @sock: The socket to receive the message from + * @msg: Received message + * @vec: Input s/g array for message data + * @num: Size of input s/g array + * @size: Number of bytes to read + * @flags: Message flags (MSG_DONTWAIT, etc...) + * + * On return the msg structure contains the scatter/gather array passed in the + * vec argument. The array is modified so that it consists of the unfilled + * portion of the original array. + * + * The returned value is the total number of bytes received, or an error. + */ int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size, int flags) { diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 9dab9573be41..92ce94f5146b 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -989,20 +989,26 @@ call_refreshresult(struct rpc_task *task) dprint_status(task); task->tk_status = 0; - task->tk_action = call_allocate; - if (status >= 0 && rpcauth_uptodatecred(task)) - return; + task->tk_action = call_refresh; switch (status) { - case -EACCES: - rpc_exit(task, -EACCES); - return; - case -ENOMEM: - rpc_exit(task, -ENOMEM); + case 0: + if (rpcauth_uptodatecred(task)) + task->tk_action = call_allocate; return; case -ETIMEDOUT: rpc_delay(task, 3*HZ); + case -EAGAIN: + status = -EACCES; + if (!task->tk_cred_retry) + break; + task->tk_cred_retry--; + dprintk("RPC: %5u %s: retry refresh creds\n", + task->tk_pid, __func__); + return; } - task->tk_action = call_refresh; + dprintk("RPC: %5u %s: refresh creds failed with error %d\n", + task->tk_pid, __func__, status); + rpc_exit(task, status); } /* diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index ea2ff78dcf7b..3f2c5559ca1a 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -212,6 +212,7 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, spin_lock(&svc_xprt_class_lock); list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) { struct svc_xprt *newxprt; + unsigned short newport; if (strcmp(xprt_name, xcl->xcl_name)) continue; @@ -230,8 +231,9 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, spin_lock_bh(&serv->sv_lock); list_add(&newxprt->xpt_list, &serv->sv_permsocks); spin_unlock_bh(&serv->sv_lock); + newport = svc_xprt_local_port(newxprt); clear_bit(XPT_BUSY, &newxprt->xpt_flags); - return svc_xprt_local_port(newxprt); + return newport; } err: spin_unlock(&svc_xprt_class_lock); @@ -425,8 +427,13 @@ void svc_xprt_received(struct svc_xprt *xprt) { BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); xprt->xpt_pool = NULL; + /* As soon as we clear busy, the xprt could be closed and + * 'put', so we need a reference to call svc_xprt_enqueue with: + */ + svc_xprt_get(xprt); clear_bit(XPT_BUSY, &xprt->xpt_flags); svc_xprt_enqueue(xprt); + svc_xprt_put(xprt); } EXPORT_SYMBOL_GPL(svc_xprt_received); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 3c95304a0817..2268e6798124 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1343,9 +1343,25 @@ static void unix_destruct_scm(struct sk_buff *skb) sock_wfree(skb); } +#define MAX_RECURSION_LEVEL 4 + static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) { int i; + unsigned char max_level = 0; + int unix_sock_count = 0; + + for (i = scm->fp->count - 1; i >= 0; i--) { + struct sock *sk = unix_get_socket(scm->fp->fp[i]); + + if (sk) { + unix_sock_count++; + max_level = max(max_level, + unix_sk(sk)->recursion_level); + } + } + if (unlikely(max_level > MAX_RECURSION_LEVEL)) + return -ETOOMANYREFS; /* * Need to duplicate file references for the sake of garbage @@ -1356,9 +1372,11 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) if (!UNIXCB(skb).fp) return -ENOMEM; - for (i = scm->fp->count-1; i >= 0; i--) - unix_inflight(scm->fp->fp[i]); - return 0; + if (unix_sock_count) { + for (i = scm->fp->count - 1; i >= 0; i--) + unix_inflight(scm->fp->fp[i]); + } + return max_level; } static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) @@ -1393,6 +1411,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, struct sk_buff *skb; long timeo; struct scm_cookie tmp_scm; + int max_level; if (NULL == siocb->scm) siocb->scm = &tmp_scm; @@ -1431,8 +1450,9 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out; err = unix_scm_to_skb(siocb->scm, skb, true); - if (err) + if (err < 0) goto out_free; + max_level = err + 1; unix_get_secdata(siocb->scm, skb); skb_reset_transport_header(skb); @@ -1514,6 +1534,8 @@ restart: if (sock_flag(other, SOCK_RCVTSTAMP)) __net_timestamp(skb); skb_queue_tail(&other->sk_receive_queue, skb); + if (max_level > unix_sk(other)->recursion_level) + unix_sk(other)->recursion_level = max_level; unix_state_unlock(other); other->sk_data_ready(other, len); sock_put(other); @@ -1544,6 +1566,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, int sent = 0; struct scm_cookie tmp_scm; bool fds_sent = false; + int max_level; if (NULL == siocb->scm) siocb->scm = &tmp_scm; @@ -1607,10 +1630,11 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, /* Only send the fds in the first buffer */ err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); - if (err) { + if (err < 0) { kfree_skb(skb); goto out_err; } + max_level = err + 1; fds_sent = true; err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); @@ -1626,6 +1650,8 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, goto pipe_err_free; skb_queue_tail(&other->sk_receive_queue, skb); + if (max_level > unix_sk(other)->recursion_level) + unix_sk(other)->recursion_level = max_level; unix_state_unlock(other); other->sk_data_ready(other, size); sent += size; @@ -1845,6 +1871,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, unix_state_lock(sk); skb = skb_dequeue(&sk->sk_receive_queue); if (skb == NULL) { + unix_sk(sk)->recursion_level = 0; if (copied >= target) goto unlock; diff --git a/net/unix/garbage.c b/net/unix/garbage.c index c8df6fda0b1f..f89f83bf828e 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -96,7 +96,7 @@ static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait); unsigned int unix_tot_inflight; -static struct sock *unix_get_socket(struct file *filp) +struct sock *unix_get_socket(struct file *filp) { struct sock *u_sock = NULL; struct inode *inode = filp->f_path.dentry->d_inode; @@ -259,9 +259,16 @@ static void inc_inflight_move_tail(struct unix_sock *u) } static bool gc_in_progress = false; +#define UNIX_INFLIGHT_TRIGGER_GC 16000 void wait_for_unix_gc(void) { + /* + * If number of inflight sockets is insane, + * force a garbage collect right now. + */ + if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) + unix_gc(); wait_event(unix_gc_wait, gc_in_progress == false); } diff --git a/net/wireless/chan.c b/net/wireless/chan.c index d0c92dddb26b..17cd0c04d139 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -44,6 +44,38 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev, return chan; } +static bool can_beacon_sec_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct ieee80211_channel *sec_chan; + int diff; + + switch (channel_type) { + case NL80211_CHAN_HT40PLUS: + diff = 20; + break; + case NL80211_CHAN_HT40MINUS: + diff = -20; + break; + default: + return false; + } + + sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); + if (!sec_chan) + return false; + + /* we'll need a DFS capability later */ + if (sec_chan->flags & (IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_PASSIVE_SCAN | + IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_RADAR)) + return false; + + return true; +} + int cfg80211_set_freq(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, int freq, enum nl80211_channel_type channel_type) @@ -68,6 +100,28 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev, if (!chan) return -EINVAL; + /* Both channels should be able to initiate communication */ + if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC || + wdev->iftype == NL80211_IFTYPE_AP || + wdev->iftype == NL80211_IFTYPE_AP_VLAN || + wdev->iftype == NL80211_IFTYPE_MESH_POINT || + wdev->iftype == NL80211_IFTYPE_P2P_GO)) { + switch (channel_type) { + case NL80211_CHAN_HT40PLUS: + case NL80211_CHAN_HT40MINUS: + if (!can_beacon_sec_chan(&rdev->wiphy, chan, + channel_type)) { + printk(KERN_DEBUG + "cfg80211: Secondary channel not " + "allowed to initiate communication\n"); + return -EINVAL; + } + break; + default: + break; + } + } + result = rdev->ops->set_channel(&rdev->wiphy, wdev ? wdev->netdev : NULL, chan, channel_type); diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c index 73e7b954ad28..b25c6463c3e9 100644 --- a/net/x25/x25_link.c +++ b/net/x25/x25_link.c @@ -394,6 +394,7 @@ void __exit x25_link_free(void) list_for_each_safe(entry, tmp, &x25_neigh_list) { nb = list_entry(entry, struct x25_neigh, node); __x25_remove_neigh(nb); + dev_put(nb->dev); } write_unlock_bh(&x25_neigh_list_lock); } diff --git a/net/xfrm/xfrm_hash.c b/net/xfrm/xfrm_hash.c index a2023ec52329..1e98bc0fe0a5 100644 --- a/net/xfrm/xfrm_hash.c +++ b/net/xfrm/xfrm_hash.c @@ -19,7 +19,7 @@ struct hlist_head *xfrm_hash_alloc(unsigned int sz) if (sz <= PAGE_SIZE) n = kzalloc(sz, GFP_KERNEL); else if (hashdist) - n = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); + n = vzalloc(sz); else n = (struct hlist_head *) __get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index eb96ce52f178..220ebc05c7af 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1268,7 +1268,7 @@ struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, return xc; error: - kfree(xc); + xfrm_state_put(xc); return NULL; } EXPORT_SYMBOL(xfrm_state_migrate); diff --git a/scripts/gfp-translate b/scripts/gfp-translate index d81b968d864e..c9230e158a8f 100644 --- a/scripts/gfp-translate +++ b/scripts/gfp-translate @@ -63,7 +63,12 @@ fi # Extract GFP flags from the kernel source TMPFILE=`mktemp -t gfptranslate-XXXXXX` || exit 1 -grep "^#define __GFP" $SOURCE/include/linux/gfp.h | sed -e 's/(__force gfp_t)//' | sed -e 's/u)/)/' | grep -v GFP_BITS | sed -e 's/)\//) \//' > $TMPFILE +grep -q ___GFP $SOURCE/include/linux/gfp.h +if [ $? -eq 0 ]; then + grep "^#define ___GFP" $SOURCE/include/linux/gfp.h | sed -e 's/u$//' | grep -v GFP_BITS > $TMPFILE +else + grep "^#define __GFP" $SOURCE/include/linux/gfp.h | sed -e 's/(__force gfp_t)//' | sed -e 's/u)/)/' | grep -v GFP_BITS | sed -e 's/)\//) \//' > $TMPFILE +fi # Parse the flags IFS=" diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 184eb6a0b505..e57826ced380 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -164,6 +164,7 @@ struct menu { struct menu *list; struct symbol *sym; struct property *prompt; + struct expr *visibility; struct expr *dep; unsigned int flags; char *help; diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 753cdbd7b805..3f7240df0f3b 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -107,6 +107,7 @@ void menu_end_menu(void); void menu_add_entry(struct symbol *sym); void menu_end_entry(void); void menu_add_dep(struct expr *dep); +void menu_add_visibility(struct expr *dep); struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep); struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 7e83aef42c6d..b9d9aa18e6d6 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -152,6 +152,12 @@ struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr return menu_add_prop(type, prompt, NULL, dep); } +void menu_add_visibility(struct expr *expr) +{ + current_entry->visibility = expr_alloc_and(current_entry->visibility, + expr); +} + void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) { menu_add_prop(type, NULL, expr, dep); @@ -410,6 +416,11 @@ bool menu_is_visible(struct menu *menu) if (!menu->prompt) return false; + if (menu->visibility) { + if (expr_calc_value(menu->visibility) == no) + return no; + } + sym = menu->sym; if (sym) { sym_calc_value(sym); diff --git a/scripts/kconfig/zconf.gperf b/scripts/kconfig/zconf.gperf index d8bc74249622..c9e690eb7545 100644 --- a/scripts/kconfig/zconf.gperf +++ b/scripts/kconfig/zconf.gperf @@ -38,6 +38,7 @@ hex, T_TYPE, TF_COMMAND, S_HEX string, T_TYPE, TF_COMMAND, S_STRING select, T_SELECT, TF_COMMAND range, T_RANGE, TF_COMMAND +visible, T_VISIBLE, TF_COMMAND option, T_OPTION, TF_COMMAND on, T_ON, TF_PARAM modules, T_OPT_MODULES, TF_OPTION diff --git a/scripts/kconfig/zconf.hash.c_shipped b/scripts/kconfig/zconf.hash.c_shipped index c1748faf4634..4055d5de1750 100644 --- a/scripts/kconfig/zconf.hash.c_shipped +++ b/scripts/kconfig/zconf.hash.c_shipped @@ -32,7 +32,7 @@ struct kconf_id; static struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len); -/* maximum key range = 47, duplicates = 0 */ +/* maximum key range = 50, duplicates = 0 */ #ifdef __GNUC__ __inline @@ -46,32 +46,32 @@ kconf_id_hash (register const char *str, register unsigned int len) { static unsigned char asso_values[] = { - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 11, 5, - 0, 0, 5, 49, 5, 20, 49, 49, 5, 20, - 5, 0, 30, 49, 0, 15, 0, 10, 0, 49, - 25, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49 + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 40, 5, + 0, 0, 5, 52, 0, 20, 52, 52, 10, 20, + 5, 0, 35, 52, 0, 30, 0, 15, 0, 52, + 15, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52 }; register int hval = len; @@ -102,25 +102,26 @@ struct kconf_id_strings_t char kconf_id_strings_str12[sizeof("default")]; char kconf_id_strings_str13[sizeof("def_bool")]; char kconf_id_strings_str14[sizeof("help")]; - char kconf_id_strings_str15[sizeof("bool")]; char kconf_id_strings_str16[sizeof("config")]; char kconf_id_strings_str17[sizeof("def_tristate")]; - char kconf_id_strings_str18[sizeof("boolean")]; + char kconf_id_strings_str18[sizeof("hex")]; char kconf_id_strings_str19[sizeof("defconfig_list")]; - char kconf_id_strings_str21[sizeof("string")]; char kconf_id_strings_str22[sizeof("if")]; char kconf_id_strings_str23[sizeof("int")]; - char kconf_id_strings_str26[sizeof("select")]; char kconf_id_strings_str27[sizeof("modules")]; char kconf_id_strings_str28[sizeof("tristate")]; char kconf_id_strings_str29[sizeof("menu")]; - char kconf_id_strings_str31[sizeof("source")]; char kconf_id_strings_str32[sizeof("comment")]; - char kconf_id_strings_str33[sizeof("hex")]; char kconf_id_strings_str35[sizeof("menuconfig")]; - char kconf_id_strings_str36[sizeof("prompt")]; - char kconf_id_strings_str37[sizeof("depends")]; + char kconf_id_strings_str36[sizeof("string")]; + char kconf_id_strings_str37[sizeof("visible")]; + char kconf_id_strings_str41[sizeof("prompt")]; + char kconf_id_strings_str42[sizeof("depends")]; + char kconf_id_strings_str44[sizeof("bool")]; + char kconf_id_strings_str46[sizeof("select")]; + char kconf_id_strings_str47[sizeof("boolean")]; char kconf_id_strings_str48[sizeof("mainmenu")]; + char kconf_id_strings_str51[sizeof("source")]; }; static struct kconf_id_strings_t kconf_id_strings_contents = { @@ -136,25 +137,26 @@ static struct kconf_id_strings_t kconf_id_strings_contents = "default", "def_bool", "help", - "bool", "config", "def_tristate", - "boolean", + "hex", "defconfig_list", - "string", "if", "int", - "select", "modules", "tristate", "menu", - "source", "comment", - "hex", "menuconfig", + "string", + "visible", "prompt", "depends", - "mainmenu" + "bool", + "select", + "boolean", + "mainmenu", + "source" }; #define kconf_id_strings ((const char *) &kconf_id_strings_contents) #ifdef __GNUC__ @@ -168,11 +170,11 @@ kconf_id_lookup (register const char *str, register unsigned int len) { enum { - TOTAL_KEYWORDS = 31, + TOTAL_KEYWORDS = 32, MIN_WORD_LENGTH = 2, MAX_WORD_LENGTH = 14, MIN_HASH_VALUE = 2, - MAX_HASH_VALUE = 48 + MAX_HASH_VALUE = 51 }; static struct kconf_id wordlist[] = @@ -191,31 +193,35 @@ kconf_id_lookup (register const char *str, register unsigned int len) {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_HELP, TF_COMMAND}, - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str15, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {-1}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_CONFIG, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE}, - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_TYPE, TF_COMMAND, S_HEX}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19, T_OPT_DEFCONFIG_LIST,TF_OPTION}, - {-1}, - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_TYPE, TF_COMMAND, S_STRING}, + {-1}, {-1}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_IF, TF_COMMAND|TF_PARAM}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_INT}, - {-1}, {-1}, - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_SELECT, TF_COMMAND}, + {-1}, {-1}, {-1}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_TYPE, TF_COMMAND, S_TRISTATE}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND}, - {-1}, - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SOURCE, TF_COMMAND}, + {-1}, {-1}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_TYPE, TF_COMMAND, S_HEX}, - {-1}, + {-1}, {-1}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_MENUCONFIG, TF_COMMAND}, - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_PROMPT, TF_COMMAND}, - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_DEPENDS, TF_COMMAND}, - {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_TYPE, TF_COMMAND, S_STRING}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_VISIBLE, TF_COMMAND}, + {-1}, {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_PROMPT, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_DEPENDS, TF_COMMAND}, {-1}, - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48, T_MAINMENU, TF_COMMAND} + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str44, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_SELECT, TF_COMMAND}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48, T_MAINMENU, TF_COMMAND}, + {-1}, {-1}, + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_SOURCE, TF_COMMAND} }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped index 699d4b265186..4c5495ea205e 100644 --- a/scripts/kconfig/zconf.tab.c_shipped +++ b/scripts/kconfig/zconf.tab.c_shipped @@ -160,18 +160,19 @@ static struct menu *current_menu, *current_entry; T_DEFAULT = 275, T_SELECT = 276, T_RANGE = 277, - T_OPTION = 278, - T_ON = 279, - T_WORD = 280, - T_WORD_QUOTE = 281, - T_UNEQUAL = 282, - T_CLOSE_PAREN = 283, - T_OPEN_PAREN = 284, - T_EOL = 285, - T_OR = 286, - T_AND = 287, - T_EQUAL = 288, - T_NOT = 289 + T_VISIBLE = 278, + T_OPTION = 279, + T_ON = 280, + T_WORD = 281, + T_WORD_QUOTE = 282, + T_UNEQUAL = 283, + T_CLOSE_PAREN = 284, + T_OPEN_PAREN = 285, + T_EOL = 286, + T_OR = 287, + T_AND = 288, + T_EQUAL = 289, + T_NOT = 290 }; #endif @@ -419,20 +420,20 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 11 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 277 +#define YYLAST 290 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 35 +#define YYNTOKENS 36 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 48 +#define YYNNTS 50 /* YYNRULES -- Number of rules. */ -#define YYNRULES 113 +#define YYNRULES 118 /* YYNRULES -- Number of states. */ -#define YYNSTATES 185 +#define YYNSTATES 191 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 289 +#define YYMAXUTOK 290 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -468,7 +469,8 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34 + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35 }; #if YYDEBUG @@ -478,72 +480,73 @@ static const yytype_uint16 yyprhs[] = { 0, 0, 3, 6, 8, 11, 13, 14, 17, 20, 23, 26, 31, 36, 40, 42, 44, 46, 48, 50, - 52, 54, 56, 58, 60, 62, 64, 66, 70, 73, - 77, 80, 84, 87, 88, 91, 94, 97, 100, 103, - 106, 110, 115, 120, 125, 131, 135, 136, 140, 141, - 144, 148, 151, 153, 157, 158, 161, 164, 167, 170, - 173, 178, 182, 185, 190, 191, 194, 198, 200, 204, - 205, 208, 211, 214, 218, 222, 225, 227, 231, 232, - 235, 238, 241, 245, 249, 252, 255, 258, 259, 262, - 265, 268, 273, 274, 277, 279, 281, 284, 287, 290, - 292, 295, 296, 299, 301, 305, 309, 313, 316, 320, - 324, 326, 328, 329 + 52, 54, 56, 58, 60, 62, 64, 66, 68, 72, + 75, 79, 82, 86, 89, 90, 93, 96, 99, 102, + 105, 108, 112, 117, 122, 127, 133, 137, 138, 142, + 143, 146, 150, 153, 155, 159, 160, 163, 166, 169, + 172, 175, 180, 184, 187, 192, 193, 196, 200, 202, + 206, 207, 210, 213, 216, 220, 224, 228, 230, 234, + 235, 238, 241, 244, 248, 252, 255, 258, 261, 262, + 265, 268, 271, 276, 277, 280, 283, 286, 287, 290, + 292, 294, 297, 300, 303, 305, 308, 309, 312, 314, + 318, 322, 326, 329, 333, 337, 339, 341, 342 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { - 36, 0, -1, 78, 37, -1, 37, -1, 62, 38, - -1, 38, -1, -1, 38, 40, -1, 38, 54, -1, - 38, 66, -1, 38, 77, -1, 38, 25, 1, 30, - -1, 38, 39, 1, 30, -1, 38, 1, 30, -1, + 37, 0, -1, 81, 38, -1, 38, -1, 63, 39, + -1, 39, -1, -1, 39, 41, -1, 39, 55, -1, + 39, 67, -1, 39, 80, -1, 39, 26, 1, 31, + -1, 39, 40, 1, 31, -1, 39, 1, 31, -1, 16, -1, 18, -1, 19, -1, 21, -1, 17, -1, - 22, -1, 20, -1, 30, -1, 60, -1, 70, -1, - 43, -1, 45, -1, 68, -1, 25, 1, 30, -1, - 1, 30, -1, 10, 25, 30, -1, 42, 46, -1, - 11, 25, 30, -1, 44, 46, -1, -1, 46, 47, - -1, 46, 48, -1, 46, 74, -1, 46, 72, -1, - 46, 41, -1, 46, 30, -1, 19, 75, 30, -1, - 18, 76, 79, 30, -1, 20, 80, 79, 30, -1, - 21, 25, 79, 30, -1, 22, 81, 81, 79, 30, - -1, 23, 49, 30, -1, -1, 49, 25, 50, -1, - -1, 33, 76, -1, 7, 82, 30, -1, 51, 55, - -1, 77, -1, 52, 57, 53, -1, -1, 55, 56, - -1, 55, 74, -1, 55, 72, -1, 55, 30, -1, - 55, 41, -1, 18, 76, 79, 30, -1, 19, 75, - 30, -1, 17, 30, -1, 20, 25, 79, 30, -1, - -1, 57, 40, -1, 14, 80, 78, -1, 77, -1, - 58, 61, 59, -1, -1, 61, 40, -1, 61, 66, - -1, 61, 54, -1, 3, 76, 78, -1, 4, 76, - 30, -1, 63, 73, -1, 77, -1, 64, 67, 65, - -1, -1, 67, 40, -1, 67, 66, -1, 67, 54, - -1, 6, 76, 30, -1, 9, 76, 30, -1, 69, - 73, -1, 12, 30, -1, 71, 13, -1, -1, 73, - 74, -1, 73, 30, -1, 73, 41, -1, 16, 24, - 80, 30, -1, -1, 76, 79, -1, 25, -1, 26, - -1, 5, 30, -1, 8, 30, -1, 15, 30, -1, - 30, -1, 78, 30, -1, -1, 14, 80, -1, 81, - -1, 81, 33, 81, -1, 81, 27, 81, -1, 29, - 80, 28, -1, 34, 80, -1, 80, 31, 80, -1, - 80, 32, 80, -1, 25, -1, 26, -1, -1, 25, - -1 + 22, -1, 20, -1, 23, -1, 31, -1, 61, -1, + 71, -1, 44, -1, 46, -1, 69, -1, 26, 1, + 31, -1, 1, 31, -1, 10, 26, 31, -1, 43, + 47, -1, 11, 26, 31, -1, 45, 47, -1, -1, + 47, 48, -1, 47, 49, -1, 47, 75, -1, 47, + 73, -1, 47, 42, -1, 47, 31, -1, 19, 78, + 31, -1, 18, 79, 82, 31, -1, 20, 83, 82, + 31, -1, 21, 26, 82, 31, -1, 22, 84, 84, + 82, 31, -1, 24, 50, 31, -1, -1, 50, 26, + 51, -1, -1, 34, 79, -1, 7, 85, 31, -1, + 52, 56, -1, 80, -1, 53, 58, 54, -1, -1, + 56, 57, -1, 56, 75, -1, 56, 73, -1, 56, + 31, -1, 56, 42, -1, 18, 79, 82, 31, -1, + 19, 78, 31, -1, 17, 31, -1, 20, 26, 82, + 31, -1, -1, 58, 41, -1, 14, 83, 81, -1, + 80, -1, 59, 62, 60, -1, -1, 62, 41, -1, + 62, 67, -1, 62, 55, -1, 3, 79, 81, -1, + 4, 79, 31, -1, 64, 76, 74, -1, 80, -1, + 65, 68, 66, -1, -1, 68, 41, -1, 68, 67, + -1, 68, 55, -1, 6, 79, 31, -1, 9, 79, + 31, -1, 70, 74, -1, 12, 31, -1, 72, 13, + -1, -1, 74, 75, -1, 74, 31, -1, 74, 42, + -1, 16, 25, 83, 31, -1, -1, 76, 77, -1, + 76, 31, -1, 23, 82, -1, -1, 79, 82, -1, + 26, -1, 27, -1, 5, 31, -1, 8, 31, -1, + 15, 31, -1, 31, -1, 81, 31, -1, -1, 14, + 83, -1, 84, -1, 84, 34, 84, -1, 84, 28, + 84, -1, 30, 83, 29, -1, 35, 83, -1, 83, + 32, 83, -1, 83, 33, 83, -1, 26, -1, 27, + -1, -1, 26, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 107, 107, 107, 109, 109, 111, 113, 114, 115, - 116, 117, 118, 122, 126, 126, 126, 126, 126, 126, - 126, 130, 131, 132, 133, 134, 135, 139, 140, 146, - 154, 160, 168, 178, 180, 181, 182, 183, 184, 185, - 188, 196, 202, 212, 218, 224, 227, 229, 240, 241, - 246, 255, 260, 268, 271, 273, 274, 275, 276, 277, - 280, 286, 297, 303, 313, 315, 320, 328, 336, 339, - 341, 342, 343, 348, 355, 362, 367, 375, 378, 380, - 381, 382, 385, 393, 400, 407, 413, 420, 422, 423, - 424, 427, 435, 437, 442, 443, 446, 447, 448, 452, - 453, 456, 457, 460, 461, 462, 463, 464, 465, 466, - 469, 470, 473, 474 + 0, 108, 108, 108, 110, 110, 112, 114, 115, 116, + 117, 118, 119, 123, 127, 127, 127, 127, 127, 127, + 127, 127, 131, 132, 133, 134, 135, 136, 140, 141, + 147, 155, 161, 169, 179, 181, 182, 183, 184, 185, + 186, 189, 197, 203, 213, 219, 225, 228, 230, 241, + 242, 247, 256, 261, 269, 272, 274, 275, 276, 277, + 278, 281, 287, 298, 304, 314, 316, 321, 329, 337, + 340, 342, 343, 344, 349, 356, 363, 368, 376, 379, + 381, 382, 383, 386, 394, 401, 408, 414, 421, 423, + 424, 425, 428, 436, 438, 439, 442, 449, 451, 456, + 457, 460, 461, 462, 466, 467, 470, 471, 474, 475, + 476, 477, 478, 479, 480, 483, 484, 487, 488 }; #endif @@ -556,7 +559,7 @@ static const char *const yytname[] = "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE", - "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", + "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL", "T_NOT", "$accept", "input", "start", "stmt_list", "option_name", "common_stmt", "option_error", "config_entry_start", "config_stmt", @@ -567,8 +570,8 @@ static const char *const yytname[] = "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu", "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt", "comment", "comment_stmt", "help_start", "help", "depends_list", - "depends", "prompt_stmt_opt", "prompt", "end", "nl", "if_expr", "expr", - "symbol", "word_opt", 0 + "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt", + "end", "nl", "if_expr", "expr", "symbol", "word_opt", 0 }; #endif @@ -580,25 +583,25 @@ static const yytype_uint16 yytoknum[] = 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289 + 285, 286, 287, 288, 289, 290 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 35, 36, 36, 37, 37, 38, 38, 38, 38, - 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, - 39, 40, 40, 40, 40, 40, 40, 41, 41, 42, - 43, 44, 45, 46, 46, 46, 46, 46, 46, 46, - 47, 47, 47, 47, 47, 48, 49, 49, 50, 50, - 51, 52, 53, 54, 55, 55, 55, 55, 55, 55, - 56, 56, 56, 56, 57, 57, 58, 59, 60, 61, - 61, 61, 61, 62, 63, 64, 65, 66, 67, 67, - 67, 67, 68, 69, 70, 71, 72, 73, 73, 73, - 73, 74, 75, 75, 76, 76, 77, 77, 77, 78, - 78, 79, 79, 80, 80, 80, 80, 80, 80, 80, - 81, 81, 82, 82 + 0, 36, 37, 37, 38, 38, 39, 39, 39, 39, + 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, + 40, 40, 41, 41, 41, 41, 41, 41, 42, 42, + 43, 44, 45, 46, 47, 47, 47, 47, 47, 47, + 47, 48, 48, 48, 48, 48, 49, 50, 50, 51, + 51, 52, 53, 54, 55, 56, 56, 56, 56, 56, + 56, 57, 57, 57, 57, 58, 58, 59, 60, 61, + 62, 62, 62, 62, 63, 64, 65, 66, 67, 68, + 68, 68, 68, 69, 70, 71, 72, 73, 74, 74, + 74, 74, 75, 76, 76, 76, 77, 78, 78, 79, + 79, 80, 80, 80, 81, 81, 82, 82, 83, 83, + 83, 83, 83, 83, 83, 84, 84, 85, 85 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -606,16 +609,16 @@ static const yytype_uint8 yyr2[] = { 0, 2, 2, 1, 2, 1, 0, 2, 2, 2, 2, 4, 4, 3, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 3, 2, 3, - 2, 3, 2, 0, 2, 2, 2, 2, 2, 2, - 3, 4, 4, 4, 5, 3, 0, 3, 0, 2, - 3, 2, 1, 3, 0, 2, 2, 2, 2, 2, - 4, 3, 2, 4, 0, 2, 3, 1, 3, 0, - 2, 2, 2, 3, 3, 2, 1, 3, 0, 2, - 2, 2, 3, 3, 2, 2, 2, 0, 2, 2, - 2, 4, 0, 2, 1, 1, 2, 2, 2, 1, - 2, 0, 2, 1, 3, 3, 3, 2, 3, 3, - 1, 1, 0, 1 + 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, + 3, 2, 3, 2, 0, 2, 2, 2, 2, 2, + 2, 3, 4, 4, 4, 5, 3, 0, 3, 0, + 2, 3, 2, 1, 3, 0, 2, 2, 2, 2, + 2, 4, 3, 2, 4, 0, 2, 3, 1, 3, + 0, 2, 2, 2, 3, 3, 3, 1, 3, 0, + 2, 2, 2, 3, 3, 2, 2, 2, 0, 2, + 2, 2, 4, 0, 2, 2, 2, 0, 2, 1, + 1, 2, 2, 2, 1, 2, 0, 2, 1, 3, + 3, 3, 2, 3, 3, 1, 1, 0, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -623,165 +626,172 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 6, 0, 99, 0, 3, 0, 6, 6, 94, 95, - 0, 1, 0, 0, 0, 0, 112, 0, 0, 0, + 6, 0, 104, 0, 3, 0, 6, 6, 99, 100, + 0, 1, 0, 0, 0, 0, 117, 0, 0, 0, 0, 0, 0, 14, 18, 15, 16, 20, 17, 19, - 0, 21, 0, 7, 33, 24, 33, 25, 54, 64, - 8, 69, 22, 87, 78, 9, 26, 87, 23, 10, - 0, 100, 2, 73, 13, 0, 96, 0, 113, 0, - 97, 0, 0, 0, 110, 111, 0, 0, 0, 103, - 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 74, 82, 50, 83, 29, 31, 0, 107, 0, - 0, 66, 0, 0, 11, 12, 0, 0, 0, 0, - 92, 0, 0, 0, 46, 0, 39, 38, 34, 35, - 0, 37, 36, 0, 0, 92, 0, 58, 59, 55, - 57, 56, 65, 53, 52, 70, 72, 68, 71, 67, - 89, 90, 88, 79, 81, 77, 80, 76, 106, 108, - 109, 105, 104, 28, 85, 0, 101, 0, 101, 101, - 101, 0, 0, 0, 86, 62, 101, 0, 101, 0, - 0, 0, 40, 93, 0, 0, 101, 48, 45, 27, - 0, 61, 0, 91, 102, 41, 42, 43, 0, 0, - 47, 60, 63, 44, 49 + 21, 0, 22, 0, 7, 34, 25, 34, 26, 55, + 65, 8, 70, 23, 93, 79, 9, 27, 88, 24, + 10, 0, 105, 2, 74, 13, 0, 101, 0, 118, + 0, 102, 0, 0, 0, 115, 116, 0, 0, 0, + 108, 103, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 75, 83, 51, 84, 30, 32, 0, 112, + 0, 0, 67, 0, 0, 11, 12, 0, 0, 0, + 0, 97, 0, 0, 0, 47, 0, 40, 39, 35, + 36, 0, 38, 37, 0, 0, 97, 0, 59, 60, + 56, 58, 57, 66, 54, 53, 71, 73, 69, 72, + 68, 106, 95, 0, 94, 80, 82, 78, 81, 77, + 90, 91, 89, 111, 113, 114, 110, 109, 29, 86, + 0, 106, 0, 106, 106, 106, 0, 0, 0, 87, + 63, 106, 0, 106, 0, 96, 0, 0, 41, 98, + 0, 0, 106, 49, 46, 28, 0, 62, 0, 107, + 92, 42, 43, 44, 0, 0, 48, 61, 64, 45, + 50 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 3, 4, 5, 32, 33, 107, 34, 35, 36, - 37, 73, 108, 109, 152, 180, 38, 39, 123, 40, - 75, 119, 76, 41, 127, 42, 77, 6, 43, 44, - 135, 45, 79, 46, 47, 48, 110, 111, 78, 112, - 147, 148, 49, 7, 161, 68, 69, 59 + -1, 3, 4, 5, 33, 34, 108, 35, 36, 37, + 38, 74, 109, 110, 157, 186, 39, 40, 124, 41, + 76, 120, 77, 42, 128, 43, 78, 6, 44, 45, + 137, 46, 80, 47, 48, 49, 111, 112, 81, 113, + 79, 134, 152, 153, 50, 7, 165, 69, 70, 60 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -89 +#define YYPACT_NINF -90 static const yytype_int16 yypact[] = { - 3, 4, -89, 20, -89, 100, -89, 7, -89, -89, - -8, -89, 17, 4, 28, 4, 37, 36, 4, 68, - 87, -18, 69, -89, -89, -89, -89, -89, -89, -89, - 128, -89, 138, -89, -89, -89, -89, -89, -89, -89, - -89, -89, -89, -89, -89, -89, -89, -89, -89, -89, - 127, -89, -89, 110, -89, 126, -89, 136, -89, 137, - -89, 147, 150, 152, -89, -89, -18, -18, 171, -14, - -89, 153, 157, 34, 67, 180, 233, 220, 207, 220, - 154, -89, -89, -89, -89, -89, -89, 0, -89, -18, - -18, 110, 44, 44, -89, -89, 163, 174, 182, 4, - 4, -18, 194, 44, -89, 219, -89, -89, -89, -89, - 223, -89, -89, 203, 4, 4, 215, -89, -89, -89, - -89, -89, -89, -89, -89, -89, -89, -89, -89, -89, - -89, -89, -89, -89, -89, -89, -89, -89, -89, 213, - -89, -89, -89, -89, -89, -18, 232, 227, 232, -5, - 232, 44, 35, 234, -89, -89, 232, 235, 232, 224, - -18, 236, -89, -89, 237, 238, 232, 216, -89, -89, - 240, -89, 241, -89, 71, -89, -89, -89, 242, 4, - -89, -89, -89, -89, -89 + 4, 42, -90, 96, -90, 111, -90, 15, -90, -90, + 75, -90, 82, 42, 104, 42, 110, 107, 42, 115, + 125, -4, 121, -90, -90, -90, -90, -90, -90, -90, + -90, 162, -90, 163, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, 139, -90, -90, 138, -90, 142, -90, 143, -90, + 152, -90, 164, 167, 168, -90, -90, -4, -4, 77, + -18, -90, 177, 185, 33, 71, 195, 247, 236, -2, + 236, 171, -90, -90, -90, -90, -90, -90, 41, -90, + -4, -4, 138, 97, 97, -90, -90, 186, 187, 194, + 42, 42, -4, 196, 97, -90, 219, -90, -90, -90, + -90, 210, -90, -90, 204, 42, 42, 199, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, 222, -90, 223, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, 215, -90, -90, -90, -90, -90, + -4, 222, 228, 222, -5, 222, 97, 35, 229, -90, + -90, 222, 232, 222, -4, -90, 135, 233, -90, -90, + 234, 235, 222, 240, -90, -90, 237, -90, 239, -13, + -90, -90, -90, -90, 244, 42, -90, -90, -90, -90, + -90 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -89, -89, 255, 267, -89, 47, -57, -89, -89, -89, - -89, 239, -89, -89, -89, -89, -89, -89, -89, 130, - -89, -89, -89, -89, -89, -89, -89, -89, -89, -89, - -89, 181, -89, -89, -89, -89, -89, 199, 229, 16, - 162, -1, 74, -7, 103, -65, -88, -89 + -90, -90, 269, 271, -90, 23, -70, -90, -90, -90, + -90, 243, -90, -90, -90, -90, -90, -90, -90, -48, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, -20, -90, -90, -90, -90, -90, 206, 205, -68, + -90, -90, 169, -1, 27, -7, 118, -66, -89, -90 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -85 +#define YYTABLE_NINF -86 static const yytype_int16 yytable[] = { - 10, 87, 88, 53, 141, 142, 1, 64, 65, 160, - 1, 66, 55, 92, 57, 151, 67, 61, 118, 93, - 11, 131, 2, 131, 139, 140, 89, 90, 138, 8, - 9, 89, 90, 2, -30, 96, 149, 51, -30, -30, - -30, -30, -30, -30, -30, -30, 97, 54, -30, -30, - 98, -30, 99, 100, 101, 102, 103, 104, 56, 105, - 167, 91, 58, 166, 106, 168, 60, -32, 96, 64, - 65, -32, -32, -32, -32, -32, -32, -32, -32, 97, - 159, -32, -32, 98, -32, 99, 100, 101, 102, 103, - 104, 121, 105, 62, 132, 174, 132, 106, 146, 70, - -5, 12, 89, 90, 13, 14, 15, 16, 17, 18, - 19, 20, 63, 156, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 122, 125, 30, 133, -4, 12, 71, - 31, 13, 14, 15, 16, 17, 18, 19, 20, 72, - 51, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 124, 129, 30, 137, -84, 96, 81, 31, -84, -84, - -84, -84, -84, -84, -84, -84, 82, 83, -84, -84, - 98, -84, -84, -84, -84, -84, -84, 84, 184, 105, - 85, 96, 86, 94, 130, -51, -51, 95, -51, -51, - -51, -51, 97, 143, -51, -51, 98, 113, 114, 115, - 116, 2, 89, 90, 144, 105, 145, 126, 96, 134, - 117, -75, -75, -75, -75, -75, -75, -75, -75, 150, - 153, -75, -75, 98, 13, 14, 15, 16, 17, 18, - 19, 20, 105, 155, 21, 22, 154, 130, 14, 15, - 158, 17, 18, 19, 20, 90, 160, 21, 22, 179, - 31, 163, 164, 165, 173, 89, 90, 162, 128, 170, - 136, 172, 52, 31, 169, 171, 175, 176, 177, 178, - 181, 182, 183, 50, 120, 74, 80, 157 + 10, 88, 89, 54, 146, 147, 119, 1, 122, 164, + 93, 141, 56, 142, 58, 156, 94, 62, 1, 90, + 91, 131, 65, 66, 144, 145, 67, 90, 91, 132, + 127, 68, 136, -31, 97, 2, 154, -31, -31, -31, + -31, -31, -31, -31, -31, 98, 52, -31, -31, 99, + -31, 100, 101, 102, 103, 104, -31, 105, 129, 106, + 138, 173, 92, 141, 107, 142, 174, 172, 8, 9, + 143, -33, 97, 90, 91, -33, -33, -33, -33, -33, + -33, -33, -33, 98, 166, -33, -33, 99, -33, 100, + 101, 102, 103, 104, -33, 105, 11, 106, 179, 151, + 123, 126, 107, 135, 125, 130, 2, 139, 2, 90, + 91, -5, 12, 55, 161, 13, 14, 15, 16, 17, + 18, 19, 20, 65, 66, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 57, 59, 31, 61, -4, + 12, 63, 32, 13, 14, 15, 16, 17, 18, 19, + 20, 64, 71, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 72, 73, 31, 180, 90, 91, 52, + 32, -85, 97, 82, 83, -85, -85, -85, -85, -85, + -85, -85, -85, 84, 190, -85, -85, 99, -85, -85, + -85, -85, -85, -85, -85, 85, 97, 106, 86, 87, + -52, -52, 140, -52, -52, -52, -52, 98, 95, -52, + -52, 99, 114, 115, 116, 117, 96, 148, 149, 150, + 158, 106, 155, 159, 97, 163, 118, -76, -76, -76, + -76, -76, -76, -76, -76, 160, 164, -76, -76, 99, + 13, 14, 15, 16, 17, 18, 19, 20, 91, 106, + 21, 22, 14, 15, 140, 17, 18, 19, 20, 168, + 175, 21, 22, 177, 181, 182, 183, 32, 187, 167, + 188, 169, 170, 171, 185, 189, 53, 51, 32, 176, + 75, 178, 121, 0, 133, 162, 0, 0, 0, 0, + 184 }; -static const yytype_uint8 yycheck[] = +static const yytype_int16 yycheck[] = { - 1, 66, 67, 10, 92, 93, 3, 25, 26, 14, - 3, 29, 13, 27, 15, 103, 34, 18, 75, 33, - 0, 78, 30, 80, 89, 90, 31, 32, 28, 25, - 26, 31, 32, 30, 0, 1, 101, 30, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 30, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 30, 25, - 25, 68, 25, 151, 30, 30, 30, 0, 1, 25, - 26, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 145, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 75, 25, 25, 78, 160, 80, 30, 99, 30, - 0, 1, 31, 32, 4, 5, 6, 7, 8, 9, - 10, 11, 25, 114, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 76, 77, 25, 79, 0, 1, 1, - 30, 4, 5, 6, 7, 8, 9, 10, 11, 1, - 30, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 76, 77, 25, 79, 0, 1, 30, 30, 4, 5, - 6, 7, 8, 9, 10, 11, 30, 30, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 30, 179, 25, - 30, 1, 30, 30, 30, 5, 6, 30, 8, 9, - 10, 11, 12, 30, 14, 15, 16, 17, 18, 19, - 20, 30, 31, 32, 30, 25, 24, 77, 1, 79, - 30, 4, 5, 6, 7, 8, 9, 10, 11, 25, - 1, 14, 15, 16, 4, 5, 6, 7, 8, 9, - 10, 11, 25, 30, 14, 15, 13, 30, 5, 6, - 25, 8, 9, 10, 11, 32, 14, 14, 15, 33, - 30, 148, 149, 150, 30, 31, 32, 30, 77, 156, - 79, 158, 7, 30, 30, 30, 30, 30, 30, 166, - 30, 30, 30, 6, 75, 36, 47, 115 + 1, 67, 68, 10, 93, 94, 76, 3, 76, 14, + 28, 81, 13, 81, 15, 104, 34, 18, 3, 32, + 33, 23, 26, 27, 90, 91, 30, 32, 33, 31, + 78, 35, 80, 0, 1, 31, 102, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 31, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 78, 26, + 80, 26, 69, 133, 31, 133, 31, 156, 26, 27, + 29, 0, 1, 32, 33, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 150, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 0, 26, 164, 100, + 77, 78, 31, 80, 77, 78, 31, 80, 31, 32, + 33, 0, 1, 31, 115, 4, 5, 6, 7, 8, + 9, 10, 11, 26, 27, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 31, 26, 26, 31, 0, + 1, 26, 31, 4, 5, 6, 7, 8, 9, 10, + 11, 26, 31, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 1, 1, 26, 31, 32, 33, 31, + 31, 0, 1, 31, 31, 4, 5, 6, 7, 8, + 9, 10, 11, 31, 185, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 31, 1, 26, 31, 31, + 5, 6, 31, 8, 9, 10, 11, 12, 31, 14, + 15, 16, 17, 18, 19, 20, 31, 31, 31, 25, + 1, 26, 26, 13, 1, 26, 31, 4, 5, 6, + 7, 8, 9, 10, 11, 31, 14, 14, 15, 16, + 4, 5, 6, 7, 8, 9, 10, 11, 33, 26, + 14, 15, 5, 6, 31, 8, 9, 10, 11, 31, + 31, 14, 15, 31, 31, 31, 31, 31, 31, 151, + 31, 153, 154, 155, 34, 31, 7, 6, 31, 161, + 37, 163, 76, -1, 79, 116, -1, -1, -1, -1, + 172 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 3, 30, 36, 37, 38, 62, 78, 25, 26, - 76, 0, 1, 4, 5, 6, 7, 8, 9, 10, + 0, 3, 31, 37, 38, 39, 63, 81, 26, 27, + 79, 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 25, 30, 39, 40, 42, 43, 44, 45, 51, 52, - 54, 58, 60, 63, 64, 66, 68, 69, 70, 77, - 38, 30, 37, 78, 30, 76, 30, 76, 25, 82, - 30, 76, 25, 25, 25, 26, 29, 34, 80, 81, - 30, 1, 1, 46, 46, 55, 57, 61, 73, 67, - 73, 30, 30, 30, 30, 30, 30, 80, 80, 31, - 32, 78, 27, 33, 30, 30, 1, 12, 16, 18, - 19, 20, 21, 22, 23, 25, 30, 41, 47, 48, - 71, 72, 74, 17, 18, 19, 20, 30, 41, 56, - 72, 74, 40, 53, 77, 40, 54, 59, 66, 77, - 30, 41, 74, 40, 54, 65, 66, 77, 28, 80, - 80, 81, 81, 30, 30, 24, 76, 75, 76, 80, - 25, 81, 49, 1, 13, 30, 76, 75, 25, 80, - 14, 79, 30, 79, 79, 79, 81, 25, 30, 30, - 79, 30, 79, 30, 80, 30, 30, 30, 79, 33, - 50, 30, 30, 30, 76 + 23, 26, 31, 40, 41, 43, 44, 45, 46, 52, + 53, 55, 59, 61, 64, 65, 67, 69, 70, 71, + 80, 39, 31, 38, 81, 31, 79, 31, 79, 26, + 85, 31, 79, 26, 26, 26, 27, 30, 35, 83, + 84, 31, 1, 1, 47, 47, 56, 58, 62, 76, + 68, 74, 31, 31, 31, 31, 31, 31, 83, 83, + 32, 33, 81, 28, 34, 31, 31, 1, 12, 16, + 18, 19, 20, 21, 22, 24, 26, 31, 42, 48, + 49, 72, 73, 75, 17, 18, 19, 20, 31, 42, + 57, 73, 75, 41, 54, 80, 41, 55, 60, 67, + 80, 23, 31, 74, 77, 41, 55, 66, 67, 80, + 31, 42, 75, 29, 83, 83, 84, 84, 31, 31, + 25, 79, 78, 79, 83, 26, 84, 50, 1, 13, + 31, 79, 78, 26, 14, 82, 83, 82, 31, 82, + 82, 82, 84, 26, 31, 31, 82, 31, 82, 83, + 31, 31, 31, 31, 82, 34, 51, 31, 31, 31, + 79 }; #define yyerrok (yyerrstatus = 0) @@ -1292,7 +1302,7 @@ yydestruct (yymsg, yytype, yyvaluep) switch (yytype) { - case 52: /* "choice_entry" */ + case 53: /* "choice_entry" */ { fprintf(stderr, "%s:%d: missing end statement for this entry\n", @@ -1302,7 +1312,7 @@ yydestruct (yymsg, yytype, yyvaluep) }; break; - case 58: /* "if_entry" */ + case 59: /* "if_entry" */ { fprintf(stderr, "%s:%d: missing end statement for this entry\n", @@ -1312,7 +1322,7 @@ yydestruct (yymsg, yytype, yyvaluep) }; break; - case 64: /* "menu_entry" */ + case 65: /* "menu_entry" */ { fprintf(stderr, "%s:%d: missing end statement for this entry\n", @@ -1644,17 +1654,17 @@ yyreduce: { zconf_error("invalid statement"); ;} break; - case 27: + case 28: { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); ;} break; - case 28: + case 29: { zconf_error("invalid option"); ;} break; - case 29: + case 30: { struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); @@ -1664,7 +1674,7 @@ yyreduce: ;} break; - case 30: + case 31: { menu_end_entry(); @@ -1672,7 +1682,7 @@ yyreduce: ;} break; - case 31: + case 32: { struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); @@ -1682,7 +1692,7 @@ yyreduce: ;} break; - case 32: + case 33: { if (current_entry->prompt) @@ -1694,7 +1704,7 @@ yyreduce: ;} break; - case 40: + case 41: { menu_set_type((yyvsp[(1) - (3)].id)->stype); @@ -1704,7 +1714,7 @@ yyreduce: ;} break; - case 41: + case 42: { menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); @@ -1712,7 +1722,7 @@ yyreduce: ;} break; - case 42: + case 43: { menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr)); @@ -1724,7 +1734,7 @@ yyreduce: ;} break; - case 43: + case 44: { menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); @@ -1732,7 +1742,7 @@ yyreduce: ;} break; - case 44: + case 45: { menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr)); @@ -1740,7 +1750,7 @@ yyreduce: ;} break; - case 47: + case 48: { struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string))); @@ -1752,17 +1762,17 @@ yyreduce: ;} break; - case 48: + case 49: { (yyval.string) = NULL; ;} break; - case 49: + case 50: { (yyval.string) = (yyvsp[(2) - (2)].string); ;} break; - case 50: + case 51: { struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE); @@ -1773,14 +1783,14 @@ yyreduce: ;} break; - case 51: + case 52: { (yyval.menu) = menu_add_menu(); ;} break; - case 52: + case 53: { if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) { @@ -1790,7 +1800,7 @@ yyreduce: ;} break; - case 60: + case 61: { menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); @@ -1798,7 +1808,7 @@ yyreduce: ;} break; - case 61: + case 62: { if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) { @@ -1811,7 +1821,7 @@ yyreduce: ;} break; - case 62: + case 63: { current_entry->sym->flags |= SYMBOL_OPTIONAL; @@ -1819,7 +1829,7 @@ yyreduce: ;} break; - case 63: + case 64: { if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) { @@ -1831,7 +1841,7 @@ yyreduce: ;} break; - case 66: + case 67: { printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); @@ -1841,7 +1851,7 @@ yyreduce: ;} break; - case 67: + case 68: { if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) { @@ -1851,14 +1861,14 @@ yyreduce: ;} break; - case 73: + case 74: { menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); ;} break; - case 74: + case 75: { menu_add_entry(NULL); @@ -1867,14 +1877,14 @@ yyreduce: ;} break; - case 75: + case 76: { (yyval.menu) = menu_add_menu(); ;} break; - case 76: + case 77: { if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) { @@ -1884,7 +1894,7 @@ yyreduce: ;} break; - case 82: + case 83: { printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); @@ -1892,7 +1902,7 @@ yyreduce: ;} break; - case 83: + case 84: { menu_add_entry(NULL); @@ -1901,14 +1911,14 @@ yyreduce: ;} break; - case 84: + case 85: { menu_end_entry(); ;} break; - case 85: + case 86: { printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); @@ -1916,14 +1926,14 @@ yyreduce: ;} break; - case 86: + case 87: { current_entry->help = (yyvsp[(2) - (2)].string); ;} break; - case 91: + case 92: { menu_add_dep((yyvsp[(3) - (4)].expr)); @@ -1931,84 +1941,91 @@ yyreduce: ;} break; - case 93: + case 96: + + { + menu_add_visibility((yyvsp[(2) - (2)].expr)); +;} + break; + + case 98: { menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr)); ;} break; - case 96: + case 101: { (yyval.id) = (yyvsp[(1) - (2)].id); ;} break; - case 97: + case 102: { (yyval.id) = (yyvsp[(1) - (2)].id); ;} break; - case 98: + case 103: { (yyval.id) = (yyvsp[(1) - (2)].id); ;} break; - case 101: + case 106: { (yyval.expr) = NULL; ;} break; - case 102: + case 107: { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;} break; - case 103: + case 108: { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;} break; - case 104: + case 109: { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;} break; - case 105: + case 110: { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;} break; - case 106: + case 111: { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;} break; - case 107: + case 112: { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;} break; - case 108: + case 113: { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;} break; - case 109: + case 114: { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;} break; - case 110: + case 115: { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;} break; - case 111: + case 116: { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;} break; - case 112: + case 117: { (yyval.string) = NULL; ;} break; @@ -2278,6 +2295,7 @@ static const char *zconf_tokenname(int token) case T_IF: return "if"; case T_ENDIF: return "endif"; case T_DEPENDS: return "depends"; + case T_VISIBLE: return "visible"; } return "<token>"; } diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index 2abd3c7ff15d..49fb4ab664c3 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -36,7 +36,7 @@ static struct menu *current_menu, *current_entry; #define YYERROR_VERBOSE #endif %} -%expect 28 +%expect 30 %union { @@ -68,6 +68,7 @@ static struct menu *current_menu, *current_entry; %token <id>T_DEFAULT %token <id>T_SELECT %token <id>T_RANGE +%token <id>T_VISIBLE %token <id>T_OPTION %token <id>T_ON %token <string> T_WORD @@ -123,7 +124,7 @@ stmt_list: ; option_name: - T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT + T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE ; common_stmt: @@ -359,7 +360,7 @@ menu: T_MENU prompt T_EOL printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); }; -menu_entry: menu depends_list +menu_entry: menu visibility_list depends_list { $$ = menu_add_menu(); }; @@ -430,6 +431,19 @@ depends: T_DEPENDS T_ON expr T_EOL printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); }; +/* visibility option */ + +visibility_list: + /* empty */ + | visibility_list visible + | visibility_list T_EOL +; + +visible: T_VISIBLE if_expr +{ + menu_add_visibility($2); +}; + /* prompt statement */ prompt_stmt_opt: @@ -526,6 +540,7 @@ static const char *zconf_tokenname(int token) case T_IF: return "if"; case T_ENDIF: return "endif"; case T_DEPENDS: return "depends"; + case T_VISIBLE: return "visible"; } return "<token>"; } diff --git a/scripts/kernel-doc b/scripts/kernel-doc index cdb6dc1f6458..39580a5dc5df 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -5,7 +5,7 @@ use strict; ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ## ## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ## ## Copyright (C) 2001 Simon Huggins ## -## Copyright (C) 2005-2009 Randy Dunlap ## +## Copyright (C) 2005-2010 Randy Dunlap ## ## ## ## #define enhancements by Armin Kuster <akuster@mvista.com> ## ## Copyright (c) 2000 MontaVista Software, Inc. ## @@ -453,7 +453,7 @@ sub output_highlight { if ($output_mode eq "html" || $output_mode eq "xml") { $contents = local_unescape($contents); # convert data read & converted thru xml_escape() into &xyz; format: - $contents =~ s/\\\\\\/&/g; + $contents =~ s/\\\\\\/\&/g; } # print STDERR "contents b4:$contents\n"; eval $dohighlight; @@ -770,7 +770,11 @@ sub output_struct_xml(%) { print $args{'type'} . " " . $args{'struct'} . " {\n"; foreach $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { - print "$parameter\n"; + my $prm = $parameter; + # convert data read & converted thru xml_escape() into &xyz; format: + # This allows us to have #define macros interspersed in a struct. + $prm =~ s/\\\\\\/\&/g; + print "$prm\n"; next; } @@ -1701,6 +1705,8 @@ sub push_parameter($$$) { } } + $param = xml_escape($param); + # strip spaces from $param so that it is one continous string # on @parameterlist; # this fixes a problem where check_sections() cannot find diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 58e933a20544..39667174971d 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -119,7 +119,7 @@ static uint_t (*Elf_r_sym)(Elf_Rel const *rp) = fn_ELF_R_SYM; static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type) { - rp->r_info = ELF_R_INFO(sym, type); + rp->r_info = _w(ELF_R_INFO(sym, type)); } static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO; diff --git a/scripts/tags.sh b/scripts/tags.sh index 8509bb512935..bbbe584d4494 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -125,7 +125,9 @@ exuberant() -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \ --extra=+f --c-kinds=-px \ --regex-asm='/^ENTRY\(([^)]*)\).*/\1/' \ - --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' + --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \ + --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/' \ + --regex-c++='/^DEFINE_EVENT\(([^,)]*).*/trace_\1/' all_kconfigs | xargs $1 -a \ --langdef=kconfig --language-force=kconfig \ diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c index f2f41c854221..6e2409181895 100644 --- a/sound/atmel/abdac.c +++ b/sound/atmel/abdac.c @@ -420,9 +420,9 @@ static int __devinit atmel_abdac_probe(struct platform_device *pdev) return PTR_ERR(pclk); } sample_clk = clk_get(&pdev->dev, "sample_clk"); - if (IS_ERR(pclk)) { + if (IS_ERR(sample_clk)) { dev_dbg(&pdev->dev, "no sample clock\n"); - retval = PTR_ERR(pclk); + retval = PTR_ERR(sample_clk); goto out_put_pclk; } clk_enable(pclk); diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 5c8c7dff8ede..b753ec661fcf 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1510,16 +1510,19 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file) { struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + int i; - substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; - if (substream != NULL) { - snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); - substream->runtime->oss.prepare = 1; - } - substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; - if (substream != NULL) { + for (i = 0; i < 2; i++) { + substream = pcm_oss_file->streams[i]; + if (!substream) + continue; + runtime = substream->runtime; snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); - substream->runtime->oss.prepare = 1; + runtime->oss.prepare = 1; + runtime->oss.buffer_used = 0; + runtime->oss.prev_hw_ptr_period = 0; + runtime->oss.period_ptr = 0; } return 0; } diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a1707cca9c66..b75db8e9cc0f 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -223,7 +223,7 @@ static void xrun_log(struct snd_pcm_substream *substream, entry->jiffies = jiffies; entry->pos = pos; entry->period_size = runtime->period_size; - entry->buffer_size = runtime->buffer_size;; + entry->buffer_size = runtime->buffer_size; entry->old_hw_ptr = runtime->status->hw_ptr; entry->hw_ptr_base = runtime->hw_ptr_base; log->idx = (log->idx + 1) % XRUN_LOG_CNT; diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c index 727bdb9ba2dc..d8cf3e58dc76 100644 --- a/sound/oss/dev_table.c +++ b/sound/oss/dev_table.c @@ -71,7 +71,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, if (sound_nblocks >= MAX_MEM_BLOCKS) sound_nblocks = MAX_MEM_BLOCKS - 1; - op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations))); + op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct audio_operations))); sound_nblocks++; if (sound_nblocks >= MAX_MEM_BLOCKS) sound_nblocks = MAX_MEM_BLOCKS - 1; @@ -81,7 +81,6 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, sound_unload_audiodev(num); return -(ENOMEM); } - memset((char *) op, 0, sizeof(struct audio_operations)); init_waitqueue_head(&op->in_sleeper); init_waitqueue_head(&op->out_sleeper); init_waitqueue_head(&op->poll_sleeper); @@ -128,7 +127,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, /* FIXME: This leaks a mixer_operations struct every time its called until you unload sound! */ - op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations))); + op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct mixer_operations))); sound_nblocks++; if (sound_nblocks >= MAX_MEM_BLOCKS) sound_nblocks = MAX_MEM_BLOCKS - 1; @@ -137,7 +136,6 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name); return -ENOMEM; } - memset((char *) op, 0, sizeof(struct mixer_operations)); memcpy((char *) op, (char *) driver, driver_size); strlcpy(op->name, name, sizeof(op->name)); diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c index 782b3b84dac6..ceedb1eff203 100644 --- a/sound/oss/midibuf.c +++ b/sound/oss/midibuf.c @@ -178,7 +178,7 @@ int MIDIbuf_open(int dev, struct file *file) return err; parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT; - midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); + midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf)); if (midi_in_buf[dev] == NULL) { @@ -188,7 +188,7 @@ int MIDIbuf_open(int dev, struct file *file) } midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; - midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); + midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf)); if (midi_out_buf[dev] == NULL) { diff --git a/sound/oss/pss.c b/sound/oss/pss.c index e19dd5dcc2de..9b800ce5100e 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -859,7 +859,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, return 0; case SNDCTL_COPR_LOAD: - buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); + buf = vmalloc(sizeof(copr_buffer)); if (buf == NULL) return -ENOSPC; if (copy_from_user(buf, arg, sizeof(copr_buffer))) { @@ -871,7 +871,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, return err; case SNDCTL_COPR_SENDMSG: - mbuf = (copr_msg *)vmalloc(sizeof(copr_msg)); + mbuf = vmalloc(sizeof(copr_msg)); if (mbuf == NULL) return -ENOSPC; if (copy_from_user(mbuf, arg, sizeof(copr_msg))) { @@ -895,7 +895,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, case SNDCTL_COPR_RCVMSG: err = 0; - mbuf = (copr_msg *)vmalloc(sizeof(copr_msg)); + mbuf = vmalloc(sizeof(copr_msg)); if (mbuf == NULL) return -ENOSPC; data = (unsigned short *)mbuf->data; diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c index e85789e53816..5ea1098ac427 100644 --- a/sound/oss/sequencer.c +++ b/sound/oss/sequencer.c @@ -1646,13 +1646,13 @@ void sequencer_init(void) { if (sequencer_ok) return; - queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ); + queue = vmalloc(SEQ_MAX_QUEUE * EV_SZ); if (queue == NULL) { printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n"); return; } - iqueue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * IEV_SZ); + iqueue = vmalloc(SEQ_MAX_QUEUE * IEV_SZ); if (iqueue == NULL) { printk(KERN_ERR "sequencer: Can't allocate memory for sequencer input queue\n"); diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 62895a719fcb..22dbd91811a4 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -435,7 +435,7 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev) struct hpi_message hm; struct hpi_response hr; struct hpi_adapter *pa; - pa = (struct hpi_adapter *)pci_get_drvdata(pci_dev); + pa = pci_get_drvdata(pci_dev); hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_DELETE_ADAPTER); diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 4679ed83a43b..2f3cacbd5528 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1129,10 +1129,11 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, count_areas = size/2; addr_area2 = addr+count_areas; - count_areas--; /* max. index */ snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n", addr, count_areas, addr_area2, count_areas); + count_areas--; /* max. index */ + /* build combined I/O buffer length word */ lengths = (count_areas << 16) | (count_areas); spin_lock_irqsave(&chip->reg_lock, flags); @@ -1740,11 +1741,15 @@ static const struct snd_pcm_hardware snd_azf3328_hardware = .rate_max = AZF_FREQ_66200, .channels_min = 1, .channels_max = 2, - .buffer_bytes_max = 65536, - .period_bytes_min = 64, - .period_bytes_max = 65536, - .periods_min = 1, - .periods_max = 1024, + .buffer_bytes_max = (64*1024), + .period_bytes_min = 1024, + .period_bytes_max = (32*1024), + /* We simply have two DMA areas (instead of a list of descriptors + such as other cards); I believe that this is a fixed hardware + attribute and there isn't much driver magic to be done to expand it. + Thus indicate that we have at least and at most 2 periods. */ + .periods_min = 2, + .periods_max = 2, /* FIXME: maybe that card actually has a FIFO? * Hmm, it seems newer revisions do have one, but we still don't know * its size... */ @@ -1980,8 +1985,13 @@ snd_azf3328_timer_stop(struct snd_timer *timer) chip = snd_timer_chip(timer); spin_lock_irqsave(&chip->reg_lock, flags); /* disable timer countdown and interrupt */ - /* FIXME: should we write TIMER_IRQ_ACK here? */ - snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); + /* Hmm, should we write TIMER_IRQ_ACK here? + YES indeed, otherwise a rogue timer operation - which prompts + ALSA(?) to call repeated stop() in vain, but NOT start() - + will never end (value 0x03 is kept shown in control byte). + Simply manually poking 0x04 _once_ immediately successfully stops + the hardware/ALSA interrupt activity. */ + snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x04); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_azf3328_dbgcallleave(); return 0; diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index 85ab43e89212..457d21189b0d 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -129,8 +129,6 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream) apcm->substream = substream; apcm->interrupt = ct_atc_pcm_interrupt; - runtime->private_data = apcm; - runtime->private_free = ct_atc_pcm_free_substream; if (IEC958 == substream->pcm->device) { runtime->hw = ct_spdif_passthru_playback_hw; atc->spdif_out_passthru(atc, 1); @@ -155,8 +153,12 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream) } apcm->timer = ct_timer_instance_new(atc->timer, apcm); - if (!apcm->timer) + if (!apcm->timer) { + kfree(apcm); return -ENOMEM; + } + runtime->private_data = apcm; + runtime->private_free = ct_atc_pcm_free_substream; return 0; } @@ -278,8 +280,6 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream) apcm->started = 0; apcm->substream = substream; apcm->interrupt = ct_atc_pcm_interrupt; - runtime->private_data = apcm; - runtime->private_free = ct_atc_pcm_free_substream; runtime->hw = ct_pcm_capture_hw; runtime->hw.rate_max = atc->rsr * atc->msr; @@ -298,8 +298,12 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream) } apcm->timer = ct_timer_instance_new(atc->timer, apcm); - if (!apcm->timer) + if (!apcm->timer) { + kfree(apcm); return -ENOMEM; + } + runtime->private_data = apcm; + runtime->private_free = ct_atc_pcm_free_substream; return 0; } diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index cb0c23a6b473..4a663471dadc 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -189,6 +189,9 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, a->channels = GRAB_BITS(buf, 0, 0, 3); a->channels++; + a->sample_bits = 0; + a->max_bitrate = 0; + a->format = GRAB_BITS(buf, 0, 3, 4); switch (a->format) { case AUDIO_CODING_TYPE_REF_STREAM_HEADER: @@ -198,7 +201,6 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, case AUDIO_CODING_TYPE_LPCM: val = GRAB_BITS(buf, 2, 0, 3); - a->sample_bits = 0; for (i = 0; i < 3; i++) if (val & (1 << i)) a->sample_bits |= cea_sample_sizes[i + 1]; @@ -598,24 +600,19 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, { int i; - pcm->rates = 0; - pcm->formats = 0; - pcm->maxbps = 0; - pcm->channels_min = -1; - pcm->channels_max = 0; + /* assume basic audio support (the basic audio flag is not in ELD; + * however, all audio capable sinks are required to support basic + * audio) */ + pcm->rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; + pcm->formats = SNDRV_PCM_FMTBIT_S16_LE; + pcm->maxbps = 16; + pcm->channels_max = 2; for (i = 0; i < eld->sad_count; i++) { struct cea_sad *a = &eld->sad[i]; pcm->rates |= a->rates; - if (a->channels < pcm->channels_min) - pcm->channels_min = a->channels; if (a->channels > pcm->channels_max) pcm->channels_max = a->channels; if (a->format == AUDIO_CODING_TYPE_LPCM) { - if (a->sample_bits & AC_SUPPCM_BITS_16) { - pcm->formats |= SNDRV_PCM_FMTBIT_S16_LE; - if (pcm->maxbps < 16) - pcm->maxbps = 16; - } if (a->sample_bits & AC_SUPPCM_BITS_20) { pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE; if (pcm->maxbps < 20) @@ -635,7 +632,6 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, /* restrict the parameters by the values the codec provides */ pcm->rates &= codec_pars->rates; pcm->formats &= codec_pars->formats; - pcm->channels_min = max(pcm->channels_min, codec_pars->channels_min); pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max); pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps); } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 21aa9b0e28f6..b030c8eba21f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2296,6 +2296,7 @@ static int azx_dev_free(struct snd_device *device) */ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1025, 0x026f, "Acer Aspire 5538", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6361f752b5f3..76bd58a0e2b6 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -2116,8 +2116,8 @@ static void cxt5066_update_speaker(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; unsigned int pinctl; - snd_printdd("CXT5066: update speaker, hp_present=%d\n", - spec->hp_present); + snd_printdd("CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n", + spec->hp_present, spec->cur_eapd); /* Port A (HP) */ pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0; @@ -2125,11 +2125,20 @@ static void cxt5066_update_speaker(struct hda_codec *codec) pinctl); /* Port D (HP/LO) */ - pinctl = ((spec->hp_present & 2) && spec->cur_eapd) - ? spec->port_d_mode : 0; - /* Mute if Port A is connected on Thinkpad */ - if (spec->thinkpad && (spec->hp_present & 1)) - pinctl = 0; + if (spec->dell_automute) { + /* DELL AIO Port Rule: PortA> PortD> IntSpk */ + pinctl = (!(spec->hp_present & 1) && spec->cur_eapd) + ? PIN_OUT : 0; + } else if (spec->thinkpad) { + if (spec->cur_eapd) + pinctl = spec->port_d_mode; + /* Mute dock line-out if Port A (laptop HP) is present */ + if (spec->hp_present& 1) + pinctl = 0; + } else { + pinctl = ((spec->hp_present & 2) && spec->cur_eapd) + ? spec->port_d_mode : 0; + } snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); @@ -2137,14 +2146,6 @@ static void cxt5066_update_speaker(struct hda_codec *codec) pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); - - if (spec->dell_automute) { - /* DELL AIO Port Rule: PortA > PortD > IntSpk */ - pinctl = (!(spec->hp_present & 1) && spec->cur_eapd) - ? PIN_OUT : 0; - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); - } } /* turn on/off EAPD (+ mute HP) as a master switch */ @@ -3095,11 +3096,11 @@ static const char *cxt5066_models[CXT5066_MODELS] = { static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), - SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", - CXT5066_DELL_LAPTOP), + SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), + SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_HP_LAPTOP), SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), @@ -3108,8 +3109,10 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x21c8, "Thinkpad Edge 11", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD), diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d3e49aa5b9ec..31df7747990d 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -834,7 +834,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, return -ENODEV; } else { /* fallback to the codec default */ - hinfo->channels_min = codec_pars->channels_min; hinfo->channels_max = codec_pars->channels_max; hinfo->rates = codec_pars->rates; hinfo->formats = codec_pars->formats; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5f00589cb791..427da45d7906 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1614,6 +1614,7 @@ do_sku: spec->init_amp = ALC_INIT_GPIO3; break; case 5: + default: spec->init_amp = ALC_INIT_DEFAULT; break; } @@ -2014,6 +2015,36 @@ static struct hda_verb alc888_acer_aspire_6530g_verbs[] = { }; /* + *ALC888 Acer Aspire 7730G model + */ + +static struct hda_verb alc888_acer_aspire_7730G_verbs[] = { +/* Bias voltage on for external mic port */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* Enable unsolicited event for HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Enable speaker output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, +/* Enable headphone output */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, +/*Enable internal subwoofer */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, + {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +/* * ALC889 Acer Aspire 8930G model */ @@ -2200,6 +2231,16 @@ static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x17; } +static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x17; +} + static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -4554,6 +4595,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), + SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG), SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), @@ -9524,13 +9566,6 @@ static struct hda_verb alc883_acer_eapd_verbs[] = { { } }; -static struct hda_verb alc888_acer_aspire_7730G_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - static void alc888_6st_dell_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -9831,7 +9866,6 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763), SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY), - SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG), SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), @@ -10328,7 +10362,7 @@ static struct alc_config_preset alc882_presets[] = { .const_channel_count = 6, .input_mux = &alc883_capture_source, .unsol_event = alc_automute_amp_unsol_event, - .setup = alc888_acer_aspire_6530g_setup, + .setup = alc888_acer_aspire_7730g_setup, .init_hook = alc_automute_amp, }, [ALC883_MEDION] = { @@ -10796,7 +10830,8 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; + int i, err, type; + int type_idx = 0; hda_nid_t nid; for (i = 0; i < cfg->num_inputs; i++) { @@ -10805,9 +10840,15 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) nid = cfg->inputs[i].pin; if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { char label[32]; + type = cfg->inputs[i].type; + if (i > 0 && type == cfg->inputs[i - 1].type) + type_idx++; + else + type_idx = 0; snprintf(label, sizeof(label), "%s Boost", hda_get_autocfg_input_label(codec, cfg, i)); - err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0, + err = add_control(spec, ALC_CTL_WIDGET_VOL, label, + type_idx, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); if (err < 0) return err; @@ -14623,7 +14664,10 @@ static int alc275_setup_dual_adc(struct hda_codec *codec) /* different alc269-variants */ enum { ALC269_TYPE_NORMAL, + ALC269_TYPE_ALC258, ALC269_TYPE_ALC259, + ALC269_TYPE_ALC269VB, + ALC269_TYPE_ALC270, ALC269_TYPE_ALC271X, }; @@ -14763,6 +14807,8 @@ static int alc269_resume(struct hda_codec *codec) enum { ALC269_FIXUP_SONY_VAIO, ALC269_FIXUP_DELL_M101Z, + ALC269_FIXUP_LENOVO_EDGE14, + ALC269_FIXUP_ASUS_G73JW, }; static const struct alc_fixup alc269_fixups[] = { @@ -14780,11 +14826,22 @@ static const struct alc_fixup alc269_fixups[] = { {} } }, + [ALC269_FIXUP_LENOVO_EDGE14] = { + .sku = ALC_FIXUP_SKU_IGNORE, + }, + [ALC269_FIXUP_ASUS_G73JW] = { + .pins = (const struct alc_pincfg[]) { + { 0x17, 0x99130111 }, /* subwoofer */ + { } + } + }, }; static struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_LENOVO_EDGE14), + SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), {} }; @@ -15023,7 +15080,7 @@ static int alc269_fill_coef(struct hda_codec *codec) static int patch_alc269(struct hda_codec *codec) { struct alc_spec *spec; - int board_config; + int board_config, coef; int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -15034,14 +15091,23 @@ static int patch_alc269(struct hda_codec *codec) alc_auto_parse_customize_define(codec); - if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){ + coef = alc_read_coef_idx(codec, 0); + if ((coef & 0x00f0) == 0x0010) { if (codec->bus->pci->subsystem_vendor == 0x1025 && spec->cdefine.platform_type == 1) { alc_codec_rename(codec, "ALC271X"); spec->codec_variant = ALC269_TYPE_ALC271X; - } else { + } else if ((coef & 0xf000) == 0x1000) { + spec->codec_variant = ALC269_TYPE_ALC270; + } else if ((coef & 0xf000) == 0x2000) { alc_codec_rename(codec, "ALC259"); spec->codec_variant = ALC269_TYPE_ALC259; + } else if ((coef & 0xf000) == 0x3000) { + alc_codec_rename(codec, "ALC258"); + spec->codec_variant = ALC269_TYPE_ALC258; + } else { + alc_codec_rename(codec, "ALC269VB"); + spec->codec_variant = ALC269_TYPE_ALC269VB; } } else alc_fix_pll_init(codec, 0x20, 0x04, 15); @@ -15104,7 +15170,7 @@ static int patch_alc269(struct hda_codec *codec) spec->stream_digital_capture = &alc269_pcm_digital_capture; if (!spec->adc_nids) { /* wasn't filled automatically? use default */ - if (spec->codec_variant != ALC269_TYPE_NORMAL) { + if (spec->codec_variant == ALC269_TYPE_NORMAL) { spec->adc_nids = alc269_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); spec->capsrc_nids = alc269_capsrc_nids; @@ -16898,7 +16964,7 @@ static struct alc_config_preset alc861vd_presets[] = { static int alc861vd_auto_create_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { - return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0); + return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0); } @@ -18952,6 +19018,8 @@ static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid) return 0x02; else if (nid >= 0x0c && nid <= 0x0e) return nid - 0x0c + 0x02; + else if (nid == 0x26) /* ALC887-VD has this DAC too */ + return 0x25; else return 0; } @@ -18960,7 +19028,7 @@ static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid) static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) { - hda_nid_t mix[4]; + hda_nid_t mix[5]; int i, num; num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); @@ -19298,6 +19366,7 @@ static const struct alc_fixup alc662_fixups[] = { static struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), + SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), {} @@ -19419,7 +19488,10 @@ static int patch_alc888(struct hda_codec *codec) { if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){ kfree(codec->chip_name); - codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL); + if (codec->vendor_id == 0x10ec0887) + codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL); + else + codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL); if (!codec->chip_name) { alc_free(codec); return -ENOMEM; @@ -19909,7 +19981,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A", .patch = patch_alc882 }, { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, - { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 }, + { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 }, { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200", .patch = patch_alc882 }, { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 }, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 93fa59cc60ef..efa4225f5fd6 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -389,6 +389,11 @@ static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { 0x11, 0x20, 0 }; +#define STAC92HD87B_NUM_DMICS 1 +static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = { + 0x11, 0 +}; + #define STAC92HD83XXX_NUM_CAPS 2 static unsigned long stac92hd83xxx_capvols[] = { HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), @@ -1622,6 +1627,8 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1, "Alienware M17x", STAC_ALIENWARE_M17X), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a, + "Alienware M17x", STAC_ALIENWARE_M17X), {} /* terminator */ }; @@ -3486,10 +3493,8 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, return err; } - if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) { + if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) snd_hda_add_imux_item(imux, label, index, NULL); - spec->num_analog_muxes++; - } } return 0; @@ -5452,12 +5457,17 @@ again: stac92hd83xxx_brd_tbl[spec->board_config]); switch (codec->vendor_id) { + case 0x111d76d1: + case 0x111d76d9: + spec->dmic_nids = stac92hd87b_dmic_nids; + spec->num_dmics = stac92xx_connected_ports(codec, + stac92hd87b_dmic_nids, + STAC92HD87B_NUM_DMICS); + /* Fall through */ case 0x111d7666: case 0x111d7667: case 0x111d7668: case 0x111d7669: - case 0x111d76d1: - case 0x111d76d9: spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids); spec->pin_nids = stac92hd88xxx_pin_nids; spec->mono_nid = 0; diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 400f9ebd243e..629a5494347a 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1866,6 +1866,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { }, { .subvendor = 0x1028, + .subdevice = 0x0182, + .name = "Dell Latitude D610", /* STAC9750/51 */ + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x1028, .subdevice = 0x0186, .name = "Dell Latitude D810", /* cf. Malone #41015 */ .type = AC97_TUNE_HP_MUTE_LED diff --git a/sound/pci/mixart/mixart_hwdep.h b/sound/pci/mixart/mixart_hwdep.h index a46f5083db99..812e288ef2e7 100644 --- a/sound/pci/mixart/mixart_hwdep.h +++ b/sound/pci/mixart/mixart_hwdep.h @@ -25,11 +25,21 @@ #include <sound/hwdep.h> +#ifndef readl_be #define readl_be(x) be32_to_cpu(__raw_readl(x)) +#endif + +#ifndef writel_be #define writel_be(data,addr) __raw_writel(cpu_to_be32(data),addr) +#endif +#ifndef readl_le #define readl_le(x) le32_to_cpu(__raw_readl(x)) +#endif + +#ifndef writel_le #define writel_le(data,addr) __raw_writel(cpu_to_le32(data),addr) +#endif #define MIXART_MEM(mgr,x) ((mgr)->mem[0].virt + (x)) #define MIXART_REG(mgr,x) ((mgr)->mem[1].virt + (x)) diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 85081172403f..b47cfd45b3b9 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -1228,10 +1228,8 @@ int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) chip->rsrc[i].start + 1, rnames[i]) == NULL) { printk(KERN_ERR "snd: can't request rsrc " - " %d (%s: 0x%016llx:%016llx)\n", - i, rnames[i], - (unsigned long long)chip->rsrc[i].start, - (unsigned long long)chip->rsrc[i].end); + " %d (%s: %pR)\n", + i, rnames[i], &chip->rsrc[i]); err = -ENODEV; goto __error; } @@ -1256,10 +1254,8 @@ int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) chip->rsrc[i].start + 1, rnames[i]) == NULL) { printk(KERN_ERR "snd: can't request rsrc " - " %d (%s: 0x%016llx:%016llx)\n", - i, rnames[i], - (unsigned long long)chip->rsrc[i].start, - (unsigned long long)chip->rsrc[i].end); + " %d (%s: %pR)\n", + i, rnames[i], &chip->rsrc[i]); err = -ENODEV; goto __error; } diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index e720d5e6f04c..bee3c94f58b0 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -16,7 +16,8 @@ config SND_ATMEL_SOC_SSC config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" - depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC + depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC && \ + AT91_PROGRAMMABLE_CLOCKS select SND_ATMEL_SOC_SSC select SND_SOC_WM8731 help @@ -25,7 +26,7 @@ config SND_AT91_SOC_SAM9G20_WM8731 config SND_AT32_SOC_PLAYPAQ tristate "SoC Audio support for PlayPaq with WM8510" - depends on SND_ATMEL_SOC && BOARD_PLAYPAQ + depends on SND_ATMEL_SOC && BOARD_PLAYPAQ && AT91_PROGRAMMABLE_CLOCKS select SND_ATMEL_SOC_SSC select SND_SOC_WM8510 help diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 293569dfd0ed..e521ada80542 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -222,9 +222,9 @@ static int __init at91sam9g20ek_init(void) } pllb = clk_get(NULL, "pllb"); - if (IS_ERR(mclk)) { + if (IS_ERR(pllb)) { printk(KERN_ERR "ASoC: Failed to get PLLB\n"); - ret = PTR_ERR(mclk); + ret = PTR_ERR(pllb); goto err_mclk; } ret = clk_set_parent(mclk, pllb); @@ -240,6 +240,7 @@ static int __init at91sam9g20ek_init(void) if (!at91sam9g20ek_snd_device) { printk(KERN_ERR "ASoC: Platform device allocation failed\n"); ret = -ENOMEM; + goto err_mclk; } platform_set_drvdata(at91sam9g20ek_snd_device, @@ -248,11 +249,13 @@ static int __init at91sam9g20ek_init(void) ret = platform_device_add(at91sam9g20ek_snd_device); if (ret) { printk(KERN_ERR "ASoC: Platform device allocation failed\n"); - platform_device_put(at91sam9g20ek_snd_device); + goto err_device_add; } return ret; +err_device_add: + platform_device_put(at91sam9g20ek_snd_device); err_mclk: clk_put(mclk); mclk = NULL; diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c index e3d283561c19..86e0f8586dc3 100644 --- a/sound/soc/atmel/snd-soc-afeb9260.c +++ b/sound/soc/atmel/snd-soc-afeb9260.c @@ -167,7 +167,6 @@ static int __init afeb9260_soc_init(void) return 0; err1: - platform_device_del(afeb9260_snd_device); platform_device_put(afeb9260_snd_device); return err; } diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index bc22ee93a75d..d63e28773eb1 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -28,6 +28,11 @@ #include <sound/max98088.h> #include "max98088.h" +enum max98088_type { + MAX98088, + MAX98089, +}; + struct max98088_cdata { unsigned int rate; unsigned int fmt; @@ -36,6 +41,7 @@ struct max98088_cdata { struct max98088_priv { u8 reg_cache[M98088_REG_CNT]; + enum max98088_type devtype; void *control_data; struct max98088_pdata *pdata; unsigned int sysclk; @@ -2013,7 +2019,10 @@ err_access: static int max98088_remove(struct snd_soc_codec *codec) { + struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); + max98088_set_bias_level(codec, SND_SOC_BIAS_OFF); + kfree(max98088->eq_texts); return 0; } @@ -2040,6 +2049,8 @@ static int max98088_i2c_probe(struct i2c_client *i2c, if (max98088 == NULL) return -ENOMEM; + max98088->devtype = id->driver_data; + i2c_set_clientdata(i2c, max98088); max98088->control_data = i2c; max98088->pdata = i2c->dev.platform_data; @@ -2059,7 +2070,8 @@ static int __devexit max98088_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id max98088_i2c_id[] = { - { "max98088", 0 }, + { "max98088", MAX98088 }, + { "max98089", MAX98089 }, { } }; MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 00d67cc8e206..061f9e5a497b 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -383,6 +383,7 @@ static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { .reg_cache_size = sizeof(stac9766_reg), .reg_word_size = sizeof(u16), .reg_cache_step = 2, + .reg_cache_default = stac9766_reg, }; static __devinit int stac9766_probe(struct platform_device *pdev) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index fc687790188b..77b8f9ae29be 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1176,7 +1176,7 @@ EXPORT_SYMBOL_GPL(aic3x_set_gpio); int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) { u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; - u8 val, bit = gpio ? 2: 1; + u8 val = 0, bit = gpio ? 2 : 1; aic3x_read(codec, reg, &val); return (val >> bit) & 1; @@ -1204,7 +1204,7 @@ EXPORT_SYMBOL_GPL(aic3x_set_headset_detection); int aic3x_headset_detected(struct snd_soc_codec *codec) { - u8 val; + u8 val = 0; aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); return (val >> 4) & 1; } @@ -1212,7 +1212,7 @@ EXPORT_SYMBOL_GPL(aic3x_headset_detected); int aic3x_button_pressed(struct snd_soc_codec *codec) { - u8 val; + u8 val = 0; aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); return (val >> 5) & 1; } diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index ee4fb201de60..d2c243095673 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -78,8 +78,10 @@ static int tpa6130a2_i2c_write(int reg, u8 value) if (data->power_state) { val = i2c_smbus_write_byte_data(tpa6130a2_client, reg, value); - if (val < 0) + if (val < 0) { dev_err(&tpa6130a2_client->dev, "Write failed\n"); + return val; + } } /* Either powered on or off, we save the context */ diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 7540a509a6f5..464f0cfa4c7a 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -597,6 +597,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .resume = uda134x_soc_resume, .reg_cache_size = sizeof(uda134x_reg), .reg_word_size = sizeof(u8), + .reg_cache_default = uda134x_reg, .reg_cache_step = 1, .read = uda134x_read_reg_cache, .write = uda134x_write, diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index f4f1fba38eb9..7611add7f8c3 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -831,7 +831,7 @@ static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai, } /* MCLK direction */ - if (dir == WM8350_MCLK_DIR_OUT) + if (dir == SND_SOC_CLOCK_OUT) wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2, WM8350_MCLK_DIR); else @@ -1586,6 +1586,13 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME, WM8350_OUT2_VU | WM8350_OUT2R_MUTE); + /* Make sure AIF tristating is disabled by default */ + wm8350_clear_bits(wm8350, WM8350_AI_FORMATING, WM8350_AIF_TRI); + + /* Make sure we've got a sane companding setup too */ + wm8350_clear_bits(wm8350, WM8350_ADC_DAC_COMP, + WM8350_DAC_COMP | WM8350_LOOPBACK); + /* Make sure jack detect is disabled to start off with */ wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, WM8350_JDL_ENA | WM8350_JDR_ENA); diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 712ef7c76f90..9a433a5396cb 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -146,7 +146,6 @@ static int wm8523_startup(struct snd_pcm_substream *substream, return -EINVAL; } - return 0; snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &wm8523->rate_constraint); diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index a2e0ed59b376..8725d4e75431 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -161,7 +161,7 @@ static const u16 wm8580_reg[] = { 0x0121, 0x017e, 0x007d, 0x0014, /*R3*/ 0x0121, 0x017e, 0x007d, 0x0194, /*R7*/ - 0x001c, 0x0002, 0x0002, 0x00c2, /*R11*/ + 0x0010, 0x0002, 0x0002, 0x00c2, /*R11*/ 0x0182, 0x0082, 0x000a, 0x0024, /*R15*/ 0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/ 0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/ @@ -491,16 +491,16 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, paifa |= 0x8; break; case SNDRV_PCM_FORMAT_S20_3LE: - paifa |= 0x10; + paifa |= 0x0; paifb |= WM8580_AIF_LENGTH_20; break; case SNDRV_PCM_FORMAT_S24_LE: - paifa |= 0x10; + paifa |= 0x0; paifb |= WM8580_AIF_LENGTH_24; break; case SNDRV_PCM_FORMAT_S32_LE: - paifa |= 0x10; - paifb |= WM8580_AIF_LENGTH_24; + paifa |= 0x0; + paifb |= WM8580_AIF_LENGTH_32; break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 631385802eb4..e725c09a3e79 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -526,7 +526,7 @@ static int wm8731_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0); /* Disable bypass path by default */ - snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0); + snd_soc_update_bits(codec, WM8731_APANA, 0x8, 0); snd_soc_add_controls(codec, wm8731_snd_controls, ARRAY_SIZE(wm8731_snd_controls)); diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 04182c464e35..0132a27140ae 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -34,7 +34,6 @@ /* codec private data */ struct wm8776_priv { enum snd_soc_control_type control_type; - u16 reg_cache[WM8776_CACHEREGNUM]; int sysclk[2]; }; diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 33be84e506ea..9001cc48ba13 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -818,7 +818,8 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); - return wm8904->deemph; + ucontrol->value.enumerated.item[0] = wm8904->deemph; + return 0; } static int wm8904_put_deemph(struct snd_kcontrol *kcontrol, @@ -2498,6 +2499,8 @@ static int wm8904_remove(struct snd_soc_codec *codec) wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF); regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); + kfree(wm8904->retune_mobile_texts); + kfree(wm8904->drc_texts); return 0; } diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index f89ad6c9a80b..9cbab8e1de01 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -380,7 +380,8 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); - return wm8955->deemph; + ucontrol->value.enumerated.item[0] = wm8955->deemph; + return 0; } static int wm8955_put_deemph(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 8d5efb333c33..21986c42272f 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -138,7 +138,8 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - return wm8960->deemph; + ucontrol->value.enumerated.item[0] = wm8960->deemph; + return 0; } static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 4f326f604104..8340485c9851 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -711,7 +711,7 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream, if (fs <= 24000) reg |= WM8961_DACSLOPE; else - reg &= WM8961_DACSLOPE; + reg &= ~WM8961_DACSLOPE; snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); return 0; @@ -736,7 +736,7 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id, freq /= 2; } else { dev_dbg(codec->dev, "Using MCLK/1 for %dHz MCLK\n", freq); - reg &= WM8961_MCLKDIV; + reg &= ~WM8961_MCLKDIV; } snd_soc_write(codec, WM8961_CLOCKING1, reg); diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 894d0cd3aa9b..1304ca91a11c 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3339,7 +3339,7 @@ static irqreturn_t wm8962_irq(int irq, void *data) int mask; int active; - mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2); + mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2_MASK); active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2); active &= ~mask; @@ -3500,8 +3500,11 @@ static ssize_t wm8962_beep_set(struct device *dev, { struct wm8962_priv *wm8962 = dev_get_drvdata(dev); long int time; + int ret; - strict_strtol(buf, 10, &time); + ret = strict_strtol(buf, 10, &time); + if (ret != 0) + return ret; input_event(wm8962->beep, EV_SND, SND_TONE, time); diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 0db59c3aa5d4..4d3e6f1ac584 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3903,6 +3903,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) return -ENOMEM; snd_soc_codec_set_drvdata(codec, wm8994); + codec->reg_cache = &wm8994->reg_cache; + wm8994->pdata = dev_get_platdata(codec->dev->parent); wm8994->codec = codec; @@ -4059,6 +4061,8 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994); wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994); + kfree(wm8994->retune_mobile_texts); + kfree(wm8994->drc_texts); kfree(wm8994); return 0; @@ -4071,6 +4075,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8994 = { .resume = wm8994_resume, .read = wm8994_read, .write = wm8994_write, + .readable_register = wm8994_readable, + .volatile_register = wm8994_volatile, .set_bias_level = wm8994_set_bias_level, }; diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 19ca782ac970..0e24092722c3 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -293,7 +293,7 @@ SOC_DOUBLE_R("Speaker Switch", SOC_DOUBLE_R("Speaker ZC Switch", WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT, 7, 1, 0), -SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 0, 3, 7, 0, +SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 3, 0, 7, 0, spkboost_tlv), SOC_ENUM("Speaker Reference", speaker_ref), SOC_ENUM("Speaker Mode", speaker_mode), diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 2b07b17a6b2d..bc9e6b0b3f6f 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -157,12 +157,23 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd) } /* davinci-evm digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link evm_dai = { +static struct snd_soc_dai_link dm6446_evm_dai = { .name = "TLV320AIC3X", .stream_name = "AIC3X", - .cpu_dai_name = "davinci-mcasp.0", + .cpu_dai_name = "davinci-mcbsp", .codec_dai_name = "tlv320aic3x-hifi", - .codec_name = "tlv320aic3x-codec.0-001a", + .codec_name = "tlv320aic3x-codec.1-001b", + .platform_name = "davinci-pcm-audio", + .init = evm_aic3x_init, + .ops = &evm_ops, +}; + +static struct snd_soc_dai_link dm355_evm_dai = { + .name = "TLV320AIC3X", + .stream_name = "AIC3X", + .cpu_dai_name = "davinci-mcbsp.1", + .codec_dai_name = "tlv320aic3x-hifi", + .codec_name = "tlv320aic3x-codec.1-001b", .platform_name = "davinci-pcm-audio", .init = evm_aic3x_init, .ops = &evm_ops, @@ -172,10 +183,10 @@ static struct snd_soc_dai_link dm365_evm_dai = { #ifdef CONFIG_SND_DM365_AIC3X_CODEC .name = "TLV320AIC3X", .stream_name = "AIC3X", - .cpu_dai_name = "davinci-i2s", + .cpu_dai_name = "davinci-mcbsp", .codec_dai_name = "tlv320aic3x-hifi", .init = evm_aic3x_init, - .codec_name = "tlv320aic3x-codec.0-001a", + .codec_name = "tlv320aic3x-codec.1-0018", .ops = &evm_ops, #elif defined(CONFIG_SND_DM365_VOICE_CODEC) .name = "Voice Codec - CQ93VC", @@ -219,10 +230,17 @@ static struct snd_soc_dai_link da8xx_evm_dai = { .ops = &evm_ops, }; -/* davinci dm6446, dm355 evm audio machine driver */ -static struct snd_soc_card snd_soc_card_evm = { - .name = "DaVinci EVM", - .dai_link = &evm_dai, +/* davinci dm6446 evm audio machine driver */ +static struct snd_soc_card dm6446_snd_soc_card_evm = { + .name = "DaVinci DM6446 EVM", + .dai_link = &dm6446_evm_dai, + .num_links = 1, +}; + +/* davinci dm355 evm audio machine driver */ +static struct snd_soc_card dm355_snd_soc_card_evm = { + .name = "DaVinci DM355 EVM", + .dai_link = &dm355_evm_dai, .num_links = 1, }; @@ -261,10 +279,10 @@ static int __init evm_init(void) int ret; if (machine_is_davinci_evm()) { - evm_snd_dev_data = &snd_soc_card_evm; + evm_snd_dev_data = &dm6446_snd_soc_card_evm; index = 0; } else if (machine_is_davinci_dm355_evm()) { - evm_snd_dev_data = &snd_soc_card_evm; + evm_snd_dev_data = &dm355_snd_soc_card_evm; index = 1; } else if (machine_is_davinci_dm365_evm()) { evm_snd_dev_data = &dm365_snd_soc_card_evm; diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index d46b545d41f4..9e0e565e6ed9 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -426,9 +426,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, snd_pcm_format_t fmt; unsigned element_cnt = 1; - dai->capture_dma_data = dev->dma_params; - dai->playback_dma_data = dev->dma_params; - /* general line settings */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { @@ -601,6 +598,15 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } +static int davinci_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); + return 0; +} + static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -612,6 +618,7 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 static struct snd_soc_dai_ops davinci_i2s_dai_ops = { + .startup = davinci_i2s_startup, .shutdown = davinci_i2s_shutdown, .prepare = davinci_i2s_prepare, .trigger = davinci_i2s_trigger, @@ -749,7 +756,7 @@ static struct platform_driver davinci_mcbsp_driver = { .probe = davinci_i2s_probe, .remove = davinci_i2s_remove, .driver = { - .name = "davinci-i2s", + .name = "davinci-mcbsp", .owner = THIS_MODULE, }, }; diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 86918ee12419..fb55d2c5d704 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -715,9 +715,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, int word_length; u8 fifo_level; - cpu_dai->capture_dma_data = dev->dma_params; - cpu_dai->playback_dma_data = dev->dma_params; - davinci_hw_common_param(dev, substream->stream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) fifo_level = dev->txnumevt; @@ -799,7 +796,17 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, return ret; } +static int davinci_mcasp_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); + return 0; +} + static struct snd_soc_dai_ops davinci_mcasp_dai_ops = { + .startup = davinci_mcasp_startup, .trigger = davinci_mcasp_trigger, .hw_params = davinci_mcasp_hw_params, .set_fmt = davinci_mcasp_set_dai_fmt, diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index 009b6521a1bf..6c6666a1f942 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -84,7 +84,7 @@ static struct snd_soc_ops sffsdr_ops = { static struct snd_soc_dai_link sffsdr_dai = { .name = "PCM3008", /* Codec name */ .stream_name = "PCM3008 HiFi", - .cpu_dai_name = "davinci-asp.0", + .cpu_dai_name = "davinci-mcbsp", .codec_dai_name = "pcm3008-hifi", .codec_name = "pcm3008-codec", .platform_name = "davinci-pcm-audio", diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index ea232f6a2c21..9d2afccc3a2d 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -97,9 +97,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, &davinci_vcif_dev->dma_params[substream->stream]; u32 w; - dai->capture_dma_data = davinci_vcif_dev->dma_params; - dai->playback_dma_data = davinci_vcif_dev->dma_params; - /* Restart the codec before setup */ davinci_vcif_stop(substream); davinci_vcif_start(substream); @@ -174,9 +171,19 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } +static int davinci_vcif_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); + return 0; +} + #define DAVINCI_VCIF_RATES SNDRV_PCM_RATE_8000_48000 static struct snd_soc_dai_ops davinci_vcif_dai_ops = { + .startup = davinci_vcif_startup, .trigger = davinci_vcif_trigger, .hw_params = davinci_vcif_hw_params, }; @@ -240,7 +247,10 @@ fail: static int davinci_vcif_remove(struct platform_device *pdev) { + struct davinci_vcif_dev *davinci_vcif_dev = dev_get_drvdata(&pdev->dev); + snd_soc_unregister_dai(&pdev->dev); + kfree(davinci_vcif_dev); return 0; } diff --git a/sound/soc/ep93xx/simone.c b/sound/soc/ep93xx/simone.c index 4b0d19913728..286817946c56 100644 --- a/sound/soc/ep93xx/simone.c +++ b/sound/soc/ep93xx/simone.c @@ -54,24 +54,26 @@ static int __init simone_init(void) ret = platform_device_add(simone_snd_ac97_device); if (ret) - goto fail; + goto fail1; simone_snd_device = platform_device_alloc("soc-audio", -1); if (!simone_snd_device) { ret = -ENOMEM; - goto fail; + goto fail2; } platform_set_drvdata(simone_snd_device, &snd_soc_simone); ret = platform_device_add(simone_snd_device); - if (ret) { - platform_device_put(simone_snd_device); - goto fail; - } + if (ret) + goto fail3; - return ret; + return 0; -fail: +fail3: + platform_device_put(simone_snd_device); +fail2: + platform_device_del(simone_snd_ac97_device); +fail1: platform_device_put(simone_snd_ac97_device); return ret; } diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c index 53251e6b5bd5..108b5d8bd0e9 100644 --- a/sound/soc/fsl/efika-audio-fabric.c +++ b/sound/soc/fsl/efika-audio-fabric.c @@ -76,6 +76,7 @@ static __init int efika_fabric_init(void) rc = platform_device_add(pdev); if (rc) { pr_err("efika_fabric_init: platform_device_add() failed\n"); + platform_device_put(pdev); return -ENODEV; } return 0; diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index dce6b551cd78..f92dca07cd35 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include <linux/of_device.h> #include <linux/slab.h> -#include <linux/of_device.h> #include <linux/of_platform.h> #include <sound/soc.h> diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 74ffed41340f..9018fa5bf0db 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -160,7 +160,7 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op, rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai)); if (rc != 0) { pr_err("Failed to register DAI\n"); - return 0; + return rc; } psc_dma = dev_get_drvdata(&op->dev); diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 0d7dcf1e4863..7d7847a1e66b 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -498,6 +498,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) dev_err(&pdev->dev, "platform device add failed\n"); goto error; } + dev_set_drvdata(&pdev->dev, sound_device); of_node_put(codec_np); diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 63b9eaa1ebc2..026b756961e0 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -498,6 +498,7 @@ static int p1022_ds_probe(struct platform_device *pdev) dev_err(&pdev->dev, "platform device add failed\n"); goto error; } + dev_set_drvdata(&pdev->dev, sound_device); of_node_put(codec_np); diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index 25f27ec1dd6e..ba4d85e317ed 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -76,6 +76,7 @@ static __init int pcm030_fabric_init(void) rc = platform_device_add(pdev); if (rc) { pr_err("pcm030_fabric_init: platform_device_add() failed\n"); + platform_device_put(pdev); return -ENODEV; } return 0; diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c index b59675257ce5..dd4fffdbd177 100644 --- a/sound/soc/imx/eukrea-tlv320.c +++ b/sound/soc/imx/eukrea-tlv320.c @@ -34,8 +34,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | @@ -79,10 +79,10 @@ static struct snd_soc_ops eukrea_tlv320_snd_ops = { static struct snd_soc_dai_link eukrea_tlv320_dai = { .name = "tlv320aic23", .stream_name = "TLV320AIC23", - .codec_dai = "tlv320aic23-hifi", + .codec_dai_name = "tlv320aic23-hifi", .platform_name = "imx-pcm-audio.0", .codec_name = "tlv320aic23-codec.0-001a", - .cpu_dai = "imx-ssi.0", + .cpu_dai_name = "imx-ssi.0", .ops = &eukrea_tlv320_snd_ops, }; diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c index fd493ee1428e..671ef8dd524c 100644 --- a/sound/soc/imx/imx-pcm-dma-mx2.c +++ b/sound/soc/imx/imx-pcm-dma-mx2.c @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/dmaengine.h> #include <sound/core.h> #include <sound/initval.h> @@ -27,165 +28,146 @@ #include <sound/pcm_params.h> #include <sound/soc.h> -#include <mach/dma-mx1-mx2.h> +#include <mach/dma.h> #include "imx-ssi.h" struct imx_pcm_runtime_data { - int sg_count; - struct scatterlist *sg_list; - int period; + int period_bytes; int periods; - unsigned long dma_addr; int dma; - struct snd_pcm_substream *substream; unsigned long offset; unsigned long size; - unsigned long period_cnt; void *buf; int period_time; + struct dma_async_tx_descriptor *desc; + struct dma_chan *dma_chan; + struct imx_dma_data dma_data; }; -/* Called by the DMA framework when a period has elapsed */ -static void imx_ssi_dma_progression(int channel, void *data, - struct scatterlist *sg) +static void audio_dma_irq(void *data) { - struct snd_pcm_substream *substream = data; + struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; - if (!sg) - return; - - runtime = iprtd->substream->runtime; + iprtd->offset += iprtd->period_bytes; + iprtd->offset %= iprtd->period_bytes * iprtd->periods; - iprtd->offset = sg->dma_address - runtime->dma_addr; - - snd_pcm_period_elapsed(iprtd->substream); + snd_pcm_period_elapsed(substream); } -static void imx_ssi_dma_callback(int channel, void *data) +static bool filter(struct dma_chan *chan, void *param) { - pr_err("%s shouldn't be called\n", __func__); -} + struct imx_pcm_runtime_data *iprtd = param; -static void snd_imx_dma_err_callback(int channel, void *data, int err) -{ - struct snd_pcm_substream *substream = data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct imx_pcm_dma_params *dma_params = - snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; - int ret; + if (!imx_dma_is_general_purpose(chan)) + return false; - pr_err("DMA timeout on channel %d -%s%s%s%s\n", - channel, - err & IMX_DMA_ERR_BURST ? " burst" : "", - err & IMX_DMA_ERR_REQUEST ? " request" : "", - err & IMX_DMA_ERR_TRANSFER ? " transfer" : "", - err & IMX_DMA_ERR_BUFFER ? " buffer" : ""); + chan->private = &iprtd->dma_data; - imx_dma_disable(iprtd->dma); - ret = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count, - IMX_DMA_LENGTH_LOOP, dma_params->dma_addr, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - DMA_MODE_WRITE : DMA_MODE_READ); - if (!ret) - imx_dma_enable(iprtd->dma); + return true; } -static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream) +static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct imx_pcm_dma_params *dma_params; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; + struct dma_slave_config slave_config; + dma_cap_mask_t mask; + enum dma_slave_buswidth buswidth; int ret; dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH); - if (iprtd->dma < 0) { - pr_err("Failed to claim the audio DMA\n"); - return -ENODEV; - } + iprtd->dma_data.peripheral_type = IMX_DMATYPE_SSI; + iprtd->dma_data.priority = DMA_PRIO_HIGH; + iprtd->dma_data.dma_request = dma_params->dma; - ret = imx_dma_setup_handlers(iprtd->dma, - imx_ssi_dma_callback, - snd_imx_dma_err_callback, substream); - if (ret) - goto out; + /* Try to grab a DMA channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + iprtd->dma_chan = dma_request_channel(mask, filter, iprtd); + if (!iprtd->dma_chan) + return -EINVAL; - ret = imx_dma_setup_progression_handler(iprtd->dma, - imx_ssi_dma_progression); - if (ret) { - pr_err("Failed to setup the DMA handler\n"); - goto out; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S24_LE: + buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + default: + return 0; } - ret = imx_dma_config_channel(iprtd->dma, - IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO, - IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, - dma_params->dma, 1); - if (ret < 0) { - pr_err("Cannot configure DMA channel: %d\n", ret); - goto out; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config.direction = DMA_TO_DEVICE; + slave_config.dst_addr = dma_params->dma_addr; + slave_config.dst_addr_width = buswidth; + slave_config.dst_maxburst = dma_params->burstsize; + } else { + slave_config.direction = DMA_FROM_DEVICE; + slave_config.src_addr = dma_params->dma_addr; + slave_config.src_addr_width = buswidth; + slave_config.src_maxburst = dma_params->burstsize; } - imx_dma_config_burstlen(iprtd->dma, dma_params->burstsize * 2); + ret = dmaengine_slave_config(iprtd->dma_chan, &slave_config); + if (ret) + return ret; return 0; -out: - imx_dma_free(iprtd->dma); - return ret; } static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; - int i; unsigned long dma_addr; + struct dma_chan *chan; + struct imx_pcm_dma_params *dma_params; + int ret; - imx_ssi_dma_alloc(substream); + dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + ret = imx_ssi_dma_alloc(substream, params); + if (ret) + return ret; + chan = iprtd->dma_chan; iprtd->size = params_buffer_bytes(params); iprtd->periods = params_periods(params); - iprtd->period = params_period_bytes(params); + iprtd->period_bytes = params_period_bytes(params); iprtd->offset = 0; iprtd->period_time = HZ / (params_rate(params) / params_period_size(params)); snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - if (iprtd->sg_count != iprtd->periods) { - kfree(iprtd->sg_list); - - iprtd->sg_list = kcalloc(iprtd->periods + 1, - sizeof(struct scatterlist), GFP_KERNEL); - if (!iprtd->sg_list) - return -ENOMEM; - iprtd->sg_count = iprtd->periods + 1; - } - - sg_init_table(iprtd->sg_list, iprtd->sg_count); dma_addr = runtime->dma_addr; - for (i = 0; i < iprtd->periods; i++) { - iprtd->sg_list[i].page_link = 0; - iprtd->sg_list[i].offset = 0; - iprtd->sg_list[i].dma_address = dma_addr; - iprtd->sg_list[i].length = iprtd->period; - dma_addr += iprtd->period; + iprtd->buf = (unsigned int *)substream->dma_buffer.area; + + iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr, + iprtd->period_bytes * iprtd->periods, + iprtd->period_bytes, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (!iprtd->desc) { + dev_err(&chan->dev->device, "cannot prepare slave dma\n"); + return -EINVAL; } - /* close the loop */ - iprtd->sg_list[iprtd->sg_count - 1].offset = 0; - iprtd->sg_list[iprtd->sg_count - 1].length = 0; - iprtd->sg_list[iprtd->sg_count - 1].page_link = - ((unsigned long) iprtd->sg_list | 0x01) & ~0x02; + iprtd->desc->callback = audio_dma_irq; + iprtd->desc->callback_param = substream; + return 0; } @@ -194,41 +176,21 @@ static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; - if (iprtd->dma >= 0) { - imx_dma_free(iprtd->dma); - iprtd->dma = -EINVAL; + if (iprtd->dma_chan) { + dma_release_channel(iprtd->dma_chan); + iprtd->dma_chan = NULL; } - kfree(iprtd->sg_list); - iprtd->sg_list = NULL; - return 0; } static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct imx_pcm_dma_params *dma_params; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; - int err; dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - iprtd->substream = substream; - iprtd->buf = (unsigned int *)substream->dma_buffer.area; - iprtd->period_cnt = 0; - - pr_debug("%s: buf: %p period: %d periods: %d\n", - __func__, iprtd->buf, iprtd->period, iprtd->periods); - - err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count, - IMX_DMA_LENGTH_LOOP, dma_params->dma_addr, - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - DMA_MODE_WRITE : DMA_MODE_READ); - if (err) - return err; - return 0; } @@ -241,14 +203,14 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - imx_dma_enable(iprtd->dma); + dmaengine_submit(iprtd->desc); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - imx_dma_disable(iprtd->dma); + dmaengine_terminate_all(iprtd->dma_chan); break; default: @@ -263,6 +225,9 @@ static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; + pr_debug("%s: %ld %ld\n", __func__, iprtd->offset, + bytes_to_frames(substream->runtime, iprtd->offset)); + return bytes_to_frames(substream->runtime, iprtd->offset); } @@ -279,7 +244,7 @@ static struct snd_pcm_hardware snd_imx_hardware = { .channels_max = 2, .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, .period_bytes_min = 128, - .period_bytes_max = 16 * 1024, + .period_bytes_max = 65535, /* Limited by SDMA engine */ .periods_min = 2, .periods_max = 255, .fifo_size = 0, @@ -304,11 +269,23 @@ static int snd_imx_open(struct snd_pcm_substream *substream) } snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); + + return 0; +} + +static int snd_imx_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct imx_pcm_runtime_data *iprtd = runtime->private_data; + + kfree(iprtd); + return 0; } static struct snd_pcm_ops imx_pcm_ops = { .open = snd_imx_open, + .close = snd_imx_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_imx_pcm_hw_params, .hw_free = snd_imx_pcm_hw_free, @@ -340,7 +317,6 @@ static struct platform_driver imx_pcm_driver = { .name = "imx-pcm-audio", .owner = THIS_MODULE, }, - .probe = imx_soc_platform_probe, .remove = __devexit_p(imx_soc_platform_remove), }; @@ -356,4 +332,3 @@ static void __exit snd_imx_pcm_exit(void) platform_driver_unregister(&imx_pcm_driver); } module_exit(snd_imx_pcm_exit); - diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index d4bd345b0a8d..390b6ffc2658 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c @@ -439,7 +439,22 @@ void imx_pcm_free(struct snd_pcm *pcm) } EXPORT_SYMBOL_GPL(imx_pcm_free); +static int imx_ssi_dai_probe(struct snd_soc_dai *dai) +{ + struct imx_ssi *ssi = dev_get_drvdata(dai->dev); + uint32_t val; + + snd_soc_dai_set_drvdata(dai, ssi); + + val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) | + SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize); + writel(val, ssi->base + SSI_SFCSR); + + return 0; +} + static struct snd_soc_dai_driver imx_ssi_dai = { + .probe = imx_ssi_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, @@ -455,20 +470,6 @@ static struct snd_soc_dai_driver imx_ssi_dai = { .ops = &imx_ssi_pcm_dai_ops, }; -static int imx_ssi_dai_probe(struct snd_soc_dai *dai) -{ - struct imx_ssi *ssi = dev_get_drvdata(dai->dev); - uint32_t val; - - snd_soc_dai_set_drvdata(dai, ssi); - - val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) | - SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize); - writel(val, ssi->base + SSI_SFCSR); - - return 0; -} - static struct snd_soc_dai_driver imx_ac97_dai = { .probe = imx_ssi_dai_probe, .ac97_control = 1, @@ -677,9 +678,25 @@ static int imx_ssi_probe(struct platform_device *pdev) goto failed_register; } - ssi->soc_platform_pdev = platform_device_alloc("imx-fiq-pcm-audio", pdev->id); - if (!ssi->soc_platform_pdev) + ssi->soc_platform_pdev_fiq = platform_device_alloc("imx-fiq-pcm-audio", pdev->id); + if (!ssi->soc_platform_pdev_fiq) { + ret = -ENOMEM; + goto failed_pdev_fiq_alloc; + } + + platform_set_drvdata(ssi->soc_platform_pdev_fiq, ssi); + ret = platform_device_add(ssi->soc_platform_pdev_fiq); + if (ret) { + dev_err(&pdev->dev, "failed to add platform device\n"); + goto failed_pdev_fiq_add; + } + + ssi->soc_platform_pdev = platform_device_alloc("imx-pcm-audio", pdev->id); + if (!ssi->soc_platform_pdev) { + ret = -ENOMEM; goto failed_pdev_alloc; + } + platform_set_drvdata(ssi->soc_platform_pdev, ssi); ret = platform_device_add(ssi->soc_platform_pdev); if (ret) { @@ -692,6 +709,10 @@ static int imx_ssi_probe(struct platform_device *pdev) failed_pdev_add: platform_device_put(ssi->soc_platform_pdev); failed_pdev_alloc: + platform_device_del(ssi->soc_platform_pdev_fiq); +failed_pdev_fiq_add: + platform_device_put(ssi->soc_platform_pdev_fiq); +failed_pdev_fiq_alloc: snd_soc_unregister_dai(&pdev->dev); failed_register: failed_ac97: @@ -712,8 +733,8 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev) struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct imx_ssi *ssi = platform_get_drvdata(pdev); - platform_device_del(ssi->soc_platform_pdev); - platform_device_put(ssi->soc_platform_pdev); + platform_device_unregister(ssi->soc_platform_pdev); + platform_device_unregister(ssi->soc_platform_pdev_fiq); snd_soc_unregister_dai(&pdev->dev); diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h index 53b780d9b2b0..a4406a134892 100644 --- a/sound/soc/imx/imx-ssi.h +++ b/sound/soc/imx/imx-ssi.h @@ -185,6 +185,9 @@ #define DRV_NAME "imx-ssi" +#include <linux/dmaengine.h> +#include <mach/dma.h> + struct imx_pcm_dma_params { int dma; unsigned long dma_addr; @@ -212,6 +215,7 @@ struct imx_ssi { int enabled; struct platform_device *soc_platform_pdev; + struct platform_device *soc_platform_pdev_fiq; }; struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev, diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c index 6a65dd705519..9eabc28667e6 100644 --- a/sound/soc/imx/phycore-ac97.c +++ b/sound/soc/imx/phycore-ac97.c @@ -20,9 +20,6 @@ #include <sound/soc-dapm.h> #include <asm/mach-types.h> -#include "../codecs/wm9712.h" -#include "imx-ssi.h" - static struct snd_soc_card imx_phycore; static struct snd_soc_ops imx_phycore_hifi_ops = { @@ -41,11 +38,12 @@ static struct snd_soc_dai_link imx_phycore_dai_ac97[] = { }; static struct snd_soc_card imx_phycore = { - .name = "PhyCORE-audio", + .name = "PhyCORE-ac97-audio", .dai_link = imx_phycore_dai_ac97, .num_links = ARRAY_SIZE(imx_phycore_dai_ac97), }; +static struct platform_device *imx_phycore_snd_ac97_device; static struct platform_device *imx_phycore_snd_device; static int __init imx_phycore_init(void) @@ -56,29 +54,42 @@ static int __init imx_phycore_init(void) /* return happy. We might run on a totally different machine */ return 0; - imx_phycore_snd_device = platform_device_alloc("soc-audio", -1); - if (!imx_phycore_snd_device) + imx_phycore_snd_ac97_device = platform_device_alloc("soc-audio", -1); + if (!imx_phycore_snd_ac97_device) return -ENOMEM; - platform_set_drvdata(imx_phycore_snd_device, &imx_phycore); - ret = platform_device_add(imx_phycore_snd_device); + platform_set_drvdata(imx_phycore_snd_ac97_device, &imx_phycore); + ret = platform_device_add(imx_phycore_snd_ac97_device); + if (ret) + goto fail1; imx_phycore_snd_device = platform_device_alloc("wm9712-codec", -1); - if (!imx_phycore_snd_device) - return -ENOMEM; + if (!imx_phycore_snd_device) { + ret = -ENOMEM; + goto fail2; + } ret = platform_device_add(imx_phycore_snd_device); if (ret) { printk(KERN_ERR "ASoC: Platform device allocation failed\n"); - platform_device_put(imx_phycore_snd_device); + goto fail3; } + return 0; + +fail3: + platform_device_put(imx_phycore_snd_device); +fail2: + platform_device_del(imx_phycore_snd_ac97_device); +fail1: + platform_device_put(imx_phycore_snd_ac97_device); return ret; } static void __exit imx_phycore_exit(void) { platform_device_unregister(imx_phycore_snd_device); + platform_device_unregister(imx_phycore_snd_ac97_device); } late_initcall(imx_phycore_init); diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index 293dc748797c..dac6732da969 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -49,7 +49,7 @@ static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97, mutex_lock(&ac97_mutex); val = nuc900_checkready(); - if (!!val) { + if (val) { dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); goto out; } @@ -102,7 +102,7 @@ static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg, mutex_lock(&ac97_mutex); tmp = nuc900_checkready(); - if (!!tmp) + if (tmp) dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); /* clear the R_WB bit and write register index */ @@ -149,7 +149,7 @@ static void nuc900_ac97_warm_reset(struct snd_ac97 *ac97) udelay(100); val = nuc900_checkready(); - if (!!val) + if (val) dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); mutex_unlock(&ac97_mutex); @@ -263,8 +263,7 @@ static int nuc900_ac97_trigger(struct snd_pcm_substream *substream, return ret; } -static int nuc900_ac97_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int nuc900_ac97_probe(struct snd_soc_dai *dai) { struct nuc900_audio *nuc900_audio = nuc900_ac97_data; unsigned long val; @@ -284,12 +283,12 @@ static int nuc900_ac97_probe(struct platform_device *pdev, return 0; } -static void nuc900_ac97_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int nuc900_ac97_remove(struct snd_soc_dai *dai) { struct nuc900_audio *nuc900_audio = nuc900_ac97_data; clk_disable(nuc900_audio->clk); + return 0; } static struct snd_soc_dai_ops nuc900_ac97_dai_ops = { @@ -313,7 +312,7 @@ static struct snd_soc_dai_driver nuc900_ac97_dai = { .channels_max = 2, }, .ops = &nuc900_ac97_dai_ops, -} +}; static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev) { @@ -384,7 +383,6 @@ out0: static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); clk_put(nuc900_ac97_data->clk); @@ -392,6 +390,7 @@ static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev) release_mem_region(nuc900_ac97_data->res->start, resource_size(nuc900_ac97_data->res)); + kfree(nuc900_ac97_data); nuc900_ac97_data = NULL; return 0; diff --git a/sound/soc/nuc900/nuc900-audio.h b/sound/soc/nuc900/nuc900-audio.h index aeed8ead2b2b..59f7e8ed1a68 100644 --- a/sound/soc/nuc900/nuc900-audio.h +++ b/sound/soc/nuc900/nuc900-audio.h @@ -110,4 +110,6 @@ struct nuc900_audio { }; +extern struct nuc900_audio *nuc900_ac97_data; + #endif /*end _NUC900_AUDIO_H */ diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c index 195d1ac94771..8263f56dc665 100644 --- a/sound/soc/nuc900/nuc900-pcm.c +++ b/sound/soc/nuc900/nuc900-pcm.c @@ -50,12 +50,12 @@ static int nuc900_dma_hw_params(struct snd_pcm_substream *substream, unsigned long flags; int ret = 0; - spin_lock_irqsave(&nuc900_audio->lock, flags); - ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); if (ret < 0) return ret; + spin_lock_irqsave(&nuc900_audio->lock, flags); + nuc900_audio->substream = substream; nuc900_audio->dma_addr[substream->stream] = runtime->dma_addr; nuc900_audio->buffersize[substream->stream] = @@ -169,6 +169,7 @@ static int nuc900_dma_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct nuc900_audio *nuc900_audio = runtime->private_data; unsigned long flags, val; + int ret = 0; spin_lock_irqsave(&nuc900_audio->lock, flags); @@ -197,10 +198,10 @@ static int nuc900_dma_prepare(struct snd_pcm_substream *substream) AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); break; default: - return -EINVAL; + ret = -EINVAL; } spin_unlock_irqrestore(&nuc900_audio->lock, flags); - return 0; + return ret; } static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd) @@ -332,7 +333,7 @@ static struct snd_soc_platform_driver nuc900_soc_platform = { .ops = &nuc900_dma_ops, .pcm_new = nuc900_dma_new, .pcm_free = nuc900_dma_free_dma_buffers, -} +}; static int __devinit nuc900_soc_platform_probe(struct platform_device *pdev) { diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index d542ea2ff6be..a088db6d5091 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -12,8 +12,8 @@ config SND_OMAP_SOC_MCPDM config SND_OMAP_SOC_N810 tristate "SoC Audio support for Nokia N810" depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C + depends on OMAP_MUX select SND_OMAP_SOC_MCBSP - select OMAP_MUX select SND_SOC_TLV320AIC3X help Say Y if you want to add support for SoC audio on Nokia N810. diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index d211c9fa5a91..7e84f24b9a88 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -644,15 +644,23 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, case OMAP_MCBSP_CLKR_SRC_CLKR: + if (cpu_class_is_omap1()) + break; omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKR); break; case OMAP_MCBSP_CLKR_SRC_CLKX: + if (cpu_class_is_omap1()) + break; omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKX); break; case OMAP_MCBSP_FSR_SRC_FSR: + if (cpu_class_is_omap1()) + break; omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSR); break; case OMAP_MCBSP_FSR_SRC_FSX: + if (cpu_class_is_omap1()) + break; omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSX); break; default: diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index dbd9d96b5f92..4ee33ce2cb98 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -306,6 +306,7 @@ static int __init omap3pandora_soc_init(void) pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n", dev_name(&omap3pandora_snd_device->dev), PTR_ERR(omap3pandora_dac_reg)); + ret = PTR_ERR(omap3pandora_dac_reg); goto fail3; } diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index f0e662556428..65ae00e976ef 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -177,7 +177,8 @@ static int __init osk_soc_init(void) tlv320aic23_mclk = clk_get(dev, "mclk"); if (IS_ERR(tlv320aic23_mclk)) { printk(KERN_ERR "Could not get mclk clock\n"); - return -ENODEV; + err = PTR_ERR(tlv320aic23_mclk); + goto err2; } /* @@ -188,7 +189,7 @@ static int __init osk_soc_init(void) if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) { printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n"); err = -ECANCELED; - goto err1; + goto err3; } } @@ -196,9 +197,12 @@ static int __init osk_soc_init(void) (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK); return 0; -err1: + +err3: clk_put(tlv320aic23_mclk); +err2: platform_device_del(osk_snd_device); +err1: platform_device_put(osk_snd_device); return err; @@ -207,6 +211,7 @@ err1: static void __exit osk_soc_exit(void) { + clk_put(tlv320aic23_mclk); platform_device_unregister(osk_snd_device); } diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 37f191bbfdd9..580f48571303 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -1,6 +1,7 @@ config SND_PXA2XX_SOC tristate "SoC Audio for the Intel PXA2xx chip" depends on ARCH_PXA + select SND_ARM select SND_PXA2XX_LIB help Say Y or M if you want to add support for codecs attached to diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 97e9423615c9..f451acd4935b 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -100,8 +100,13 @@ static int corgi_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; + mutex_lock(&codec->mutex); + /* check the jack status at stream startup */ corgi_ext_control(codec); + + mutex_unlock(&codec->mutex); + return 0; } diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index b8207ced4072..5ef0526924b9 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -72,9 +72,13 @@ static int magician_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; + mutex_lock(&codec->mutex); + /* check the jack status at stream startup */ magician_ext_control(codec); + mutex_unlock(&codec->mutex); + return 0; } diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index af84ee9c5e11..84edd0385a21 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -77,8 +77,13 @@ static int poodle_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; + mutex_lock(&codec->mutex); + /* check the jack status at stream startup */ poodle_ext_control(codec); + + mutex_unlock(&codec->mutex); + return 0; } diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index f470f360f4dd..0b30d7de24ec 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -108,8 +108,13 @@ static int spitz_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; + mutex_lock(&codec->mutex); + /* check the jack status at stream startup */ spitz_ext_control(codec); + + mutex_unlock(&codec->mutex); + return 0; } diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 73d0edd8ded9..7b983f935454 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -81,8 +81,13 @@ static int tosa_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; + mutex_lock(&codec->mutex); + /* check the jack status at stream startup */ tosa_ext_control(codec); + + mutex_unlock(&codec->mutex); + return 0; } diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 8a6b53ccd203..d85bf8a0abb2 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -2,6 +2,7 @@ config SND_S3C24XX_SOC tristate "SoC Audio for the Samsung S3CXXXX chips" depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 select S3C64XX_DMA if ARCH_S3C64XX + select S3C2410_DMA if ARCH_S3C2410 help Say Y or M if you want to add support for codecs attached to the S3C24XX AC97 or I2S interfaces. You will also need to diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/s3c24xx/rx1950_uda1380.c index ffd5cf2fb0a9..468cc11fdf47 100644 --- a/sound/soc/s3c24xx/rx1950_uda1380.c +++ b/sound/soc/s3c24xx/rx1950_uda1380.c @@ -50,7 +50,6 @@ static unsigned int rates[] = { 16000, 44100, 48000, - 88200, }; static struct snd_pcm_hw_constraint_list hw_rates = { @@ -130,7 +129,6 @@ static const struct snd_soc_dapm_route audio_map[] = { }; static struct platform_device *s3c24xx_snd_device; -static struct clk *xtal; static int rx1950_startup(struct snd_pcm_substream *substream) { @@ -179,10 +177,8 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream, case 44100: case 88200: clk_source = S3C24XX_CLKSRC_MPLL; - fs_mode = S3C2410_IISMOD_256FS; - div = clk_get_rate(xtal) / (256 * rate); - if (clk_get_rate(xtal) % (256 * rate) > (128 * rate)) - div++; + fs_mode = S3C2410_IISMOD_384FS; + div = 1; break; default: printk(KERN_ERR "%s: rate %d is not supported\n", @@ -210,7 +206,7 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream, /* set MCLK division for sample rate */ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, - S3C2410_IISMOD_384FS); + fs_mode); if (ret < 0) return ret; @@ -295,17 +291,8 @@ static int __init rx1950_init(void) goto err_plat_add; } - xtal = clk_get(&s3c24xx_snd_device->dev, "xtal"); - - if (IS_ERR(xtal)) { - ret = PTR_ERR(xtal); - platform_device_unregister(s3c24xx_snd_device); - goto err_clk; - } - return 0; -err_clk: err_plat_add: err_plat_alloc: err_gpio_conf: @@ -320,7 +307,6 @@ static void __exit rx1950_exit(void) platform_device_unregister(s3c24xx_snd_device); snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), hp_jack_gpios); - clk_put(xtal); gpio_free(S3C2410_GPA(1)); } diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/s3c24xx/smdk_spdif.c index f31d22ad7c88..c8bd90488a87 100644 --- a/sound/soc/s3c24xx/smdk_spdif.c +++ b/sound/soc/s3c24xx/smdk_spdif.c @@ -38,7 +38,7 @@ static int set_audio_clock_heirachy(struct platform_device *pdev) } mout_epll = clk_get(NULL, "mout_epll"); - if (IS_ERR(fout_epll)) { + if (IS_ERR(mout_epll)) { printk(KERN_WARNING "%s: Cannot find mout_epll.\n", __func__); ret = -EINVAL; @@ -54,7 +54,7 @@ static int set_audio_clock_heirachy(struct platform_device *pdev) } sclk_spdif = clk_get(NULL, "sclk_spdif"); - if (IS_ERR(fout_epll)) { + if (IS_ERR(sclk_spdif)) { printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n", __func__); ret = -EINVAL; diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c index 8778faa174a6..3052f64b2403 100644 --- a/sound/soc/s6000/s6000-i2s.c +++ b/sound/soc/s6000/s6000-i2s.c @@ -434,7 +434,7 @@ static struct snd_soc_dai_driver s6000_i2s_dai = { .rate_max = 1562500, }, .ops = &s6000_i2s_dai_ops, -} +}; static int __devinit s6000_i2s_probe(struct platform_device *pdev) { diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c index 271fd222bf19..ab3ccaec72d2 100644 --- a/sound/soc/s6000/s6000-pcm.c +++ b/sound/soc/s6000/s6000-pcm.c @@ -473,7 +473,7 @@ static int s6000_pcm_new(struct snd_card *card, } res = request_irq(params->irq, s6000_pcm_irq, IRQF_SHARED, - s6000_soc_platform.name, pcm); + "s6000-audio", pcm); if (res) { printk(KERN_ERR "s6000-pcm couldn't get IRQ\n"); return res; diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c index 96c05e137538..c1244c5bc730 100644 --- a/sound/soc/s6000/s6105-ipcam.c +++ b/sound/soc/s6000/s6105-ipcam.c @@ -167,7 +167,7 @@ static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_sync(codec); - snd_ctl_add(codec->snd_card, snd_ctl_new1(&audio_out_mux, codec)); + snd_ctl_add(codec->card->snd_card, snd_ctl_new1(&audio_out_mux, codec)); return 0; } diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 507e709f2807..4c2404b1b862 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -132,6 +132,8 @@ struct fsi_priv { struct fsi_stream playback; struct fsi_stream capture; + long rate; + u32 mst_ctrl; }; @@ -854,10 +856,17 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); int is_play = fsi_is_play(substream); + struct fsi_master *master = fsi_get_master(fsi); + int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); fsi_irq_disable(fsi, is_play); fsi_clk_ctrl(fsi, 0); + set_rate = master->info->set_rate; + if (set_rate && fsi->rate) + set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); + fsi->rate = 0; + pm_runtime_put_sync(dai->dev); } @@ -891,20 +900,20 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); struct fsi_master *master = fsi_get_master(fsi); - int (*set_rate)(int is_porta, int rate) = master->info->set_rate; + int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); int fsi_ver = master->core->ver; - int is_play = fsi_is_play(substream); + long rate = params_rate(params); int ret; - /* if slave mode, set_rate is not needed */ - if (!fsi_is_master_mode(fsi, is_play)) + set_rate = master->info->set_rate; + if (!set_rate) return 0; - /* it is error if no set_rate */ - if (!set_rate) - return -EIO; + ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1); + if (ret < 0) /* error */ + return ret; - ret = set_rate(fsi_is_port_a(fsi), params_rate(params)); + fsi->rate = rate; if (ret > 0) { u32 data = 0; diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 40bbdf1591dc..05192d97b377 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -387,7 +387,7 @@ static int __devinit sh4_soc_dai_probe(struct platform_device *pdev) static int __devexit sh4_soc_dai_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai)); + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai)); return 0; } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 614a8b30d87b..85b7d548f167 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1619,12 +1619,14 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) #ifdef CONFIG_SND_SOC_AC97_BUS /* register any AC97 codecs */ for (i = 0; i < card->num_rtd; i++) { - ret = soc_register_ac97_dai_link(&card->rtd[i]); - if (ret < 0) { - printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name); - goto probe_dai_err; - } + ret = soc_register_ac97_dai_link(&card->rtd[i]); + if (ret < 0) { + printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name); + while (--i >= 0) + soc_unregister_ac97_dai_link(&card->rtd[i]); + goto probe_dai_err; } + } #endif card->instantiated = 1; @@ -3043,8 +3045,10 @@ int snd_soc_register_dais(struct device *dev, for (i = 0; i < count; i++) { dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); - if (dai == NULL) - return -ENOMEM; + if (dai == NULL) { + ret = -ENOMEM; + goto err; + } /* create DAI component name */ dai->name = fmt_multiple_name(dev, &dai_drv[i]); @@ -3070,7 +3074,9 @@ int snd_soc_register_dais(struct device *dev, pr_debug("Registered DAI '%s'\n", dai->name); } + mutex_lock(&client_mutex); snd_soc_instantiate_cards(); + mutex_unlock(&client_mutex); return 0; err: @@ -3263,9 +3269,6 @@ int snd_soc_register_codec(struct device *dev, return 0; error: - for (i--; i >= 0; i--) - snd_soc_unregister_dai(dev); - if (codec->reg_cache) kfree(codec->reg_cache); kfree(codec->name); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7d85c6496afa..c721502833bc 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -683,12 +683,12 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, struct snd_soc_dapm_widget *b, int sort[]) { - if (a->codec != b->codec) - return (unsigned long)a - (unsigned long)b; if (sort[a->id] != sort[b->id]) return sort[a->id] - sort[b->id]; if (a->reg != b->reg) return a->reg - b->reg; + if (a->codec != b->codec) + return (unsigned long)a->codec - (unsigned long)b->codec; return 0; } @@ -944,6 +944,9 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) case SND_SOC_DAPM_STREAM_RESUME: sys_power = 1; break; + case SND_SOC_DAPM_STREAM_STOP: + sys_power = !!codec->active; + break; case SND_SOC_DAPM_STREAM_SUSPEND: sys_power = 0; break; diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 1bc56b2b94e2..337a00241a1f 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -155,7 +155,7 @@ static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip) if (max_tries < 1) max_tries = 1; - /* ssc_div must be a power of 2. */ + /* ssc_div must be even. */ ssc_div = (ssc_div + 1) & ~1UL; if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) { diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 93bd2ff001fb..564491fa18b2 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -197,7 +197,7 @@ static void sig_atexit(void) if (child_pid > 0) kill(child_pid, SIGTERM); - if (signr == -1) + if (signr == -1 || signr == SIGUSR1) return; signal(signr, SIG_DFL); @@ -515,6 +515,7 @@ static int __cmd_record(int argc, const char **argv) atexit(sig_atexit); signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); + signal(SIGUSR1, sig_handler); if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { perror("failed to create pipes"); @@ -606,6 +607,7 @@ static int __cmd_record(int argc, const char **argv) execvp(argv[0], (char **)argv); perror(argv[0]); + kill(getppid(), SIGUSR1); exit(-1); } @@ -697,17 +699,18 @@ static int __cmd_record(int argc, const char **argv) if (err < 0) err = event__synthesize_kernel_mmap(process_synthesized_event, session, machine, "_stext"); - if (err < 0) { - pr_err("Couldn't record kernel reference relocation symbol.\n"); - return err; - } + if (err < 0) + pr_err("Couldn't record kernel reference relocation symbol\n" + "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" + "Check /proc/kallsyms permission or run as root.\n"); err = event__synthesize_modules(process_synthesized_event, session, machine); - if (err < 0) { - pr_err("Couldn't record kernel reference relocation symbol.\n"); - return err; - } + if (err < 0) + pr_err("Couldn't record kernel module information.\n" + "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" + "Check /proc/modules permission or run as root.\n"); + if (perf_guest) perf_session__process_machines(session, event__synthesize_guest_os); @@ -761,7 +764,7 @@ static int __cmd_record(int argc, const char **argv) } } - if (quiet) + if (quiet || signr == SIGUSR1) return 0; fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index d7e67b167ea3..64a85bafde63 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -946,11 +946,16 @@ perf_header__find_attr(u64 id, struct perf_header *header) /* * We set id to -1 if the data file doesn't contain sample - * ids. Check for this and avoid walking through the entire - * list of ids which may be large. + * ids. This can happen when the data file contains one type + * of event and in that case, the header can still store the + * event attribute information. Check for this and avoid + * walking through the entire list of ids which may be large. */ - if (id == -1ULL) + if (id == -1ULL) { + if (header->attrs > 0) + return &header->attr[0]->attr; return NULL; + } for (i = 0; i < header->attrs; i++) { struct perf_header_attr *attr = header->attr[i]; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b39f499e575a..d628c8d1cf5e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -295,7 +295,9 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) { struct rb_node **p = &self->rb_node; struct rb_node *parent = NULL; - struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; + struct symbol_name_rb_node *symn, *s; + + symn = container_of(sym, struct symbol_name_rb_node, sym); while (*p != NULL) { parent = *p; @@ -530,7 +532,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct machine *machine = kmaps->machine; struct map *curr_map = map; struct symbol *pos; - int count = 0; + int count = 0, moved = 0; struct rb_root *root = &self->symbols[map->type]; struct rb_node *next = rb_first(root); int kernel_range = 0; @@ -588,6 +590,11 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, char dso_name[PATH_MAX]; struct dso *dso; + if (count == 0) { + curr_map = map; + goto filter_symbol; + } + if (self->kernel == DSO_TYPE_GUEST_KERNEL) snprintf(dso_name, sizeof(dso_name), "[guest.kernel].%d", @@ -613,7 +620,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, map_groups__insert(kmaps, curr_map); ++kernel_range; } - +filter_symbol: if (filter && filter(curr_map, pos)) { discard_symbol: rb_erase(&pos->rb_node, root); symbol__delete(pos); @@ -621,8 +628,9 @@ discard_symbol: rb_erase(&pos->rb_node, root); if (curr_map != map) { rb_erase(&pos->rb_node, root); symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); - } - count++; + ++moved; + } else + ++count; } } @@ -632,7 +640,7 @@ discard_symbol: rb_erase(&pos->rb_node, root); dso__set_loaded(curr_map->dso, curr_map->type); } - return count; + return count + moved; } int dso__load_kallsyms(struct dso *self, const char *filename, @@ -2123,14 +2131,55 @@ static struct dso *machine__create_kernel(struct machine *self) return kernel; } +struct process_args { + u64 start; +}; + +static int symbol__in_kernel(void *arg, const char *name, + char type __used, u64 start) +{ + struct process_args *args = arg; + + if (strchr(name, '[')) + return 0; + + args->start = start; + return 1; +} + +/* Figure out the start address of kernel map from /proc/kallsyms */ +static u64 machine__get_kernel_start_addr(struct machine *machine) +{ + const char *filename; + char path[PATH_MAX]; + struct process_args args; + + if (machine__is_host(machine)) { + filename = "/proc/kallsyms"; + } else { + if (machine__is_default_guest(machine)) + filename = (char *)symbol_conf.default_guest_kallsyms; + else { + sprintf(path, "%s/proc/kallsyms", machine->root_dir); + filename = path; + } + } + + if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) + return 0; + + return args.start; +} + int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) { enum map_type type; + u64 start = machine__get_kernel_start_addr(self); for (type = 0; type < MAP__NR_TYPES; ++type) { struct kmap *kmap; - self->vmlinux_maps[type] = map__new2(0, kernel, type); + self->vmlinux_maps[type] = map__new2(start, kernel, type); if (self->vmlinux_maps[type] == NULL) return -1; diff --git a/usr/initramfs_data.S b/usr/initramfs_data.S index 792a750d9441..c14322d1c0cf 100644 --- a/usr/initramfs_data.S +++ b/usr/initramfs_data.S @@ -22,14 +22,15 @@ */ #include <linux/stringify.h> +#include <asm-generic/vmlinux.lds.h> .section .init.ramfs,"a" __irf_start: .incbin __stringify(INITRAMFS_IMAGE) __irf_end: .section .init.ramfs.info,"a" -.globl __initramfs_size -__initramfs_size: +.globl VMLINUX_SYMBOL(__initramfs_size) +VMLINUX_SYMBOL(__initramfs_size): #ifdef CONFIG_64BIT .quad __irf_end - __irf_start #else |