Merge branch 'tracing/ftrace'; commit 'v2.6.29-rc6' into tracing/core
This commit is contained in:
commit
a7f4463e03
126 changed files with 3467 additions and 1057 deletions
|
@ -6,7 +6,7 @@
|
|||
# To add a new book the only step required is to add the book to the
|
||||
# list of DOCBOOKS.
|
||||
|
||||
DOCBOOKS := z8530book.xml mcabook.xml \
|
||||
DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
|
||||
kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
|
||||
procfs-guide.xml writing_usb_driver.xml networking.xml \
|
||||
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
|
||||
|
|
418
Documentation/DocBook/device-drivers.tmpl
Normal file
418
Documentation/DocBook/device-drivers.tmpl
Normal file
|
@ -0,0 +1,418 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
|
||||
|
||||
<book id="LinuxDriversAPI">
|
||||
<bookinfo>
|
||||
<title>Linux Device Drivers</title>
|
||||
|
||||
<legalnotice>
|
||||
<para>
|
||||
This documentation is free software; you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For more details see the file COPYING in the source
|
||||
distribution of Linux.
|
||||
</para>
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
<toc></toc>
|
||||
|
||||
<chapter id="Basics">
|
||||
<title>Driver Basics</title>
|
||||
<sect1><title>Driver Entry and Exit points</title>
|
||||
!Iinclude/linux/init.h
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Atomic and pointer manipulation</title>
|
||||
!Iarch/x86/include/asm/atomic_32.h
|
||||
!Iarch/x86/include/asm/unaligned.h
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Delaying, scheduling, and timer routines</title>
|
||||
!Iinclude/linux/sched.h
|
||||
!Ekernel/sched.c
|
||||
!Ekernel/timer.c
|
||||
</sect1>
|
||||
<sect1><title>High-resolution timers</title>
|
||||
!Iinclude/linux/ktime.h
|
||||
!Iinclude/linux/hrtimer.h
|
||||
!Ekernel/hrtimer.c
|
||||
</sect1>
|
||||
<sect1><title>Workqueues and Kevents</title>
|
||||
!Ekernel/workqueue.c
|
||||
</sect1>
|
||||
<sect1><title>Internal Functions</title>
|
||||
!Ikernel/exit.c
|
||||
!Ikernel/signal.c
|
||||
!Iinclude/linux/kthread.h
|
||||
!Ekernel/kthread.c
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Kernel objects manipulation</title>
|
||||
<!--
|
||||
X!Iinclude/linux/kobject.h
|
||||
-->
|
||||
!Elib/kobject.c
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Kernel utility functions</title>
|
||||
!Iinclude/linux/kernel.h
|
||||
!Ekernel/printk.c
|
||||
!Ekernel/panic.c
|
||||
!Ekernel/sys.c
|
||||
!Ekernel/rcupdate.c
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Device Resource Management</title>
|
||||
!Edrivers/base/devres.c
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
||||
<chapter id="devdrivers">
|
||||
<title>Device drivers infrastructure</title>
|
||||
<sect1><title>Device Drivers Base</title>
|
||||
<!--
|
||||
X!Iinclude/linux/device.h
|
||||
-->
|
||||
!Edrivers/base/driver.c
|
||||
!Edrivers/base/core.c
|
||||
!Edrivers/base/class.c
|
||||
!Edrivers/base/firmware_class.c
|
||||
!Edrivers/base/transport_class.c
|
||||
<!-- Cannot be included, because
|
||||
attribute_container_add_class_device_adapter
|
||||
and attribute_container_classdev_to_container
|
||||
exceed allowed 44 characters maximum
|
||||
X!Edrivers/base/attribute_container.c
|
||||
-->
|
||||
!Edrivers/base/sys.c
|
||||
<!--
|
||||
X!Edrivers/base/interface.c
|
||||
-->
|
||||
!Edrivers/base/platform.c
|
||||
!Edrivers/base/bus.c
|
||||
</sect1>
|
||||
<sect1><title>Device Drivers Power Management</title>
|
||||
!Edrivers/base/power/main.c
|
||||
</sect1>
|
||||
<sect1><title>Device Drivers ACPI Support</title>
|
||||
<!-- Internal functions only
|
||||
X!Edrivers/acpi/sleep/main.c
|
||||
X!Edrivers/acpi/sleep/wakeup.c
|
||||
X!Edrivers/acpi/motherboard.c
|
||||
X!Edrivers/acpi/bus.c
|
||||
-->
|
||||
!Edrivers/acpi/scan.c
|
||||
!Idrivers/acpi/scan.c
|
||||
<!-- No correct structured comments
|
||||
X!Edrivers/acpi/pci_bind.c
|
||||
-->
|
||||
</sect1>
|
||||
<sect1><title>Device drivers PnP support</title>
|
||||
!Idrivers/pnp/core.c
|
||||
<!-- No correct structured comments
|
||||
X!Edrivers/pnp/system.c
|
||||
-->
|
||||
!Edrivers/pnp/card.c
|
||||
!Idrivers/pnp/driver.c
|
||||
!Edrivers/pnp/manager.c
|
||||
!Edrivers/pnp/support.c
|
||||
</sect1>
|
||||
<sect1><title>Userspace IO devices</title>
|
||||
!Edrivers/uio/uio.c
|
||||
!Iinclude/linux/uio_driver.h
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter id="parportdev">
|
||||
<title>Parallel Port Devices</title>
|
||||
!Iinclude/linux/parport.h
|
||||
!Edrivers/parport/ieee1284.c
|
||||
!Edrivers/parport/share.c
|
||||
!Idrivers/parport/daisy.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="message_devices">
|
||||
<title>Message-based devices</title>
|
||||
<sect1><title>Fusion message devices</title>
|
||||
!Edrivers/message/fusion/mptbase.c
|
||||
!Idrivers/message/fusion/mptbase.c
|
||||
!Edrivers/message/fusion/mptscsih.c
|
||||
!Idrivers/message/fusion/mptscsih.c
|
||||
!Idrivers/message/fusion/mptctl.c
|
||||
!Idrivers/message/fusion/mptspi.c
|
||||
!Idrivers/message/fusion/mptfc.c
|
||||
!Idrivers/message/fusion/mptlan.c
|
||||
</sect1>
|
||||
<sect1><title>I2O message devices</title>
|
||||
!Iinclude/linux/i2o.h
|
||||
!Idrivers/message/i2o/core.h
|
||||
!Edrivers/message/i2o/iop.c
|
||||
!Idrivers/message/i2o/iop.c
|
||||
!Idrivers/message/i2o/config-osm.c
|
||||
!Edrivers/message/i2o/exec-osm.c
|
||||
!Idrivers/message/i2o/exec-osm.c
|
||||
!Idrivers/message/i2o/bus-osm.c
|
||||
!Edrivers/message/i2o/device.c
|
||||
!Idrivers/message/i2o/device.c
|
||||
!Idrivers/message/i2o/driver.c
|
||||
!Idrivers/message/i2o/pci.c
|
||||
!Idrivers/message/i2o/i2o_block.c
|
||||
!Idrivers/message/i2o/i2o_scsi.c
|
||||
!Idrivers/message/i2o/i2o_proc.c
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter id="snddev">
|
||||
<title>Sound Devices</title>
|
||||
!Iinclude/sound/core.h
|
||||
!Esound/sound_core.c
|
||||
!Iinclude/sound/pcm.h
|
||||
!Esound/core/pcm.c
|
||||
!Esound/core/device.c
|
||||
!Esound/core/info.c
|
||||
!Esound/core/rawmidi.c
|
||||
!Esound/core/sound.c
|
||||
!Esound/core/memory.c
|
||||
!Esound/core/pcm_memory.c
|
||||
!Esound/core/init.c
|
||||
!Esound/core/isadma.c
|
||||
!Esound/core/control.c
|
||||
!Esound/core/pcm_lib.c
|
||||
!Esound/core/hwdep.c
|
||||
!Esound/core/pcm_native.c
|
||||
!Esound/core/memalloc.c
|
||||
<!-- FIXME: Removed for now since no structured comments in source
|
||||
X!Isound/sound_firmware.c
|
||||
-->
|
||||
</chapter>
|
||||
|
||||
<chapter id="uart16x50">
|
||||
<title>16x50 UART Driver</title>
|
||||
!Iinclude/linux/serial_core.h
|
||||
!Edrivers/serial/serial_core.c
|
||||
!Edrivers/serial/8250.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="fbdev">
|
||||
<title>Frame Buffer Library</title>
|
||||
|
||||
<para>
|
||||
The frame buffer drivers depend heavily on four data structures.
|
||||
These structures are declared in include/linux/fb.h. They are
|
||||
fb_info, fb_var_screeninfo, fb_fix_screeninfo and fb_monospecs.
|
||||
The last three can be made available to and from userland.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
fb_info defines the current state of a particular video card.
|
||||
Inside fb_info, there exists a fb_ops structure which is a
|
||||
collection of needed functions to make fbdev and fbcon work.
|
||||
fb_info is only visible to the kernel.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
fb_var_screeninfo is used to describe the features of a video card
|
||||
that are user defined. With fb_var_screeninfo, things such as
|
||||
depth and the resolution may be defined.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The next structure is fb_fix_screeninfo. This defines the
|
||||
properties of a card that are created when a mode is set and can't
|
||||
be changed otherwise. A good example of this is the start of the
|
||||
frame buffer memory. This "locks" the address of the frame buffer
|
||||
memory, so that it cannot be changed or moved.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The last structure is fb_monospecs. In the old API, there was
|
||||
little importance for fb_monospecs. This allowed for forbidden things
|
||||
such as setting a mode of 800x600 on a fix frequency monitor. With
|
||||
the new API, fb_monospecs prevents such things, and if used
|
||||
correctly, can prevent a monitor from being cooked. fb_monospecs
|
||||
will not be useful until kernels 2.5.x.
|
||||
</para>
|
||||
|
||||
<sect1><title>Frame Buffer Memory</title>
|
||||
!Edrivers/video/fbmem.c
|
||||
</sect1>
|
||||
<!--
|
||||
<sect1><title>Frame Buffer Console</title>
|
||||
X!Edrivers/video/console/fbcon.c
|
||||
</sect1>
|
||||
-->
|
||||
<sect1><title>Frame Buffer Colormap</title>
|
||||
!Edrivers/video/fbcmap.c
|
||||
</sect1>
|
||||
<!-- FIXME:
|
||||
drivers/video/fbgen.c has no docs, which stuffs up the sgml. Comment
|
||||
out until somebody adds docs. KAO
|
||||
<sect1><title>Frame Buffer Generic Functions</title>
|
||||
X!Idrivers/video/fbgen.c
|
||||
</sect1>
|
||||
KAO -->
|
||||
<sect1><title>Frame Buffer Video Mode Database</title>
|
||||
!Idrivers/video/modedb.c
|
||||
!Edrivers/video/modedb.c
|
||||
</sect1>
|
||||
<sect1><title>Frame Buffer Macintosh Video Mode Database</title>
|
||||
!Edrivers/video/macmodes.c
|
||||
</sect1>
|
||||
<sect1><title>Frame Buffer Fonts</title>
|
||||
<para>
|
||||
Refer to the file drivers/video/console/fonts.c for more information.
|
||||
</para>
|
||||
<!-- FIXME: Removed for now since no structured comments in source
|
||||
X!Idrivers/video/console/fonts.c
|
||||
-->
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter id="input_subsystem">
|
||||
<title>Input Subsystem</title>
|
||||
!Iinclude/linux/input.h
|
||||
!Edrivers/input/input.c
|
||||
!Edrivers/input/ff-core.c
|
||||
!Edrivers/input/ff-memless.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="spi">
|
||||
<title>Serial Peripheral Interface (SPI)</title>
|
||||
<para>
|
||||
SPI is the "Serial Peripheral Interface", widely used with
|
||||
embedded systems because it is a simple and efficient
|
||||
interface: basically a multiplexed shift register.
|
||||
Its three signal wires hold a clock (SCK, often in the range
|
||||
of 1-20 MHz), a "Master Out, Slave In" (MOSI) data line, and
|
||||
a "Master In, Slave Out" (MISO) data line.
|
||||
SPI is a full duplex protocol; for each bit shifted out the
|
||||
MOSI line (one per clock) another is shifted in on the MISO line.
|
||||
Those bits are assembled into words of various sizes on the
|
||||
way to and from system memory.
|
||||
An additional chipselect line is usually active-low (nCS);
|
||||
four signals are normally used for each peripheral, plus
|
||||
sometimes an interrupt.
|
||||
</para>
|
||||
<para>
|
||||
The SPI bus facilities listed here provide a generalized
|
||||
interface to declare SPI busses and devices, manage them
|
||||
according to the standard Linux driver model, and perform
|
||||
input/output operations.
|
||||
At this time, only "master" side interfaces are supported,
|
||||
where Linux talks to SPI peripherals and does not implement
|
||||
such a peripheral itself.
|
||||
(Interfaces to support implementing SPI slaves would
|
||||
necessarily look different.)
|
||||
</para>
|
||||
<para>
|
||||
The programming interface is structured around two kinds of driver,
|
||||
and two kinds of device.
|
||||
A "Controller Driver" abstracts the controller hardware, which may
|
||||
be as simple as a set of GPIO pins or as complex as a pair of FIFOs
|
||||
connected to dual DMA engines on the other side of the SPI shift
|
||||
register (maximizing throughput). Such drivers bridge between
|
||||
whatever bus they sit on (often the platform bus) and SPI, and
|
||||
expose the SPI side of their device as a
|
||||
<structname>struct spi_master</structname>.
|
||||
SPI devices are children of that master, represented as a
|
||||
<structname>struct spi_device</structname> and manufactured from
|
||||
<structname>struct spi_board_info</structname> descriptors which
|
||||
are usually provided by board-specific initialization code.
|
||||
A <structname>struct spi_driver</structname> is called a
|
||||
"Protocol Driver", and is bound to a spi_device using normal
|
||||
driver model calls.
|
||||
</para>
|
||||
<para>
|
||||
The I/O model is a set of queued messages. Protocol drivers
|
||||
submit one or more <structname>struct spi_message</structname>
|
||||
objects, which are processed and completed asynchronously.
|
||||
(There are synchronous wrappers, however.) Messages are
|
||||
built from one or more <structname>struct spi_transfer</structname>
|
||||
objects, each of which wraps a full duplex SPI transfer.
|
||||
A variety of protocol tweaking options are needed, because
|
||||
different chips adopt very different policies for how they
|
||||
use the bits transferred with SPI.
|
||||
</para>
|
||||
!Iinclude/linux/spi/spi.h
|
||||
!Fdrivers/spi/spi.c spi_register_board_info
|
||||
!Edrivers/spi/spi.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="i2c">
|
||||
<title>I<superscript>2</superscript>C and SMBus Subsystem</title>
|
||||
|
||||
<para>
|
||||
I<superscript>2</superscript>C (or without fancy typography, "I2C")
|
||||
is an acronym for the "Inter-IC" bus, a simple bus protocol which is
|
||||
widely used where low data rate communications suffice.
|
||||
Since it's also a licensed trademark, some vendors use another
|
||||
name (such as "Two-Wire Interface", TWI) for the same bus.
|
||||
I2C only needs two signals (SCL for clock, SDA for data), conserving
|
||||
board real estate and minimizing signal quality issues.
|
||||
Most I2C devices use seven bit addresses, and bus speeds of up
|
||||
to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet
|
||||
found wide use.
|
||||
I2C is a multi-master bus; open drain signaling is used to
|
||||
arbitrate between masters, as well as to handshake and to
|
||||
synchronize clocks from slower clients.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The Linux I2C programming interfaces support only the master
|
||||
side of bus interactions, not the slave side.
|
||||
The programming interface is structured around two kinds of driver,
|
||||
and two kinds of device.
|
||||
An I2C "Adapter Driver" abstracts the controller hardware; it binds
|
||||
to a physical device (perhaps a PCI device or platform_device) and
|
||||
exposes a <structname>struct i2c_adapter</structname> representing
|
||||
each I2C bus segment it manages.
|
||||
On each I2C bus segment will be I2C devices represented by a
|
||||
<structname>struct i2c_client</structname>. Those devices will
|
||||
be bound to a <structname>struct i2c_driver</structname>,
|
||||
which should follow the standard Linux driver model.
|
||||
(At this writing, a legacy model is more widely used.)
|
||||
There are functions to perform various I2C protocol operations; at
|
||||
this writing all such functions are usable only from task context.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The System Management Bus (SMBus) is a sibling protocol. Most SMBus
|
||||
systems are also I2C conformant. The electrical constraints are
|
||||
tighter for SMBus, and it standardizes particular protocol messages
|
||||
and idioms. Controllers that support I2C can also support most
|
||||
SMBus operations, but SMBus controllers don't support all the protocol
|
||||
options that an I2C controller will.
|
||||
There are functions to perform various SMBus protocol operations,
|
||||
either using I2C primitives or by issuing SMBus commands to
|
||||
i2c_adapter devices which don't support those I2C operations.
|
||||
</para>
|
||||
|
||||
!Iinclude/linux/i2c.h
|
||||
!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info
|
||||
!Edrivers/i2c/i2c-core.c
|
||||
</chapter>
|
||||
|
||||
</book>
|
|
@ -38,58 +38,6 @@
|
|||
|
||||
<toc></toc>
|
||||
|
||||
<chapter id="Basics">
|
||||
<title>Driver Basics</title>
|
||||
<sect1><title>Driver Entry and Exit points</title>
|
||||
!Iinclude/linux/init.h
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Atomic and pointer manipulation</title>
|
||||
!Iarch/x86/include/asm/atomic_32.h
|
||||
!Iarch/x86/include/asm/unaligned.h
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Delaying, scheduling, and timer routines</title>
|
||||
!Iinclude/linux/sched.h
|
||||
!Ekernel/sched.c
|
||||
!Ekernel/timer.c
|
||||
</sect1>
|
||||
<sect1><title>High-resolution timers</title>
|
||||
!Iinclude/linux/ktime.h
|
||||
!Iinclude/linux/hrtimer.h
|
||||
!Ekernel/hrtimer.c
|
||||
</sect1>
|
||||
<sect1><title>Workqueues and Kevents</title>
|
||||
!Ekernel/workqueue.c
|
||||
</sect1>
|
||||
<sect1><title>Internal Functions</title>
|
||||
!Ikernel/exit.c
|
||||
!Ikernel/signal.c
|
||||
!Iinclude/linux/kthread.h
|
||||
!Ekernel/kthread.c
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Kernel objects manipulation</title>
|
||||
<!--
|
||||
X!Iinclude/linux/kobject.h
|
||||
-->
|
||||
!Elib/kobject.c
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Kernel utility functions</title>
|
||||
!Iinclude/linux/kernel.h
|
||||
!Ekernel/printk.c
|
||||
!Ekernel/panic.c
|
||||
!Ekernel/sys.c
|
||||
!Ekernel/rcupdate.c
|
||||
</sect1>
|
||||
|
||||
<sect1><title>Device Resource Management</title>
|
||||
!Edrivers/base/devres.c
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
||||
<chapter id="adt">
|
||||
<title>Data Types</title>
|
||||
<sect1><title>Doubly Linked Lists</title>
|
||||
|
@ -298,62 +246,6 @@ X!Earch/x86/kernel/mca_32.c
|
|||
!Ikernel/acct.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="devdrivers">
|
||||
<title>Device drivers infrastructure</title>
|
||||
<sect1><title>Device Drivers Base</title>
|
||||
<!--
|
||||
X!Iinclude/linux/device.h
|
||||
-->
|
||||
!Edrivers/base/driver.c
|
||||
!Edrivers/base/core.c
|
||||
!Edrivers/base/class.c
|
||||
!Edrivers/base/firmware_class.c
|
||||
!Edrivers/base/transport_class.c
|
||||
<!-- Cannot be included, because
|
||||
attribute_container_add_class_device_adapter
|
||||
and attribute_container_classdev_to_container
|
||||
exceed allowed 44 characters maximum
|
||||
X!Edrivers/base/attribute_container.c
|
||||
-->
|
||||
!Edrivers/base/sys.c
|
||||
<!--
|
||||
X!Edrivers/base/interface.c
|
||||
-->
|
||||
!Edrivers/base/platform.c
|
||||
!Edrivers/base/bus.c
|
||||
</sect1>
|
||||
<sect1><title>Device Drivers Power Management</title>
|
||||
!Edrivers/base/power/main.c
|
||||
</sect1>
|
||||
<sect1><title>Device Drivers ACPI Support</title>
|
||||
<!-- Internal functions only
|
||||
X!Edrivers/acpi/sleep/main.c
|
||||
X!Edrivers/acpi/sleep/wakeup.c
|
||||
X!Edrivers/acpi/motherboard.c
|
||||
X!Edrivers/acpi/bus.c
|
||||
-->
|
||||
!Edrivers/acpi/scan.c
|
||||
!Idrivers/acpi/scan.c
|
||||
<!-- No correct structured comments
|
||||
X!Edrivers/acpi/pci_bind.c
|
||||
-->
|
||||
</sect1>
|
||||
<sect1><title>Device drivers PnP support</title>
|
||||
!Idrivers/pnp/core.c
|
||||
<!-- No correct structured comments
|
||||
X!Edrivers/pnp/system.c
|
||||
-->
|
||||
!Edrivers/pnp/card.c
|
||||
!Idrivers/pnp/driver.c
|
||||
!Edrivers/pnp/manager.c
|
||||
!Edrivers/pnp/support.c
|
||||
</sect1>
|
||||
<sect1><title>Userspace IO devices</title>
|
||||
!Edrivers/uio/uio.c
|
||||
!Iinclude/linux/uio_driver.h
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter id="blkdev">
|
||||
<title>Block Devices</title>
|
||||
!Eblock/blk-core.c
|
||||
|
@ -381,275 +273,6 @@ X!Edrivers/pnp/system.c
|
|||
!Edrivers/char/misc.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="parportdev">
|
||||
<title>Parallel Port Devices</title>
|
||||
!Iinclude/linux/parport.h
|
||||
!Edrivers/parport/ieee1284.c
|
||||
!Edrivers/parport/share.c
|
||||
!Idrivers/parport/daisy.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="message_devices">
|
||||
<title>Message-based devices</title>
|
||||
<sect1><title>Fusion message devices</title>
|
||||
!Edrivers/message/fusion/mptbase.c
|
||||
!Idrivers/message/fusion/mptbase.c
|
||||
!Edrivers/message/fusion/mptscsih.c
|
||||
!Idrivers/message/fusion/mptscsih.c
|
||||
!Idrivers/message/fusion/mptctl.c
|
||||
!Idrivers/message/fusion/mptspi.c
|
||||
!Idrivers/message/fusion/mptfc.c
|
||||
!Idrivers/message/fusion/mptlan.c
|
||||
</sect1>
|
||||
<sect1><title>I2O message devices</title>
|
||||
!Iinclude/linux/i2o.h
|
||||
!Idrivers/message/i2o/core.h
|
||||
!Edrivers/message/i2o/iop.c
|
||||
!Idrivers/message/i2o/iop.c
|
||||
!Idrivers/message/i2o/config-osm.c
|
||||
!Edrivers/message/i2o/exec-osm.c
|
||||
!Idrivers/message/i2o/exec-osm.c
|
||||
!Idrivers/message/i2o/bus-osm.c
|
||||
!Edrivers/message/i2o/device.c
|
||||
!Idrivers/message/i2o/device.c
|
||||
!Idrivers/message/i2o/driver.c
|
||||
!Idrivers/message/i2o/pci.c
|
||||
!Idrivers/message/i2o/i2o_block.c
|
||||
!Idrivers/message/i2o/i2o_scsi.c
|
||||
!Idrivers/message/i2o/i2o_proc.c
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter id="snddev">
|
||||
<title>Sound Devices</title>
|
||||
!Iinclude/sound/core.h
|
||||
!Esound/sound_core.c
|
||||
!Iinclude/sound/pcm.h
|
||||
!Esound/core/pcm.c
|
||||
!Esound/core/device.c
|
||||
!Esound/core/info.c
|
||||
!Esound/core/rawmidi.c
|
||||
!Esound/core/sound.c
|
||||
!Esound/core/memory.c
|
||||
!Esound/core/pcm_memory.c
|
||||
!Esound/core/init.c
|
||||
!Esound/core/isadma.c
|
||||
!Esound/core/control.c
|
||||
!Esound/core/pcm_lib.c
|
||||
!Esound/core/hwdep.c
|
||||
!Esound/core/pcm_native.c
|
||||
!Esound/core/memalloc.c
|
||||
<!-- FIXME: Removed for now since no structured comments in source
|
||||
X!Isound/sound_firmware.c
|
||||
-->
|
||||
</chapter>
|
||||
|
||||
<chapter id="uart16x50">
|
||||
<title>16x50 UART Driver</title>
|
||||
!Iinclude/linux/serial_core.h
|
||||
!Edrivers/serial/serial_core.c
|
||||
!Edrivers/serial/8250.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="fbdev">
|
||||
<title>Frame Buffer Library</title>
|
||||
|
||||
<para>
|
||||
The frame buffer drivers depend heavily on four data structures.
|
||||
These structures are declared in include/linux/fb.h. They are
|
||||
fb_info, fb_var_screeninfo, fb_fix_screeninfo and fb_monospecs.
|
||||
The last three can be made available to and from userland.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
fb_info defines the current state of a particular video card.
|
||||
Inside fb_info, there exists a fb_ops structure which is a
|
||||
collection of needed functions to make fbdev and fbcon work.
|
||||
fb_info is only visible to the kernel.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
fb_var_screeninfo is used to describe the features of a video card
|
||||
that are user defined. With fb_var_screeninfo, things such as
|
||||
depth and the resolution may be defined.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The next structure is fb_fix_screeninfo. This defines the
|
||||
properties of a card that are created when a mode is set and can't
|
||||
be changed otherwise. A good example of this is the start of the
|
||||
frame buffer memory. This "locks" the address of the frame buffer
|
||||
memory, so that it cannot be changed or moved.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The last structure is fb_monospecs. In the old API, there was
|
||||
little importance for fb_monospecs. This allowed for forbidden things
|
||||
such as setting a mode of 800x600 on a fix frequency monitor. With
|
||||
the new API, fb_monospecs prevents such things, and if used
|
||||
correctly, can prevent a monitor from being cooked. fb_monospecs
|
||||
will not be useful until kernels 2.5.x.
|
||||
</para>
|
||||
|
||||
<sect1><title>Frame Buffer Memory</title>
|
||||
!Edrivers/video/fbmem.c
|
||||
</sect1>
|
||||
<!--
|
||||
<sect1><title>Frame Buffer Console</title>
|
||||
X!Edrivers/video/console/fbcon.c
|
||||
</sect1>
|
||||
-->
|
||||
<sect1><title>Frame Buffer Colormap</title>
|
||||
!Edrivers/video/fbcmap.c
|
||||
</sect1>
|
||||
<!-- FIXME:
|
||||
drivers/video/fbgen.c has no docs, which stuffs up the sgml. Comment
|
||||
out until somebody adds docs. KAO
|
||||
<sect1><title>Frame Buffer Generic Functions</title>
|
||||
X!Idrivers/video/fbgen.c
|
||||
</sect1>
|
||||
KAO -->
|
||||
<sect1><title>Frame Buffer Video Mode Database</title>
|
||||
!Idrivers/video/modedb.c
|
||||
!Edrivers/video/modedb.c
|
||||
</sect1>
|
||||
<sect1><title>Frame Buffer Macintosh Video Mode Database</title>
|
||||
!Edrivers/video/macmodes.c
|
||||
</sect1>
|
||||
<sect1><title>Frame Buffer Fonts</title>
|
||||
<para>
|
||||
Refer to the file drivers/video/console/fonts.c for more information.
|
||||
</para>
|
||||
<!-- FIXME: Removed for now since no structured comments in source
|
||||
X!Idrivers/video/console/fonts.c
|
||||
-->
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter id="input_subsystem">
|
||||
<title>Input Subsystem</title>
|
||||
!Iinclude/linux/input.h
|
||||
!Edrivers/input/input.c
|
||||
!Edrivers/input/ff-core.c
|
||||
!Edrivers/input/ff-memless.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="spi">
|
||||
<title>Serial Peripheral Interface (SPI)</title>
|
||||
<para>
|
||||
SPI is the "Serial Peripheral Interface", widely used with
|
||||
embedded systems because it is a simple and efficient
|
||||
interface: basically a multiplexed shift register.
|
||||
Its three signal wires hold a clock (SCK, often in the range
|
||||
of 1-20 MHz), a "Master Out, Slave In" (MOSI) data line, and
|
||||
a "Master In, Slave Out" (MISO) data line.
|
||||
SPI is a full duplex protocol; for each bit shifted out the
|
||||
MOSI line (one per clock) another is shifted in on the MISO line.
|
||||
Those bits are assembled into words of various sizes on the
|
||||
way to and from system memory.
|
||||
An additional chipselect line is usually active-low (nCS);
|
||||
four signals are normally used for each peripheral, plus
|
||||
sometimes an interrupt.
|
||||
</para>
|
||||
<para>
|
||||
The SPI bus facilities listed here provide a generalized
|
||||
interface to declare SPI busses and devices, manage them
|
||||
according to the standard Linux driver model, and perform
|
||||
input/output operations.
|
||||
At this time, only "master" side interfaces are supported,
|
||||
where Linux talks to SPI peripherals and does not implement
|
||||
such a peripheral itself.
|
||||
(Interfaces to support implementing SPI slaves would
|
||||
necessarily look different.)
|
||||
</para>
|
||||
<para>
|
||||
The programming interface is structured around two kinds of driver,
|
||||
and two kinds of device.
|
||||
A "Controller Driver" abstracts the controller hardware, which may
|
||||
be as simple as a set of GPIO pins or as complex as a pair of FIFOs
|
||||
connected to dual DMA engines on the other side of the SPI shift
|
||||
register (maximizing throughput). Such drivers bridge between
|
||||
whatever bus they sit on (often the platform bus) and SPI, and
|
||||
expose the SPI side of their device as a
|
||||
<structname>struct spi_master</structname>.
|
||||
SPI devices are children of that master, represented as a
|
||||
<structname>struct spi_device</structname> and manufactured from
|
||||
<structname>struct spi_board_info</structname> descriptors which
|
||||
are usually provided by board-specific initialization code.
|
||||
A <structname>struct spi_driver</structname> is called a
|
||||
"Protocol Driver", and is bound to a spi_device using normal
|
||||
driver model calls.
|
||||
</para>
|
||||
<para>
|
||||
The I/O model is a set of queued messages. Protocol drivers
|
||||
submit one or more <structname>struct spi_message</structname>
|
||||
objects, which are processed and completed asynchronously.
|
||||
(There are synchronous wrappers, however.) Messages are
|
||||
built from one or more <structname>struct spi_transfer</structname>
|
||||
objects, each of which wraps a full duplex SPI transfer.
|
||||
A variety of protocol tweaking options are needed, because
|
||||
different chips adopt very different policies for how they
|
||||
use the bits transferred with SPI.
|
||||
</para>
|
||||
!Iinclude/linux/spi/spi.h
|
||||
!Fdrivers/spi/spi.c spi_register_board_info
|
||||
!Edrivers/spi/spi.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="i2c">
|
||||
<title>I<superscript>2</superscript>C and SMBus Subsystem</title>
|
||||
|
||||
<para>
|
||||
I<superscript>2</superscript>C (or without fancy typography, "I2C")
|
||||
is an acronym for the "Inter-IC" bus, a simple bus protocol which is
|
||||
widely used where low data rate communications suffice.
|
||||
Since it's also a licensed trademark, some vendors use another
|
||||
name (such as "Two-Wire Interface", TWI) for the same bus.
|
||||
I2C only needs two signals (SCL for clock, SDA for data), conserving
|
||||
board real estate and minimizing signal quality issues.
|
||||
Most I2C devices use seven bit addresses, and bus speeds of up
|
||||
to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet
|
||||
found wide use.
|
||||
I2C is a multi-master bus; open drain signaling is used to
|
||||
arbitrate between masters, as well as to handshake and to
|
||||
synchronize clocks from slower clients.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The Linux I2C programming interfaces support only the master
|
||||
side of bus interactions, not the slave side.
|
||||
The programming interface is structured around two kinds of driver,
|
||||
and two kinds of device.
|
||||
An I2C "Adapter Driver" abstracts the controller hardware; it binds
|
||||
to a physical device (perhaps a PCI device or platform_device) and
|
||||
exposes a <structname>struct i2c_adapter</structname> representing
|
||||
each I2C bus segment it manages.
|
||||
On each I2C bus segment will be I2C devices represented by a
|
||||
<structname>struct i2c_client</structname>. Those devices will
|
||||
be bound to a <structname>struct i2c_driver</structname>,
|
||||
which should follow the standard Linux driver model.
|
||||
(At this writing, a legacy model is more widely used.)
|
||||
There are functions to perform various I2C protocol operations; at
|
||||
this writing all such functions are usable only from task context.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The System Management Bus (SMBus) is a sibling protocol. Most SMBus
|
||||
systems are also I2C conformant. The electrical constraints are
|
||||
tighter for SMBus, and it standardizes particular protocol messages
|
||||
and idioms. Controllers that support I2C can also support most
|
||||
SMBus operations, but SMBus controllers don't support all the protocol
|
||||
options that an I2C controller will.
|
||||
There are functions to perform various SMBus protocol operations,
|
||||
either using I2C primitives or by issuing SMBus commands to
|
||||
i2c_adapter devices which don't support those I2C operations.
|
||||
</para>
|
||||
|
||||
!Iinclude/linux/i2c.h
|
||||
!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info
|
||||
!Edrivers/i2c/i2c-core.c
|
||||
</chapter>
|
||||
|
||||
<chapter id="clk">
|
||||
<title>Clock Framework</title>
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ into the rest of the kernel, none in performance critical paths:
|
|||
- in fork and exit, to attach and detach a task from its cpuset.
|
||||
- in sched_setaffinity, to mask the requested CPUs by what's
|
||||
allowed in that tasks cpuset.
|
||||
- in sched.c migrate_all_tasks(), to keep migrating tasks within
|
||||
- in sched.c migrate_live_tasks(), to keep migrating tasks within
|
||||
the CPUs allowed by their cpuset, if possible.
|
||||
- in the mbind and set_mempolicy system calls, to mask the requested
|
||||
Memory Nodes by what's allowed in that tasks cpuset.
|
||||
|
@ -175,6 +175,10 @@ files describing that cpuset:
|
|||
- mem_exclusive flag: is memory placement exclusive?
|
||||
- mem_hardwall flag: is memory allocation hardwalled
|
||||
- memory_pressure: measure of how much paging pressure in cpuset
|
||||
- memory_spread_page flag: if set, spread page cache evenly on allowed nodes
|
||||
- memory_spread_slab flag: if set, spread slab cache evenly on allowed nodes
|
||||
- sched_load_balance flag: if set, load balance within CPUs on that cpuset
|
||||
- sched_relax_domain_level: the searching range when migrating tasks
|
||||
|
||||
In addition, the root cpuset only has the following file:
|
||||
- memory_pressure_enabled flag: compute memory_pressure?
|
||||
|
@ -252,7 +256,7 @@ is causing.
|
|||
|
||||
This is useful both on tightly managed systems running a wide mix of
|
||||
submitted jobs, which may choose to terminate or re-prioritize jobs that
|
||||
are trying to use more memory than allowed on the nodes assigned them,
|
||||
are trying to use more memory than allowed on the nodes assigned to them,
|
||||
and with tightly coupled, long running, massively parallel scientific
|
||||
computing jobs that will dramatically fail to meet required performance
|
||||
goals if they start to use more memory than allowed to them.
|
||||
|
@ -378,7 +382,7 @@ as cpusets and sched_setaffinity.
|
|||
The algorithmic cost of load balancing and its impact on key shared
|
||||
kernel data structures such as the task list increases more than
|
||||
linearly with the number of CPUs being balanced. So the scheduler
|
||||
has support to partition the systems CPUs into a number of sched
|
||||
has support to partition the systems CPUs into a number of sched
|
||||
domains such that it only load balances within each sched domain.
|
||||
Each sched domain covers some subset of the CPUs in the system;
|
||||
no two sched domains overlap; some CPUs might not be in any sched
|
||||
|
@ -485,17 +489,22 @@ of CPUs allowed to a cpuset having 'sched_load_balance' enabled.
|
|||
The internal kernel cpuset to scheduler interface passes from the
|
||||
cpuset code to the scheduler code a partition of the load balanced
|
||||
CPUs in the system. This partition is a set of subsets (represented
|
||||
as an array of cpumask_t) of CPUs, pairwise disjoint, that cover all
|
||||
the CPUs that must be load balanced.
|
||||
as an array of struct cpumask) of CPUs, pairwise disjoint, that cover
|
||||
all the CPUs that must be load balanced.
|
||||
|
||||
Whenever the 'sched_load_balance' flag changes, or CPUs come or go
|
||||
from a cpuset with this flag enabled, or a cpuset with this flag
|
||||
enabled is removed, the cpuset code builds a new such partition and
|
||||
passes it to the scheduler sched domain setup code, to have the sched
|
||||
domains rebuilt as necessary.
|
||||
The cpuset code builds a new such partition and passes it to the
|
||||
scheduler sched domain setup code, to have the sched domains rebuilt
|
||||
as necessary, whenever:
|
||||
- the 'sched_load_balance' flag of a cpuset with non-empty CPUs changes,
|
||||
- or CPUs come or go from a cpuset with this flag enabled,
|
||||
- or 'sched_relax_domain_level' value of a cpuset with non-empty CPUs
|
||||
and with this flag enabled changes,
|
||||
- or a cpuset with non-empty CPUs and with this flag enabled is removed,
|
||||
- or a cpu is offlined/onlined.
|
||||
|
||||
This partition exactly defines what sched domains the scheduler should
|
||||
setup - one sched domain for each element (cpumask_t) in the partition.
|
||||
setup - one sched domain for each element (struct cpumask) in the
|
||||
partition.
|
||||
|
||||
The scheduler remembers the currently active sched domain partitions.
|
||||
When the scheduler routine partition_sched_domains() is invoked from
|
||||
|
@ -559,7 +568,7 @@ domain, the largest value among those is used. Be careful, if one
|
|||
requests 0 and others are -1 then 0 is used.
|
||||
|
||||
Note that modifying this file will have both good and bad effects,
|
||||
and whether it is acceptable or not will be depend on your situation.
|
||||
and whether it is acceptable or not depends on your situation.
|
||||
Don't modify this file if you are not sure.
|
||||
|
||||
If your situation is:
|
||||
|
@ -600,19 +609,15 @@ to allocate a page of memory for that task.
|
|||
|
||||
If a cpuset has its 'cpus' modified, then each task in that cpuset
|
||||
will have its allowed CPU placement changed immediately. Similarly,
|
||||
if a tasks pid is written to a cpusets 'tasks' file, in either its
|
||||
current cpuset or another cpuset, then its allowed CPU placement is
|
||||
changed immediately. If such a task had been bound to some subset
|
||||
of its cpuset using the sched_setaffinity() call, the task will be
|
||||
allowed to run on any CPU allowed in its new cpuset, negating the
|
||||
affect of the prior sched_setaffinity() call.
|
||||
if a tasks pid is written to another cpusets 'tasks' file, then its
|
||||
allowed CPU placement is changed immediately. If such a task had been
|
||||
bound to some subset of its cpuset using the sched_setaffinity() call,
|
||||
the task will be allowed to run on any CPU allowed in its new cpuset,
|
||||
negating the effect of the prior sched_setaffinity() call.
|
||||
|
||||
In summary, the memory placement of a task whose cpuset is changed is
|
||||
updated by the kernel, on the next allocation of a page for that task,
|
||||
but the processor placement is not updated, until that tasks pid is
|
||||
rewritten to the 'tasks' file of its cpuset. This is done to avoid
|
||||
impacting the scheduler code in the kernel with a check for changes
|
||||
in a tasks processor placement.
|
||||
and the processor placement is updated immediately.
|
||||
|
||||
Normally, once a page is allocated (given a physical page
|
||||
of main memory) then that page stays on whatever node it
|
||||
|
@ -681,10 +686,14 @@ and then start a subshell 'sh' in that cpuset:
|
|||
# The next line should display '/Charlie'
|
||||
cat /proc/self/cpuset
|
||||
|
||||
In the future, a C library interface to cpusets will likely be
|
||||
available. For now, the only way to query or modify cpusets is
|
||||
via the cpuset file system, using the various cd, mkdir, echo, cat,
|
||||
rmdir commands from the shell, or their equivalent from C.
|
||||
There are ways to query or modify cpusets:
|
||||
- via the cpuset file system directly, using the various cd, mkdir, echo,
|
||||
cat, rmdir commands from the shell, or their equivalent from C.
|
||||
- via the C library libcpuset.
|
||||
- via the C library libcgroup.
|
||||
(http://sourceforge.net/proects/libcg/)
|
||||
- via the python application cset.
|
||||
(http://developer.novell.com/wiki/index.php/Cpuset)
|
||||
|
||||
The sched_setaffinity calls can also be done at the shell prompt using
|
||||
SGI's runon or Robert Love's taskset. The mbind and set_mempolicy
|
||||
|
@ -756,7 +765,7 @@ mount -t cpuset X /dev/cpuset
|
|||
|
||||
is equivalent to
|
||||
|
||||
mount -t cgroup -ocpuset X /dev/cpuset
|
||||
mount -t cgroup -ocpuset,noprefix X /dev/cpuset
|
||||
echo "/sbin/cpuset_release_agent" > /dev/cpuset/release_agent
|
||||
|
||||
2.2 Adding/removing cpus
|
||||
|
|
|
@ -127,9 +127,11 @@ void unlock_device(struct device * dev);
|
|||
Attributes
|
||||
~~~~~~~~~~
|
||||
struct device_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off);
|
||||
ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off);
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
|
||||
char *buf);
|
||||
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
};
|
||||
|
||||
Attributes of devices can be exported via drivers using a simple
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
sysfs - _The_ filesystem for exporting kernel objects.
|
||||
|
||||
Patrick Mochel <mochel@osdl.org>
|
||||
Mike Murphy <mamurph@cs.clemson.edu>
|
||||
|
||||
10 January 2003
|
||||
Revised: 22 February 2009
|
||||
Original: 10 January 2003
|
||||
|
||||
|
||||
What it is:
|
||||
|
@ -64,12 +66,13 @@ An attribute definition is simply:
|
|||
|
||||
struct attribute {
|
||||
char * name;
|
||||
struct module *owner;
|
||||
mode_t mode;
|
||||
};
|
||||
|
||||
|
||||
int sysfs_create_file(struct kobject * kobj, struct attribute * attr);
|
||||
void sysfs_remove_file(struct kobject * kobj, struct attribute * attr);
|
||||
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
|
||||
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
|
||||
|
||||
|
||||
A bare attribute contains no means to read or write the value of the
|
||||
|
@ -80,9 +83,11 @@ a specific object type.
|
|||
For example, the driver model defines struct device_attribute like:
|
||||
|
||||
struct device_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device * dev, char * buf);
|
||||
ssize_t (*store)(struct device * dev, const char * buf);
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
|
||||
char *buf);
|
||||
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
};
|
||||
|
||||
int device_create_file(struct device *, struct device_attribute *);
|
||||
|
@ -90,12 +95,8 @@ void device_remove_file(struct device *, struct device_attribute *);
|
|||
|
||||
It also defines this helper for defining device attributes:
|
||||
|
||||
#define DEVICE_ATTR(_name, _mode, _show, _store) \
|
||||
struct device_attribute dev_attr_##_name = { \
|
||||
.attr = {.name = __stringify(_name) , .mode = _mode }, \
|
||||
.show = _show, \
|
||||
.store = _store, \
|
||||
};
|
||||
#define DEVICE_ATTR(_name, _mode, _show, _store) \
|
||||
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
|
||||
|
||||
For example, declaring
|
||||
|
||||
|
@ -107,9 +108,9 @@ static struct device_attribute dev_attr_foo = {
|
|||
.attr = {
|
||||
.name = "foo",
|
||||
.mode = S_IWUSR | S_IRUGO,
|
||||
.show = show_foo,
|
||||
.store = store_foo,
|
||||
},
|
||||
.show = show_foo,
|
||||
.store = store_foo,
|
||||
};
|
||||
|
||||
|
||||
|
@ -161,10 +162,12 @@ To read or write attributes, show() or store() methods must be
|
|||
specified when declaring the attribute. The method types should be as
|
||||
simple as those defined for device attributes:
|
||||
|
||||
ssize_t (*show)(struct device * dev, char * buf);
|
||||
ssize_t (*store)(struct device * dev, const char * buf);
|
||||
ssize_t (*show)(struct device * dev, struct device_attribute * attr,
|
||||
char * buf);
|
||||
ssize_t (*store)(struct device * dev, struct device_attribute * attr,
|
||||
const char * buf);
|
||||
|
||||
IOW, they should take only an object and a buffer as parameters.
|
||||
IOW, they should take only an object, an attribute, and a buffer as parameters.
|
||||
|
||||
|
||||
sysfs allocates a buffer of size (PAGE_SIZE) and passes it to the
|
||||
|
@ -299,14 +302,16 @@ The following interface layers currently exist in sysfs:
|
|||
Structure:
|
||||
|
||||
struct device_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device * dev, char * buf);
|
||||
ssize_t (*store)(struct device * dev, const char * buf);
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
|
||||
char *buf);
|
||||
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
};
|
||||
|
||||
Declaring:
|
||||
|
||||
DEVICE_ATTR(_name, _str, _mode, _show, _store);
|
||||
DEVICE_ATTR(_name, _mode, _show, _store);
|
||||
|
||||
Creation/Removal:
|
||||
|
||||
|
@ -342,7 +347,8 @@ Structure:
|
|||
struct driver_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device_driver *, char * buf);
|
||||
ssize_t (*store)(struct device_driver *, const char * buf);
|
||||
ssize_t (*store)(struct device_driver *, const char * buf,
|
||||
size_t count);
|
||||
};
|
||||
|
||||
Declaring:
|
||||
|
|
|
@ -135,7 +135,7 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
|
||||
acpi= [HW,ACPI,X86-64,i386]
|
||||
Advanced Configuration and Power Interface
|
||||
Format: { force | off | ht | strict | noirq }
|
||||
Format: { force | off | ht | strict | noirq | rsdt }
|
||||
force -- enable ACPI if default was off
|
||||
off -- disable ACPI if default was on
|
||||
noirq -- do not use ACPI for IRQ routing
|
||||
|
|
|
@ -3340,8 +3340,8 @@ P: Jeremy Fitzhardinge
|
|||
M: jeremy@xensource.com
|
||||
P: Chris Wright
|
||||
M: chrisw@sous-sol.org
|
||||
P: Zachary Amsden
|
||||
M: zach@vmware.com
|
||||
P: Alok Kataria
|
||||
M: akataria@vmware.com
|
||||
P: Rusty Russell
|
||||
M: rusty@rustcorp.com.au
|
||||
L: virtualization@lists.osdl.org
|
||||
|
|
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
|||
VERSION = 2
|
||||
PATCHLEVEL = 6
|
||||
SUBLEVEL = 29
|
||||
EXTRAVERSION = -rc5
|
||||
EXTRAVERSION = -rc6
|
||||
NAME = Erotic Pickled Herring
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
2
README
2
README
|
@ -188,7 +188,7 @@ CONFIGURING the kernel:
|
|||
values to random values.
|
||||
|
||||
You can find more information on using the Linux kernel config tools
|
||||
in Documentation/kbuild/make-configs.txt.
|
||||
in Documentation/kbuild/kconfig.txt.
|
||||
|
||||
NOTES on "make config":
|
||||
- having unnecessary drivers will make the kernel bigger, and can
|
||||
|
|
|
@ -224,7 +224,11 @@ config IA64_HP_SIM
|
|||
|
||||
config IA64_XEN_GUEST
|
||||
bool "Xen guest"
|
||||
select SWIOTLB
|
||||
depends on XEN
|
||||
help
|
||||
Build a kernel that runs on Xen guest domain. At this moment only
|
||||
16KB page size in supported.
|
||||
|
||||
endchoice
|
||||
|
||||
|
@ -482,8 +486,7 @@ config HOLES_IN_ZONE
|
|||
default y if VIRTUAL_MEM_MAP
|
||||
|
||||
config HAVE_ARCH_EARLY_PFN_TO_NID
|
||||
def_bool y
|
||||
depends on NEED_MULTIPLE_NODES
|
||||
def_bool NUMA && SPARSEMEM
|
||||
|
||||
config HAVE_ARCH_NODEDATA_EXTENSION
|
||||
def_bool y
|
||||
|
|
1601
arch/ia64/configs/xen_domu_defconfig
Normal file
1601
arch/ia64/configs/xen_domu_defconfig
Normal file
File diff suppressed because it is too large
Load diff
|
@ -39,7 +39,7 @@
|
|||
/* BTE status register only supports 16 bits for length field */
|
||||
#define BTE_LEN_BITS (16)
|
||||
#define BTE_LEN_MASK ((1 << BTE_LEN_BITS) - 1)
|
||||
#define BTE_MAX_XFER ((1 << BTE_LEN_BITS) * L1_CACHE_BYTES)
|
||||
#define BTE_MAX_XFER (BTE_LEN_MASK << L1_CACHE_SHIFT)
|
||||
|
||||
|
||||
/* Define hardware */
|
||||
|
|
|
@ -736,14 +736,15 @@ int __cpu_disable(void)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
cpu_clear(cpu, cpu_online_map);
|
||||
|
||||
if (migrate_platform_irqs(cpu)) {
|
||||
cpu_set(cpu, cpu_online_map);
|
||||
return (-EBUSY);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
remove_siblinginfo(cpu);
|
||||
fixup_irqs();
|
||||
cpu_clear(cpu, cpu_online_map);
|
||||
local_flush_tlb_all();
|
||||
cpu_clear(cpu, cpu_callin_map);
|
||||
return 0;
|
||||
|
|
|
@ -97,9 +97,10 @@ bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification)
|
|||
return BTE_SUCCESS;
|
||||
}
|
||||
|
||||
BUG_ON((len & L1_CACHE_MASK) ||
|
||||
(src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK));
|
||||
BUG_ON(!(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)));
|
||||
BUG_ON(len & L1_CACHE_MASK);
|
||||
BUG_ON(src & L1_CACHE_MASK);
|
||||
BUG_ON(dest & L1_CACHE_MASK);
|
||||
BUG_ON(len > BTE_MAX_XFER);
|
||||
|
||||
/*
|
||||
* Start with interface corresponding to cpu number
|
||||
|
|
|
@ -8,8 +8,7 @@ config XEN
|
|||
depends on PARAVIRT && MCKINLEY && IA64_PAGE_SIZE_16KB && EXPERIMENTAL
|
||||
select XEN_XENCOMM
|
||||
select NO_IDLE_HZ
|
||||
|
||||
# those are required to save/restore.
|
||||
# followings are required to save/restore.
|
||||
select ARCH_SUSPEND_POSSIBLE
|
||||
select SUSPEND
|
||||
select PM_SLEEP
|
||||
|
|
|
@ -153,7 +153,7 @@ xen_post_smp_prepare_boot_cpu(void)
|
|||
xen_setup_vcpu_info_placement();
|
||||
}
|
||||
|
||||
static const struct pv_init_ops xen_init_ops __initdata = {
|
||||
static const struct pv_init_ops xen_init_ops __initconst = {
|
||||
.banner = xen_banner,
|
||||
|
||||
.reserve_memory = xen_reserve_memory,
|
||||
|
@ -337,7 +337,7 @@ xen_iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
|
|||
HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op);
|
||||
}
|
||||
|
||||
static const struct pv_iosapic_ops xen_iosapic_ops __initdata = {
|
||||
static const struct pv_iosapic_ops xen_iosapic_ops __initconst = {
|
||||
.pcat_compat_init = xen_pcat_compat_init,
|
||||
.__get_irq_chip = xen_iosapic_get_irq_chip,
|
||||
|
||||
|
|
|
@ -187,8 +187,8 @@ __asm__ (__ALIGN_STR "\n" \
|
|||
" jbra ret_from_interrupt\n" \
|
||||
: : "i" (&kstat_cpu(0).irqs[n+8]), "i" (&irq_handler[n+8]), \
|
||||
"n" (PT_OFF_SR), "n" (n), \
|
||||
"i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a) \
|
||||
: (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)), \
|
||||
"i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &st_mfp.int_mk_a) \
|
||||
: (n & 16 ? &tt_mfp.int_mk_b : &st_mfp.int_mk_b)), \
|
||||
"m" (preempt_count()), "di" (HARDIRQ_OFFSET) \
|
||||
); \
|
||||
for (;;); /* fake noreturn */ \
|
||||
|
@ -366,14 +366,14 @@ void __init atari_init_IRQ(void)
|
|||
/* Initialize the MFP(s) */
|
||||
|
||||
#ifdef ATARI_USE_SOFTWARE_EOI
|
||||
mfp.vec_adr = 0x48; /* Software EOI-Mode */
|
||||
st_mfp.vec_adr = 0x48; /* Software EOI-Mode */
|
||||
#else
|
||||
mfp.vec_adr = 0x40; /* Automatic EOI-Mode */
|
||||
st_mfp.vec_adr = 0x40; /* Automatic EOI-Mode */
|
||||
#endif
|
||||
mfp.int_en_a = 0x00; /* turn off MFP-Ints */
|
||||
mfp.int_en_b = 0x00;
|
||||
mfp.int_mk_a = 0xff; /* no Masking */
|
||||
mfp.int_mk_b = 0xff;
|
||||
st_mfp.int_en_a = 0x00; /* turn off MFP-Ints */
|
||||
st_mfp.int_en_b = 0x00;
|
||||
st_mfp.int_mk_a = 0xff; /* no Masking */
|
||||
st_mfp.int_mk_b = 0xff;
|
||||
|
||||
if (ATARIHW_PRESENT(TT_MFP)) {
|
||||
#ifdef ATARI_USE_SOFTWARE_EOI
|
||||
|
|
|
@ -609,10 +609,10 @@ int atari_keyb_init(void)
|
|||
ACIA_RHTID : 0);
|
||||
|
||||
/* make sure the interrupt line is up */
|
||||
} while ((mfp.par_dt_reg & 0x10) == 0);
|
||||
} while ((st_mfp.par_dt_reg & 0x10) == 0);
|
||||
|
||||
/* enable ACIA Interrupts */
|
||||
mfp.active_edge &= ~0x10;
|
||||
st_mfp.active_edge &= ~0x10;
|
||||
atari_turnon_irq(IRQ_MFP_ACIA);
|
||||
|
||||
ikbd_self_test = 1;
|
||||
|
|
|
@ -258,7 +258,7 @@ void __init config_atari(void)
|
|||
printk("STND_SHIFTER ");
|
||||
}
|
||||
}
|
||||
if (hwreg_present(&mfp.par_dt_reg)) {
|
||||
if (hwreg_present(&st_mfp.par_dt_reg)) {
|
||||
ATARIHW_SET(ST_MFP);
|
||||
printk("ST_MFP ");
|
||||
}
|
||||
|
|
|
@ -34,9 +34,9 @@ static struct console atari_console_driver = {
|
|||
|
||||
static inline void ata_mfp_out(char c)
|
||||
{
|
||||
while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
|
||||
while (!(st_mfp.trn_stat & 0x80)) /* wait for tx buf empty */
|
||||
barrier();
|
||||
mfp.usart_dta = c;
|
||||
st_mfp.usart_dta = c;
|
||||
}
|
||||
|
||||
static void atari_mfp_console_write(struct console *co, const char *str,
|
||||
|
@ -91,7 +91,7 @@ static int ata_par_out(char c)
|
|||
/* This a some-seconds timeout in case no printer is connected */
|
||||
unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ;
|
||||
|
||||
while ((mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */
|
||||
while ((st_mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */
|
||||
;
|
||||
if (!i)
|
||||
return 0;
|
||||
|
@ -131,9 +131,9 @@ static void atari_par_console_write(struct console *co, const char *str,
|
|||
#if 0
|
||||
int atari_mfp_console_wait_key(struct console *co)
|
||||
{
|
||||
while (!(mfp.rcv_stat & 0x80)) /* wait for rx buf filled */
|
||||
while (!(st_mfp.rcv_stat & 0x80)) /* wait for rx buf filled */
|
||||
barrier();
|
||||
return mfp.usart_dta;
|
||||
return st_mfp.usart_dta;
|
||||
}
|
||||
|
||||
int atari_scc_console_wait_key(struct console *co)
|
||||
|
@ -175,12 +175,12 @@ static void __init atari_init_mfp_port(int cflag)
|
|||
baud = B9600; /* use default 9600bps for non-implemented rates */
|
||||
baud -= B1200; /* baud_table[] starts at 1200bps */
|
||||
|
||||
mfp.trn_stat &= ~0x01; /* disable TX */
|
||||
mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
|
||||
mfp.tim_ct_cd &= 0x70; /* stop timer D */
|
||||
mfp.tim_dt_d = baud_table[baud];
|
||||
mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
|
||||
mfp.trn_stat |= 0x01; /* enable TX */
|
||||
st_mfp.trn_stat &= ~0x01; /* disable TX */
|
||||
st_mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
|
||||
st_mfp.tim_ct_cd &= 0x70; /* stop timer D */
|
||||
st_mfp.tim_dt_d = baud_table[baud];
|
||||
st_mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
|
||||
st_mfp.trn_stat |= 0x01; /* enable TX */
|
||||
}
|
||||
|
||||
#define SCC_WRITE(reg, val) \
|
||||
|
|
|
@ -27,9 +27,9 @@ void __init
|
|||
atari_sched_init(irq_handler_t timer_routine)
|
||||
{
|
||||
/* set Timer C data Register */
|
||||
mfp.tim_dt_c = INT_TICKS;
|
||||
st_mfp.tim_dt_c = INT_TICKS;
|
||||
/* start timer C, div = 1:100 */
|
||||
mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60;
|
||||
st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
|
||||
/* install interrupt service routine for MFP Timer C */
|
||||
if (request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
|
||||
"timer", timer_routine))
|
||||
|
@ -46,11 +46,11 @@ unsigned long atari_gettimeoffset (void)
|
|||
unsigned long ticks, offset = 0;
|
||||
|
||||
/* read MFP timer C current value */
|
||||
ticks = mfp.tim_dt_c;
|
||||
ticks = st_mfp.tim_dt_c;
|
||||
/* The probability of underflow is less than 2% */
|
||||
if (ticks > INT_TICKS - INT_TICKS / 50)
|
||||
/* Check for pending timer interrupt */
|
||||
if (mfp.int_pn_b & (1 << 5))
|
||||
if (st_mfp.int_pn_b & (1 << 5))
|
||||
offset = TICK_SIZE;
|
||||
|
||||
ticks = INT_TICKS - ticks;
|
||||
|
|
|
@ -113,7 +113,7 @@ extern struct atari_hw_present atari_hw_present;
|
|||
* of nops on various machines. Somebody claimed that the tstb takes 600 ns.
|
||||
*/
|
||||
#define MFPDELAY() \
|
||||
__asm__ __volatile__ ( "tstb %0" : : "m" (mfp.par_dt_reg) : "cc" );
|
||||
__asm__ __volatile__ ( "tstb %0" : : "m" (st_mfp.par_dt_reg) : "cc" );
|
||||
|
||||
/* Do cache push/invalidate for DMA read/write. This function obeys the
|
||||
* snooping on some machines (Medusa) and processors: The Medusa itself can
|
||||
|
@ -565,7 +565,7 @@ struct MFP
|
|||
u_char char_dummy23;
|
||||
u_char usart_dta;
|
||||
};
|
||||
# define mfp ((*(volatile struct MFP*)MFP_BAS))
|
||||
# define st_mfp ((*(volatile struct MFP*)MFP_BAS))
|
||||
|
||||
/* TT's second MFP */
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ static inline int get_mfp_bit( unsigned irq, int type )
|
|||
{ unsigned char mask, *reg;
|
||||
|
||||
mask = 1 << (irq & 7);
|
||||
reg = (unsigned char *)&mfp.int_en_a + type*4 +
|
||||
reg = (unsigned char *)&st_mfp.int_en_a + type*4 +
|
||||
((irq & 8) >> 2) + (((irq-8) & 16) << 3);
|
||||
return( *reg & mask );
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ static inline void set_mfp_bit( unsigned irq, int type )
|
|||
{ unsigned char mask, *reg;
|
||||
|
||||
mask = 1 << (irq & 7);
|
||||
reg = (unsigned char *)&mfp.int_en_a + type*4 +
|
||||
reg = (unsigned char *)&st_mfp.int_en_a + type*4 +
|
||||
((irq & 8) >> 2) + (((irq-8) & 16) << 3);
|
||||
__asm__ __volatile__ ( "orb %0,%1"
|
||||
: : "di" (mask), "m" (*reg) : "memory" );
|
||||
|
@ -134,7 +134,7 @@ static inline void clear_mfp_bit( unsigned irq, int type )
|
|||
{ unsigned char mask, *reg;
|
||||
|
||||
mask = ~(1 << (irq & 7));
|
||||
reg = (unsigned char *)&mfp.int_en_a + type*4 +
|
||||
reg = (unsigned char *)&st_mfp.int_en_a + type*4 +
|
||||
((irq & 8) >> 2) + (((irq-8) & 16) << 3);
|
||||
if (type == MFP_PENDING || type == MFP_SERVICE)
|
||||
__asm__ __volatile__ ( "moveb %0,%1"
|
||||
|
|
|
@ -7,6 +7,7 @@ mainmenu "Linux Kernel Configuration"
|
|||
|
||||
config MN10300
|
||||
def_bool y
|
||||
select HAVE_OPROFILE
|
||||
|
||||
config AM33
|
||||
def_bool y
|
||||
|
|
|
@ -173,7 +173,7 @@ static int pci_ampci_write_config_byte(struct pci_bus *bus, unsigned int devfn,
|
|||
BRIDGEREGB(where) = value;
|
||||
} else {
|
||||
if (bus->number == 0 &&
|
||||
(devfn == PCI_DEVFN(2, 0) && devfn == PCI_DEVFN(3, 0))
|
||||
(devfn == PCI_DEVFN(2, 0) || devfn == PCI_DEVFN(3, 0))
|
||||
)
|
||||
__pcidebug("<= %02x", bus, devfn, where, value);
|
||||
CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
|
||||
|
|
|
@ -78,7 +78,7 @@ void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init)
|
|||
{
|
||||
struct vde_open_args *args;
|
||||
|
||||
vpri->args = kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL);
|
||||
vpri->args = uml_kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL);
|
||||
if (vpri->args == NULL) {
|
||||
printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args "
|
||||
"allocation failed");
|
||||
|
@ -91,8 +91,8 @@ void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init)
|
|||
args->group = init->group;
|
||||
args->mode = init->mode ? init->mode : 0700;
|
||||
|
||||
args->port ? printk(UM_KERN_INFO "port %d", args->port) :
|
||||
printk(UM_KERN_INFO "undefined port");
|
||||
args->port ? printk("port %d", args->port) :
|
||||
printk("undefined port");
|
||||
}
|
||||
|
||||
int vde_user_read(void *conn, void *buf, int len)
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
* Hooray, we are in Long 64-bit mode (but still running in low memory)
|
||||
*/
|
||||
ENTRY(wakeup_long64)
|
||||
wakeup_long64:
|
||||
movq saved_magic, %rax
|
||||
movq $0x123456789abcdef0, %rdx
|
||||
cmpq %rdx, %rax
|
||||
|
@ -34,16 +33,12 @@ wakeup_long64:
|
|||
|
||||
movq saved_rip, %rax
|
||||
jmp *%rax
|
||||
ENDPROC(wakeup_long64)
|
||||
|
||||
bogus_64_magic:
|
||||
jmp bogus_64_magic
|
||||
|
||||
.align 2
|
||||
.p2align 4,,15
|
||||
.globl do_suspend_lowlevel
|
||||
.type do_suspend_lowlevel,@function
|
||||
do_suspend_lowlevel:
|
||||
.LFB5:
|
||||
ENTRY(do_suspend_lowlevel)
|
||||
subq $8, %rsp
|
||||
xorl %eax, %eax
|
||||
call save_processor_state
|
||||
|
@ -67,7 +62,7 @@ do_suspend_lowlevel:
|
|||
pushfq
|
||||
popq pt_regs_flags(%rax)
|
||||
|
||||
movq $.L97, saved_rip(%rip)
|
||||
movq $resume_point, saved_rip(%rip)
|
||||
|
||||
movq %rsp, saved_rsp
|
||||
movq %rbp, saved_rbp
|
||||
|
@ -78,14 +73,12 @@ do_suspend_lowlevel:
|
|||
addq $8, %rsp
|
||||
movl $3, %edi
|
||||
xorl %eax, %eax
|
||||
jmp acpi_enter_sleep_state
|
||||
.L97:
|
||||
.p2align 4,,7
|
||||
.L99:
|
||||
.align 4
|
||||
movl $24, %eax
|
||||
movw %ax, %ds
|
||||
call acpi_enter_sleep_state
|
||||
/* in case something went wrong, restore the machine status and go on */
|
||||
jmp resume_point
|
||||
|
||||
.align 4
|
||||
resume_point:
|
||||
/* We don't restore %rax, it must be 0 anyway */
|
||||
movq $saved_context, %rax
|
||||
movq saved_context_cr4(%rax), %rbx
|
||||
|
@ -117,12 +110,9 @@ do_suspend_lowlevel:
|
|||
xorl %eax, %eax
|
||||
addq $8, %rsp
|
||||
jmp restore_processor_state
|
||||
.LFE5:
|
||||
.Lfe5:
|
||||
.size do_suspend_lowlevel, .Lfe5-do_suspend_lowlevel
|
||||
|
||||
ENDPROC(do_suspend_lowlevel)
|
||||
|
||||
.data
|
||||
ALIGN
|
||||
ENTRY(saved_rbp) .quad 0
|
||||
ENTRY(saved_rsi) .quad 0
|
||||
ENTRY(saved_rdi) .quad 0
|
||||
|
|
|
@ -1192,6 +1192,7 @@ static int suspend(int vetoable)
|
|||
device_suspend(PMSG_SUSPEND);
|
||||
local_irq_disable();
|
||||
device_power_down(PMSG_SUSPEND);
|
||||
sysdev_suspend(PMSG_SUSPEND);
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
|
@ -1208,6 +1209,7 @@ static int suspend(int vetoable)
|
|||
if (err != APM_SUCCESS)
|
||||
apm_error("suspend", err);
|
||||
err = (err == APM_SUCCESS) ? 0 : -EIO;
|
||||
sysdev_resume();
|
||||
device_power_up(PMSG_RESUME);
|
||||
local_irq_enable();
|
||||
device_resume(PMSG_RESUME);
|
||||
|
@ -1228,6 +1230,7 @@ static void standby(void)
|
|||
|
||||
local_irq_disable();
|
||||
device_power_down(PMSG_SUSPEND);
|
||||
sysdev_suspend(PMSG_SUSPEND);
|
||||
local_irq_enable();
|
||||
|
||||
err = set_system_power_state(APM_STATE_STANDBY);
|
||||
|
@ -1235,6 +1238,7 @@ static void standby(void)
|
|||
apm_error("standby", err);
|
||||
|
||||
local_irq_disable();
|
||||
sysdev_resume();
|
||||
device_power_up(PMSG_RESUME);
|
||||
local_irq_enable();
|
||||
}
|
||||
|
|
|
@ -490,7 +490,7 @@ static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
|
|||
|
||||
}
|
||||
|
||||
static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
|
||||
static void mce_cpu_features(struct cpuinfo_x86 *c)
|
||||
{
|
||||
switch (c->x86_vendor) {
|
||||
case X86_VENDOR_INTEL:
|
||||
|
|
|
@ -121,7 +121,7 @@ static long threshold_restart_bank(void *_tr)
|
|||
}
|
||||
|
||||
/* cpu init entry point, called from mce.c with preempt off */
|
||||
void __cpuinit mce_amd_feature_init(struct cpuinfo_x86 *c)
|
||||
void mce_amd_feature_init(struct cpuinfo_x86 *c)
|
||||
{
|
||||
unsigned int bank, block;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
|
|
@ -30,7 +30,7 @@ asmlinkage void smp_thermal_interrupt(void)
|
|||
irq_exit();
|
||||
}
|
||||
|
||||
static void __cpuinit intel_init_thermal(struct cpuinfo_x86 *c)
|
||||
static void intel_init_thermal(struct cpuinfo_x86 *c)
|
||||
{
|
||||
u32 l, h;
|
||||
int tm2 = 0;
|
||||
|
@ -84,7 +84,7 @@ static void __cpuinit intel_init_thermal(struct cpuinfo_x86 *c)
|
|||
return;
|
||||
}
|
||||
|
||||
void __cpuinit mce_intel_feature_init(struct cpuinfo_x86 *c)
|
||||
void mce_intel_feature_init(struct cpuinfo_x86 *c)
|
||||
{
|
||||
intel_init_thermal(c);
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ unsigned long __init calibrate_cpu(void)
|
|||
|
||||
static struct irqaction irq0 = {
|
||||
.handler = timer_interrupt,
|
||||
.flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
|
||||
.flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING | IRQF_TIMER,
|
||||
.mask = CPU_MASK_NONE,
|
||||
.name = "timer"
|
||||
};
|
||||
|
|
|
@ -202,7 +202,7 @@ static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id)
|
|||
static struct irqaction vmi_clock_action = {
|
||||
.name = "vmi-timer",
|
||||
.handler = vmi_timer_interrupt,
|
||||
.flags = IRQF_DISABLED | IRQF_NOBALANCING,
|
||||
.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
|
||||
.mask = CPU_MASK_ALL,
|
||||
};
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ void __init trap_init_hook(void)
|
|||
|
||||
static struct irqaction irq0 = {
|
||||
.handler = timer_interrupt,
|
||||
.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL,
|
||||
.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
|
||||
.mask = CPU_MASK_NONE,
|
||||
.name = "timer"
|
||||
};
|
||||
|
|
|
@ -56,7 +56,7 @@ void __init trap_init_hook(void)
|
|||
|
||||
static struct irqaction irq0 = {
|
||||
.handler = timer_interrupt,
|
||||
.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL,
|
||||
.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
|
||||
.mask = CPU_MASK_NONE,
|
||||
.name = "timer"
|
||||
};
|
||||
|
|
|
@ -254,13 +254,6 @@ config ACPI_PCI_SLOT
|
|||
help you correlate PCI bus addresses with the physical geography
|
||||
of your slots. If you are unsure, say N.
|
||||
|
||||
config ACPI_SYSTEM
|
||||
bool
|
||||
default y
|
||||
help
|
||||
This driver will enable your system to shut down using ACPI, and
|
||||
dump your ACPI DSDT table using /proc/acpi/dsdt.
|
||||
|
||||
config X86_PM_TIMER
|
||||
bool "Power Management Timer Support" if EMBEDDED
|
||||
depends on X86
|
||||
|
|
|
@ -52,7 +52,7 @@ obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
|
|||
obj-$(CONFIG_ACPI_CONTAINER) += container.o
|
||||
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
|
||||
obj-y += power.o
|
||||
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
|
||||
obj-y += system.o event.o
|
||||
obj-$(CONFIG_ACPI_DEBUG) += debug.o
|
||||
obj-$(CONFIG_ACPI_NUMA) += numa.o
|
||||
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
|
||||
|
|
|
@ -138,6 +138,29 @@ static int acpi_battery_technology(struct acpi_battery *battery)
|
|||
|
||||
static int acpi_battery_get_state(struct acpi_battery *battery);
|
||||
|
||||
static int acpi_battery_is_charged(struct acpi_battery *battery)
|
||||
{
|
||||
/* either charging or discharging */
|
||||
if (battery->state != 0)
|
||||
return 0;
|
||||
|
||||
/* battery not reporting charge */
|
||||
if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
|
||||
battery->capacity_now == 0)
|
||||
return 0;
|
||||
|
||||
/* good batteries update full_charge as the batteries degrade */
|
||||
if (battery->full_charge_capacity == battery->capacity_now)
|
||||
return 1;
|
||||
|
||||
/* fallback to using design values for broken batteries */
|
||||
if (battery->design_capacity == battery->capacity_now)
|
||||
return 1;
|
||||
|
||||
/* we don't do any sort of metric based on percentages */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_battery_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
|
@ -155,7 +178,7 @@ static int acpi_battery_get_property(struct power_supply *psy,
|
|||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
else if (battery->state & 0x02)
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else if (battery->state == 0)
|
||||
else if (acpi_battery_is_charged(battery))
|
||||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
|
|
|
@ -120,6 +120,8 @@ static struct acpi_ec {
|
|||
spinlock_t curr_lock;
|
||||
} *boot_ec, *first_ec;
|
||||
|
||||
static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Transaction Management
|
||||
-------------------------------------------------------------------------- */
|
||||
|
@ -259,6 +261,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
|
|||
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
|
||||
acpi_disable_gpe(NULL, ec->gpe);
|
||||
}
|
||||
if (EC_FLAGS_MSI)
|
||||
udelay(ACPI_EC_DELAY);
|
||||
/* start transaction */
|
||||
spin_lock_irqsave(&ec->curr_lock, tmp);
|
||||
/* following two actions should be kept atomic */
|
||||
|
@ -967,6 +971,11 @@ int __init acpi_ec_ecdt_probe(void)
|
|||
/*
|
||||
* Generate a boot ec context
|
||||
*/
|
||||
if (dmi_name_in_vendors("Micro-Star") ||
|
||||
dmi_name_in_vendors("Notebook")) {
|
||||
pr_info(PREFIX "Enabling special treatment for EC from MSI.\n");
|
||||
EC_FLAGS_MSI = 1;
|
||||
}
|
||||
status = acpi_get_table(ACPI_SIG_ECDT, 1,
|
||||
(struct acpi_table_header **)&ecdt_ptr);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
|
|
|
@ -88,8 +88,6 @@ extern void driver_detach(struct device_driver *drv);
|
|||
extern int driver_probe_device(struct device_driver *drv, struct device *dev);
|
||||
|
||||
extern void sysdev_shutdown(void);
|
||||
extern int sysdev_suspend(pm_message_t state);
|
||||
extern int sysdev_resume(void);
|
||||
|
||||
extern char *make_class_name(const char *name, struct kobject *kobj);
|
||||
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/async.h>
|
||||
|
||||
#include "base.h"
|
||||
#include "power/power.h"
|
||||
|
@ -167,6 +169,21 @@ int driver_probe_done(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* wait_for_device_probe
|
||||
* Wait for device probing to be completed.
|
||||
*
|
||||
* Note: this function polls at 100 msec intervals.
|
||||
*/
|
||||
int wait_for_device_probe(void)
|
||||
{
|
||||
/* wait for the known devices to complete their probing */
|
||||
while (driver_probe_done() != 0)
|
||||
msleep(100);
|
||||
async_synchronize_full();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* driver_probe_device - attempt to bind device & driver together
|
||||
* @drv: driver to bind a device to
|
||||
|
|
|
@ -333,7 +333,6 @@ static void dpm_power_up(pm_message_t state)
|
|||
*/
|
||||
void device_power_up(pm_message_t state)
|
||||
{
|
||||
sysdev_resume();
|
||||
dpm_power_up(state);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_power_up);
|
||||
|
@ -577,8 +576,6 @@ int device_power_down(pm_message_t state)
|
|||
}
|
||||
dev->power.status = DPM_OFF_IRQ;
|
||||
}
|
||||
if (!error)
|
||||
error = sysdev_suspend(state);
|
||||
if (error)
|
||||
dpm_power_up(resume_event(state));
|
||||
return error;
|
||||
|
|
|
@ -303,7 +303,6 @@ void sysdev_unregister(struct sys_device * sysdev)
|
|||
* is guaranteed by virtue of the fact that child devices are registered
|
||||
* after their parents.
|
||||
*/
|
||||
|
||||
void sysdev_shutdown(void)
|
||||
{
|
||||
struct sysdev_class * cls;
|
||||
|
@ -363,7 +362,6 @@ static void __sysdev_resume(struct sys_device *dev)
|
|||
* This is only called by the device PM core, so we let them handle
|
||||
* all synchronization.
|
||||
*/
|
||||
|
||||
int sysdev_suspend(pm_message_t state)
|
||||
{
|
||||
struct sysdev_class * cls;
|
||||
|
@ -432,7 +430,7 @@ aux_driver:
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(sysdev_suspend);
|
||||
|
||||
/**
|
||||
* sysdev_resume - Bring system devices back to life.
|
||||
|
@ -442,7 +440,6 @@ aux_driver:
|
|||
*
|
||||
* Note: Interrupts are disabled when called.
|
||||
*/
|
||||
|
||||
int sysdev_resume(void)
|
||||
{
|
||||
struct sysdev_class * cls;
|
||||
|
@ -463,7 +460,7 @@ int sysdev_resume(void)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(sysdev_resume);
|
||||
|
||||
int __init system_bus_init(void)
|
||||
{
|
||||
|
|
|
@ -1730,7 +1730,7 @@ static int __init fd_test_drive_present( int drive )
|
|||
|
||||
timeout = jiffies + 2*HZ+HZ/2;
|
||||
while (time_before(jiffies, timeout))
|
||||
if (!(mfp.par_dt_reg & 0x20))
|
||||
if (!(st_mfp.par_dt_reg & 0x20))
|
||||
break;
|
||||
|
||||
status = FDC_READ( FDCREG_STATUS );
|
||||
|
@ -1747,7 +1747,7 @@ static int __init fd_test_drive_present( int drive )
|
|||
/* dummy seek command to make WP bit accessible */
|
||||
FDC_WRITE( FDCREG_DATA, 0 );
|
||||
FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK );
|
||||
while( mfp.par_dt_reg & 0x20 )
|
||||
while( st_mfp.par_dt_reg & 0x20 )
|
||||
;
|
||||
status = FDC_READ( FDCREG_STATUS );
|
||||
}
|
||||
|
|
|
@ -387,7 +387,7 @@ struct scc_port {
|
|||
/* The SCC needs 3.5 PCLK cycles recovery time between to register
|
||||
* accesses. PCLK runs with 8 MHz on an Atari, so this delay is 3.5 *
|
||||
* 125 ns = 437.5 ns. This is too short for udelay().
|
||||
* 10/16/95: A tstb mfp.par_dt_reg takes 600ns (sure?) and thus should be
|
||||
* 10/16/95: A tstb st_mfp.par_dt_reg takes 600ns (sure?) and thus should be
|
||||
* quite right
|
||||
*/
|
||||
|
||||
|
|
|
@ -1746,9 +1746,10 @@ static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
|
|||
sx_dprintk(SX_DEBUG_FIRMWARE, "returning type= %ld\n", rc);
|
||||
break;
|
||||
case SXIO_DO_RAMTEST:
|
||||
if (sx_initialized) /* Already initialized: better not ramtest the board. */
|
||||
if (sx_initialized) { /* Already initialized: better not ramtest the board. */
|
||||
rc = -EPERM;
|
||||
break;
|
||||
}
|
||||
if (IS_SX_BOARD(board)) {
|
||||
rc = do_memtest(board, 0, 0x7000);
|
||||
if (!rc)
|
||||
|
@ -1788,7 +1789,7 @@ static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
|
|||
nbytes - i : SX_CHUNK_SIZE)) {
|
||||
kfree(tmp);
|
||||
rc = -EFAULT;
|
||||
break;
|
||||
goto out;
|
||||
}
|
||||
memcpy_toio(board->base2 + offset + i, tmp,
|
||||
(i + SX_CHUNK_SIZE > nbytes) ?
|
||||
|
|
|
@ -1741,9 +1741,8 @@ out:
|
|||
* RETURNS:
|
||||
* Zero on success, errno on failure.
|
||||
*/
|
||||
void drm_fb_release(struct file *filp)
|
||||
void drm_fb_release(struct drm_file *priv)
|
||||
{
|
||||
struct drm_file *priv = filp->private_data;
|
||||
struct drm_device *dev = priv->minor->dev;
|
||||
struct drm_framebuffer *fb, *tfb;
|
||||
|
||||
|
|
|
@ -512,8 +512,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
|||
if (drm_mode_equal(&saved_mode, &crtc->mode)) {
|
||||
if (saved_x != crtc->x || saved_y != crtc->y ||
|
||||
depth_changed || bpp_changed) {
|
||||
crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
|
||||
old_fb);
|
||||
ret = !crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
|
||||
old_fb);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
@ -552,7 +552,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
|||
/* Set up the DPLL and any encoders state that needs to adjust or depend
|
||||
* on the DPLL.
|
||||
*/
|
||||
crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
|
||||
ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
|
||||
if (!ret)
|
||||
goto done;
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
|
||||
|
@ -752,6 +754,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
|
||||
set->x, set->y,
|
||||
old_fb)) {
|
||||
DRM_ERROR("failed to set mode on crtc %p\n",
|
||||
set->crtc);
|
||||
ret = -EINVAL;
|
||||
goto fail_set_mode;
|
||||
}
|
||||
|
@ -765,7 +769,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
old_fb = set->crtc->fb;
|
||||
if (set->crtc->fb != set->fb)
|
||||
set->crtc->fb = set->fb;
|
||||
crtc_funcs->mode_set_base(set->crtc, set->x, set->y, old_fb);
|
||||
ret = crtc_funcs->mode_set_base(set->crtc,
|
||||
set->x, set->y, old_fb);
|
||||
if (ret != 0)
|
||||
goto fail_set_mode;
|
||||
}
|
||||
|
||||
kfree(save_encoders);
|
||||
|
@ -775,8 +782,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
fail_set_mode:
|
||||
set->crtc->enabled = save_enabled;
|
||||
count = 0;
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (!connector->encoder)
|
||||
continue;
|
||||
|
||||
connector->encoder->crtc = save_crtcs[count++];
|
||||
}
|
||||
fail_no_encoder:
|
||||
kfree(save_crtcs);
|
||||
count = 0;
|
||||
|
|
|
@ -457,6 +457,9 @@ int drm_release(struct inode *inode, struct file *filp)
|
|||
if (dev->driver->driver_features & DRIVER_GEM)
|
||||
drm_gem_release(dev, file_priv);
|
||||
|
||||
if (dev->driver->driver_features & DRIVER_MODESET)
|
||||
drm_fb_release(file_priv);
|
||||
|
||||
mutex_lock(&dev->ctxlist_mutex);
|
||||
if (!list_empty(&dev->ctxlist)) {
|
||||
struct drm_ctx_list *pos, *n;
|
||||
|
|
|
@ -104,8 +104,8 @@ drm_gem_init(struct drm_device *dev)
|
|||
|
||||
if (drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
|
||||
DRM_FILE_PAGE_OFFSET_SIZE)) {
|
||||
drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
|
||||
drm_ht_remove(&mm->offset_hash);
|
||||
drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -295,35 +295,37 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
|
|||
return -EBADF;
|
||||
|
||||
again:
|
||||
if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0)
|
||||
return -ENOMEM;
|
||||
if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
spin_lock(&dev->object_name_lock);
|
||||
if (obj->name) {
|
||||
args->name = obj->name;
|
||||
if (!obj->name) {
|
||||
ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
|
||||
&obj->name);
|
||||
args->name = (uint64_t) obj->name;
|
||||
spin_unlock(&dev->object_name_lock);
|
||||
return 0;
|
||||
}
|
||||
ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
|
||||
&obj->name);
|
||||
spin_unlock(&dev->object_name_lock);
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
|
||||
if (ret != 0) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
/* Allocate a reference for the name table. */
|
||||
drm_gem_object_reference(obj);
|
||||
} else {
|
||||
args->name = (uint64_t) obj->name;
|
||||
spin_unlock(&dev->object_name_lock);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Leave the reference from the lookup around as the
|
||||
* name table now holds one
|
||||
*/
|
||||
args->name = (uint64_t) obj->name;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -448,6 +450,7 @@ drm_gem_object_handle_free(struct kref *kref)
|
|||
spin_lock(&dev->object_name_lock);
|
||||
if (obj->name) {
|
||||
idr_remove(&dev->object_name_idr, obj->name);
|
||||
obj->name = 0;
|
||||
spin_unlock(&dev->object_name_lock);
|
||||
/*
|
||||
* The object name held a reference to this object, drop
|
||||
|
@ -460,6 +463,26 @@ drm_gem_object_handle_free(struct kref *kref)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_gem_object_handle_free);
|
||||
|
||||
void drm_gem_vm_open(struct vm_area_struct *vma)
|
||||
{
|
||||
struct drm_gem_object *obj = vma->vm_private_data;
|
||||
|
||||
drm_gem_object_reference(obj);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_vm_open);
|
||||
|
||||
void drm_gem_vm_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct drm_gem_object *obj = vma->vm_private_data;
|
||||
struct drm_device *dev = obj->dev;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_vm_close);
|
||||
|
||||
|
||||
/**
|
||||
* drm_gem_mmap - memory map routine for GEM objects
|
||||
* @filp: DRM file pointer
|
||||
|
@ -521,6 +544,14 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
#endif
|
||||
vma->vm_page_prot = __pgprot(prot);
|
||||
|
||||
/* Take a ref for this mapping of the object, so that the fault
|
||||
* handler can dereference the mmap offset's pointer to the object.
|
||||
* This reference is cleaned up by the corresponding vm_close
|
||||
* (which should happen whether the vma was created by this call, or
|
||||
* by a vm_open due to mremap or partial unmap or whatever).
|
||||
*/
|
||||
drm_gem_object_reference(obj);
|
||||
|
||||
vma->vm_file = filp; /* Needed for drm_vm_open() */
|
||||
drm_vm_open_locked(vma);
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
|
|||
dev_priv->ring.map.flags = 0;
|
||||
dev_priv->ring.map.mtrr = 0;
|
||||
|
||||
drm_core_ioremap(&dev_priv->ring.map, dev);
|
||||
drm_core_ioremap_wc(&dev_priv->ring.map, dev);
|
||||
|
||||
if (dev_priv->ring.map.handle == NULL) {
|
||||
i915_dma_cleanup(dev);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "i915_drm.h"
|
||||
|
@ -66,6 +67,12 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
|||
|
||||
i915_save_state(dev);
|
||||
|
||||
/* If KMS is active, we do the leavevt stuff here */
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET) && i915_gem_idle(dev)) {
|
||||
dev_err(&dev->pdev->dev, "GEM idle failed, aborting suspend\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
intel_opregion_free(dev);
|
||||
|
||||
if (state.event == PM_EVENT_SUSPEND) {
|
||||
|
@ -79,6 +86,9 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
|||
|
||||
static int i915_resume(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret = 0;
|
||||
|
||||
pci_set_power_state(dev->pdev, PCI_D0);
|
||||
pci_restore_state(dev->pdev);
|
||||
if (pci_enable_device(dev->pdev))
|
||||
|
@ -89,11 +99,24 @@ static int i915_resume(struct drm_device *dev)
|
|||
|
||||
intel_opregion_init(dev);
|
||||
|
||||
return 0;
|
||||
/* KMS EnterVT equivalent */
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
dev_priv->mm.suspended = 0;
|
||||
|
||||
ret = i915_gem_init_ringbuffer(dev);
|
||||
if (ret != 0)
|
||||
ret = -1;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct vm_operations_struct i915_gem_vm_ops = {
|
||||
.fault = i915_gem_fault,
|
||||
.open = drm_gem_vm_open,
|
||||
.close = drm_gem_vm_close,
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
|
|
|
@ -184,6 +184,8 @@ typedef struct drm_i915_private {
|
|||
unsigned int lvds_dither:1;
|
||||
unsigned int lvds_vbt:1;
|
||||
unsigned int int_crt_support:1;
|
||||
unsigned int lvds_use_ssc:1;
|
||||
int lvds_ssc_freq;
|
||||
|
||||
struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
|
||||
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
|
||||
|
@ -616,6 +618,7 @@ 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,
|
||||
unsigned long end);
|
||||
int i915_gem_idle(struct drm_device *dev);
|
||||
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
|
||||
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
|
||||
int write);
|
||||
|
|
|
@ -34,10 +34,6 @@
|
|||
|
||||
#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
|
||||
|
||||
static void
|
||||
i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
|
||||
uint32_t read_domains,
|
||||
uint32_t write_domain);
|
||||
static void 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);
|
||||
|
@ -607,8 +603,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
case -EAGAIN:
|
||||
return VM_FAULT_OOM;
|
||||
case -EFAULT:
|
||||
case -EBUSY:
|
||||
DRM_ERROR("can't insert pfn?? fault or busy...\n");
|
||||
return VM_FAULT_SIGBUS;
|
||||
default:
|
||||
return VM_FAULT_NOPAGE;
|
||||
|
@ -684,6 +678,30 @@ out_free_list:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
i915_gem_free_mmap_offset(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev = obj->dev;
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
struct drm_gem_mm *mm = dev->mm_private;
|
||||
struct drm_map_list *list;
|
||||
|
||||
list = &obj->map_list;
|
||||
drm_ht_remove_item(&mm->offset_hash, &list->hash);
|
||||
|
||||
if (list->file_offset_node) {
|
||||
drm_mm_put_block(list->file_offset_node);
|
||||
list->file_offset_node = NULL;
|
||||
}
|
||||
|
||||
if (list->map) {
|
||||
drm_free(list->map, sizeof(struct drm_map), DRM_MEM_DRIVER);
|
||||
list->map = NULL;
|
||||
}
|
||||
|
||||
obj_priv->mmap_offset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_get_gtt_alignment - return required GTT alignment for an object
|
||||
* @obj: object to check
|
||||
|
@ -758,8 +776,11 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
|
|||
|
||||
if (!obj_priv->mmap_offset) {
|
||||
ret = i915_gem_create_mmap_offset(obj);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
args->offset = obj_priv->mmap_offset;
|
||||
|
@ -1996,30 +2017,28 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
|
|||
* drm_agp_chipset_flush
|
||||
*/
|
||||
static void
|
||||
i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
|
||||
uint32_t read_domains,
|
||||
uint32_t write_domain)
|
||||
i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev = obj->dev;
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
uint32_t invalidate_domains = 0;
|
||||
uint32_t flush_domains = 0;
|
||||
|
||||
BUG_ON(read_domains & I915_GEM_DOMAIN_CPU);
|
||||
BUG_ON(write_domain == I915_GEM_DOMAIN_CPU);
|
||||
BUG_ON(obj->pending_read_domains & I915_GEM_DOMAIN_CPU);
|
||||
BUG_ON(obj->pending_write_domain == I915_GEM_DOMAIN_CPU);
|
||||
|
||||
#if WATCH_BUF
|
||||
DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
|
||||
__func__, obj,
|
||||
obj->read_domains, read_domains,
|
||||
obj->write_domain, write_domain);
|
||||
obj->read_domains, obj->pending_read_domains,
|
||||
obj->write_domain, obj->pending_write_domain);
|
||||
#endif
|
||||
/*
|
||||
* If the object isn't moving to a new write domain,
|
||||
* let the object stay in multiple read domains
|
||||
*/
|
||||
if (write_domain == 0)
|
||||
read_domains |= obj->read_domains;
|
||||
if (obj->pending_write_domain == 0)
|
||||
obj->pending_read_domains |= obj->read_domains;
|
||||
else
|
||||
obj_priv->dirty = 1;
|
||||
|
||||
|
@ -2029,15 +2048,17 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
|
|||
* any read domains which differ from the old
|
||||
* write domain
|
||||
*/
|
||||
if (obj->write_domain && obj->write_domain != read_domains) {
|
||||
if (obj->write_domain &&
|
||||
obj->write_domain != obj->pending_read_domains) {
|
||||
flush_domains |= obj->write_domain;
|
||||
invalidate_domains |= read_domains & ~obj->write_domain;
|
||||
invalidate_domains |=
|
||||
obj->pending_read_domains & ~obj->write_domain;
|
||||
}
|
||||
/*
|
||||
* Invalidate any read caches which may have
|
||||
* stale data. That is, any new read domains.
|
||||
*/
|
||||
invalidate_domains |= read_domains & ~obj->read_domains;
|
||||
invalidate_domains |= obj->pending_read_domains & ~obj->read_domains;
|
||||
if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) {
|
||||
#if WATCH_BUF
|
||||
DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n",
|
||||
|
@ -2046,9 +2067,15 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
|
|||
i915_gem_clflush_object(obj);
|
||||
}
|
||||
|
||||
if ((write_domain | flush_domains) != 0)
|
||||
obj->write_domain = write_domain;
|
||||
obj->read_domains = read_domains;
|
||||
/* The actual obj->write_domain will be updated with
|
||||
* pending_write_domain after we emit the accumulated flush for all
|
||||
* of our domain changes in execbuffers (which clears objects'
|
||||
* write_domains). So if we have a current write domain that we
|
||||
* aren't changing, set pending_write_domain to that.
|
||||
*/
|
||||
if (flush_domains == 0 && obj->pending_write_domain == 0)
|
||||
obj->pending_write_domain = obj->write_domain;
|
||||
obj->read_domains = obj->pending_read_domains;
|
||||
|
||||
dev->invalidate_domains |= invalidate_domains;
|
||||
dev->flush_domains |= flush_domains;
|
||||
|
@ -2251,6 +2278,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
|
|||
(int) reloc.offset,
|
||||
reloc.read_domains,
|
||||
reloc.write_domain);
|
||||
drm_gem_object_unreference(target_obj);
|
||||
i915_gem_object_unpin(obj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -2480,13 +2509,15 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
|||
if (dev_priv->mm.wedged) {
|
||||
DRM_ERROR("Execbuf while wedged\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto pre_mutex_err;
|
||||
}
|
||||
|
||||
if (dev_priv->mm.suspended) {
|
||||
DRM_ERROR("Execbuf while VT-switched.\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
goto pre_mutex_err;
|
||||
}
|
||||
|
||||
/* Look up object handles */
|
||||
|
@ -2554,9 +2585,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
|||
struct drm_gem_object *obj = object_list[i];
|
||||
|
||||
/* Compute new gpu domains and update invalidate/flush */
|
||||
i915_gem_object_set_to_gpu_domain(obj,
|
||||
obj->pending_read_domains,
|
||||
obj->pending_write_domain);
|
||||
i915_gem_object_set_to_gpu_domain(obj);
|
||||
}
|
||||
|
||||
i915_verify_inactive(dev, __FILE__, __LINE__);
|
||||
|
@ -2575,6 +2604,12 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
|||
(void)i915_add_request(dev, dev->flush_domains);
|
||||
}
|
||||
|
||||
for (i = 0; i < args->buffer_count; i++) {
|
||||
struct drm_gem_object *obj = object_list[i];
|
||||
|
||||
obj->write_domain = obj->pending_write_domain;
|
||||
}
|
||||
|
||||
i915_verify_inactive(dev, __FILE__, __LINE__);
|
||||
|
||||
#if WATCH_COHERENCY
|
||||
|
@ -2632,15 +2667,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
|||
|
||||
i915_verify_inactive(dev, __FILE__, __LINE__);
|
||||
|
||||
/* Copy the new buffer offsets back to the user's exec list. */
|
||||
ret = copy_to_user((struct drm_i915_relocation_entry __user *)
|
||||
(uintptr_t) args->buffers_ptr,
|
||||
exec_list,
|
||||
sizeof(*exec_list) * args->buffer_count);
|
||||
if (ret)
|
||||
DRM_ERROR("failed to copy %d exec entries "
|
||||
"back to user (%d)\n",
|
||||
args->buffer_count, ret);
|
||||
err:
|
||||
for (i = 0; i < pinned; i++)
|
||||
i915_gem_object_unpin(object_list[i]);
|
||||
|
@ -2650,6 +2676,18 @@ err:
|
|||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (!ret) {
|
||||
/* Copy the new buffer offsets back to the user's exec list. */
|
||||
ret = copy_to_user((struct drm_i915_relocation_entry __user *)
|
||||
(uintptr_t) args->buffers_ptr,
|
||||
exec_list,
|
||||
sizeof(*exec_list) * args->buffer_count);
|
||||
if (ret)
|
||||
DRM_ERROR("failed to copy %d exec entries "
|
||||
"back to user (%d)\n",
|
||||
args->buffer_count, ret);
|
||||
}
|
||||
|
||||
pre_mutex_err:
|
||||
drm_free(object_list, sizeof(*object_list) * args->buffer_count,
|
||||
DRM_MEM_DRIVER);
|
||||
|
@ -2753,6 +2791,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
|
|||
if (obj_priv->pin_filp != NULL && obj_priv->pin_filp != file_priv) {
|
||||
DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n",
|
||||
args->handle);
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -2833,6 +2872,13 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
|
|||
return -EBADF;
|
||||
}
|
||||
|
||||
/* Update the active list for the hardware's current position.
|
||||
* Otherwise this only updates on a delayed timer or when irqs are
|
||||
* actually unmasked, and our working set ends up being larger than
|
||||
* required.
|
||||
*/
|
||||
i915_gem_retire_requests(dev);
|
||||
|
||||
obj_priv = obj->driver_private;
|
||||
/* Don't count being on the flushing list against the object being
|
||||
* done. Otherwise, a buffer left on the flushing list but not getting
|
||||
|
@ -2885,9 +2931,6 @@ int i915_gem_init_object(struct drm_gem_object *obj)
|
|||
void i915_gem_free_object(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev = obj->dev;
|
||||
struct drm_gem_mm *mm = dev->mm_private;
|
||||
struct drm_map_list *list;
|
||||
struct drm_map *map;
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
|
||||
while (obj_priv->pin_count > 0)
|
||||
|
@ -2898,19 +2941,7 @@ void i915_gem_free_object(struct drm_gem_object *obj)
|
|||
|
||||
i915_gem_object_unbind(obj);
|
||||
|
||||
list = &obj->map_list;
|
||||
drm_ht_remove_item(&mm->offset_hash, &list->hash);
|
||||
|
||||
if (list->file_offset_node) {
|
||||
drm_mm_put_block(list->file_offset_node);
|
||||
list->file_offset_node = NULL;
|
||||
}
|
||||
|
||||
map = list->map;
|
||||
if (map) {
|
||||
drm_free(map, sizeof(*map), DRM_MEM_DRIVER);
|
||||
list->map = NULL;
|
||||
}
|
||||
i915_gem_free_mmap_offset(obj);
|
||||
|
||||
drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER);
|
||||
drm_free(obj->driver_private, 1, DRM_MEM_DRIVER);
|
||||
|
@ -2949,7 +2980,7 @@ i915_gem_evict_from_list(struct drm_device *dev, struct list_head *head)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
i915_gem_idle(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
@ -3095,6 +3126,7 @@ i915_gem_init_hws(struct drm_device *dev)
|
|||
if (dev_priv->hw_status_page == NULL) {
|
||||
DRM_ERROR("Failed to map status page.\n");
|
||||
memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
|
||||
i915_gem_object_unpin(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -3107,6 +3139,31 @@ i915_gem_init_hws(struct drm_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
i915_gem_cleanup_hws(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
|
||||
if (dev_priv->hws_obj == NULL)
|
||||
return;
|
||||
|
||||
obj = dev_priv->hws_obj;
|
||||
obj_priv = obj->driver_private;
|
||||
|
||||
kunmap(obj_priv->page_list[0]);
|
||||
i915_gem_object_unpin(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
dev_priv->hws_obj = NULL;
|
||||
|
||||
memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
|
||||
dev_priv->hw_status_page = NULL;
|
||||
|
||||
/* Write high address into HWS_PGA when disabling. */
|
||||
I915_WRITE(HWS_PGA, 0x1ffff000);
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_init_ringbuffer(struct drm_device *dev)
|
||||
{
|
||||
|
@ -3124,6 +3181,7 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
|
|||
obj = drm_gem_object_alloc(dev, 128 * 1024);
|
||||
if (obj == NULL) {
|
||||
DRM_ERROR("Failed to allocate ringbuffer\n");
|
||||
i915_gem_cleanup_hws(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
obj_priv = obj->driver_private;
|
||||
|
@ -3131,6 +3189,7 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
|
|||
ret = i915_gem_object_pin(obj, 4096);
|
||||
if (ret != 0) {
|
||||
drm_gem_object_unreference(obj);
|
||||
i915_gem_cleanup_hws(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3148,7 +3207,9 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
|
|||
if (ring->map.handle == NULL) {
|
||||
DRM_ERROR("Failed to map ringbuffer.\n");
|
||||
memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
|
||||
i915_gem_object_unpin(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
i915_gem_cleanup_hws(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
ring->ring_obj = obj;
|
||||
|
@ -3228,20 +3289,7 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
|
|||
dev_priv->ring.ring_obj = NULL;
|
||||
memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
|
||||
|
||||
if (dev_priv->hws_obj != NULL) {
|
||||
struct drm_gem_object *obj = dev_priv->hws_obj;
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
|
||||
kunmap(obj_priv->page_list[0]);
|
||||
i915_gem_object_unpin(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
dev_priv->hws_obj = NULL;
|
||||
memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
|
||||
dev_priv->hw_status_page = NULL;
|
||||
|
||||
/* Write high address into HWS_PGA when disabling. */
|
||||
I915_WRITE(HWS_PGA, 0x1ffff000);
|
||||
}
|
||||
i915_gem_cleanup_hws(dev);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -299,9 +299,8 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
|
|||
}
|
||||
obj_priv->stride = args->stride;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -340,9 +339,8 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
|
|||
DRM_ERROR("unknown tiling mode\n");
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -135,6 +135,14 @@ parse_general_features(struct drm_i915_private *dev_priv,
|
|||
if (general) {
|
||||
dev_priv->int_tv_support = general->int_tv_support;
|
||||
dev_priv->int_crt_support = general->int_crt_support;
|
||||
dev_priv->lvds_use_ssc = general->enable_ssc;
|
||||
|
||||
if (dev_priv->lvds_use_ssc) {
|
||||
if (IS_I855(dev_priv->dev))
|
||||
dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48;
|
||||
else
|
||||
dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,12 +90,12 @@ typedef struct {
|
|||
#define I9XX_DOT_MAX 400000
|
||||
#define I9XX_VCO_MIN 1400000
|
||||
#define I9XX_VCO_MAX 2800000
|
||||
#define I9XX_N_MIN 3
|
||||
#define I9XX_N_MAX 8
|
||||
#define I9XX_N_MIN 1
|
||||
#define I9XX_N_MAX 6
|
||||
#define I9XX_M_MIN 70
|
||||
#define I9XX_M_MAX 120
|
||||
#define I9XX_M1_MIN 10
|
||||
#define I9XX_M1_MAX 20
|
||||
#define I9XX_M1_MAX 22
|
||||
#define I9XX_M2_MIN 5
|
||||
#define I9XX_M2_MAX 9
|
||||
#define I9XX_P_SDVO_DAC_MIN 5
|
||||
|
@ -189,9 +189,7 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
|
|||
return limit;
|
||||
}
|
||||
|
||||
/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
|
||||
|
||||
static void i8xx_clock(int refclk, intel_clock_t *clock)
|
||||
static void intel_clock(int refclk, intel_clock_t *clock)
|
||||
{
|
||||
clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
|
||||
clock->p = clock->p1 * clock->p2;
|
||||
|
@ -199,25 +197,6 @@ static void i8xx_clock(int refclk, intel_clock_t *clock)
|
|||
clock->dot = clock->vco / clock->p;
|
||||
}
|
||||
|
||||
/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */
|
||||
|
||||
static void i9xx_clock(int refclk, intel_clock_t *clock)
|
||||
{
|
||||
clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
|
||||
clock->p = clock->p1 * clock->p2;
|
||||
clock->vco = refclk * clock->m / (clock->n + 2);
|
||||
clock->dot = clock->vco / clock->p;
|
||||
}
|
||||
|
||||
static void intel_clock(struct drm_device *dev, int refclk,
|
||||
intel_clock_t *clock)
|
||||
{
|
||||
if (IS_I9XX(dev))
|
||||
i9xx_clock (refclk, clock);
|
||||
else
|
||||
i8xx_clock (refclk, clock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether any output on the specified pipe is of the specified type
|
||||
*/
|
||||
|
@ -238,7 +217,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
|
|||
return false;
|
||||
}
|
||||
|
||||
#define INTELPllInvalid(s) { /* ErrorF (s) */; return false; }
|
||||
#define INTELPllInvalid(s) do { DRM_DEBUG(s); return false; } while (0)
|
||||
/**
|
||||
* Returns whether the given set of divisors are valid for a given refclk with
|
||||
* the given connectors.
|
||||
|
@ -318,7 +297,7 @@ static bool intel_find_best_PLL(struct drm_crtc *crtc, int target,
|
|||
clock.p1 <= limit->p1.max; clock.p1++) {
|
||||
int this_err;
|
||||
|
||||
intel_clock(dev, refclk, &clock);
|
||||
intel_clock(refclk, &clock);
|
||||
|
||||
if (!intel_PLL_is_valid(crtc, &clock))
|
||||
continue;
|
||||
|
@ -343,7 +322,7 @@ intel_wait_for_vblank(struct drm_device *dev)
|
|||
udelay(20000);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
|
@ -361,11 +340,21 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
|
||||
int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
|
||||
u32 dspcntr, alignment;
|
||||
int ret;
|
||||
|
||||
/* no fb bound */
|
||||
if (!crtc->fb) {
|
||||
DRM_DEBUG("No FB bound\n");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
intel_fb = to_intel_framebuffer(crtc->fb);
|
||||
|
@ -377,28 +366,30 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
alignment = 64 * 1024;
|
||||
break;
|
||||
case I915_TILING_X:
|
||||
if (IS_I9XX(dev))
|
||||
alignment = 1024 * 1024;
|
||||
else
|
||||
alignment = 512 * 1024;
|
||||
/* pin() will align the object as required by fence */
|
||||
alignment = 0;
|
||||
break;
|
||||
case I915_TILING_Y:
|
||||
/* FIXME: Is this true? */
|
||||
DRM_ERROR("Y tiled not allowed for scan out buffers\n");
|
||||
return;
|
||||
return -EINVAL;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (i915_gem_object_pin(intel_fb->obj, alignment))
|
||||
return;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = i915_gem_object_pin(intel_fb->obj, alignment);
|
||||
if (ret != 0) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1);
|
||||
|
||||
Start = obj_priv->gtt_offset;
|
||||
Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
|
||||
|
||||
I915_WRITE(dspstride, crtc->fb->pitch);
|
||||
ret = i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1);
|
||||
if (ret != 0) {
|
||||
i915_gem_object_unpin(intel_fb->obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dspcntr = I915_READ(dspcntr_reg);
|
||||
/* Mask out pixel format bits in case we change it */
|
||||
|
@ -419,11 +410,17 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
break;
|
||||
default:
|
||||
DRM_ERROR("Unknown color depth\n");
|
||||
return;
|
||||
i915_gem_object_unpin(intel_fb->obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
I915_WRITE(dspcntr_reg, dspcntr);
|
||||
|
||||
Start = obj_priv->gtt_offset;
|
||||
Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
|
||||
|
||||
DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
|
||||
I915_WRITE(dspstride, crtc->fb->pitch);
|
||||
if (IS_I965G(dev)) {
|
||||
I915_WRITE(dspbase, Offset);
|
||||
I915_READ(dspbase);
|
||||
|
@ -440,27 +437,24 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
intel_fb = to_intel_framebuffer(old_fb);
|
||||
i915_gem_object_unpin(intel_fb->obj);
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (!dev->primary->master)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
master_priv = dev->primary->master->driver_priv;
|
||||
if (!master_priv->sarea_priv)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
master_priv->sarea_priv->pipeA_x = x;
|
||||
master_priv->sarea_priv->pipeA_y = y;
|
||||
break;
|
||||
case 1:
|
||||
if (pipe) {
|
||||
master_priv->sarea_priv->pipeB_x = x;
|
||||
master_priv->sarea_priv->pipeB_y = y;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
|
||||
break;
|
||||
} else {
|
||||
master_priv->sarea_priv->pipeA_x = x;
|
||||
master_priv->sarea_priv->pipeA_y = y;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -708,11 +702,11 @@ static int intel_panel_fitter_pipe (struct drm_device *dev)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
@ -732,13 +726,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
|
||||
int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
|
||||
int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
|
||||
int refclk;
|
||||
int refclk, num_outputs = 0;
|
||||
intel_clock_t clock;
|
||||
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
|
||||
bool ok, is_sdvo = false, is_dvo = false;
|
||||
bool is_crt = false, is_lvds = false, is_tv = false;
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
struct drm_connector *connector;
|
||||
int ret;
|
||||
|
||||
drm_vblank_pre_modeset(dev, pipe);
|
||||
|
||||
|
@ -768,9 +763,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
is_crt = true;
|
||||
break;
|
||||
}
|
||||
|
||||
num_outputs++;
|
||||
}
|
||||
|
||||
if (IS_I9XX(dev)) {
|
||||
if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2) {
|
||||
refclk = dev_priv->lvds_ssc_freq * 1000;
|
||||
DRM_DEBUG("using SSC reference clock of %d MHz\n", refclk / 1000);
|
||||
} else if (IS_I9XX(dev)) {
|
||||
refclk = 96000;
|
||||
} else {
|
||||
refclk = 48000;
|
||||
|
@ -779,7 +779,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock);
|
||||
if (!ok) {
|
||||
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
|
||||
|
@ -829,11 +829,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
}
|
||||
}
|
||||
|
||||
if (is_tv) {
|
||||
if (is_sdvo && is_tv)
|
||||
dpll |= PLL_REF_INPUT_TVCLKINBC;
|
||||
else if (is_tv)
|
||||
/* XXX: just matching BIOS for now */
|
||||
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
|
||||
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
|
||||
dpll |= 3;
|
||||
}
|
||||
else if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2)
|
||||
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
|
||||
else
|
||||
dpll |= PLL_REF_INPUT_DREFCLK;
|
||||
|
||||
|
@ -950,9 +953,13 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
I915_WRITE(dspcntr_reg, dspcntr);
|
||||
|
||||
/* Flush the plane changes */
|
||||
intel_pipe_set_base(crtc, x, y, old_fb);
|
||||
ret = intel_pipe_set_base(crtc, x, y, old_fb);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
drm_vblank_post_modeset(dev, pipe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Loads the palette/gamma unit for the CRTC with the prepared values */
|
||||
|
@ -1001,6 +1008,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
temp = CURSOR_MODE_DISABLE;
|
||||
addr = 0;
|
||||
bo = NULL;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
|
@ -1023,18 +1031,19 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
}
|
||||
|
||||
/* we only need to pin inside GTT if cursor is non-phy */
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (!dev_priv->cursor_needs_physical) {
|
||||
ret = i915_gem_object_pin(bo, PAGE_SIZE);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to pin cursor bo\n");
|
||||
goto fail;
|
||||
goto fail_locked;
|
||||
}
|
||||
addr = obj_priv->gtt_offset;
|
||||
} else {
|
||||
ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to attach phys object\n");
|
||||
goto fail;
|
||||
goto fail_locked;
|
||||
}
|
||||
addr = obj_priv->phys_obj->handle->busaddr;
|
||||
}
|
||||
|
@ -1054,10 +1063,9 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
|
||||
} else
|
||||
i915_gem_object_unpin(intel_crtc->cursor_bo);
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_gem_object_unreference(intel_crtc->cursor_bo);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
intel_crtc->cursor_addr = addr;
|
||||
intel_crtc->cursor_bo = bo;
|
||||
|
@ -1065,6 +1073,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
return 0;
|
||||
fail:
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
fail_locked:
|
||||
drm_gem_object_unreference(bo);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
|
@ -1292,7 +1301,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
|
|||
}
|
||||
|
||||
/* XXX: Handle the 100Mhz refclk */
|
||||
i9xx_clock(96000, &clock);
|
||||
intel_clock(96000, &clock);
|
||||
} else {
|
||||
bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
|
||||
|
||||
|
@ -1304,9 +1313,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
|
|||
if ((dpll & PLL_REF_INPUT_MASK) ==
|
||||
PLLB_REF_INPUT_SPREADSPECTRUMIN) {
|
||||
/* XXX: might not be 66MHz */
|
||||
i8xx_clock(66000, &clock);
|
||||
intel_clock(66000, &clock);
|
||||
} else
|
||||
i8xx_clock(48000, &clock);
|
||||
intel_clock(48000, &clock);
|
||||
} else {
|
||||
if (dpll & PLL_P1_DIVIDE_BY_TWO)
|
||||
clock.p1 = 2;
|
||||
|
@ -1319,7 +1328,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
|
|||
else
|
||||
clock.p2 = 2;
|
||||
|
||||
i8xx_clock(48000, &clock);
|
||||
intel_clock(48000, &clock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1598,7 +1607,9 @@ intel_user_framebuffer_create(struct drm_device *dev,
|
|||
|
||||
ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj);
|
||||
if (ret) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -473,7 +473,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
|||
ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to allocate fb.\n");
|
||||
goto out_unref;
|
||||
goto out_unpin;
|
||||
}
|
||||
|
||||
list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
|
||||
|
@ -484,7 +484,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
|||
info = framebuffer_alloc(sizeof(struct intelfb_par), device);
|
||||
if (!info) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unref;
|
||||
goto out_unpin;
|
||||
}
|
||||
|
||||
par = info->par;
|
||||
|
@ -513,7 +513,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
|||
size);
|
||||
if (!info->screen_base) {
|
||||
ret = -ENOSPC;
|
||||
goto out_unref;
|
||||
goto out_unpin;
|
||||
}
|
||||
info->screen_size = size;
|
||||
|
||||
|
@ -608,6 +608,8 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
|||
mutex_unlock(&dev->struct_mutex);
|
||||
return 0;
|
||||
|
||||
out_unpin:
|
||||
i915_gem_object_unpin(fbo);
|
||||
out_unref:
|
||||
drm_gem_object_unreference(fbo);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
|
|
@ -481,8 +481,6 @@ void intel_lvds_init(struct drm_device *dev)
|
|||
if (dev_priv->panel_fixed_mode) {
|
||||
dev_priv->panel_fixed_mode->type |=
|
||||
DRM_MODE_TYPE_PREFERRED;
|
||||
drm_mode_probed_add(connector,
|
||||
dev_priv->panel_fixed_mode);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,7 +193,7 @@ static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
|
|||
|
||||
#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
|
||||
/** Mapping of command numbers to names, for debug output */
|
||||
const static struct _sdvo_cmd_name {
|
||||
static const struct _sdvo_cmd_name {
|
||||
u8 cmd;
|
||||
char *name;
|
||||
} sdvo_cmd_names[] = {
|
||||
|
|
|
@ -411,7 +411,7 @@ struct tv_mode {
|
|||
* These values account for -1s required.
|
||||
*/
|
||||
|
||||
const static struct tv_mode tv_modes[] = {
|
||||
static const struct tv_mode tv_modes[] = {
|
||||
{
|
||||
.name = "NTSC-M",
|
||||
.clock = 107520,
|
||||
|
|
|
@ -557,8 +557,10 @@ static int radeon_do_engine_reset(struct drm_device * dev)
|
|||
}
|
||||
|
||||
static void radeon_cp_init_ring_buffer(struct drm_device * dev,
|
||||
drm_radeon_private_t * dev_priv)
|
||||
drm_radeon_private_t *dev_priv,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_radeon_master_private *master_priv;
|
||||
u32 ring_start, cur_read_ptr;
|
||||
u32 tmp;
|
||||
|
||||
|
@ -677,6 +679,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
|
|||
dev_priv->scratch[2] = 0;
|
||||
RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0);
|
||||
|
||||
/* reset sarea copies of these */
|
||||
master_priv = file_priv->master->driver_priv;
|
||||
if (master_priv->sarea_priv) {
|
||||
master_priv->sarea_priv->last_frame = 0;
|
||||
master_priv->sarea_priv->last_dispatch = 0;
|
||||
master_priv->sarea_priv->last_clear = 0;
|
||||
}
|
||||
|
||||
radeon_do_wait_for_idle(dev_priv);
|
||||
|
||||
/* Sync everything up */
|
||||
|
@ -1215,7 +1225,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
|
|||
}
|
||||
|
||||
radeon_cp_load_microcode(dev_priv);
|
||||
radeon_cp_init_ring_buffer(dev, dev_priv);
|
||||
radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
|
||||
|
||||
dev_priv->last_buf = 0;
|
||||
|
||||
|
@ -1281,7 +1291,7 @@ static int radeon_do_cleanup_cp(struct drm_device * dev)
|
|||
*
|
||||
* Charl P. Botha <http://cpbotha.net>
|
||||
*/
|
||||
static int radeon_do_resume_cp(struct drm_device * dev)
|
||||
static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_priv)
|
||||
{
|
||||
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
|
@ -1304,7 +1314,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
|
|||
}
|
||||
|
||||
radeon_cp_load_microcode(dev_priv);
|
||||
radeon_cp_init_ring_buffer(dev, dev_priv);
|
||||
radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
|
||||
|
||||
radeon_do_engine_reset(dev);
|
||||
radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
|
||||
|
@ -1479,8 +1489,7 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri
|
|||
*/
|
||||
int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
|
||||
return radeon_do_resume_cp(dev);
|
||||
return radeon_do_resume_cp(dev, file_priv);
|
||||
}
|
||||
|
||||
int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
|
|
|
@ -84,7 +84,7 @@ parport_atari_frob_control(struct parport *p, unsigned char mask,
|
|||
static unsigned char
|
||||
parport_atari_read_status(struct parport *p)
|
||||
{
|
||||
return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
|
||||
return ((st_mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
|
||||
PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
|
||||
}
|
||||
|
||||
|
@ -193,9 +193,9 @@ static int __init parport_atari_init(void)
|
|||
sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
|
||||
local_irq_restore(flags);
|
||||
/* MFP port I0 as input. */
|
||||
mfp.data_dir &= ~1;
|
||||
st_mfp.data_dir &= ~1;
|
||||
/* MFP port I0 interrupt on high->low edge. */
|
||||
mfp.active_edge &= ~1;
|
||||
st_mfp.active_edge &= ~1;
|
||||
p = parport_register_port((unsigned long)&sound_ym.wd_data,
|
||||
IRQ_MFP_BUSY, PARPORT_DMA_NONE,
|
||||
&parport_atari_ops);
|
||||
|
|
|
@ -166,6 +166,7 @@ struct fujitsu_hotkey_t {
|
|||
struct platform_device *pf_device;
|
||||
struct kfifo *fifo;
|
||||
spinlock_t fifo_lock;
|
||||
int rfkill_supported;
|
||||
int rfkill_state;
|
||||
int logolamp_registered;
|
||||
int kblamps_registered;
|
||||
|
@ -526,7 +527,7 @@ static ssize_t
|
|||
show_lid_state(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
|
||||
if (!(fujitsu_hotkey->rfkill_supported & 0x100))
|
||||
return sprintf(buf, "unknown\n");
|
||||
if (fujitsu_hotkey->rfkill_state & 0x100)
|
||||
return sprintf(buf, "open\n");
|
||||
|
@ -538,7 +539,7 @@ static ssize_t
|
|||
show_dock_state(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
|
||||
if (!(fujitsu_hotkey->rfkill_supported & 0x200))
|
||||
return sprintf(buf, "unknown\n");
|
||||
if (fujitsu_hotkey->rfkill_state & 0x200)
|
||||
return sprintf(buf, "docked\n");
|
||||
|
@ -550,7 +551,7 @@ static ssize_t
|
|||
show_radios_state(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
|
||||
if (!(fujitsu_hotkey->rfkill_supported & 0x20))
|
||||
return sprintf(buf, "unknown\n");
|
||||
if (fujitsu_hotkey->rfkill_state & 0x20)
|
||||
return sprintf(buf, "on\n");
|
||||
|
@ -928,8 +929,17 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
|
|||
; /* No action, result is discarded */
|
||||
vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
|
||||
|
||||
fujitsu_hotkey->rfkill_state =
|
||||
call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
|
||||
fujitsu_hotkey->rfkill_supported =
|
||||
call_fext_func(FUNC_RFKILL, 0x0, 0x0, 0x0);
|
||||
|
||||
/* Make sure our bitmask of supported functions is cleared if the
|
||||
RFKILL function block is not implemented, like on the S7020. */
|
||||
if (fujitsu_hotkey->rfkill_supported == UNSUPPORTED_CMD)
|
||||
fujitsu_hotkey->rfkill_supported = 0;
|
||||
|
||||
if (fujitsu_hotkey->rfkill_supported)
|
||||
fujitsu_hotkey->rfkill_state =
|
||||
call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
|
||||
|
||||
/* Suspect this is a keymap of the application panel, print it */
|
||||
printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n",
|
||||
|
@ -1005,8 +1015,9 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
|
|||
|
||||
input = fujitsu_hotkey->input;
|
||||
|
||||
fujitsu_hotkey->rfkill_state =
|
||||
call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
|
||||
if (fujitsu_hotkey->rfkill_supported)
|
||||
fujitsu_hotkey->rfkill_state =
|
||||
call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
|
||||
|
||||
switch (event) {
|
||||
case ACPI_FUJITSU_NOTIFY_CODE1:
|
||||
|
|
|
@ -1573,9 +1573,6 @@ static int ibmvfc_queuecommand(struct scsi_cmnd *cmnd,
|
|||
vfc_cmd->resp_len = sizeof(vfc_cmd->rsp);
|
||||
vfc_cmd->cancel_key = (unsigned long)cmnd->device->hostdata;
|
||||
vfc_cmd->tgt_scsi_id = rport->port_id;
|
||||
if ((rport->supported_classes & FC_COS_CLASS3) &&
|
||||
(fc_host_supported_classes(vhost->host) & FC_COS_CLASS3))
|
||||
vfc_cmd->flags = IBMVFC_CLASS_3_ERR;
|
||||
vfc_cmd->iu.xfer_len = scsi_bufflen(cmnd);
|
||||
int_to_scsilun(cmnd->device->lun, &vfc_cmd->iu.lun);
|
||||
memcpy(vfc_cmd->iu.cdb, cmnd->cmnd, cmnd->cmd_len);
|
||||
|
@ -3266,6 +3263,7 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(tgt, 0, sizeof(*tgt));
|
||||
tgt->scsi_id = scsi_id;
|
||||
tgt->new_scsi_id = scsi_id;
|
||||
tgt->vhost = vhost;
|
||||
|
@ -3576,9 +3574,18 @@ static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events)
|
|||
static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
|
||||
{
|
||||
struct ibmvfc_host *vhost = tgt->vhost;
|
||||
struct fc_rport *rport;
|
||||
struct fc_rport *rport = tgt->rport;
|
||||
unsigned long flags;
|
||||
|
||||
if (rport) {
|
||||
tgt_dbg(tgt, "Setting rport roles\n");
|
||||
fc_remote_port_rolechg(rport, tgt->ids.roles);
|
||||
spin_lock_irqsave(vhost->host->host_lock, flags);
|
||||
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
|
||||
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
tgt_dbg(tgt, "Adding rport\n");
|
||||
rport = fc_remote_port_add(vhost->host, 0, &tgt->ids);
|
||||
spin_lock_irqsave(vhost->host->host_lock, flags);
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#define IBMVFC_DRIVER_VERSION "1.0.4"
|
||||
#define IBMVFC_DRIVER_DATE "(November 14, 2008)"
|
||||
|
||||
#define IBMVFC_DEFAULT_TIMEOUT 15
|
||||
#define IBMVFC_DEFAULT_TIMEOUT 60
|
||||
#define IBMVFC_INIT_TIMEOUT 120
|
||||
#define IBMVFC_MAX_REQUESTS_DEFAULT 100
|
||||
|
||||
|
|
|
@ -432,6 +432,7 @@ static int map_sg_data(struct scsi_cmnd *cmd,
|
|||
sdev_printk(KERN_ERR, cmd->device,
|
||||
"Can't allocate memory "
|
||||
"for indirect table\n");
|
||||
scsi_dma_unmap(cmd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1998,6 +1998,8 @@ int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev)
|
|||
if (!shost->can_queue)
|
||||
shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX;
|
||||
|
||||
if (!shost->transportt->eh_timed_out)
|
||||
shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
|
||||
return scsi_add_host(shost, pdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_host_add);
|
||||
|
@ -2020,7 +2022,6 @@ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
|
|||
shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size);
|
||||
if (!shost)
|
||||
return NULL;
|
||||
shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
|
||||
|
||||
if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
|
||||
if (qdepth != 0)
|
||||
|
|
|
@ -5258,6 +5258,7 @@ lpfc_send_els_event(struct lpfc_vport *vport,
|
|||
sizeof(struct lpfc_name));
|
||||
break;
|
||||
default:
|
||||
kfree(els_data);
|
||||
return;
|
||||
}
|
||||
memcpy(els_data->wwpn, &ndlp->nlp_portname, sizeof(struct lpfc_name));
|
||||
|
|
|
@ -1265,13 +1265,6 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
|
|||
test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags))
|
||||
msleep(1000);
|
||||
|
||||
if (ha->mqenable) {
|
||||
if (qla25xx_delete_queues(vha, 0) != QLA_SUCCESS)
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Queue delete failed.\n");
|
||||
vha->req_ques[0] = ha->req_q_map[0]->id;
|
||||
}
|
||||
|
||||
qla24xx_disable_vp(vha);
|
||||
|
||||
fc_remove_host(vha->host);
|
||||
|
@ -1293,6 +1286,12 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
|
|||
vha->host_no, vha->vp_idx, vha));
|
||||
}
|
||||
|
||||
if (ha->mqenable) {
|
||||
if (qla25xx_delete_queues(vha, 0) != QLA_SUCCESS)
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Queue delete failed.\n");
|
||||
}
|
||||
|
||||
scsi_host_put(vha->host);
|
||||
qla_printk(KERN_INFO, ha, "vport %d deleted\n", id);
|
||||
return 0;
|
||||
|
|
|
@ -2135,6 +2135,7 @@ struct qla_msix_entry {
|
|||
/* Work events. */
|
||||
enum qla_work_type {
|
||||
QLA_EVT_AEN,
|
||||
QLA_EVT_IDC_ACK,
|
||||
};
|
||||
|
||||
|
||||
|
@ -2149,6 +2150,10 @@ struct qla_work_evt {
|
|||
enum fc_host_event_code code;
|
||||
u32 data;
|
||||
} aen;
|
||||
struct {
|
||||
#define QLA_IDC_ACK_REGS 7
|
||||
uint16_t mb[QLA_IDC_ACK_REGS];
|
||||
} idc_ack;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ static char *qla2x00_model_name[QLA_MODEL_NAMES*2] = {
|
|||
"QLA2462", "Sun PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x141 */
|
||||
"QLE2460", "Sun PCI-Express to 2Gb FC, Single Channel", /* 0x142 */
|
||||
"QLE2462", "Sun PCI-Express to 4Gb FC, Single Channel", /* 0x143 */
|
||||
"QEM2462" "Server I/O Module 4Gb FC, Dual Channel", /* 0x144 */
|
||||
"QEM2462", "Server I/O Module 4Gb FC, Dual Channel", /* 0x144 */
|
||||
"QLE2440", "PCI-Express to 4Gb FC, Single Channel", /* 0x145 */
|
||||
"QLE2464", "PCI-Express to 4Gb FC, Quad Channel", /* 0x146 */
|
||||
"QLA2440", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x147 */
|
||||
|
|
|
@ -1402,6 +1402,8 @@ struct access_chip_rsp_84xx {
|
|||
#define MBA_IDC_NOTIFY 0x8101
|
||||
#define MBA_IDC_TIME_EXT 0x8102
|
||||
|
||||
#define MBC_IDC_ACK 0x101
|
||||
|
||||
struct nvram_81xx {
|
||||
/* NVRAM header. */
|
||||
uint8_t id[4];
|
||||
|
|
|
@ -72,6 +72,7 @@ extern int qla2x00_loop_reset(scsi_qla_host_t *);
|
|||
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
|
||||
extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum
|
||||
fc_host_event_code, u32);
|
||||
extern int qla2x00_post_idc_ack_work(struct scsi_qla_host *, uint16_t *);
|
||||
|
||||
extern void qla2x00_abort_fcport_cmds(fc_port_t *);
|
||||
extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *,
|
||||
|
@ -266,6 +267,8 @@ qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
|
|||
|
||||
extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *);
|
||||
|
||||
extern int qla81xx_idc_ack(scsi_qla_host_t *, uint16_t *);
|
||||
|
||||
/*
|
||||
* Global Function Prototypes in qla_isr.c source file.
|
||||
*/
|
||||
|
@ -376,10 +379,8 @@ extern int qla2x00_dfs_remove(scsi_qla_host_t *);
|
|||
|
||||
/* Globa function prototypes for multi-q */
|
||||
extern int qla25xx_request_irq(struct rsp_que *);
|
||||
extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *,
|
||||
uint8_t);
|
||||
extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *,
|
||||
uint8_t);
|
||||
extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *);
|
||||
extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *);
|
||||
extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t,
|
||||
uint16_t, uint8_t, uint8_t);
|
||||
extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t,
|
||||
|
|
|
@ -1226,9 +1226,8 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
|
|||
icb->firmware_options_2 |=
|
||||
__constant_cpu_to_le32(BIT_18);
|
||||
|
||||
icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_22);
|
||||
icb->firmware_options_2 &= __constant_cpu_to_le32(~BIT_22);
|
||||
icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23);
|
||||
ha->rsp_q_map[0]->options = icb->firmware_options_2;
|
||||
|
||||
WRT_REG_DWORD(®->isp25mq.req_q_in, 0);
|
||||
WRT_REG_DWORD(®->isp25mq.req_q_out, 0);
|
||||
|
@ -3493,7 +3492,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
|
|||
rsp = ha->rsp_q_map[i];
|
||||
if (rsp) {
|
||||
rsp->options &= ~BIT_0;
|
||||
ret = qla25xx_init_rsp_que(base_vha, rsp, rsp->options);
|
||||
ret = qla25xx_init_rsp_que(base_vha, rsp);
|
||||
if (ret != QLA_SUCCESS)
|
||||
DEBUG2_17(printk(KERN_WARNING
|
||||
"%s Rsp que:%d init failed\n", __func__,
|
||||
|
@ -3507,7 +3506,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
|
|||
if (req) {
|
||||
/* Clear outstanding commands array. */
|
||||
req->options &= ~BIT_0;
|
||||
ret = qla25xx_init_req_que(base_vha, req, req->options);
|
||||
ret = qla25xx_init_req_que(base_vha, req);
|
||||
if (ret != QLA_SUCCESS)
|
||||
DEBUG2_17(printk(KERN_WARNING
|
||||
"%s Req que:%d init failed\n", __func__,
|
||||
|
|
|
@ -266,6 +266,40 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
|
||||
{
|
||||
static char *event[] =
|
||||
{ "Complete", "Request Notification", "Time Extension" };
|
||||
int rval;
|
||||
struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24;
|
||||
uint16_t __iomem *wptr;
|
||||
uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];
|
||||
|
||||
/* Seed data -- mailbox1 -> mailbox7. */
|
||||
wptr = (uint16_t __iomem *)®24->mailbox1;
|
||||
for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
|
||||
mb[cnt] = RD_REG_WORD(wptr);
|
||||
|
||||
DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
|
||||
"%04x %04x %04x %04x %04x %04x %04x.\n", vha->host_no,
|
||||
event[aen & 0xff],
|
||||
mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6]));
|
||||
|
||||
/* Acknowledgement needed? [Notify && non-zero timeout]. */
|
||||
timeout = (descr >> 8) & 0xf;
|
||||
if (aen != MBA_IDC_NOTIFY || !timeout)
|
||||
return;
|
||||
|
||||
DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
|
||||
"ACK timeout=%d.\n", vha->host_no, event[aen & 0xff], timeout));
|
||||
|
||||
rval = qla2x00_post_idc_ack_work(vha, mb);
|
||||
if (rval != QLA_SUCCESS)
|
||||
qla_printk(KERN_WARNING, vha->hw,
|
||||
"IDC failed to post ACK.\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* qla2x00_async_event() - Process aynchronous events.
|
||||
* @ha: SCSI driver HA context
|
||||
|
@ -714,21 +748,9 @@ skip_rio:
|
|||
"%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
|
||||
break;
|
||||
case MBA_IDC_COMPLETE:
|
||||
DEBUG2(printk("scsi(%ld): Inter-Driver Commucation "
|
||||
"Complete -- %04x %04x %04x\n", vha->host_no, mb[1], mb[2],
|
||||
mb[3]));
|
||||
break;
|
||||
case MBA_IDC_NOTIFY:
|
||||
DEBUG2(printk("scsi(%ld): Inter-Driver Commucation "
|
||||
"Request Notification -- %04x %04x %04x\n", vha->host_no,
|
||||
mb[1], mb[2], mb[3]));
|
||||
/**** Mailbox registers 4 - 7 valid!!! */
|
||||
break;
|
||||
case MBA_IDC_TIME_EXT:
|
||||
DEBUG2(printk("scsi(%ld): Inter-Driver Commucation "
|
||||
"Time Extension -- %04x %04x %04x\n", vha->host_no, mb[1],
|
||||
mb[2], mb[3]));
|
||||
/**** Mailbox registers 4 - 7 valid!!! */
|
||||
qla81xx_idc_event(vha, mb[0], mb[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1707,7 +1729,6 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
|
|||
struct qla_hw_data *ha;
|
||||
struct rsp_que *rsp;
|
||||
struct device_reg_24xx __iomem *reg;
|
||||
uint16_t msix_disabled_hccr = 0;
|
||||
|
||||
rsp = (struct rsp_que *) dev_id;
|
||||
if (!rsp) {
|
||||
|
@ -1720,17 +1741,8 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
|
|||
|
||||
spin_lock_irq(&ha->hardware_lock);
|
||||
|
||||
msix_disabled_hccr = rsp->options;
|
||||
if (!rsp->id)
|
||||
msix_disabled_hccr &= __constant_cpu_to_le32(BIT_22);
|
||||
else
|
||||
msix_disabled_hccr &= __constant_cpu_to_le32(BIT_6);
|
||||
|
||||
qla24xx_process_response_queue(rsp);
|
||||
|
||||
if (!msix_disabled_hccr)
|
||||
WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT);
|
||||
|
||||
spin_unlock_irq(&ha->hardware_lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
|
|
@ -3090,8 +3090,7 @@ verify_done:
|
|||
}
|
||||
|
||||
int
|
||||
qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req,
|
||||
uint8_t options)
|
||||
qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
|
||||
{
|
||||
int rval;
|
||||
unsigned long flags;
|
||||
|
@ -3101,7 +3100,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req,
|
|||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
mcp->mb[0] = MBC_INITIALIZE_MULTIQ;
|
||||
mcp->mb[1] = options;
|
||||
mcp->mb[1] = req->options;
|
||||
mcp->mb[2] = MSW(LSD(req->dma));
|
||||
mcp->mb[3] = LSW(LSD(req->dma));
|
||||
mcp->mb[6] = MSW(MSD(req->dma));
|
||||
|
@ -3128,7 +3127,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req,
|
|||
mcp->tov = 60;
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
if (!(options & BIT_0)) {
|
||||
if (!(req->options & BIT_0)) {
|
||||
WRT_REG_DWORD(®->req_q_in, 0);
|
||||
WRT_REG_DWORD(®->req_q_out, 0);
|
||||
}
|
||||
|
@ -3142,8 +3141,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req,
|
|||
}
|
||||
|
||||
int
|
||||
qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp,
|
||||
uint8_t options)
|
||||
qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
||||
{
|
||||
int rval;
|
||||
unsigned long flags;
|
||||
|
@ -3153,7 +3151,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp,
|
|||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
mcp->mb[0] = MBC_INITIALIZE_MULTIQ;
|
||||
mcp->mb[1] = options;
|
||||
mcp->mb[1] = rsp->options;
|
||||
mcp->mb[2] = MSW(LSD(rsp->dma));
|
||||
mcp->mb[3] = LSW(LSD(rsp->dma));
|
||||
mcp->mb[6] = MSW(MSD(rsp->dma));
|
||||
|
@ -3178,7 +3176,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp,
|
|||
mcp->tov = 60;
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
if (!(options & BIT_0)) {
|
||||
if (!(rsp->options & BIT_0)) {
|
||||
WRT_REG_DWORD(®->rsp_q_out, 0);
|
||||
WRT_REG_DWORD(®->rsp_q_in, 0);
|
||||
}
|
||||
|
@ -3193,3 +3191,29 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp,
|
|||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
|
||||
DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
|
||||
|
||||
mcp->mb[0] = MBC_IDC_ACK;
|
||||
memcpy(&mcp->mb[1], mb, QLA_IDC_ACK_REGS * sizeof(uint16_t));
|
||||
mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
|
||||
vha->host_no, rval, mcp->mb[0]));
|
||||
} else {
|
||||
DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
|
|
@ -396,7 +396,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
|
|||
|
||||
qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL);
|
||||
|
||||
memset(vha->req_ques, 0, sizeof(vha->req_ques) * QLA_MAX_HOST_QUES);
|
||||
memset(vha->req_ques, 0, sizeof(vha->req_ques));
|
||||
vha->req_ques[0] = ha->req_q_map[0]->id;
|
||||
host->can_queue = ha->req_q_map[0]->length + 128;
|
||||
host->this_id = 255;
|
||||
|
@ -471,7 +471,7 @@ qla25xx_delete_req_que(struct scsi_qla_host *vha, struct req_que *req)
|
|||
|
||||
if (req) {
|
||||
req->options |= BIT_0;
|
||||
ret = qla25xx_init_req_que(vha, req, req->options);
|
||||
ret = qla25xx_init_req_que(vha, req);
|
||||
}
|
||||
if (ret == QLA_SUCCESS)
|
||||
qla25xx_free_req_que(vha, req);
|
||||
|
@ -486,7 +486,7 @@ qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
|||
|
||||
if (rsp) {
|
||||
rsp->options |= BIT_0;
|
||||
ret = qla25xx_init_rsp_que(vha, rsp, rsp->options);
|
||||
ret = qla25xx_init_rsp_que(vha, rsp);
|
||||
}
|
||||
if (ret == QLA_SUCCESS)
|
||||
qla25xx_free_rsp_que(vha, rsp);
|
||||
|
@ -502,7 +502,7 @@ int qla25xx_update_req_que(struct scsi_qla_host *vha, uint8_t que, uint8_t qos)
|
|||
|
||||
req->options |= BIT_3;
|
||||
req->qos = qos;
|
||||
ret = qla25xx_init_req_que(vha, req, req->options);
|
||||
ret = qla25xx_init_req_que(vha, req);
|
||||
if (ret != QLA_SUCCESS)
|
||||
DEBUG2_17(printk(KERN_WARNING "%s failed\n", __func__));
|
||||
/* restore options bit */
|
||||
|
@ -632,7 +632,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
|
|||
req->max_q_depth = ha->req_q_map[0]->max_q_depth;
|
||||
mutex_unlock(&ha->vport_lock);
|
||||
|
||||
ret = qla25xx_init_req_que(base_vha, req, options);
|
||||
ret = qla25xx_init_req_que(base_vha, req);
|
||||
if (ret != QLA_SUCCESS) {
|
||||
qla_printk(KERN_WARNING, ha, "%s failed\n", __func__);
|
||||
mutex_lock(&ha->vport_lock);
|
||||
|
@ -710,7 +710,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
|
|||
if (ret)
|
||||
goto que_failed;
|
||||
|
||||
ret = qla25xx_init_rsp_que(base_vha, rsp, options);
|
||||
ret = qla25xx_init_rsp_que(base_vha, rsp);
|
||||
if (ret != QLA_SUCCESS) {
|
||||
qla_printk(KERN_WARNING, ha, "%s failed\n", __func__);
|
||||
mutex_lock(&ha->vport_lock);
|
||||
|
|
|
@ -2522,6 +2522,19 @@ qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code,
|
|||
return qla2x00_post_work(vha, e, 1);
|
||||
}
|
||||
|
||||
int
|
||||
qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb)
|
||||
{
|
||||
struct qla_work_evt *e;
|
||||
|
||||
e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK, 1);
|
||||
if (!e)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t));
|
||||
return qla2x00_post_work(vha, e, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_do_work(struct scsi_qla_host *vha)
|
||||
{
|
||||
|
@ -2539,6 +2552,9 @@ qla2x00_do_work(struct scsi_qla_host *vha)
|
|||
fc_host_post_event(vha->host, fc_get_event_number(),
|
||||
e->u.aen.code, e->u.aen.data);
|
||||
break;
|
||||
case QLA_EVT_IDC_ACK:
|
||||
qla81xx_idc_ack(vha, e->u.idc_ack.mb);
|
||||
break;
|
||||
}
|
||||
if (e->flags & QLA_EVT_FLAG_FREE)
|
||||
kfree(e);
|
||||
|
|
|
@ -684,7 +684,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
|
|||
"end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start,
|
||||
le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size)));
|
||||
|
||||
switch (le32_to_cpu(region->code)) {
|
||||
switch (le32_to_cpu(region->code) & 0xff) {
|
||||
case FLT_REG_FW:
|
||||
ha->flt_region_fw = start;
|
||||
break;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
/*
|
||||
* Driver version
|
||||
*/
|
||||
#define QLA2XXX_VERSION "8.03.00-k2"
|
||||
#define QLA2XXX_VERSION "8.03.00-k3"
|
||||
|
||||
#define QLA_DRIVER_MAJOR_VER 8
|
||||
#define QLA_DRIVER_MINOR_VER 3
|
||||
|
|
|
@ -317,6 +317,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
|
|||
return sdev;
|
||||
|
||||
out_device_destroy:
|
||||
scsi_device_set_state(sdev, SDEV_DEL);
|
||||
transport_destroy_device(&sdev->sdev_gendev);
|
||||
put_device(&sdev->sdev_gendev);
|
||||
out:
|
||||
|
|
|
@ -1078,7 +1078,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
|
|||
case BLKTRACESETUP:
|
||||
return blk_trace_setup(sdp->device->request_queue,
|
||||
sdp->disk->disk_name,
|
||||
sdp->device->sdev_gendev.devt,
|
||||
MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
|
||||
(char *)arg);
|
||||
case BLKTRACESTART:
|
||||
return blk_trace_startstop(sdp->device->request_queue, 1);
|
||||
|
|
|
@ -2083,6 +2083,20 @@ static int serial8250_startup(struct uart_port *port)
|
|||
|
||||
serial8250_set_mctrl(&up->port, up->port.mctrl);
|
||||
|
||||
/* Serial over Lan (SoL) hack:
|
||||
Intel 8257x Gigabit ethernet chips have a
|
||||
16550 emulation, to be used for Serial Over Lan.
|
||||
Those chips take a longer time than a normal
|
||||
serial device to signalize that a transmission
|
||||
data was queued. Due to that, the above test generally
|
||||
fails. One solution would be to delay the reading of
|
||||
iir. However, this is not reliable, since the timeout
|
||||
is variable. So, let's just don't test if we receive
|
||||
TX irq. This way, we'll never enable UART_BUG_TXEN.
|
||||
*/
|
||||
if (up->port.flags & UPF_NO_TXEN_TEST)
|
||||
goto dont_test_tx_en;
|
||||
|
||||
/*
|
||||
* Do a quick test to see if we receive an
|
||||
* interrupt when we enable the TX irq.
|
||||
|
@ -2102,6 +2116,7 @@ static int serial8250_startup(struct uart_port *port)
|
|||
up->bugs &= ~UART_BUG_TXEN;
|
||||
}
|
||||
|
||||
dont_test_tx_en:
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
|
||||
/*
|
||||
|
|
|
@ -798,6 +798,21 @@ pci_default_setup(struct serial_private *priv,
|
|||
return setup_port(priv, port, bar, offset, board->reg_shift);
|
||||
}
|
||||
|
||||
static int skip_tx_en_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_port *port, int idx)
|
||||
{
|
||||
port->flags |= UPF_NO_TXEN_TEST;
|
||||
printk(KERN_DEBUG "serial8250: skipping TxEn test for device "
|
||||
"[%04x:%04x] subsystem [%04x:%04x]\n",
|
||||
priv->dev->vendor,
|
||||
priv->dev->device,
|
||||
priv->dev->subsystem_vendor,
|
||||
priv->dev->subsystem_device);
|
||||
|
||||
return pci_default_setup(priv, board, port, idx);
|
||||
}
|
||||
|
||||
/* This should be in linux/pci_ids.h */
|
||||
#define PCI_VENDOR_ID_SBSMODULARIO 0x124B
|
||||
#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B
|
||||
|
@ -864,6 +879,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
|||
.init = pci_inteli960ni_init,
|
||||
.setup = pci_default_setup,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = PCI_DEVICE_ID_INTEL_8257X_SOL,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = skip_tx_en_setup,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = PCI_DEVICE_ID_INTEL_82573L_SOL,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = skip_tx_en_setup,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = PCI_DEVICE_ID_INTEL_82573E_SOL,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = skip_tx_en_setup,
|
||||
},
|
||||
/*
|
||||
* ITE
|
||||
*/
|
||||
|
|
|
@ -841,7 +841,7 @@ static int tt_detect(void)
|
|||
tt_dmasnd.ctrl = DMASND_CTRL_OFF;
|
||||
udelay(20); /* wait a while for things to settle down */
|
||||
}
|
||||
mono_moni = (mfp.par_dt_reg & 0x80) == 0;
|
||||
mono_moni = (st_mfp.par_dt_reg & 0x80) == 0;
|
||||
|
||||
tt_get_par(&par);
|
||||
tt_encode_var(&atafb_predefined[0], &par);
|
||||
|
@ -2035,7 +2035,7 @@ static int stste_detect(void)
|
|||
tt_dmasnd.ctrl = DMASND_CTRL_OFF;
|
||||
udelay(20); /* wait a while for things to settle down */
|
||||
}
|
||||
mono_moni = (mfp.par_dt_reg & 0x80) == 0;
|
||||
mono_moni = (st_mfp.par_dt_reg & 0x80) == 0;
|
||||
|
||||
stste_get_par(&par);
|
||||
stste_encode_var(&atafb_predefined[0], &par);
|
||||
|
@ -2086,20 +2086,20 @@ static void st_ovsc_switch(void)
|
|||
return;
|
||||
local_irq_save(flags);
|
||||
|
||||
mfp.tim_ct_b = 0x10;
|
||||
mfp.active_edge |= 8;
|
||||
mfp.tim_ct_b = 0;
|
||||
mfp.tim_dt_b = 0xf0;
|
||||
mfp.tim_ct_b = 8;
|
||||
while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */
|
||||
st_mfp.tim_ct_b = 0x10;
|
||||
st_mfp.active_edge |= 8;
|
||||
st_mfp.tim_ct_b = 0;
|
||||
st_mfp.tim_dt_b = 0xf0;
|
||||
st_mfp.tim_ct_b = 8;
|
||||
while (st_mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */
|
||||
;
|
||||
new = mfp.tim_dt_b;
|
||||
new = st_mfp.tim_dt_b;
|
||||
do {
|
||||
udelay(LINE_DELAY);
|
||||
old = new;
|
||||
new = mfp.tim_dt_b;
|
||||
new = st_mfp.tim_dt_b;
|
||||
} while (old != new);
|
||||
mfp.tim_ct_b = 0x10;
|
||||
st_mfp.tim_ct_b = 0x10;
|
||||
udelay(SYNC_DELAY);
|
||||
|
||||
if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
|
||||
|
|
|
@ -2365,7 +2365,6 @@ static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx
|
|||
static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
|
||||
{
|
||||
u32 pmgt;
|
||||
u16 pwr_command;
|
||||
struct pci_dev *pdev = par->pdev;
|
||||
|
||||
if (!par->pm_reg)
|
||||
|
|
|
@ -45,6 +45,13 @@ static int xen_suspend(void *data)
|
|||
err);
|
||||
return err;
|
||||
}
|
||||
err = sysdev_suspend(PMSG_SUSPEND);
|
||||
if (err) {
|
||||
printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
|
||||
err);
|
||||
device_power_up(PMSG_RESUME);
|
||||
return err;
|
||||
}
|
||||
|
||||
xen_mm_pin_all();
|
||||
gnttab_suspend();
|
||||
|
@ -61,6 +68,7 @@ static int xen_suspend(void *data)
|
|||
gnttab_resume();
|
||||
xen_mm_unpin_all();
|
||||
|
||||
sysdev_resume();
|
||||
device_power_up(PMSG_RESUME);
|
||||
|
||||
if (!*cancelled) {
|
||||
|
|
|
@ -1222,7 +1222,7 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
|
|||
/*
|
||||
* ok we haven't committed the transaction yet, lets do a commit
|
||||
*/
|
||||
if (file->private_data)
|
||||
if (file && file->private_data)
|
||||
btrfs_ioctl_trans_end(file);
|
||||
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
|
@ -1231,7 +1231,7 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = btrfs_log_dentry_safe(trans, root, file->f_dentry);
|
||||
ret = btrfs_log_dentry_safe(trans, root, dentry);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -1245,7 +1245,7 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
|
|||
* file again, but that will end up using the synchronization
|
||||
* inside btrfs_sync_log to keep things safe.
|
||||
*/
|
||||
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
|
||||
if (ret > 0) {
|
||||
ret = btrfs_commit_transaction(trans, root);
|
||||
|
@ -1253,7 +1253,7 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
|
|||
btrfs_sync_log(trans, root);
|
||||
ret = btrfs_end_transaction(trans, root);
|
||||
}
|
||||
mutex_lock(&file->f_dentry->d_inode->i_mutex);
|
||||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
out:
|
||||
return ret > 0 ? EIO : ret;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
Version 1.57
|
||||
------------
|
||||
Improve support for multiple security contexts to the same server. We
|
||||
used to use the same "vcnumber" for all connections which could cause
|
||||
the server to treat subsequent connections, especially those that
|
||||
are authenticated as guest, as reconnections, invalidating the earlier
|
||||
user's smb session. This fix allows cifs to mount multiple times to the
|
||||
same server with different userids without risking invalidating earlier
|
||||
established security contexts.
|
||||
|
||||
Version 1.56
|
||||
------------
|
||||
Add "forcemandatorylock" mount option to allow user to use mandatory
|
||||
|
@ -7,7 +17,10 @@ specified and user does not have access to query information about the
|
|||
top of the share. Fix problem in 2.6.28 resolving DFS paths to
|
||||
Samba servers (worked to Windows). Fix rmdir so that pending search
|
||||
(readdir) requests do not get invalid results which include the now
|
||||
removed directory.
|
||||
removed directory. Fix oops in cifs_dfs_ref.c when prefixpath is not reachable
|
||||
when using DFS. Add better file create support to servers which support
|
||||
the CIFS POSIX protocol extensions (this adds support for new flags
|
||||
on create, and improves semantics for write of locked ranges).
|
||||
|
||||
Version 1.55
|
||||
------------
|
||||
|
|
|
@ -100,5 +100,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
|||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* EXPERIMENTAL */
|
||||
|
||||
#define CIFS_VERSION "1.56"
|
||||
#define CIFS_VERSION "1.57"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -164,9 +164,12 @@ struct TCP_Server_Info {
|
|||
/* multiplexed reads or writes */
|
||||
unsigned int maxBuf; /* maxBuf specifies the maximum */
|
||||
/* message size the server can send or receive for non-raw SMBs */
|
||||
unsigned int maxRw; /* maxRw specifies the maximum */
|
||||
unsigned int max_rw; /* maxRw specifies the maximum */
|
||||
/* message size the server can send or receive for */
|
||||
/* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
|
||||
unsigned int max_vcs; /* maximum number of smb sessions, at least
|
||||
those that can be specified uniquely with
|
||||
vcnumbers */
|
||||
char sessid[4]; /* unique token id for this session */
|
||||
/* (returned on Negotiate */
|
||||
int capabilities; /* allow selective disabling of caps by smb sess */
|
||||
|
@ -210,6 +213,7 @@ struct cifsSesInfo {
|
|||
unsigned overrideSecFlg; /* if non-zero override global sec flags */
|
||||
__u16 ipc_tid; /* special tid for connection to IPC share */
|
||||
__u16 flags;
|
||||
__u16 vcnum;
|
||||
char *serverOS; /* name of operating system underlying server */
|
||||
char *serverNOS; /* name of network operating system of server */
|
||||
char *serverDomain; /* security realm of server */
|
||||
|
|
|
@ -42,6 +42,7 @@ extern void _FreeXid(unsigned int);
|
|||
#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current_fsuid()));
|
||||
#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));}
|
||||
extern char *build_path_from_dentry(struct dentry *);
|
||||
extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb);
|
||||
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
|
||||
/* extern void renew_parental_timestamps(struct dentry *direntry);*/
|
||||
extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
|
||||
|
@ -91,6 +92,9 @@ extern u64 cifs_UnixTimeToNT(struct timespec);
|
|||
extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
|
||||
extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
|
||||
|
||||
extern void posix_fill_in_inode(struct inode *tmp_inode,
|
||||
FILE_UNIX_BASIC_INFO *pData, int isNewInode);
|
||||
extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum);
|
||||
extern int cifs_get_inode_info(struct inode **pinode,
|
||||
const unsigned char *search_path,
|
||||
FILE_ALL_INFO *pfile_info,
|
||||
|
|
|
@ -528,14 +528,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
|
||||
server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
|
||||
(__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
|
||||
server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
|
||||
GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
|
||||
/* even though we do not use raw we might as well set this
|
||||
accurately, in case we ever find a need for it */
|
||||
if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
|
||||
server->maxRw = 0xFF00;
|
||||
server->max_rw = 0xFF00;
|
||||
server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
|
||||
} else {
|
||||
server->maxRw = 0;/* we do not need to use raw anyway */
|
||||
server->max_rw = 0;/* do not need to use raw anyway */
|
||||
server->capabilities = CAP_MPX_MODE;
|
||||
}
|
||||
tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
|
||||
|
@ -638,7 +639,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
/* probably no need to store and check maxvcs */
|
||||
server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
|
||||
(__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
|
||||
server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
|
||||
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
|
||||
cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
|
||||
GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
|
||||
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/utsname.h>
|
||||
|
@ -35,6 +34,7 @@
|
|||
#include <linux/freezer.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/processor.h>
|
||||
#include <net/ipv6.h>
|
||||
#include "cifspdu.h"
|
||||
#include "cifsglob.h"
|
||||
#include "cifsproto.h"
|
||||
|
@ -1379,8 +1379,8 @@ cifs_find_tcp_session(struct sockaddr_storage *addr)
|
|||
server->addr.sockAddr.sin_addr.s_addr))
|
||||
continue;
|
||||
else if (addr->ss_family == AF_INET6 &&
|
||||
memcmp(&server->addr.sockAddr6.sin6_addr,
|
||||
&addr6->sin6_addr, sizeof(addr6->sin6_addr)))
|
||||
!ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
|
||||
&addr6->sin6_addr))
|
||||
continue;
|
||||
|
||||
++server->srv_count;
|
||||
|
@ -2180,6 +2180,33 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
|
|||
"mount option supported"));
|
||||
}
|
||||
|
||||
static int
|
||||
is_path_accessible(int xid, struct cifsTconInfo *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path)
|
||||
{
|
||||
int rc;
|
||||
__u64 inode_num;
|
||||
FILE_ALL_INFO *pfile_info;
|
||||
|
||||
rc = CIFSGetSrvInodeNumber(xid, tcon, full_path, &inode_num,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc != -EOPNOTSUPP)
|
||||
return rc;
|
||||
|
||||
pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
|
||||
if (pfile_info == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
|
||||
0 /* not legacy */, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
kfree(pfile_info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
char *mount_data, const char *devname)
|
||||
|
@ -2190,6 +2217,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
struct cifsSesInfo *pSesInfo = NULL;
|
||||
struct cifsTconInfo *tcon = NULL;
|
||||
struct TCP_Server_Info *srvTcp = NULL;
|
||||
char *full_path;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
|
@ -2426,6 +2454,23 @@ mount_fail_check:
|
|||
cifs_sb->rsize = min(cifs_sb->rsize,
|
||||
(tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
|
||||
|
||||
if (!rc && cifs_sb->prepathlen) {
|
||||
/* build_path_to_root works only when we have a valid tcon */
|
||||
full_path = cifs_build_path_to_root(cifs_sb);
|
||||
if (full_path == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto mount_fail_check;
|
||||
}
|
||||
rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
|
||||
if (rc) {
|
||||
cERROR(1, ("Path %s in not accessible: %d",
|
||||
full_path, rc));
|
||||
kfree(full_path);
|
||||
goto mount_fail_check;
|
||||
}
|
||||
kfree(full_path);
|
||||
}
|
||||
|
||||
/* volume_info->password is freed above when existing session found
|
||||
(in which case it is not needed anymore) but when new sesion is created
|
||||
the password ptr is put in the new session structure (in which case the
|
||||
|
|
301
fs/cifs/dir.c
301
fs/cifs/dir.c
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* vfs operations that deal with dentries
|
||||
*
|
||||
* Copyright (C) International Business Machines Corp., 2002,2008
|
||||
* Copyright (C) International Business Machines Corp., 2002,2009
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
|
@ -129,6 +129,78 @@ cifs_bp_rename_retry:
|
|||
return full_path;
|
||||
}
|
||||
|
||||
static int cifs_posix_open(char *full_path, struct inode **pinode,
|
||||
struct super_block *sb, int mode, int oflags,
|
||||
int *poplock, __u16 *pnetfid, int xid)
|
||||
{
|
||||
int rc;
|
||||
__u32 oplock;
|
||||
FILE_UNIX_BASIC_INFO *presp_data;
|
||||
__u32 posix_flags = 0;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
|
||||
cFYI(1, ("posix open %s", full_path));
|
||||
|
||||
presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
|
||||
if (presp_data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* So far cifs posix extensions can only map the following flags.
|
||||
There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but
|
||||
so far we do not seem to need them, and we can treat them as local only */
|
||||
if ((oflags & (FMODE_READ | FMODE_WRITE)) ==
|
||||
(FMODE_READ | FMODE_WRITE))
|
||||
posix_flags = SMB_O_RDWR;
|
||||
else if (oflags & FMODE_READ)
|
||||
posix_flags = SMB_O_RDONLY;
|
||||
else if (oflags & FMODE_WRITE)
|
||||
posix_flags = SMB_O_WRONLY;
|
||||
if (oflags & O_CREAT)
|
||||
posix_flags |= SMB_O_CREAT;
|
||||
if (oflags & O_EXCL)
|
||||
posix_flags |= SMB_O_EXCL;
|
||||
if (oflags & O_TRUNC)
|
||||
posix_flags |= SMB_O_TRUNC;
|
||||
if (oflags & O_APPEND)
|
||||
posix_flags |= SMB_O_APPEND;
|
||||
if (oflags & O_SYNC)
|
||||
posix_flags |= SMB_O_SYNC;
|
||||
if (oflags & O_DIRECTORY)
|
||||
posix_flags |= SMB_O_DIRECTORY;
|
||||
if (oflags & O_NOFOLLOW)
|
||||
posix_flags |= SMB_O_NOFOLLOW;
|
||||
if (oflags & O_DIRECT)
|
||||
posix_flags |= SMB_O_DIRECT;
|
||||
|
||||
|
||||
rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
|
||||
pnetfid, presp_data, &oplock, full_path,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc)
|
||||
goto posix_open_ret;
|
||||
|
||||
if (presp_data->Type == cpu_to_le32(-1))
|
||||
goto posix_open_ret; /* open ok, caller does qpathinfo */
|
||||
|
||||
/* get new inode and set it up */
|
||||
if (!pinode)
|
||||
goto posix_open_ret; /* caller does not need info */
|
||||
|
||||
*pinode = cifs_new_inode(sb, &presp_data->UniqueId);
|
||||
|
||||
/* We do not need to close the file if new_inode fails since
|
||||
the caller will retry qpathinfo as long as inode is null */
|
||||
if (*pinode == NULL)
|
||||
goto posix_open_ret;
|
||||
|
||||
posix_fill_in_inode(*pinode, presp_data, 1);
|
||||
|
||||
posix_open_ret:
|
||||
kfree(presp_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void setup_cifs_dentry(struct cifsTconInfo *tcon,
|
||||
struct dentry *direntry,
|
||||
struct inode *newinode)
|
||||
|
@ -150,7 +222,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
int xid;
|
||||
int create_options = CREATE_NOT_DIR;
|
||||
int oplock = 0;
|
||||
/* BB below access is too much for the mknod to request */
|
||||
int oflags;
|
||||
/*
|
||||
* BB below access is probably too much for mknod to request
|
||||
* but we have to do query and setpathinfo so requesting
|
||||
* less could fail (unless we want to request getatr and setatr
|
||||
* permissions (only). At least for POSIX we do not have to
|
||||
* request so much.
|
||||
*/
|
||||
int desiredAccess = GENERIC_READ | GENERIC_WRITE;
|
||||
__u16 fileHandle;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
|
@ -174,13 +253,43 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
}
|
||||
|
||||
mode &= ~current->fs->umask;
|
||||
if (oplockEnabled)
|
||||
oplock = REQ_OPLOCK;
|
||||
|
||||
if (nd && (nd->flags & LOOKUP_OPEN))
|
||||
oflags = nd->intent.open.flags;
|
||||
else
|
||||
oflags = FMODE_READ;
|
||||
|
||||
if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
|
||||
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
||||
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
||||
rc = cifs_posix_open(full_path, &newinode, inode->i_sb,
|
||||
mode, oflags, &oplock, &fileHandle, xid);
|
||||
/* EIO could indicate that (posix open) operation is not
|
||||
supported, despite what server claimed in capability
|
||||
negotation. EREMOTE indicates DFS junction, which is not
|
||||
handled in posix open */
|
||||
|
||||
if ((rc == 0) && (newinode == NULL))
|
||||
goto cifs_create_get_file_info; /* query inode info */
|
||||
else if (rc == 0) /* success, no need to query */
|
||||
goto cifs_create_set_dentry;
|
||||
else if ((rc != -EIO) && (rc != -EREMOTE) &&
|
||||
(rc != -EOPNOTSUPP)) /* path not found or net err */
|
||||
goto cifs_create_out;
|
||||
/* else fallthrough to retry, using older open call, this is
|
||||
case where server does not support this SMB level, and
|
||||
falsely claims capability (also get here for DFS case
|
||||
which should be rare for path not covered on files) */
|
||||
}
|
||||
|
||||
if (nd && (nd->flags & LOOKUP_OPEN)) {
|
||||
int oflags = nd->intent.open.flags;
|
||||
|
||||
/* if the file is going to stay open, then we
|
||||
need to set the desired access properly */
|
||||
desiredAccess = 0;
|
||||
if (oflags & FMODE_READ)
|
||||
desiredAccess |= GENERIC_READ;
|
||||
desiredAccess |= GENERIC_READ; /* is this too little? */
|
||||
if (oflags & FMODE_WRITE) {
|
||||
desiredAccess |= GENERIC_WRITE;
|
||||
if (!(oflags & FMODE_READ))
|
||||
|
@ -199,8 +308,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
|
||||
/* BB add processing to set equivalent of mode - e.g. via CreateX with
|
||||
ACLs */
|
||||
if (oplockEnabled)
|
||||
oplock = REQ_OPLOCK;
|
||||
|
||||
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
|
||||
if (buf == NULL) {
|
||||
|
@ -233,116 +340,112 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
}
|
||||
if (rc) {
|
||||
cFYI(1, ("cifs_create returned 0x%x", rc));
|
||||
} else {
|
||||
/* If Open reported that we actually created a file
|
||||
then we now have to set the mode if possible */
|
||||
if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
|
||||
struct cifs_unix_set_info_args args = {
|
||||
goto cifs_create_out;
|
||||
}
|
||||
|
||||
/* If Open reported that we actually created a file
|
||||
then we now have to set the mode if possible */
|
||||
if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
|
||||
struct cifs_unix_set_info_args args = {
|
||||
.mode = mode,
|
||||
.ctime = NO_CHANGE_64,
|
||||
.atime = NO_CHANGE_64,
|
||||
.mtime = NO_CHANGE_64,
|
||||
.device = 0,
|
||||
};
|
||||
};
|
||||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
|
||||
args.uid = (__u64) current_fsuid();
|
||||
if (inode->i_mode & S_ISGID)
|
||||
args.gid = (__u64) inode->i_gid;
|
||||
else
|
||||
args.gid = (__u64) current_fsgid();
|
||||
} else {
|
||||
args.uid = NO_CHANGE_64;
|
||||
args.gid = NO_CHANGE_64;
|
||||
}
|
||||
CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
|
||||
args.uid = (__u64) current_fsuid();
|
||||
if (inode->i_mode & S_ISGID)
|
||||
args.gid = (__u64) inode->i_gid;
|
||||
else
|
||||
args.gid = (__u64) current_fsgid();
|
||||
} else {
|
||||
/* BB implement mode setting via Windows security
|
||||
descriptors e.g. */
|
||||
/* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
|
||||
|
||||
/* Could set r/o dos attribute if mode & 0222 == 0 */
|
||||
args.uid = NO_CHANGE_64;
|
||||
args.gid = NO_CHANGE_64;
|
||||
}
|
||||
CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
} else {
|
||||
/* BB implement mode setting via Windows security
|
||||
descriptors e.g. */
|
||||
/* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
|
||||
|
||||
/* server might mask mode so we have to query for it */
|
||||
if (tcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&newinode, full_path,
|
||||
inode->i_sb, xid);
|
||||
else {
|
||||
rc = cifs_get_inode_info(&newinode, full_path,
|
||||
buf, inode->i_sb, xid,
|
||||
&fileHandle);
|
||||
if (newinode) {
|
||||
if (cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_DYNPERM)
|
||||
newinode->i_mode = mode;
|
||||
if ((oplock & CIFS_CREATE_ACTION) &&
|
||||
(cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_SET_UID)) {
|
||||
newinode->i_uid = current_fsuid();
|
||||
if (inode->i_mode & S_ISGID)
|
||||
newinode->i_gid =
|
||||
inode->i_gid;
|
||||
else
|
||||
newinode->i_gid =
|
||||
current_fsgid();
|
||||
}
|
||||
/* Could set r/o dos attribute if mode & 0222 == 0 */
|
||||
}
|
||||
|
||||
cifs_create_get_file_info:
|
||||
/* server might mask mode so we have to query for it */
|
||||
if (tcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&newinode, full_path,
|
||||
inode->i_sb, xid);
|
||||
else {
|
||||
rc = cifs_get_inode_info(&newinode, full_path, buf,
|
||||
inode->i_sb, xid, &fileHandle);
|
||||
if (newinode) {
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
|
||||
newinode->i_mode = mode;
|
||||
if ((oplock & CIFS_CREATE_ACTION) &&
|
||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
|
||||
newinode->i_uid = current_fsuid();
|
||||
if (inode->i_mode & S_ISGID)
|
||||
newinode->i_gid = inode->i_gid;
|
||||
else
|
||||
newinode->i_gid = current_fsgid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
cFYI(1, ("Create worked, get_inode_info failed rc = %d",
|
||||
rc));
|
||||
} else
|
||||
setup_cifs_dentry(tcon, direntry, newinode);
|
||||
cifs_create_set_dentry:
|
||||
if (rc == 0)
|
||||
setup_cifs_dentry(tcon, direntry, newinode);
|
||||
else
|
||||
cFYI(1, ("Create worked, get_inode_info failed rc = %d", rc));
|
||||
|
||||
if ((nd == NULL /* nfsd case - nfs srv does not set nd */) ||
|
||||
(!(nd->flags & LOOKUP_OPEN))) {
|
||||
/* mknod case - do not leave file open */
|
||||
CIFSSMBClose(xid, tcon, fileHandle);
|
||||
} else if (newinode) {
|
||||
struct cifsFileInfo *pCifsFile =
|
||||
kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
||||
/* nfsd case - nfs srv does not set nd */
|
||||
if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) {
|
||||
/* mknod case - do not leave file open */
|
||||
CIFSSMBClose(xid, tcon, fileHandle);
|
||||
} else if (newinode) {
|
||||
struct cifsFileInfo *pCifsFile =
|
||||
kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
||||
|
||||
if (pCifsFile == NULL)
|
||||
goto cifs_create_out;
|
||||
pCifsFile->netfid = fileHandle;
|
||||
pCifsFile->pid = current->tgid;
|
||||
pCifsFile->pInode = newinode;
|
||||
pCifsFile->invalidHandle = false;
|
||||
pCifsFile->closePend = false;
|
||||
init_MUTEX(&pCifsFile->fh_sem);
|
||||
mutex_init(&pCifsFile->lock_mutex);
|
||||
INIT_LIST_HEAD(&pCifsFile->llist);
|
||||
atomic_set(&pCifsFile->wrtPending, 0);
|
||||
if (pCifsFile == NULL)
|
||||
goto cifs_create_out;
|
||||
pCifsFile->netfid = fileHandle;
|
||||
pCifsFile->pid = current->tgid;
|
||||
pCifsFile->pInode = newinode;
|
||||
pCifsFile->invalidHandle = false;
|
||||
pCifsFile->closePend = false;
|
||||
init_MUTEX(&pCifsFile->fh_sem);
|
||||
mutex_init(&pCifsFile->lock_mutex);
|
||||
INIT_LIST_HEAD(&pCifsFile->llist);
|
||||
atomic_set(&pCifsFile->wrtPending, 0);
|
||||
|
||||
/* set the following in open now
|
||||
/* set the following in open now
|
||||
pCifsFile->pfile = file; */
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_add(&pCifsFile->tlist, &tcon->openFileList);
|
||||
pCifsInode = CIFS_I(newinode);
|
||||
if (pCifsInode) {
|
||||
/* if readable file instance put first in list*/
|
||||
if (write_only) {
|
||||
list_add_tail(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
} else {
|
||||
list_add(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
}
|
||||
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
|
||||
pCifsInode->clientCanCacheAll = true;
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
cFYI(1, ("Exclusive Oplock inode %p",
|
||||
newinode));
|
||||
} else if ((oplock & 0xF) == OPLOCK_READ)
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_add(&pCifsFile->tlist, &tcon->openFileList);
|
||||
pCifsInode = CIFS_I(newinode);
|
||||
if (pCifsInode) {
|
||||
/* if readable file instance put first in list*/
|
||||
if (write_only) {
|
||||
list_add_tail(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
} else {
|
||||
list_add(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
}
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
|
||||
pCifsInode->clientCanCacheAll = true;
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
cFYI(1, ("Exclusive Oplock inode %p",
|
||||
newinode));
|
||||
} else if ((oplock & 0xF) == OPLOCK_READ)
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
}
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
}
|
||||
cifs_create_out:
|
||||
kfree(buf);
|
||||
|
|
104
fs/cifs/inode.c
104
fs/cifs/inode.c
|
@ -199,6 +199,49 @@ static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
|
|||
pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
|
||||
}
|
||||
|
||||
/**
|
||||
* cifs_new inode - create new inode, initialize, and hash it
|
||||
* @sb - pointer to superblock
|
||||
* @inum - if valid pointer and serverino is enabled, replace i_ino with val
|
||||
*
|
||||
* Create a new inode, initialize it for CIFS and hash it. Returns the new
|
||||
* inode or NULL if one couldn't be allocated.
|
||||
*
|
||||
* If the share isn't mounted with "serverino" or inum is a NULL pointer then
|
||||
* we'll just use the inode number assigned by new_inode(). Note that this can
|
||||
* mean i_ino collisions since the i_ino assigned by new_inode is not
|
||||
* guaranteed to be unique.
|
||||
*/
|
||||
struct inode *
|
||||
cifs_new_inode(struct super_block *sb, __u64 *inum)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
inode = new_inode(sb);
|
||||
if (inode == NULL)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we
|
||||
* stop passing inum as ptr. Are there sanity checks we can use to
|
||||
* ensure that the server is really filling in that field? Also,
|
||||
* if serverino is disabled, perhaps we should be using iunique()?
|
||||
*/
|
||||
if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
|
||||
inode->i_ino = (unsigned long) *inum;
|
||||
|
||||
/*
|
||||
* must set this here instead of cifs_alloc_inode since VFS will
|
||||
* clobber i_flags
|
||||
*/
|
||||
if (sb->s_flags & MS_NOATIME)
|
||||
inode->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
|
||||
insert_inode_hash(inode);
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
const unsigned char *full_path, struct super_block *sb, int xid)
|
||||
{
|
||||
|
@ -233,22 +276,11 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|||
|
||||
/* get new inode */
|
||||
if (*pinode == NULL) {
|
||||
*pinode = new_inode(sb);
|
||||
*pinode = cifs_new_inode(sb, &find_data.UniqueId);
|
||||
if (*pinode == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cgiiu_exit;
|
||||
}
|
||||
/* Is an i_ino of zero legal? */
|
||||
/* note ino incremented to unique num in new_inode */
|
||||
/* Are there sanity checks we can use to ensure that
|
||||
the server is really filling in that field? */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
|
||||
(*pinode)->i_ino = (unsigned long)find_data.UniqueId;
|
||||
|
||||
if (sb->s_flags & MS_NOATIME)
|
||||
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
|
||||
insert_inode_hash(*pinode);
|
||||
}
|
||||
|
||||
inode = *pinode;
|
||||
|
@ -465,11 +497,9 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
|
||||
/* get new inode */
|
||||
if (*pinode == NULL) {
|
||||
*pinode = new_inode(sb);
|
||||
if (*pinode == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cgii_exit;
|
||||
}
|
||||
__u64 inode_num;
|
||||
__u64 *pinum = &inode_num;
|
||||
|
||||
/* Is an i_ino of zero legal? Can we use that to check
|
||||
if the server supports returning inode numbers? Are
|
||||
there other sanity checks we can use to ensure that
|
||||
|
@ -486,22 +516,26 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
||||
int rc1 = 0;
|
||||
__u64 inode_num;
|
||||
|
||||
rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
|
||||
full_path, &inode_num,
|
||||
full_path, pinum,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc1) {
|
||||
cFYI(1, ("GetSrvInodeNum rc %d", rc1));
|
||||
pinum = NULL;
|
||||
/* BB EOPNOSUPP disable SERVER_INUM? */
|
||||
} else /* do we need cast or hash to ino? */
|
||||
(*pinode)->i_ino = inode_num;
|
||||
} /* else ino incremented to unique num in new_inode*/
|
||||
if (sb->s_flags & MS_NOATIME)
|
||||
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
insert_inode_hash(*pinode);
|
||||
}
|
||||
} else {
|
||||
pinum = NULL;
|
||||
}
|
||||
|
||||
*pinode = cifs_new_inode(sb, pinum);
|
||||
if (*pinode == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cgii_exit;
|
||||
}
|
||||
}
|
||||
inode = *pinode;
|
||||
cifsInfo = CIFS_I(inode);
|
||||
|
@ -621,7 +655,7 @@ static const struct inode_operations cifs_ipc_inode_ops = {
|
|||
.lookup = cifs_lookup,
|
||||
};
|
||||
|
||||
static char *build_path_to_root(struct cifs_sb_info *cifs_sb)
|
||||
char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
int pplen = cifs_sb->prepathlen;
|
||||
int dfsplen;
|
||||
|
@ -678,7 +712,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
|||
return inode;
|
||||
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
full_path = build_path_to_root(cifs_sb);
|
||||
full_path = cifs_build_path_to_root(cifs_sb);
|
||||
if (full_path == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
@ -1017,7 +1051,7 @@ out_reval:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void posix_fill_in_inode(struct inode *tmp_inode,
|
||||
void posix_fill_in_inode(struct inode *tmp_inode,
|
||||
FILE_UNIX_BASIC_INFO *pData, int isNewInode)
|
||||
{
|
||||
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
|
||||
|
@ -1114,24 +1148,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|||
else
|
||||
direntry->d_op = &cifs_dentry_ops;
|
||||
|
||||
newinode = new_inode(inode->i_sb);
|
||||
newinode = cifs_new_inode(inode->i_sb,
|
||||
&pInfo->UniqueId);
|
||||
if (newinode == NULL) {
|
||||
kfree(pInfo);
|
||||
goto mkdir_get_info;
|
||||
}
|
||||
|
||||
/* Is an i_ino of zero legal? */
|
||||
/* Are there sanity checks we can use to ensure that
|
||||
the server is really filling in that field? */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
||||
newinode->i_ino =
|
||||
(unsigned long)pInfo->UniqueId;
|
||||
} /* note ino incremented to unique num in new_inode */
|
||||
if (inode->i_sb->s_flags & MS_NOATIME)
|
||||
newinode->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
newinode->i_nlink = 2;
|
||||
|
||||
insert_inode_hash(newinode);
|
||||
d_instantiate(direntry, newinode);
|
||||
|
||||
/* we already checked in POSIXCreate whether
|
||||
|
|
|
@ -56,35 +56,34 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
|
|||
}
|
||||
#endif /* DEBUG2 */
|
||||
|
||||
/* Returns one if new inode created (which therefore needs to be hashed) */
|
||||
/* Returns 1 if new inode created, 2 if both dentry and inode were */
|
||||
/* Might check in the future if inode number changed so we can rehash inode */
|
||||
static int construct_dentry(struct qstr *qstring, struct file *file,
|
||||
struct inode **ptmp_inode, struct dentry **pnew_dentry)
|
||||
static int
|
||||
construct_dentry(struct qstr *qstring, struct file *file,
|
||||
struct inode **ptmp_inode, struct dentry **pnew_dentry,
|
||||
__u64 *inum)
|
||||
{
|
||||
struct dentry *tmp_dentry;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
struct dentry *tmp_dentry = NULL;
|
||||
struct super_block *sb = file->f_path.dentry->d_sb;
|
||||
int rc = 0;
|
||||
|
||||
cFYI(1, ("For %s", qstring->name));
|
||||
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
||||
pTcon = cifs_sb->tcon;
|
||||
|
||||
qstring->hash = full_name_hash(qstring->name, qstring->len);
|
||||
tmp_dentry = d_lookup(file->f_path.dentry, qstring);
|
||||
if (tmp_dentry) {
|
||||
/* BB: overwrite old name? i.e. tmp_dentry->d_name and
|
||||
* tmp_dentry->d_name.len??
|
||||
*/
|
||||
cFYI(0, ("existing dentry with inode 0x%p",
|
||||
tmp_dentry->d_inode));
|
||||
*ptmp_inode = tmp_dentry->d_inode;
|
||||
/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
|
||||
if (*ptmp_inode == NULL) {
|
||||
*ptmp_inode = new_inode(file->f_path.dentry->d_sb);
|
||||
*ptmp_inode = cifs_new_inode(sb, inum);
|
||||
if (*ptmp_inode == NULL)
|
||||
return rc;
|
||||
rc = 1;
|
||||
}
|
||||
if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
|
||||
(*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
} else {
|
||||
tmp_dentry = d_alloc(file->f_path.dentry, qstring);
|
||||
if (tmp_dentry == NULL) {
|
||||
|
@ -93,15 +92,14 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
|
|||
return rc;
|
||||
}
|
||||
|
||||
*ptmp_inode = new_inode(file->f_path.dentry->d_sb);
|
||||
if (pTcon->nocase)
|
||||
if (CIFS_SB(sb)->tcon->nocase)
|
||||
tmp_dentry->d_op = &cifs_ci_dentry_ops;
|
||||
else
|
||||
tmp_dentry->d_op = &cifs_dentry_ops;
|
||||
|
||||
*ptmp_inode = cifs_new_inode(sb, inum);
|
||||
if (*ptmp_inode == NULL)
|
||||
return rc;
|
||||
if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
|
||||
(*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
rc = 2;
|
||||
}
|
||||
|
||||
|
@ -822,7 +820,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
|
|||
/* inode num, inode type and filename returned */
|
||||
static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
||||
char *current_entry, __u16 level, unsigned int unicode,
|
||||
struct cifs_sb_info *cifs_sb, int max_len, ino_t *pinum)
|
||||
struct cifs_sb_info *cifs_sb, int max_len, __u64 *pinum)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned int len = 0;
|
||||
|
@ -842,9 +840,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
|||
len = strnlen(filename, PATH_MAX);
|
||||
}
|
||||
|
||||
/* BB fixme - hash low and high 32 bits if not 64 bit arch BB */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
|
||||
*pinum = pFindData->UniqueId;
|
||||
*pinum = pFindData->UniqueId;
|
||||
} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
|
||||
FILE_DIRECTORY_INFO *pFindData =
|
||||
(FILE_DIRECTORY_INFO *)current_entry;
|
||||
|
@ -907,7 +903,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
|
|||
struct qstr qstring;
|
||||
struct cifsFileInfo *pCifsF;
|
||||
unsigned int obj_type;
|
||||
ino_t inum;
|
||||
__u64 inum;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct inode *tmp_inode;
|
||||
struct dentry *tmp_dentry;
|
||||
|
@ -940,20 +936,18 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry);
|
||||
/* only these two infolevels return valid inode numbers */
|
||||
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX ||
|
||||
pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
|
||||
rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
|
||||
&inum);
|
||||
else
|
||||
rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
|
||||
NULL);
|
||||
|
||||
if ((tmp_inode == NULL) || (tmp_dentry == NULL))
|
||||
return -ENOMEM;
|
||||
|
||||
if (rc) {
|
||||
/* inode created, we need to hash it with right inode number */
|
||||
if (inum != 0) {
|
||||
/* BB fixme - hash the 2 32 quantities bits together if
|
||||
* necessary BB */
|
||||
tmp_inode->i_ino = inum;
|
||||
}
|
||||
insert_inode_hash(tmp_inode);
|
||||
}
|
||||
|
||||
/* we pass in rc below, indicating whether it is a new inode,
|
||||
so we can figure out whether to invalidate the inode cached
|
||||
data if the file has changed */
|
||||
|
|
|
@ -34,15 +34,99 @@
|
|||
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
/* Checks if this is the first smb session to be reconnected after
|
||||
the socket has been reestablished (so we know whether to use vc 0).
|
||||
Called while holding the cifs_tcp_ses_lock, so do not block */
|
||||
static bool is_first_ses_reconnect(struct cifsSesInfo *ses)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct cifsSesInfo *tmp_ses;
|
||||
|
||||
list_for_each(tmp, &ses->server->smb_ses_list) {
|
||||
tmp_ses = list_entry(tmp, struct cifsSesInfo,
|
||||
smb_ses_list);
|
||||
if (tmp_ses->need_reconnect == false)
|
||||
return false;
|
||||
}
|
||||
/* could not find a session that was already connected,
|
||||
this must be the first one we are reconnecting */
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* vc number 0 is treated specially by some servers, and should be the
|
||||
* first one we request. After that we can use vcnumbers up to maxvcs,
|
||||
* one for each smb session (some Windows versions set maxvcs incorrectly
|
||||
* so maxvc=1 can be ignored). If we have too many vcs, we can reuse
|
||||
* any vc but zero (some servers reset the connection on vcnum zero)
|
||||
*
|
||||
*/
|
||||
static __le16 get_next_vcnum(struct cifsSesInfo *ses)
|
||||
{
|
||||
__u16 vcnum = 0;
|
||||
struct list_head *tmp;
|
||||
struct cifsSesInfo *tmp_ses;
|
||||
__u16 max_vcs = ses->server->max_vcs;
|
||||
__u16 i;
|
||||
int free_vc_found = 0;
|
||||
|
||||
/* Quoting the MS-SMB specification: "Windows-based SMB servers set this
|
||||
field to one but do not enforce this limit, which allows an SMB client
|
||||
to establish more virtual circuits than allowed by this value ... but
|
||||
other server implementations can enforce this limit." */
|
||||
if (max_vcs < 2)
|
||||
max_vcs = 0xFFFF;
|
||||
|
||||
write_lock(&cifs_tcp_ses_lock);
|
||||
if ((ses->need_reconnect) && is_first_ses_reconnect(ses))
|
||||
goto get_vc_num_exit; /* vcnum will be zero */
|
||||
for (i = ses->server->srv_count - 1; i < max_vcs; i++) {
|
||||
if (i == 0) /* this is the only connection, use vc 0 */
|
||||
break;
|
||||
|
||||
free_vc_found = 1;
|
||||
|
||||
list_for_each(tmp, &ses->server->smb_ses_list) {
|
||||
tmp_ses = list_entry(tmp, struct cifsSesInfo,
|
||||
smb_ses_list);
|
||||
if (tmp_ses->vcnum == i) {
|
||||
free_vc_found = 0;
|
||||
break; /* found duplicate, try next vcnum */
|
||||
}
|
||||
}
|
||||
if (free_vc_found)
|
||||
break; /* we found a vcnumber that will work - use it */
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
vcnum = 0; /* for most common case, ie if one smb session, use
|
||||
vc zero. Also for case when no free vcnum, zero
|
||||
is safest to send (some clients only send zero) */
|
||||
else if (free_vc_found == 0)
|
||||
vcnum = 1; /* we can not reuse vc=0 safely, since some servers
|
||||
reset all uids on that, but 1 is ok. */
|
||||
else
|
||||
vcnum = i;
|
||||
ses->vcnum = vcnum;
|
||||
get_vc_num_exit:
|
||||
write_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
return le16_to_cpu(vcnum);
|
||||
}
|
||||
|
||||
static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
|
||||
{
|
||||
__u32 capabilities = 0;
|
||||
|
||||
/* init fields common to all four types of SessSetup */
|
||||
/* note that header is initialized to zero in header_assemble */
|
||||
/* Note that offsets for first seven fields in req struct are same */
|
||||
/* in CIFS Specs so does not matter which of 3 forms of struct */
|
||||
/* that we use in next few lines */
|
||||
/* Note that header is initialized to zero in header_assemble */
|
||||
pSMB->req.AndXCommand = 0xFF;
|
||||
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
|
||||
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
|
||||
pSMB->req.VcNumber = get_next_vcnum(ses);
|
||||
|
||||
/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
|
||||
|
||||
|
@ -71,7 +155,6 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
|
|||
if (ses->capabilities & CAP_UNIX)
|
||||
capabilities |= CAP_UNIX;
|
||||
|
||||
/* BB check whether to init vcnum BB */
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
|
@ -228,7 +311,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
|
|||
|
||||
kfree(ses->serverOS);
|
||||
/* UTF-8 string will not grow more than four times as big as UCS-16 */
|
||||
ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
|
||||
ses->serverOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL);
|
||||
if (ses->serverOS != NULL)
|
||||
cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp);
|
||||
data += 2 * (len + 1);
|
||||
|
@ -241,7 +324,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
|
|||
return rc;
|
||||
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
|
||||
ses->serverNOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL);
|
||||
if (ses->serverNOS != NULL) {
|
||||
cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
|
||||
nls_cp);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue