mirror of
https://github.com/torvalds/linux.git
synced 2024-11-18 10:01:43 +00:00
Merge branches 'tracing/ftrace', 'tracing/hw-branch-tracing' and 'linus' into tracing/core
This commit is contained in:
commit
e36b1e136a
@ -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
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include <asm/elf.h>
|
||||
#include <asm/mach-types.h>
|
||||
@ -201,8 +202,13 @@ static struct platform_device *devs[] __initdata = {
|
||||
&pata_device,
|
||||
};
|
||||
|
||||
static struct i2c_board_info i2c_rtc = {
|
||||
I2C_BOARD_INFO("pcf8583", 0x50)
|
||||
};
|
||||
|
||||
static int __init rpc_init(void)
|
||||
{
|
||||
i2c_register_board_info(0, &i2c_rtc, 1);
|
||||
return platform_add_devices(devs, ARRAY_SIZE(devs));
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -80,8 +80,6 @@
|
||||
|
||||
#define PTRACE_SINGLEBLOCK 33 /* resume execution until next branch */
|
||||
|
||||
#ifdef CONFIG_X86_PTRACE_BTS
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <linux/types.h>
|
||||
|
||||
@ -140,6 +138,5 @@ struct ptrace_bts_config {
|
||||
BTS records are read from oldest to newest.
|
||||
Returns number of BTS records drained.
|
||||
*/
|
||||
#endif /* CONFIG_X86_PTRACE_BTS */
|
||||
|
||||
#endif /* _ASM_X86_PTRACE_ABI_H */
|
||||
|
@ -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"
|
||||
};
|
||||
|
@ -214,7 +214,7 @@ static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
|
||||
seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
|
||||
"yes" : "no");
|
||||
seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
|
||||
seq_printf(m, "digestsize : %u\n", alg->cra_hash.digestsize);
|
||||
seq_printf(m, "digestsize : %u\n", alg->cra_ahash.digestsize);
|
||||
}
|
||||
|
||||
const struct crypto_type crypto_ahash_type = {
|
||||
|
@ -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)) {
|
||||
|
@ -901,7 +901,7 @@ static int __devinit eeprom_read(struct lanai_dev *lanai)
|
||||
clock_l(); udelay(5);
|
||||
for (i = 128; i != 0; i >>= 1) { /* write command out */
|
||||
tmp = (lanai->conf1 & ~CONFIG1_PROMDATA) |
|
||||
(data & i) ? CONFIG1_PROMDATA : 0;
|
||||
((data & i) ? CONFIG1_PROMDATA : 0);
|
||||
if (lanai->conf1 != tmp) {
|
||||
set_config1(tmp);
|
||||
udelay(5); /* Let new data settle */
|
||||
|
@ -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,14 @@ 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)) {
|
||||
if (i915_gem_idle(dev))
|
||||
dev_err(&dev->pdev->dev,
|
||||
"GEM idle failed, resume may fail\n");
|
||||
drm_irq_uninstall(dev);
|
||||
}
|
||||
|
||||
intel_opregion_free(dev);
|
||||
|
||||
if (state.event == PM_EVENT_SUSPEND) {
|
||||
@ -79,6 +88,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 +101,26 @@ 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);
|
||||
|
||||
drm_irq_install(dev);
|
||||
}
|
||||
|
||||
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;
|
||||
@ -1030,6 +1051,9 @@ i915_gem_retire_requests(struct drm_device *dev)
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
uint32_t seqno;
|
||||
|
||||
if (!dev_priv->hw_status_page)
|
||||
return;
|
||||
|
||||
seqno = i915_get_gem_seqno(dev);
|
||||
|
||||
while (!list_empty(&dev_priv->mm.request_list)) {
|
||||
@ -1996,30 +2020,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 +2051,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 +2070,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 +2281,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 +2512,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 +2588,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 +2607,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 +2670,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 +2679,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 +2794,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 +2875,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 +2934,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 +2944,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 +2983,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 +3129,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 +3142,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 +3184,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 +3192,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 +3210,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 +3292,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)
|
||||
|
@ -79,10 +79,11 @@ static struct i2c_algo_bit_data ioc_data = {
|
||||
.getsda = ioc_getsda,
|
||||
.getscl = ioc_getscl,
|
||||
.udelay = 80,
|
||||
.timeout = 100
|
||||
.timeout = HZ,
|
||||
};
|
||||
|
||||
static struct i2c_adapter ioc_ops = {
|
||||
.nr = 0,
|
||||
.algo_data = &ioc_data,
|
||||
};
|
||||
|
||||
@ -90,7 +91,7 @@ static int __init i2c_ioc_init(void)
|
||||
{
|
||||
force_ones = FORCE_ONES | SCL | SDA;
|
||||
|
||||
return i2c_bit_add_bus(&ioc_ops);
|
||||
return i2c_bit_add_numbered_bus(&ioc_ops);
|
||||
}
|
||||
|
||||
module_init(i2c_ioc_init);
|
||||
|
@ -72,7 +72,7 @@ static unsigned int amd_ec_wait_write(struct amd_smbus *smbus)
|
||||
{
|
||||
int timeout = 500;
|
||||
|
||||
while (timeout-- && (inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF))
|
||||
while ((inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF) && --timeout)
|
||||
udelay(1);
|
||||
|
||||
if (!timeout) {
|
||||
@ -88,7 +88,7 @@ static unsigned int amd_ec_wait_read(struct amd_smbus *smbus)
|
||||
{
|
||||
int timeout = 500;
|
||||
|
||||
while (timeout-- && (~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF))
|
||||
while ((~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF) && --timeout)
|
||||
udelay(1);
|
||||
|
||||
if (!timeout) {
|
||||
|
@ -114,7 +114,7 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev)
|
||||
drv_data->algo_data.getsda = ixp2000_bit_getsda;
|
||||
drv_data->algo_data.getscl = ixp2000_bit_getscl;
|
||||
drv_data->algo_data.udelay = 6;
|
||||
drv_data->algo_data.timeout = 100;
|
||||
drv_data->algo_data.timeout = HZ;
|
||||
|
||||
strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
|
||||
sizeof(drv_data->adapter.name));
|
||||
|
@ -644,7 +644,7 @@ static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
|
||||
|
||||
i2c_pxa_start_message(i2c);
|
||||
|
||||
while (timeout-- && i2c->msg_num > 0) {
|
||||
while (i2c->msg_num > 0 && --timeout) {
|
||||
i2c_pxa_handler(0, i2c);
|
||||
udelay(10);
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ static struct i2c_algo_bit_data scx200_i2c_data = {
|
||||
.getsda = scx200_i2c_getsda,
|
||||
.getscl = scx200_i2c_getscl,
|
||||
.udelay = 10,
|
||||
.timeout = 100,
|
||||
.timeout = HZ,
|
||||
};
|
||||
|
||||
static struct i2c_adapter scx200_i2c_ops = {
|
||||
|
@ -1831,7 +1831,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
|
||||
case I2C_SMBUS_QUICK:
|
||||
msg[0].len = 0;
|
||||
/* Special case: The read/write field is used as data */
|
||||
msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;
|
||||
msg[0].flags = flags | (read_write == I2C_SMBUS_READ ?
|
||||
I2C_M_RD : 0);
|
||||
num = 1;
|
||||
break;
|
||||
case I2C_SMBUS_BYTE:
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static struct i2c_driver i2cdev_driver;
|
||||
@ -422,7 +423,10 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
client->adapter->retries = arg;
|
||||
break;
|
||||
case I2C_TIMEOUT:
|
||||
client->adapter->timeout = arg;
|
||||
/* For historical reasons, user-space sets the timeout
|
||||
* value in units of 10 ms.
|
||||
*/
|
||||
client->adapter->timeout = msecs_to_jiffies(arg * 10);
|
||||
break;
|
||||
default:
|
||||
/* NOTE: returning a fault code here could cause trouble
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
struct file;
|
||||
struct pci_dev;
|
||||
struct scatterlist;
|
||||
struct vm_area_struct;
|
||||
|
@ -1314,6 +1314,7 @@ EXPORT_SYMBOL(hpsb_make_lock64packet);
|
||||
EXPORT_SYMBOL(hpsb_make_phypacket);
|
||||
EXPORT_SYMBOL(hpsb_read);
|
||||
EXPORT_SYMBOL(hpsb_write);
|
||||
EXPORT_SYMBOL(hpsb_lock);
|
||||
EXPORT_SYMBOL(hpsb_packet_success);
|
||||
|
||||
/** highlevel.c **/
|
||||
|
@ -501,8 +501,6 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
|
||||
if (length == 0)
|
||||
return -EINVAL;
|
||||
|
||||
BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
|
||||
|
||||
packet = hpsb_make_readpacket(host, node, addr, length);
|
||||
|
||||
if (!packet) {
|
||||
@ -550,8 +548,6 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
|
||||
if (length == 0)
|
||||
return -EINVAL;
|
||||
|
||||
BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
|
||||
|
||||
packet = hpsb_make_writepacket(host, node, addr, buffer, length);
|
||||
|
||||
if (!packet)
|
||||
@ -570,3 +566,30 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
|
||||
u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
|
||||
{
|
||||
struct hpsb_packet *packet;
|
||||
int retval = 0;
|
||||
|
||||
packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
|
||||
if (!packet)
|
||||
return -ENOMEM;
|
||||
|
||||
packet->generation = generation;
|
||||
retval = hpsb_send_packet_and_wait(packet);
|
||||
if (retval < 0)
|
||||
goto hpsb_lock_fail;
|
||||
|
||||
retval = hpsb_packet_success(packet);
|
||||
|
||||
if (retval == 0)
|
||||
*data = packet->data[0];
|
||||
|
||||
hpsb_lock_fail:
|
||||
hpsb_free_tlabel(packet);
|
||||
hpsb_free_packet(packet);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
|
||||
u64 addr, quadlet_t *buffer, size_t length);
|
||||
int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
|
||||
u64 addr, quadlet_t *buffer, size_t length);
|
||||
int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
|
||||
u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
|
||||
|
||||
#ifdef HPSB_DEBUG_TLABELS
|
||||
extern spinlock_t hpsb_tlabel_lock;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#define IEEE1394_ISO_H
|
||||
|
||||
#include <linux/spinlock_types.h>
|
||||
#include <linux/wait.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
|
@ -971,6 +971,9 @@ static struct unit_directory *nodemgr_process_unit_directory
|
||||
ud->ud_kv = ud_kv;
|
||||
ud->id = (*id)++;
|
||||
|
||||
/* inherit vendor_id from root directory if none exists in unit dir */
|
||||
ud->vendor_id = ne->vendor_id;
|
||||
|
||||
csr1212_for_each_dir_entry(ne->csr, kv, ud_kv, dentry) {
|
||||
switch (kv->key.id) {
|
||||
case CSR1212_KV_ID_VENDOR:
|
||||
@ -1265,7 +1268,8 @@ static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr,
|
||||
csr1212_destroy_csr(csr);
|
||||
}
|
||||
|
||||
/* Mark the node current */
|
||||
/* Finally, mark the node current */
|
||||
smp_wmb();
|
||||
ne->generation = generation;
|
||||
|
||||
if (ne->in_limbo) {
|
||||
@ -1798,7 +1802,7 @@ void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet)
|
||||
{
|
||||
packet->host = ne->host;
|
||||
packet->generation = ne->generation;
|
||||
barrier();
|
||||
smp_rmb();
|
||||
packet->node_id = ne->nodeid;
|
||||
}
|
||||
|
||||
@ -1807,7 +1811,7 @@ int hpsb_node_write(struct node_entry *ne, u64 addr,
|
||||
{
|
||||
unsigned int generation = ne->generation;
|
||||
|
||||
barrier();
|
||||
smp_rmb();
|
||||
return hpsb_write(ne->host, ne->nodeid, generation,
|
||||
addr, buffer, length);
|
||||
}
|
||||
|
@ -21,9 +21,11 @@
|
||||
#define _IEEE1394_NODEMGR_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#include "ieee1394_core.h"
|
||||
#include "ieee1394_transactions.h"
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
struct csr1212_csr;
|
||||
@ -154,6 +156,22 @@ static inline int hpsb_node_entry_valid(struct node_entry *ne)
|
||||
void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet);
|
||||
int hpsb_node_write(struct node_entry *ne, u64 addr,
|
||||
quadlet_t *buffer, size_t length);
|
||||
static inline int hpsb_node_read(struct node_entry *ne, u64 addr,
|
||||
quadlet_t *buffer, size_t length)
|
||||
{
|
||||
unsigned int g = ne->generation;
|
||||
|
||||
smp_rmb();
|
||||
return hpsb_read(ne->host, ne->nodeid, g, addr, buffer, length);
|
||||
}
|
||||
static inline int hpsb_node_lock(struct node_entry *ne, u64 addr, int extcode,
|
||||
quadlet_t *buffer, quadlet_t arg)
|
||||
{
|
||||
unsigned int g = ne->generation;
|
||||
|
||||
smp_rmb();
|
||||
return hpsb_lock(ne->host, ne->nodeid, g, addr, extcode, buffer, arg);
|
||||
}
|
||||
int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *));
|
||||
|
||||
int init_ieee1394_nodemgr(void);
|
||||
|
@ -54,7 +54,7 @@ void memcpy_toshmem(int card, void *dest, const void *src, size_t n)
|
||||
spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
|
||||
pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
|
||||
((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
|
||||
pr_debug("%s: copying %d bytes from %#lx to %#lx\n",
|
||||
pr_debug("%s: copying %zu bytes from %#lx to %#lx\n",
|
||||
sc_adapter[card]->devicename, n,
|
||||
(unsigned long) src,
|
||||
sc_adapter[card]->rambase + ((unsigned long) dest %0x4000));
|
||||
|
@ -51,6 +51,10 @@ comment "Supported SDMC DM1105 Adapters"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
source "drivers/media/dvb/dm1105/Kconfig"
|
||||
|
||||
comment "Supported FireWire (IEEE 1394) Adapters"
|
||||
depends on DVB_CORE && IEEE1394
|
||||
source "drivers/media/dvb/firewire/Kconfig"
|
||||
|
||||
comment "Supported DVB Frontends"
|
||||
depends on DVB_CORE
|
||||
source "drivers/media/dvb/frontends/Kconfig"
|
||||
|
@ -3,3 +3,5 @@
|
||||
#
|
||||
|
||||
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/
|
||||
|
||||
obj-$(CONFIG_DVB_FIREDTV) += firewire/
|
||||
|
22
drivers/media/dvb/firewire/Kconfig
Normal file
22
drivers/media/dvb/firewire/Kconfig
Normal file
@ -0,0 +1,22 @@
|
||||
config DVB_FIREDTV
|
||||
tristate "FireDTV and FloppyDTV"
|
||||
depends on DVB_CORE && IEEE1394
|
||||
help
|
||||
Support for DVB receivers from Digital Everywhere
|
||||
which are connected via IEEE 1394 (FireWire).
|
||||
|
||||
These devices don't have an MPEG decoder built in,
|
||||
so you need an external software decoder to watch TV.
|
||||
|
||||
To compile this driver as a module, say M here:
|
||||
the module will be called firedtv.
|
||||
|
||||
if DVB_FIREDTV
|
||||
|
||||
config DVB_FIREDTV_IEEE1394
|
||||
def_bool IEEE1394
|
||||
|
||||
config DVB_FIREDTV_INPUT
|
||||
def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m)
|
||||
|
||||
endif # DVB_FIREDTV
|
8
drivers/media/dvb/firewire/Makefile
Normal file
8
drivers/media/dvb/firewire/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
|
||||
|
||||
firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o
|
||||
firedtv-$(CONFIG_DVB_FIREDTV_IEEE1394) += firedtv-1394.o
|
||||
firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o
|
||||
|
||||
ccflags-y += -Idrivers/media/dvb/dvb-core
|
||||
ccflags-$(CONFIG_DVB_FIREDTV_IEEE1394) += -Idrivers/ieee1394
|
285
drivers/media/dvb/firewire/firedtv-1394.c
Normal file
285
drivers/media/dvb/firewire/firedtv-1394.c
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* FireDTV driver (formerly known as FireSAT)
|
||||
*
|
||||
* Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
|
||||
* Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com>
|
||||
* Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <dma.h>
|
||||
#include <csr1212.h>
|
||||
#include <highlevel.h>
|
||||
#include <hosts.h>
|
||||
#include <ieee1394.h>
|
||||
#include <iso.h>
|
||||
#include <nodemgr.h>
|
||||
|
||||
#include "firedtv.h"
|
||||
|
||||
static LIST_HEAD(node_list);
|
||||
static DEFINE_SPINLOCK(node_list_lock);
|
||||
|
||||
#define FIREWIRE_HEADER_SIZE 4
|
||||
#define CIP_HEADER_SIZE 8
|
||||
|
||||
static void rawiso_activity_cb(struct hpsb_iso *iso)
|
||||
{
|
||||
struct firedtv *f, *fdtv = NULL;
|
||||
unsigned int i, num, packet;
|
||||
unsigned char *buf;
|
||||
unsigned long flags;
|
||||
int count;
|
||||
|
||||
spin_lock_irqsave(&node_list_lock, flags);
|
||||
list_for_each_entry(f, &node_list, list)
|
||||
if (f->backend_data == iso) {
|
||||
fdtv = f;
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&node_list_lock, flags);
|
||||
|
||||
packet = iso->first_packet;
|
||||
num = hpsb_iso_n_ready(iso);
|
||||
|
||||
if (!fdtv) {
|
||||
dev_err(fdtv->device, "received at unknown iso channel\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++, packet = (packet + 1) % iso->buf_packets) {
|
||||
buf = dma_region_i(&iso->data_buf, unsigned char,
|
||||
iso->infos[packet].offset + CIP_HEADER_SIZE);
|
||||
count = (iso->infos[packet].len - CIP_HEADER_SIZE) /
|
||||
(188 + FIREWIRE_HEADER_SIZE);
|
||||
|
||||
/* ignore empty packet */
|
||||
if (iso->infos[packet].len <= CIP_HEADER_SIZE)
|
||||
continue;
|
||||
|
||||
while (count--) {
|
||||
if (buf[FIREWIRE_HEADER_SIZE] == 0x47)
|
||||
dvb_dmx_swfilter_packets(&fdtv->demux,
|
||||
&buf[FIREWIRE_HEADER_SIZE], 1);
|
||||
else
|
||||
dev_err(fdtv->device,
|
||||
"skipping invalid packet\n");
|
||||
buf += 188 + FIREWIRE_HEADER_SIZE;
|
||||
}
|
||||
}
|
||||
out:
|
||||
hpsb_iso_recv_release_packets(iso, num);
|
||||
}
|
||||
|
||||
static inline struct node_entry *node_of(struct firedtv *fdtv)
|
||||
{
|
||||
return container_of(fdtv->device, struct unit_directory, device)->ne;
|
||||
}
|
||||
|
||||
static int node_lock(struct firedtv *fdtv, u64 addr, void *data, __be32 arg)
|
||||
{
|
||||
return hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP, data,
|
||||
(__force quadlet_t)arg);
|
||||
}
|
||||
|
||||
static int node_read(struct firedtv *fdtv, u64 addr, void *data, size_t len)
|
||||
{
|
||||
return hpsb_node_read(node_of(fdtv), addr, data, len);
|
||||
}
|
||||
|
||||
static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
|
||||
{
|
||||
return hpsb_node_write(node_of(fdtv), addr, data, len);
|
||||
}
|
||||
|
||||
#define FDTV_ISO_BUFFER_PACKETS 256
|
||||
#define FDTV_ISO_BUFFER_SIZE (FDTV_ISO_BUFFER_PACKETS * 200)
|
||||
|
||||
static int start_iso(struct firedtv *fdtv)
|
||||
{
|
||||
struct hpsb_iso *iso_handle;
|
||||
int ret;
|
||||
|
||||
iso_handle = hpsb_iso_recv_init(node_of(fdtv)->host,
|
||||
FDTV_ISO_BUFFER_SIZE, FDTV_ISO_BUFFER_PACKETS,
|
||||
fdtv->isochannel, HPSB_ISO_DMA_DEFAULT,
|
||||
-1, /* stat.config.irq_interval */
|
||||
rawiso_activity_cb);
|
||||
if (iso_handle == NULL) {
|
||||
dev_err(fdtv->device, "cannot initialize iso receive\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
fdtv->backend_data = iso_handle;
|
||||
|
||||
ret = hpsb_iso_recv_start(iso_handle, -1, -1, 0);
|
||||
if (ret != 0) {
|
||||
dev_err(fdtv->device, "cannot start iso receive\n");
|
||||
hpsb_iso_shutdown(iso_handle);
|
||||
fdtv->backend_data = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stop_iso(struct firedtv *fdtv)
|
||||
{
|
||||
struct hpsb_iso *iso_handle = fdtv->backend_data;
|
||||
|
||||
if (iso_handle != NULL) {
|
||||
hpsb_iso_stop(iso_handle);
|
||||
hpsb_iso_shutdown(iso_handle);
|
||||
}
|
||||
fdtv->backend_data = NULL;
|
||||
}
|
||||
|
||||
static const struct firedtv_backend fdtv_1394_backend = {
|
||||
.lock = node_lock,
|
||||
.read = node_read,
|
||||
.write = node_write,
|
||||
.start_iso = start_iso,
|
||||
.stop_iso = stop_iso,
|
||||
};
|
||||
|
||||
static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
|
||||
int cts, u8 *data, size_t length)
|
||||
{
|
||||
struct firedtv *f, *fdtv = NULL;
|
||||
unsigned long flags;
|
||||
int su;
|
||||
|
||||
if (length == 0 || (data[0] & 0xf0) != 0)
|
||||
return;
|
||||
|
||||
su = data[1] & 0x7;
|
||||
|
||||
spin_lock_irqsave(&node_list_lock, flags);
|
||||
list_for_each_entry(f, &node_list, list)
|
||||
if (node_of(f)->host == host &&
|
||||
node_of(f)->nodeid == nodeid &&
|
||||
(f->subunit == su || (f->subunit == 0 && su == 0x7))) {
|
||||
fdtv = f;
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&node_list_lock, flags);
|
||||
|
||||
if (fdtv)
|
||||
avc_recv(fdtv, data, length);
|
||||
}
|
||||
|
||||
static int node_probe(struct device *dev)
|
||||
{
|
||||
struct unit_directory *ud =
|
||||
container_of(dev, struct unit_directory, device);
|
||||
struct firedtv *fdtv;
|
||||
int kv_len, err;
|
||||
void *kv_str;
|
||||
|
||||
kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t);
|
||||
kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
|
||||
|
||||
fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len);
|
||||
if (!fdtv)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Work around a bug in udev's path_id script: Use the fw-host's dev
|
||||
* instead of the unit directory's dev as parent of the input device.
|
||||
*/
|
||||
err = fdtv_register_rc(fdtv, dev->parent->parent);
|
||||
if (err)
|
||||
goto fail_free;
|
||||
|
||||
spin_lock_irq(&node_list_lock);
|
||||
list_add_tail(&fdtv->list, &node_list);
|
||||
spin_unlock_irq(&node_list_lock);
|
||||
|
||||
err = avc_identify_subunit(fdtv);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
err = fdtv_dvb_register(fdtv);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
avc_register_remote_control(fdtv);
|
||||
return 0;
|
||||
fail:
|
||||
spin_lock_irq(&node_list_lock);
|
||||
list_del(&fdtv->list);
|
||||
spin_unlock_irq(&node_list_lock);
|
||||
fdtv_unregister_rc(fdtv);
|
||||
fail_free:
|
||||
kfree(fdtv);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int node_remove(struct device *dev)
|
||||
{
|
||||
struct firedtv *fdtv = dev->driver_data;
|
||||
|
||||
fdtv_dvb_unregister(fdtv);
|
||||
|
||||
spin_lock_irq(&node_list_lock);
|
||||
list_del(&fdtv->list);
|
||||
spin_unlock_irq(&node_list_lock);
|
||||
|
||||
cancel_work_sync(&fdtv->remote_ctrl_work);
|
||||
fdtv_unregister_rc(fdtv);
|
||||
|
||||
kfree(fdtv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int node_update(struct unit_directory *ud)
|
||||
{
|
||||
struct firedtv *fdtv = ud->device.driver_data;
|
||||
|
||||
if (fdtv->isochannel >= 0)
|
||||
cmp_establish_pp_connection(fdtv, fdtv->subunit,
|
||||
fdtv->isochannel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hpsb_protocol_driver fdtv_driver = {
|
||||
.name = "firedtv",
|
||||
.update = node_update,
|
||||
.driver = {
|
||||
.probe = node_probe,
|
||||
.remove = node_remove,
|
||||
},
|
||||
};
|
||||
|
||||
static struct hpsb_highlevel fdtv_highlevel = {
|
||||
.name = "firedtv",
|
||||
.fcp_request = fcp_request,
|
||||
};
|
||||
|
||||
int __init fdtv_1394_init(struct ieee1394_device_id id_table[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
hpsb_register_highlevel(&fdtv_highlevel);
|
||||
fdtv_driver.id_table = id_table;
|
||||
ret = hpsb_register_protocol(&fdtv_driver);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "firedtv: failed to register protocol\n");
|
||||
hpsb_unregister_highlevel(&fdtv_highlevel);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __exit fdtv_1394_exit(void)
|
||||
{
|
||||
hpsb_unregister_protocol(&fdtv_driver);
|
||||
hpsb_unregister_highlevel(&fdtv_highlevel);
|
||||
}
|
1315
drivers/media/dvb/firewire/firedtv-avc.c
Normal file
1315
drivers/media/dvb/firewire/firedtv-avc.c
Normal file
File diff suppressed because it is too large
Load Diff
260
drivers/media/dvb/firewire/firedtv-ci.c
Normal file
260
drivers/media/dvb/firewire/firedtv-ci.c
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* FireDTV driver (formerly known as FireSAT)
|
||||
*
|
||||
* Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
|
||||
* Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/dvb/ca.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <dvbdev.h>
|
||||
|
||||
#include "firedtv.h"
|
||||
|
||||
#define EN50221_TAG_APP_INFO_ENQUIRY 0x9f8020
|
||||
#define EN50221_TAG_CA_INFO_ENQUIRY 0x9f8030
|
||||
#define EN50221_TAG_CA_PMT 0x9f8032
|
||||
#define EN50221_TAG_ENTER_MENU 0x9f8022
|
||||
|
||||
static int fdtv_ca_ready(struct firedtv_tuner_status *stat)
|
||||
{
|
||||
return stat->ca_initialization_status == 1 &&
|
||||
stat->ca_error_flag == 0 &&
|
||||
stat->ca_dvb_flag == 1 &&
|
||||
stat->ca_module_present_status == 1;
|
||||
}
|
||||
|
||||
static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if (stat->ca_module_present_status == 1)
|
||||
flags |= CA_CI_MODULE_PRESENT;
|
||||
if (stat->ca_initialization_status == 1 &&
|
||||
stat->ca_error_flag == 0 &&
|
||||
stat->ca_dvb_flag == 1)
|
||||
flags |= CA_CI_MODULE_READY;
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int fdtv_ca_reset(struct firedtv *fdtv)
|
||||
{
|
||||
return avc_ca_reset(fdtv) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int fdtv_ca_get_caps(void *arg)
|
||||
{
|
||||
struct ca_caps *cap = arg;
|
||||
|
||||
cap->slot_num = 1;
|
||||
cap->slot_type = CA_CI;
|
||||
cap->descr_num = 1;
|
||||
cap->descr_type = CA_ECD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg)
|
||||
{
|
||||
struct firedtv_tuner_status stat;
|
||||
struct ca_slot_info *slot = arg;
|
||||
|
||||
if (avc_tuner_status(fdtv, &stat))
|
||||
return -EFAULT;
|
||||
|
||||
if (slot->num != 0)
|
||||
return -EFAULT;
|
||||
|
||||
slot->type = CA_CI;
|
||||
slot->flags = fdtv_get_ca_flags(&stat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg)
|
||||
{
|
||||
struct ca_msg *reply = arg;
|
||||
|
||||
return avc_ca_app_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int fdtv_ca_info(struct firedtv *fdtv, void *arg)
|
||||
{
|
||||
struct ca_msg *reply = arg;
|
||||
|
||||
return avc_ca_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg)
|
||||
{
|
||||
struct ca_msg *reply = arg;
|
||||
|
||||
return avc_ca_get_mmi(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg)
|
||||
{
|
||||
struct firedtv_tuner_status stat;
|
||||
int err;
|
||||
|
||||
switch (fdtv->ca_last_command) {
|
||||
case EN50221_TAG_APP_INFO_ENQUIRY:
|
||||
err = fdtv_ca_app_info(fdtv, arg);
|
||||
break;
|
||||
case EN50221_TAG_CA_INFO_ENQUIRY:
|
||||
err = fdtv_ca_info(fdtv, arg);
|
||||
break;
|
||||
default:
|
||||
if (avc_tuner_status(fdtv, &stat))
|
||||
err = -EFAULT;
|
||||
else if (stat.ca_mmi == 1)
|
||||
err = fdtv_ca_get_mmi(fdtv, arg);
|
||||
else {
|
||||
dev_info(fdtv->device, "unhandled CA message 0x%08x\n",
|
||||
fdtv->ca_last_command);
|
||||
err = -EFAULT;
|
||||
}
|
||||
}
|
||||
fdtv->ca_last_command = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg)
|
||||
{
|
||||
struct ca_msg *msg = arg;
|
||||
int data_pos;
|
||||
int data_length;
|
||||
int i;
|
||||
|
||||
data_pos = 4;
|
||||
if (msg->msg[3] & 0x80) {
|
||||
data_length = 0;
|
||||
for (i = 0; i < (msg->msg[3] & 0x7f); i++)
|
||||
data_length = (data_length << 8) + msg->msg[data_pos++];
|
||||
} else {
|
||||
data_length = msg->msg[3];
|
||||
}
|
||||
|
||||
return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
|
||||
{
|
||||
struct ca_msg *msg = arg;
|
||||
int err;
|
||||
|
||||
/* Do we need a semaphore for this? */
|
||||
fdtv->ca_last_command =
|
||||
(msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2];
|
||||
switch (fdtv->ca_last_command) {
|
||||
case EN50221_TAG_CA_PMT:
|
||||
err = fdtv_ca_pmt(fdtv, arg);
|
||||
break;
|
||||
case EN50221_TAG_APP_INFO_ENQUIRY:
|
||||
/* handled in ca_get_msg */
|
||||
err = 0;
|
||||
break;
|
||||
case EN50221_TAG_CA_INFO_ENQUIRY:
|
||||
/* handled in ca_get_msg */
|
||||
err = 0;
|
||||
break;
|
||||
case EN50221_TAG_ENTER_MENU:
|
||||
err = avc_ca_enter_menu(fdtv);
|
||||
break;
|
||||
default:
|
||||
dev_err(fdtv->device, "unhandled CA message 0x%08x\n",
|
||||
fdtv->ca_last_command);
|
||||
err = -EFAULT;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fdtv_ca_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct firedtv *fdtv = dvbdev->priv;
|
||||
struct firedtv_tuner_status stat;
|
||||
int err;
|
||||
|
||||
switch (cmd) {
|
||||
case CA_RESET:
|
||||
err = fdtv_ca_reset(fdtv);
|
||||
break;
|
||||
case CA_GET_CAP:
|
||||
err = fdtv_ca_get_caps(arg);
|
||||
break;
|
||||
case CA_GET_SLOT_INFO:
|
||||
err = fdtv_ca_get_slot_info(fdtv, arg);
|
||||
break;
|
||||
case CA_GET_MSG:
|
||||
err = fdtv_ca_get_msg(fdtv, arg);
|
||||
break;
|
||||
case CA_SEND_MSG:
|
||||
err = fdtv_ca_send_msg(fdtv, arg);
|
||||
break;
|
||||
default:
|
||||
dev_info(fdtv->device, "unhandled CA ioctl %u\n", cmd);
|
||||
err = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* FIXME Is this necessary? */
|
||||
avc_tuner_status(fdtv, &stat);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
return POLLIN;
|
||||
}
|
||||
|
||||
static struct file_operations fdtv_ca_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.ioctl = dvb_generic_ioctl,
|
||||
.open = dvb_generic_open,
|
||||
.release = dvb_generic_release,
|
||||
.poll = fdtv_ca_io_poll,
|
||||
};
|
||||
|
||||
static struct dvb_device fdtv_ca = {
|
||||
.users = 1,
|
||||
.readers = 1,
|
||||
.writers = 1,
|
||||
.fops = &fdtv_ca_fops,
|
||||
.kernel_ioctl = fdtv_ca_ioctl,
|
||||
};
|
||||
|
||||
int fdtv_ca_register(struct firedtv *fdtv)
|
||||
{
|
||||
struct firedtv_tuner_status stat;
|
||||
int err;
|
||||
|
||||
if (avc_tuner_status(fdtv, &stat))
|
||||
return -EINVAL;
|
||||
|
||||
if (!fdtv_ca_ready(&stat))
|
||||
return -EFAULT;
|
||||
|
||||
err = dvb_register_device(&fdtv->adapter, &fdtv->cadev,
|
||||
&fdtv_ca, fdtv, DVB_DEVICE_CA);
|
||||
|
||||
if (stat.ca_application_info == 0)
|
||||
dev_err(fdtv->device, "CaApplicationInfo is not set\n");
|
||||
if (stat.ca_date_time_request == 1)
|
||||
avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void fdtv_ca_release(struct firedtv *fdtv)
|
||||
{
|
||||
if (fdtv->cadev)
|
||||
dvb_unregister_device(fdtv->cadev);
|
||||
}
|
364
drivers/media/dvb/firewire/firedtv-dvb.c
Normal file
364
drivers/media/dvb/firewire/firedtv-dvb.c
Normal file
@ -0,0 +1,364 @@
|
||||
/*
|
||||
* FireDTV driver (formerly known as FireSAT)
|
||||
*
|
||||
* Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
|
||||
* Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <dmxdev.h>
|
||||
#include <dvb_demux.h>
|
||||
#include <dvbdev.h>
|
||||
#include <dvb_frontend.h>
|
||||
|
||||
#include "firedtv.h"
|
||||
|
||||
static int alloc_channel(struct firedtv *fdtv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if (!__test_and_set_bit(i, &fdtv->channel_active))
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])
|
||||
{
|
||||
int i, n;
|
||||
|
||||
for (i = 0, n = 0; i < 16; i++)
|
||||
if (test_bit(i, &fdtv->channel_active))
|
||||
pid[n++] = fdtv->channel_pid[i];
|
||||
*pidc = n;
|
||||
}
|
||||
|
||||
static inline void dealloc_channel(struct firedtv *fdtv, int i)
|
||||
{
|
||||
__clear_bit(i, &fdtv->channel_active);
|
||||
}
|
||||
|
||||
int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct firedtv *fdtv = dvbdmxfeed->demux->priv;
|
||||
int pidc, c, ret;
|
||||
u16 pids[16];
|
||||
|
||||
switch (dvbdmxfeed->type) {
|
||||
case DMX_TYPE_TS:
|
||||
case DMX_TYPE_SEC:
|
||||
break;
|
||||
default:
|
||||
dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",
|
||||
dvbdmxfeed->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mutex_lock_interruptible(&fdtv->demux_mutex))
|
||||
return -EINTR;
|
||||
|
||||
if (dvbdmxfeed->type == DMX_TYPE_TS) {
|
||||
switch (dvbdmxfeed->pes_type) {
|
||||
case DMX_TS_PES_VIDEO:
|
||||
case DMX_TS_PES_AUDIO:
|
||||
case DMX_TS_PES_TELETEXT:
|
||||
case DMX_TS_PES_PCR:
|
||||
case DMX_TS_PES_OTHER:
|
||||
c = alloc_channel(fdtv);
|
||||
break;
|
||||
default:
|
||||
dev_err(fdtv->device,
|
||||
"can't start dmx feed: invalid pes type %u\n",
|
||||
dvbdmxfeed->pes_type);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
c = alloc_channel(fdtv);
|
||||
}
|
||||
|
||||
if (c > 15) {
|
||||
dev_err(fdtv->device, "can't start dmx feed: busy\n");
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;
|
||||
fdtv->channel_pid[c] = dvbdmxfeed->pid;
|
||||
collect_channels(fdtv, &pidc, pids);
|
||||
|
||||
if (dvbdmxfeed->pid == 8192) {
|
||||
ret = avc_tuner_get_ts(fdtv);
|
||||
if (ret) {
|
||||
dealloc_channel(fdtv, c);
|
||||
dev_err(fdtv->device, "can't get TS\n");
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
ret = avc_tuner_set_pids(fdtv, pidc, pids);
|
||||
if (ret) {
|
||||
dealloc_channel(fdtv, c);
|
||||
dev_err(fdtv->device, "can't set PIDs\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&fdtv->demux_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct dvb_demux *demux = dvbdmxfeed->demux;
|
||||
struct firedtv *fdtv = demux->priv;
|
||||
int pidc, c, ret;
|
||||
u16 pids[16];
|
||||
|
||||
if (dvbdmxfeed->type == DMX_TYPE_TS &&
|
||||
!((dvbdmxfeed->ts_type & TS_PACKET) &&
|
||||
(demux->dmx.frontend->source != DMX_MEMORY_FE))) {
|
||||
|
||||
if (dvbdmxfeed->ts_type & TS_DECODER) {
|
||||
if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
|
||||
!demux->pesfilter[dvbdmxfeed->pes_type])
|
||||
return -EINVAL;
|
||||
|
||||
demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
|
||||
demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
|
||||
}
|
||||
|
||||
if (!(dvbdmxfeed->ts_type & TS_DECODER &&
|
||||
dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mutex_lock_interruptible(&fdtv->demux_mutex))
|
||||
return -EINTR;
|
||||
|
||||
c = (unsigned long)dvbdmxfeed->priv;
|
||||
dealloc_channel(fdtv, c);
|
||||
collect_channels(fdtv, &pidc, pids);
|
||||
|
||||
ret = avc_tuner_set_pids(fdtv, pidc, pids);
|
||||
|
||||
mutex_unlock(&fdtv->demux_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
int fdtv_dvb_register(struct firedtv *fdtv)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dvb_register_adapter(&fdtv->adapter, fdtv_model_names[fdtv->type],
|
||||
THIS_MODULE, fdtv->device, adapter_nr);
|
||||
if (err < 0)
|
||||
goto fail_log;
|
||||
|
||||
/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
|
||||
fdtv->demux.dmx.capabilities = 0;
|
||||
|
||||
fdtv->demux.priv = fdtv;
|
||||
fdtv->demux.filternum = 16;
|
||||
fdtv->demux.feednum = 16;
|
||||
fdtv->demux.start_feed = fdtv_start_feed;
|
||||
fdtv->demux.stop_feed = fdtv_stop_feed;
|
||||
fdtv->demux.write_to_decoder = NULL;
|
||||
|
||||
err = dvb_dmx_init(&fdtv->demux);
|
||||
if (err)
|
||||
goto fail_unreg_adapter;
|
||||
|
||||
fdtv->dmxdev.filternum = 16;
|
||||
fdtv->dmxdev.demux = &fdtv->demux.dmx;
|
||||
fdtv->dmxdev.capabilities = 0;
|
||||
|
||||
err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
|
||||
if (err)
|
||||
goto fail_dmx_release;
|
||||
|
||||
fdtv->frontend.source = DMX_FRONTEND_0;
|
||||
|
||||
err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);
|
||||
if (err)
|
||||
goto fail_dmxdev_release;
|
||||
|
||||
err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
|
||||
&fdtv->frontend);
|
||||
if (err)
|
||||
goto fail_rem_frontend;
|
||||
|
||||
dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
|
||||
|
||||
fdtv_frontend_init(fdtv);
|
||||
err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
|
||||
if (err)
|
||||
goto fail_net_release;
|
||||
|
||||
err = fdtv_ca_register(fdtv);
|
||||
if (err)
|
||||
dev_info(fdtv->device,
|
||||
"Conditional Access Module not enabled\n");
|
||||
return 0;
|
||||
|
||||
fail_net_release:
|
||||
dvb_net_release(&fdtv->dvbnet);
|
||||
fdtv->demux.dmx.close(&fdtv->demux.dmx);
|
||||
fail_rem_frontend:
|
||||
fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
|
||||
fail_dmxdev_release:
|
||||
dvb_dmxdev_release(&fdtv->dmxdev);
|
||||
fail_dmx_release:
|
||||
dvb_dmx_release(&fdtv->demux);
|
||||
fail_unreg_adapter:
|
||||
dvb_unregister_adapter(&fdtv->adapter);
|
||||
fail_log:
|
||||
dev_err(fdtv->device, "DVB initialization failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
void fdtv_dvb_unregister(struct firedtv *fdtv)
|
||||
{
|
||||
fdtv_ca_release(fdtv);
|
||||
dvb_unregister_frontend(&fdtv->fe);
|
||||
dvb_net_release(&fdtv->dvbnet);
|
||||
fdtv->demux.dmx.close(&fdtv->demux.dmx);
|
||||
fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
|
||||
dvb_dmxdev_release(&fdtv->dmxdev);
|
||||
dvb_dmx_release(&fdtv->demux);
|
||||
dvb_unregister_adapter(&fdtv->adapter);
|
||||
}
|
||||
|
||||
const char *fdtv_model_names[] = {
|
||||
[FIREDTV_UNKNOWN] = "unknown type",
|
||||
[FIREDTV_DVB_S] = "FireDTV S/CI",
|
||||
[FIREDTV_DVB_C] = "FireDTV C/CI",
|
||||
[FIREDTV_DVB_T] = "FireDTV T/CI",
|
||||
[FIREDTV_DVB_S2] = "FireDTV S2 ",
|
||||
};
|
||||
|
||||
struct firedtv *fdtv_alloc(struct device *dev,
|
||||
const struct firedtv_backend *backend,
|
||||
const char *name, size_t name_len)
|
||||
{
|
||||
struct firedtv *fdtv;
|
||||
int i;
|
||||
|
||||
fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL);
|
||||
if (!fdtv)
|
||||
return NULL;
|
||||
|
||||
dev->driver_data = fdtv;
|
||||
fdtv->device = dev;
|
||||
fdtv->isochannel = -1;
|
||||
fdtv->voltage = 0xff;
|
||||
fdtv->tone = 0xff;
|
||||
fdtv->backend = backend;
|
||||
|
||||
mutex_init(&fdtv->avc_mutex);
|
||||
init_waitqueue_head(&fdtv->avc_wait);
|
||||
fdtv->avc_reply_received = true;
|
||||
mutex_init(&fdtv->demux_mutex);
|
||||
INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
|
||||
|
||||
for (i = ARRAY_SIZE(fdtv_model_names); --i; )
|
||||
if (strlen(fdtv_model_names[i]) <= name_len &&
|
||||
strncmp(name, fdtv_model_names[i], name_len) == 0)
|
||||
break;
|
||||
fdtv->type = i;
|
||||
|
||||
return fdtv;
|
||||
}
|
||||
|
||||
#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
|
||||
IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION)
|
||||
|
||||
#define DIGITAL_EVERYWHERE_OUI 0x001287
|
||||
#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d
|
||||
#define AVC_SW_VERSION_ENTRY 0x010001
|
||||
|
||||
static struct ieee1394_device_id fdtv_id_table[] = {
|
||||
{
|
||||
/* FloppyDTV S/CI and FloppyDTV S2 */
|
||||
.match_flags = MATCH_FLAGS,
|
||||
.vendor_id = DIGITAL_EVERYWHERE_OUI,
|
||||
.model_id = 0x000024,
|
||||
.specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
|
||||
.version = AVC_SW_VERSION_ENTRY,
|
||||
}, {
|
||||
/* FloppyDTV T/CI */
|
||||
.match_flags = MATCH_FLAGS,
|
||||
.vendor_id = DIGITAL_EVERYWHERE_OUI,
|
||||
.model_id = 0x000025,
|
||||
.specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
|
||||
.version = AVC_SW_VERSION_ENTRY,
|
||||
}, {
|
||||
/* FloppyDTV C/CI */
|
||||
.match_flags = MATCH_FLAGS,
|
||||
.vendor_id = DIGITAL_EVERYWHERE_OUI,
|
||||
.model_id = 0x000026,
|
||||
.specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
|
||||
.version = AVC_SW_VERSION_ENTRY,
|
||||
}, {
|
||||
/* FireDTV S/CI and FloppyDTV S2 */
|
||||
.match_flags = MATCH_FLAGS,
|
||||
.vendor_id = DIGITAL_EVERYWHERE_OUI,
|
||||
.model_id = 0x000034,
|
||||
.specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
|
||||
.version = AVC_SW_VERSION_ENTRY,
|
||||
}, {
|
||||
/* FireDTV T/CI */
|
||||
.match_flags = MATCH_FLAGS,
|
||||
.vendor_id = DIGITAL_EVERYWHERE_OUI,
|
||||
.model_id = 0x000035,
|
||||
.specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
|
||||
.version = AVC_SW_VERSION_ENTRY,
|
||||
}, {
|
||||
/* FireDTV C/CI */
|
||||
.match_flags = MATCH_FLAGS,
|
||||
.vendor_id = DIGITAL_EVERYWHERE_OUI,
|
||||
.model_id = 0x000036,
|
||||
.specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
|
||||
.version = AVC_SW_VERSION_ENTRY,
|
||||
}, {}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
|
||||
|
||||
static int __init fdtv_init(void)
|
||||
{
|
||||
return fdtv_1394_init(fdtv_id_table);
|
||||
}
|
||||
|
||||
static void __exit fdtv_exit(void)
|
||||
{
|
||||
fdtv_1394_exit();
|
||||
}
|
||||
|
||||
module_init(fdtv_init);
|
||||
module_exit(fdtv_exit);
|
||||
|
||||
MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
|
||||
MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
|
||||
MODULE_DESCRIPTION("FireDTV DVB Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_SUPPORTED_DEVICE("FireDTV DVB");
|
247
drivers/media/dvb/firewire/firedtv-fe.c
Normal file
247
drivers/media/dvb/firewire/firedtv-fe.c
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* FireDTV driver (formerly known as FireSAT)
|
||||
*
|
||||
* Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
|
||||
* Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <dvb_frontend.h>
|
||||
|
||||
#include "firedtv.h"
|
||||
|
||||
static int fdtv_dvb_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct firedtv *fdtv = fe->sec_priv;
|
||||
int err;
|
||||
|
||||
/* FIXME - allocate free channel at IRM */
|
||||
fdtv->isochannel = fdtv->adapter.num;
|
||||
|
||||
err = cmp_establish_pp_connection(fdtv, fdtv->subunit,
|
||||
fdtv->isochannel);
|
||||
if (err) {
|
||||
dev_err(fdtv->device,
|
||||
"could not establish point to point connection\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return fdtv->backend->start_iso(fdtv);
|
||||
}
|
||||
|
||||
static int fdtv_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct firedtv *fdtv = fe->sec_priv;
|
||||
|
||||
fdtv->backend->stop_iso(fdtv);
|
||||
cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel);
|
||||
fdtv->isochannel = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define LNBCONTROL_DONTCARE 0xff
|
||||
|
||||
static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe,
|
||||
struct dvb_diseqc_master_cmd *cmd)
|
||||
{
|
||||
struct firedtv *fdtv = fe->sec_priv;
|
||||
|
||||
return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE,
|
||||
LNBCONTROL_DONTCARE, 1, cmd);
|
||||
}
|
||||
|
||||
static int fdtv_diseqc_send_burst(struct dvb_frontend *fe,
|
||||
fe_sec_mini_cmd_t minicmd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
|
||||
{
|
||||
struct firedtv *fdtv = fe->sec_priv;
|
||||
|
||||
fdtv->tone = tone;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdtv_set_voltage(struct dvb_frontend *fe,
|
||||
fe_sec_voltage_t voltage)
|
||||
{
|
||||
struct firedtv *fdtv = fe->sec_priv;
|
||||
|
||||
fdtv->voltage = voltage;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct firedtv *fdtv = fe->sec_priv;
|
||||
struct firedtv_tuner_status stat;
|
||||
|
||||
if (avc_tuner_status(fdtv, &stat))
|
||||
return -EINVAL;
|
||||
|
||||
if (stat.no_rf)
|
||||
*status = 0;
|
||||
else
|
||||
*status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC |
|
||||
FE_HAS_CARRIER | FE_HAS_LOCK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct firedtv *fdtv = fe->sec_priv;
|
||||
struct firedtv_tuner_status stat;
|
||||
|
||||
if (avc_tuner_status(fdtv, &stat))
|
||||
return -EINVAL;
|
||||
|
||||
*ber = stat.ber;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdtv_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
{
|
||||
struct firedtv *fdtv = fe->sec_priv;
|
||||
struct firedtv_tuner_status stat;
|
||||
|
||||
if (avc_tuner_status(fdtv, &stat))
|
||||
return -EINVAL;
|
||||
|
||||
*strength = stat.signal_strength << 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct firedtv *fdtv = fe->sec_priv;
|
||||
struct firedtv_tuner_status stat;
|
||||
|
||||
if (avc_tuner_status(fdtv, &stat))
|
||||
return -EINVAL;
|
||||
|
||||
/* C/N[dB] = -10 * log10(snr / 65535) */
|
||||
*snr = stat.carrier_noise_ratio * 257;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#define ACCEPTED 0x9
|
||||
|
||||
static int fdtv_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct firedtv *fdtv = fe->sec_priv;
|
||||
|
||||
/* FIXME: avc_tuner_dsd never returns ACCEPTED. Check status? */
|
||||
if (avc_tuner_dsd(fdtv, params) != ACCEPTED)
|
||||
return -EINVAL;
|
||||
else
|
||||
return 0; /* not sure of this... */
|
||||
}
|
||||
|
||||
static int fdtv_get_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
void fdtv_frontend_init(struct firedtv *fdtv)
|
||||
{
|
||||
struct dvb_frontend_ops *ops = &fdtv->fe.ops;
|
||||
struct dvb_frontend_info *fi = &ops->info;
|
||||
|
||||
ops->init = fdtv_dvb_init;
|
||||
ops->sleep = fdtv_sleep;
|
||||
|
||||
ops->set_frontend = fdtv_set_frontend;
|
||||
ops->get_frontend = fdtv_get_frontend;
|
||||
|
||||
ops->read_status = fdtv_read_status;
|
||||
ops->read_ber = fdtv_read_ber;
|
||||
ops->read_signal_strength = fdtv_read_signal_strength;
|
||||
ops->read_snr = fdtv_read_snr;
|
||||
ops->read_ucblocks = fdtv_read_uncorrected_blocks;
|
||||
|
||||
ops->diseqc_send_master_cmd = fdtv_diseqc_send_master_cmd;
|
||||
ops->diseqc_send_burst = fdtv_diseqc_send_burst;
|
||||
ops->set_tone = fdtv_set_tone;
|
||||
ops->set_voltage = fdtv_set_voltage;
|
||||
|
||||
switch (fdtv->type) {
|
||||
case FIREDTV_DVB_S:
|
||||
case FIREDTV_DVB_S2:
|
||||
fi->type = FE_QPSK;
|
||||
|
||||
fi->frequency_min = 950000;
|
||||
fi->frequency_max = 2150000;
|
||||
fi->frequency_stepsize = 125;
|
||||
fi->symbol_rate_min = 1000000;
|
||||
fi->symbol_rate_max = 40000000;
|
||||
|
||||
fi->caps = FE_CAN_INVERSION_AUTO |
|
||||
FE_CAN_FEC_1_2 |
|
||||
FE_CAN_FEC_2_3 |
|
||||
FE_CAN_FEC_3_4 |
|
||||
FE_CAN_FEC_5_6 |
|
||||
FE_CAN_FEC_7_8 |
|
||||
FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QPSK;
|
||||
break;
|
||||
|
||||
case FIREDTV_DVB_C:
|
||||
fi->type = FE_QAM;
|
||||
|
||||
fi->frequency_min = 47000000;
|
||||
fi->frequency_max = 866000000;
|
||||
fi->frequency_stepsize = 62500;
|
||||
fi->symbol_rate_min = 870000;
|
||||
fi->symbol_rate_max = 6900000;
|
||||
|
||||
fi->caps = FE_CAN_INVERSION_AUTO |
|
||||
FE_CAN_QAM_16 |
|
||||
FE_CAN_QAM_32 |
|
||||
FE_CAN_QAM_64 |
|
||||
FE_CAN_QAM_128 |
|
||||
FE_CAN_QAM_256 |
|
||||
FE_CAN_QAM_AUTO;
|
||||
break;
|
||||
|
||||
case FIREDTV_DVB_T:
|
||||
fi->type = FE_OFDM;
|
||||
|
||||
fi->frequency_min = 49000000;
|
||||
fi->frequency_max = 861000000;
|
||||
fi->frequency_stepsize = 62500;
|
||||
|
||||
fi->caps = FE_CAN_INVERSION_AUTO |
|
||||
FE_CAN_FEC_2_3 |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO |
|
||||
FE_CAN_HIERARCHY_AUTO;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(fdtv->device, "no frontend for model type %d\n",
|
||||
fdtv->type);
|
||||
}
|
||||
strcpy(fi->name, fdtv_model_names[fdtv->type]);
|
||||
|
||||
fdtv->fe.dvb = &fdtv->adapter;
|
||||
fdtv->fe.sec_priv = fdtv;
|
||||
}
|
190
drivers/media/dvb/firewire/firedtv-rc.c
Normal file
190
drivers/media/dvb/firewire/firedtv-rc.c
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* FireDTV driver (formerly known as FireSAT)
|
||||
*
|
||||
* Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "firedtv.h"
|
||||
|
||||
/* fixed table with older keycodes, geared towards MythTV */
|
||||
const static u16 oldtable[] = {
|
||||
|
||||
/* code from device: 0x4501...0x451f */
|
||||
|
||||
KEY_ESC,
|
||||
KEY_F9,
|
||||
KEY_1,
|
||||
KEY_2,
|
||||
KEY_3,
|
||||
KEY_4,
|
||||
KEY_5,
|
||||
KEY_6,
|
||||
KEY_7,
|
||||
KEY_8,
|
||||
KEY_9,
|
||||
KEY_I,
|
||||
KEY_0,
|
||||
KEY_ENTER,
|
||||
KEY_RED,
|
||||
KEY_UP,
|
||||
KEY_GREEN,
|
||||
KEY_F10,
|
||||
KEY_SPACE,
|
||||
KEY_F11,
|
||||
KEY_YELLOW,
|
||||
KEY_DOWN,
|
||||
KEY_BLUE,
|
||||
KEY_Z,
|
||||
KEY_P,
|
||||
KEY_PAGEDOWN,
|
||||
KEY_LEFT,
|
||||
KEY_W,
|
||||
KEY_RIGHT,
|
||||
KEY_P,
|
||||
KEY_M,
|
||||
|
||||
/* code from device: 0x4540...0x4542 */
|
||||
|
||||
KEY_R,
|
||||
KEY_V,
|
||||
KEY_C,
|
||||
};
|
||||
|
||||
/* user-modifiable table for a remote as sold in 2008 */
|
||||
const static u16 keytable[] = {
|
||||
|
||||
/* code from device: 0x0300...0x031f */
|
||||
|
||||
[0x00] = KEY_POWER,
|
||||
[0x01] = KEY_SLEEP,
|
||||
[0x02] = KEY_STOP,
|
||||
[0x03] = KEY_OK,
|
||||
[0x04] = KEY_RIGHT,
|
||||
[0x05] = KEY_1,
|
||||
[0x06] = KEY_2,
|
||||
[0x07] = KEY_3,
|
||||
[0x08] = KEY_LEFT,
|
||||
[0x09] = KEY_4,
|
||||
[0x0a] = KEY_5,
|
||||
[0x0b] = KEY_6,
|
||||
[0x0c] = KEY_UP,
|
||||
[0x0d] = KEY_7,
|
||||
[0x0e] = KEY_8,
|
||||
[0x0f] = KEY_9,
|
||||
[0x10] = KEY_DOWN,
|
||||
[0x11] = KEY_TITLE, /* "OSD" - fixme */
|
||||
[0x12] = KEY_0,
|
||||
[0x13] = KEY_F20, /* "16:9" - fixme */
|
||||
[0x14] = KEY_SCREEN, /* "FULL" - fixme */
|
||||
[0x15] = KEY_MUTE,
|
||||
[0x16] = KEY_SUBTITLE,
|
||||
[0x17] = KEY_RECORD,
|
||||
[0x18] = KEY_TEXT,
|
||||
[0x19] = KEY_AUDIO,
|
||||
[0x1a] = KEY_RED,
|
||||
[0x1b] = KEY_PREVIOUS,
|
||||
[0x1c] = KEY_REWIND,
|
||||
[0x1d] = KEY_PLAYPAUSE,
|
||||
[0x1e] = KEY_NEXT,
|
||||
[0x1f] = KEY_VOLUMEUP,
|
||||
|
||||
/* code from device: 0x0340...0x0354 */
|
||||
|
||||
[0x20] = KEY_CHANNELUP,
|
||||
[0x21] = KEY_F21, /* "4:3" - fixme */
|
||||
[0x22] = KEY_TV,
|
||||
[0x23] = KEY_DVD,
|
||||
[0x24] = KEY_VCR,
|
||||
[0x25] = KEY_AUX,
|
||||
[0x26] = KEY_GREEN,
|
||||
[0x27] = KEY_YELLOW,
|
||||
[0x28] = KEY_BLUE,
|
||||
[0x29] = KEY_CHANNEL, /* "CH.LIST" */
|
||||
[0x2a] = KEY_VENDOR, /* "CI" - fixme */
|
||||
[0x2b] = KEY_VOLUMEDOWN,
|
||||
[0x2c] = KEY_CHANNELDOWN,
|
||||
[0x2d] = KEY_LAST,
|
||||
[0x2e] = KEY_INFO,
|
||||
[0x2f] = KEY_FORWARD,
|
||||
[0x30] = KEY_LIST,
|
||||
[0x31] = KEY_FAVORITES,
|
||||
[0x32] = KEY_MENU,
|
||||
[0x33] = KEY_EPG,
|
||||
[0x34] = KEY_EXIT,
|
||||
};
|
||||
|
||||
int fdtv_register_rc(struct firedtv *fdtv, struct device *dev)
|
||||
{
|
||||
struct input_dev *idev;
|
||||
int i, err;
|
||||
|
||||
idev = input_allocate_device();
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
fdtv->remote_ctrl_dev = idev;
|
||||
idev->name = "FireDTV remote control";
|
||||
idev->dev.parent = dev;
|
||||
idev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL);
|
||||
if (!idev->keycode) {
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
idev->keycodesize = sizeof(keytable[0]);
|
||||
idev->keycodemax = ARRAY_SIZE(keytable);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(keytable); i++)
|
||||
set_bit(keytable[i], idev->keybit);
|
||||
|
||||
err = input_register_device(idev);
|
||||
if (err)
|
||||
goto fail_free_keymap;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_free_keymap:
|
||||
kfree(idev->keycode);
|
||||
fail:
|
||||
input_free_device(idev);
|
||||
return err;
|
||||
}
|
||||
|
||||
void fdtv_unregister_rc(struct firedtv *fdtv)
|
||||
{
|
||||
kfree(fdtv->remote_ctrl_dev->keycode);
|
||||
input_unregister_device(fdtv->remote_ctrl_dev);
|
||||
}
|
||||
|
||||
void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code)
|
||||
{
|
||||
u16 *keycode = fdtv->remote_ctrl_dev->keycode;
|
||||
|
||||
if (code >= 0x0300 && code <= 0x031f)
|
||||
code = keycode[code - 0x0300];
|
||||
else if (code >= 0x0340 && code <= 0x0354)
|
||||
code = keycode[code - 0x0320];
|
||||
else if (code >= 0x4501 && code <= 0x451f)
|
||||
code = oldtable[code - 0x4501];
|
||||
else if (code >= 0x4540 && code <= 0x4542)
|
||||
code = oldtable[code - 0x4521];
|
||||
else {
|
||||
printk(KERN_DEBUG "firedtv: invalid key code 0x%04x "
|
||||
"from remote control\n", code);
|
||||
return;
|
||||
}
|
||||
|
||||
input_report_key(fdtv->remote_ctrl_dev, code, 1);
|
||||
input_report_key(fdtv->remote_ctrl_dev, code, 0);
|
||||
}
|
182
drivers/media/dvb/firewire/firedtv.h
Normal file
182
drivers/media/dvb/firewire/firedtv.h
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* FireDTV driver (formerly known as FireSAT)
|
||||
*
|
||||
* Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
|
||||
* Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _FIREDTV_H
|
||||
#define _FIREDTV_H
|
||||
|
||||
#include <linux/dvb/dmx.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock_types.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <demux.h>
|
||||
#include <dmxdev.h>
|
||||
#include <dvb_demux.h>
|
||||
#include <dvb_frontend.h>
|
||||
#include <dvb_net.h>
|
||||
#include <dvbdev.h>
|
||||
|
||||
struct firedtv_tuner_status {
|
||||
unsigned active_system:8;
|
||||
unsigned searching:1;
|
||||
unsigned moving:1;
|
||||
unsigned no_rf:1;
|
||||
unsigned input:1;
|
||||
unsigned selected_antenna:7;
|
||||
unsigned ber:32;
|
||||
unsigned signal_strength:8;
|
||||
unsigned raster_frequency:2;
|
||||
unsigned rf_frequency:22;
|
||||
unsigned man_dep_info_length:8;
|
||||
unsigned front_end_error:1;
|
||||
unsigned antenna_error:1;
|
||||
unsigned front_end_power_status:1;
|
||||
unsigned power_supply:1;
|
||||
unsigned carrier_noise_ratio:16;
|
||||
unsigned power_supply_voltage:8;
|
||||
unsigned antenna_voltage:8;
|
||||
unsigned firewire_bus_voltage:8;
|
||||
unsigned ca_mmi:1;
|
||||
unsigned ca_pmt_reply:1;
|
||||
unsigned ca_date_time_request:1;
|
||||
unsigned ca_application_info:1;
|
||||
unsigned ca_module_present_status:1;
|
||||
unsigned ca_dvb_flag:1;
|
||||
unsigned ca_error_flag:1;
|
||||
unsigned ca_initialization_status:1;
|
||||
};
|
||||
|
||||
enum model_type {
|
||||
FIREDTV_UNKNOWN = 0,
|
||||
FIREDTV_DVB_S = 1,
|
||||
FIREDTV_DVB_C = 2,
|
||||
FIREDTV_DVB_T = 3,
|
||||
FIREDTV_DVB_S2 = 4,
|
||||
};
|
||||
|
||||
struct device;
|
||||
struct input_dev;
|
||||
struct firedtv;
|
||||
|
||||
struct firedtv_backend {
|
||||
int (*lock)(struct firedtv *fdtv, u64 addr, void *data, __be32 arg);
|
||||
int (*read)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
|
||||
int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
|
||||
int (*start_iso)(struct firedtv *fdtv);
|
||||
void (*stop_iso)(struct firedtv *fdtv);
|
||||
};
|
||||
|
||||
struct firedtv {
|
||||
struct device *device;
|
||||
struct list_head list;
|
||||
|
||||
struct dvb_adapter adapter;
|
||||
struct dmxdev dmxdev;
|
||||
struct dvb_demux demux;
|
||||
struct dmx_frontend frontend;
|
||||
struct dvb_net dvbnet;
|
||||
struct dvb_frontend fe;
|
||||
|
||||
struct dvb_device *cadev;
|
||||
int ca_last_command;
|
||||
int ca_time_interval;
|
||||
|
||||
struct mutex avc_mutex;
|
||||
wait_queue_head_t avc_wait;
|
||||
bool avc_reply_received;
|
||||
struct work_struct remote_ctrl_work;
|
||||
struct input_dev *remote_ctrl_dev;
|
||||
|
||||
enum model_type type;
|
||||
char subunit;
|
||||
char isochannel;
|
||||
fe_sec_voltage_t voltage;
|
||||
fe_sec_tone_mode_t tone;
|
||||
|
||||
const struct firedtv_backend *backend;
|
||||
void *backend_data;
|
||||
|
||||
struct mutex demux_mutex;
|
||||
unsigned long channel_active;
|
||||
u16 channel_pid[16];
|
||||
|
||||
size_t response_length;
|
||||
u8 response[512];
|
||||
};
|
||||
|
||||
/* firedtv-1394.c */
|
||||
#ifdef CONFIG_DVB_FIREDTV_IEEE1394
|
||||
int fdtv_1394_init(struct ieee1394_device_id id_table[]);
|
||||
void fdtv_1394_exit(void);
|
||||
#else
|
||||
static inline int fdtv_1394_init(struct ieee1394_device_id it[]) { return 0; }
|
||||
static inline void fdtv_1394_exit(void) {}
|
||||
#endif
|
||||
|
||||
/* firedtv-avc.c */
|
||||
int avc_recv(struct firedtv *fdtv, void *data, size_t length);
|
||||
int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat);
|
||||
struct dvb_frontend_parameters;
|
||||
int avc_tuner_dsd(struct firedtv *fdtv, struct dvb_frontend_parameters *params);
|
||||
int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]);
|
||||
int avc_tuner_get_ts(struct firedtv *fdtv);
|
||||
int avc_identify_subunit(struct firedtv *fdtv);
|
||||
struct dvb_diseqc_master_cmd;
|
||||
int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
|
||||
char conttone, char nrdiseq,
|
||||
struct dvb_diseqc_master_cmd *diseqcmd);
|
||||
void avc_remote_ctrl_work(struct work_struct *work);
|
||||
int avc_register_remote_control(struct firedtv *fdtv);
|
||||
int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
|
||||
int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
|
||||
int avc_ca_reset(struct firedtv *fdtv);
|
||||
int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length);
|
||||
int avc_ca_get_time_date(struct firedtv *fdtv, int *interval);
|
||||
int avc_ca_enter_menu(struct firedtv *fdtv);
|
||||
int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len);
|
||||
int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel);
|
||||
void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel);
|
||||
|
||||
/* firedtv-ci.c */
|
||||
int fdtv_ca_register(struct firedtv *fdtv);
|
||||
void fdtv_ca_release(struct firedtv *fdtv);
|
||||
|
||||
/* firedtv-dvb.c */
|
||||
int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed);
|
||||
int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed);
|
||||
int fdtv_dvb_register(struct firedtv *fdtv);
|
||||
void fdtv_dvb_unregister(struct firedtv *fdtv);
|
||||
struct firedtv *fdtv_alloc(struct device *dev,
|
||||
const struct firedtv_backend *backend,
|
||||
const char *name, size_t name_len);
|
||||
extern const char *fdtv_model_names[];
|
||||
|
||||
/* firedtv-fe.c */
|
||||
void fdtv_frontend_init(struct firedtv *fdtv);
|
||||
|
||||
/* firedtv-rc.c */
|
||||
#ifdef CONFIG_DVB_FIREDTV_INPUT
|
||||
int fdtv_register_rc(struct firedtv *fdtv, struct device *dev);
|
||||
void fdtv_unregister_rc(struct firedtv *fdtv);
|
||||
void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code);
|
||||
#else
|
||||
static inline int fdtv_register_rc(struct firedtv *fdtv,
|
||||
struct device *dev) { return 0; }
|
||||
static inline void fdtv_unregister_rc(struct firedtv *fdtv) {}
|
||||
static inline void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) {}
|
||||
#endif
|
||||
|
||||
#endif /* _FIREDTV_H */
|
@ -2342,6 +2342,17 @@ config ATL1E
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called atl1e.
|
||||
|
||||
config ATL1C
|
||||
tristate "Atheros L1C Gigabit Ethernet support (EXPERIMENTAL)"
|
||||
depends on PCI && EXPERIMENTAL
|
||||
select CRC32
|
||||
select MII
|
||||
help
|
||||
This driver supports the Atheros L1C gigabit ethernet adapter.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called atl1c.
|
||||
|
||||
config JME
|
||||
tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
|
||||
depends on PCI
|
||||
|
@ -17,6 +17,7 @@ obj-$(CONFIG_BONDING) += bonding/
|
||||
obj-$(CONFIG_ATL1) += atlx/
|
||||
obj-$(CONFIG_ATL2) += atlx/
|
||||
obj-$(CONFIG_ATL1E) += atl1e/
|
||||
obj-$(CONFIG_ATL1C) += atl1c/
|
||||
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
|
||||
obj-$(CONFIG_TEHUTI) += tehuti.o
|
||||
obj-$(CONFIG_ENIC) += enic/
|
||||
|
2
drivers/net/atl1c/Makefile
Normal file
2
drivers/net/atl1c/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_ATL1C) += atl1c.o
|
||||
atl1c-objs := atl1c_main.o atl1c_hw.o atl1c_ethtool.o
|
606
drivers/net/atl1c/atl1c.h
Normal file
606
drivers/net/atl1c/atl1c.h
Normal file
@ -0,0 +1,606 @@
|
||||
/*
|
||||
* Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
|
||||
*
|
||||
* Derived from Intel e1000 driver
|
||||
* Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _ATL1C_H_
|
||||
#define _ATL1C_H_
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
|
||||
#include "atl1c_hw.h"
|
||||
|
||||
/* Wake Up Filter Control */
|
||||
#define AT_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
|
||||
#define AT_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
|
||||
#define AT_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
|
||||
#define AT_WUFC_MC 0x00000008 /* Multicast Wakeup Enable */
|
||||
#define AT_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
|
||||
|
||||
#define AT_VLAN_TO_TAG(_vlan, _tag) \
|
||||
_tag = ((((_vlan) >> 8) & 0xFF) |\
|
||||
(((_vlan) & 0xFF) << 8))
|
||||
|
||||
#define AT_TAG_TO_VLAN(_tag, _vlan) \
|
||||
_vlan = ((((_tag) >> 8) & 0xFF) |\
|
||||
(((_tag) & 0xFF) << 8))
|
||||
|
||||
#define SPEED_0 0xffff
|
||||
#define HALF_DUPLEX 1
|
||||
#define FULL_DUPLEX 2
|
||||
|
||||
#define AT_RX_BUF_SIZE (ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN)
|
||||
#define MAX_JUMBO_FRAME_SIZE (9*1024)
|
||||
#define MAX_TX_OFFLOAD_THRESH (9*1024)
|
||||
|
||||
#define AT_MAX_RECEIVE_QUEUE 4
|
||||
#define AT_DEF_RECEIVE_QUEUE 1
|
||||
#define AT_MAX_TRANSMIT_QUEUE 2
|
||||
|
||||
#define AT_DMA_HI_ADDR_MASK 0xffffffff00000000ULL
|
||||
#define AT_DMA_LO_ADDR_MASK 0x00000000ffffffffULL
|
||||
|
||||
#define AT_TX_WATCHDOG (5 * HZ)
|
||||
#define AT_MAX_INT_WORK 5
|
||||
#define AT_TWSI_EEPROM_TIMEOUT 100
|
||||
#define AT_HW_MAX_IDLE_DELAY 10
|
||||
#define AT_SUSPEND_LINK_TIMEOUT 28
|
||||
|
||||
#define AT_ASPM_L0S_TIMER 6
|
||||
#define AT_ASPM_L1_TIMER 12
|
||||
|
||||
#define ATL1C_PCIE_L0S_L1_DISABLE 0x01
|
||||
#define ATL1C_PCIE_PHY_RESET 0x02
|
||||
|
||||
#define ATL1C_ASPM_L0s_ENABLE 0x0001
|
||||
#define ATL1C_ASPM_L1_ENABLE 0x0002
|
||||
|
||||
#define AT_REGS_LEN (75 * sizeof(u32))
|
||||
#define AT_EEPROM_LEN 512
|
||||
|
||||
#define ATL1C_GET_DESC(R, i, type) (&(((type *)((R)->desc))[i]))
|
||||
#define ATL1C_RFD_DESC(R, i) ATL1C_GET_DESC(R, i, struct atl1c_rx_free_desc)
|
||||
#define ATL1C_TPD_DESC(R, i) ATL1C_GET_DESC(R, i, struct atl1c_tpd_desc)
|
||||
#define ATL1C_RRD_DESC(R, i) ATL1C_GET_DESC(R, i, struct atl1c_recv_ret_status)
|
||||
|
||||
/* tpd word 1 bit 0:7 General Checksum task offload */
|
||||
#define TPD_L4HDR_OFFSET_MASK 0x00FF
|
||||
#define TPD_L4HDR_OFFSET_SHIFT 0
|
||||
|
||||
/* tpd word 1 bit 0:7 Large Send task offload (IPv4/IPV6) */
|
||||
#define TPD_TCPHDR_OFFSET_MASK 0x00FF
|
||||
#define TPD_TCPHDR_OFFSET_SHIFT 0
|
||||
|
||||
/* tpd word 1 bit 0:7 Custom Checksum task offload */
|
||||
#define TPD_PLOADOFFSET_MASK 0x00FF
|
||||
#define TPD_PLOADOFFSET_SHIFT 0
|
||||
|
||||
/* tpd word 1 bit 8:17 */
|
||||
#define TPD_CCSUM_EN_MASK 0x0001
|
||||
#define TPD_CCSUM_EN_SHIFT 8
|
||||
#define TPD_IP_CSUM_MASK 0x0001
|
||||
#define TPD_IP_CSUM_SHIFT 9
|
||||
#define TPD_TCP_CSUM_MASK 0x0001
|
||||
#define TPD_TCP_CSUM_SHIFT 10
|
||||
#define TPD_UDP_CSUM_MASK 0x0001
|
||||
#define TPD_UDP_CSUM_SHIFT 11
|
||||
#define TPD_LSO_EN_MASK 0x0001 /* TCP Large Send Offload */
|
||||
#define TPD_LSO_EN_SHIFT 12
|
||||
#define TPD_LSO_VER_MASK 0x0001
|
||||
#define TPD_LSO_VER_SHIFT 13 /* 0 : ipv4; 1 : ipv4/ipv6 */
|
||||
#define TPD_CON_VTAG_MASK 0x0001
|
||||
#define TPD_CON_VTAG_SHIFT 14
|
||||
#define TPD_INS_VTAG_MASK 0x0001
|
||||
#define TPD_INS_VTAG_SHIFT 15
|
||||
#define TPD_IPV4_PACKET_MASK 0x0001 /* valid when LSO VER is 1 */
|
||||
#define TPD_IPV4_PACKET_SHIFT 16
|
||||
#define TPD_ETH_TYPE_MASK 0x0001
|
||||
#define TPD_ETH_TYPE_SHIFT 17 /* 0 : 802.3 frame; 1 : Ethernet */
|
||||
|
||||
/* tpd word 18:25 Custom Checksum task offload */
|
||||
#define TPD_CCSUM_OFFSET_MASK 0x00FF
|
||||
#define TPD_CCSUM_OFFSET_SHIFT 18
|
||||
#define TPD_CCSUM_EPAD_MASK 0x0001
|
||||
#define TPD_CCSUM_EPAD_SHIFT 30
|
||||
|
||||
/* tpd word 18:30 Large Send task offload (IPv4/IPV6) */
|
||||
#define TPD_MSS_MASK 0x1FFF
|
||||
#define TPD_MSS_SHIFT 18
|
||||
|
||||
#define TPD_EOP_MASK 0x0001
|
||||
#define TPD_EOP_SHIFT 31
|
||||
|
||||
struct atl1c_tpd_desc {
|
||||
__le16 buffer_len; /* include 4-byte CRC */
|
||||
__le16 vlan_tag;
|
||||
__le32 word1;
|
||||
__le64 buffer_addr;
|
||||
};
|
||||
|
||||
struct atl1c_tpd_ext_desc {
|
||||
u32 reservd_0;
|
||||
__le32 word1;
|
||||
__le32 pkt_len;
|
||||
u32 reservd_1;
|
||||
};
|
||||
/* rrs word 0 bit 0:31 */
|
||||
#define RRS_RX_CSUM_MASK 0xFFFF
|
||||
#define RRS_RX_CSUM_SHIFT 0
|
||||
#define RRS_RX_RFD_CNT_MASK 0x000F
|
||||
#define RRS_RX_RFD_CNT_SHIFT 16
|
||||
#define RRS_RX_RFD_INDEX_MASK 0x0FFF
|
||||
#define RRS_RX_RFD_INDEX_SHIFT 20
|
||||
|
||||
/* rrs flag bit 0:16 */
|
||||
#define RRS_HEAD_LEN_MASK 0x00FF
|
||||
#define RRS_HEAD_LEN_SHIFT 0
|
||||
#define RRS_HDS_TYPE_MASK 0x0003
|
||||
#define RRS_HDS_TYPE_SHIFT 8
|
||||
#define RRS_CPU_NUM_MASK 0x0003
|
||||
#define RRS_CPU_NUM_SHIFT 10
|
||||
#define RRS_HASH_FLG_MASK 0x000F
|
||||
#define RRS_HASH_FLG_SHIFT 12
|
||||
|
||||
#define RRS_HDS_TYPE_HEAD 1
|
||||
#define RRS_HDS_TYPE_DATA 2
|
||||
|
||||
#define RRS_IS_NO_HDS_TYPE(flag) \
|
||||
(((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == 0)
|
||||
|
||||
#define RRS_IS_HDS_HEAD(flag) \
|
||||
(((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \
|
||||
RRS_HDS_TYPE_HEAD)
|
||||
|
||||
#define RRS_IS_HDS_DATA(flag) \
|
||||
(((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \
|
||||
RRS_HDS_TYPE_DATA)
|
||||
|
||||
/* rrs word 3 bit 0:31 */
|
||||
#define RRS_PKT_SIZE_MASK 0x3FFF
|
||||
#define RRS_PKT_SIZE_SHIFT 0
|
||||
#define RRS_ERR_L4_CSUM_MASK 0x0001
|
||||
#define RRS_ERR_L4_CSUM_SHIFT 14
|
||||
#define RRS_ERR_IP_CSUM_MASK 0x0001
|
||||
#define RRS_ERR_IP_CSUM_SHIFT 15
|
||||
#define RRS_VLAN_INS_MASK 0x0001
|
||||
#define RRS_VLAN_INS_SHIFT 16
|
||||
#define RRS_PROT_ID_MASK 0x0007
|
||||
#define RRS_PROT_ID_SHIFT 17
|
||||
#define RRS_RX_ERR_SUM_MASK 0x0001
|
||||
#define RRS_RX_ERR_SUM_SHIFT 20
|
||||
#define RRS_RX_ERR_CRC_MASK 0x0001
|
||||
#define RRS_RX_ERR_CRC_SHIFT 21
|
||||
#define RRS_RX_ERR_FAE_MASK 0x0001
|
||||
#define RRS_RX_ERR_FAE_SHIFT 22
|
||||
#define RRS_RX_ERR_TRUNC_MASK 0x0001
|
||||
#define RRS_RX_ERR_TRUNC_SHIFT 23
|
||||
#define RRS_RX_ERR_RUNC_MASK 0x0001
|
||||
#define RRS_RX_ERR_RUNC_SHIFT 24
|
||||
#define RRS_RX_ERR_ICMP_MASK 0x0001
|
||||
#define RRS_RX_ERR_ICMP_SHIFT 25
|
||||
#define RRS_PACKET_BCAST_MASK 0x0001
|
||||
#define RRS_PACKET_BCAST_SHIFT 26
|
||||
#define RRS_PACKET_MCAST_MASK 0x0001
|
||||
#define RRS_PACKET_MCAST_SHIFT 27
|
||||
#define RRS_PACKET_TYPE_MASK 0x0001
|
||||
#define RRS_PACKET_TYPE_SHIFT 28
|
||||
#define RRS_FIFO_FULL_MASK 0x0001
|
||||
#define RRS_FIFO_FULL_SHIFT 29
|
||||
#define RRS_802_3_LEN_ERR_MASK 0x0001
|
||||
#define RRS_802_3_LEN_ERR_SHIFT 30
|
||||
#define RRS_RXD_UPDATED_MASK 0x0001
|
||||
#define RRS_RXD_UPDATED_SHIFT 31
|
||||
|
||||
#define RRS_ERR_L4_CSUM 0x00004000
|
||||
#define RRS_ERR_IP_CSUM 0x00008000
|
||||
#define RRS_VLAN_INS 0x00010000
|
||||
#define RRS_RX_ERR_SUM 0x00100000
|
||||
#define RRS_RX_ERR_CRC 0x00200000
|
||||
#define RRS_802_3_LEN_ERR 0x40000000
|
||||
#define RRS_RXD_UPDATED 0x80000000
|
||||
|
||||
#define RRS_PACKET_TYPE_802_3 1
|
||||
#define RRS_PACKET_TYPE_ETH 0
|
||||
#define RRS_PACKET_IS_ETH(word) \
|
||||
(((word) >> RRS_PACKET_TYPE_SHIFT) & RRS_PACKET_TYPE_MASK == \
|
||||
RRS_PACKET_TYPE_ETH)
|
||||
#define RRS_RXD_IS_VALID(word) \
|
||||
((((word) >> RRS_RXD_UPDATED_SHIFT) & RRS_RXD_UPDATED_MASK) == 1)
|
||||
|
||||
#define RRS_PACKET_PROT_IS_IPV4_ONLY(word) \
|
||||
((((word) >> RRS_PROT_ID_SHIFT) & RRS_PROT_ID_MASK) == 1)
|
||||
#define RRS_PACKET_PROT_IS_IPV6_ONLY(word) \
|
||||
((((word) >> RRS_PROT_ID_SHIFT) & RRS_PROT_ID_MASK) == 6)
|
||||
|
||||
struct atl1c_recv_ret_status {
|
||||
__le32 word0;
|
||||
__le32 rss_hash;
|
||||
__le16 vlan_tag;
|
||||
__le16 flag;
|
||||
__le32 word3;
|
||||
};
|
||||
|
||||
/* RFD desciptor */
|
||||
struct atl1c_rx_free_desc {
|
||||
__le64 buffer_addr;
|
||||
};
|
||||
|
||||
/* DMA Order Settings */
|
||||
enum atl1c_dma_order {
|
||||
atl1c_dma_ord_in = 1,
|
||||
atl1c_dma_ord_enh = 2,
|
||||
atl1c_dma_ord_out = 4
|
||||
};
|
||||
|
||||
enum atl1c_dma_rcb {
|
||||
atl1c_rcb_64 = 0,
|
||||
atl1c_rcb_128 = 1
|
||||
};
|
||||
|
||||
enum atl1c_mac_speed {
|
||||
atl1c_mac_speed_0 = 0,
|
||||
atl1c_mac_speed_10_100 = 1,
|
||||
atl1c_mac_speed_1000 = 2
|
||||
};
|
||||
|
||||
enum atl1c_dma_req_block {
|
||||
atl1c_dma_req_128 = 0,
|
||||
atl1c_dma_req_256 = 1,
|
||||
atl1c_dma_req_512 = 2,
|
||||
atl1c_dma_req_1024 = 3,
|
||||
atl1c_dma_req_2048 = 4,
|
||||
atl1c_dma_req_4096 = 5
|
||||
};
|
||||
|
||||
enum atl1c_rss_mode {
|
||||
atl1c_rss_mode_disable = 0,
|
||||
atl1c_rss_sig_que = 1,
|
||||
atl1c_rss_mul_que_sig_int = 2,
|
||||
atl1c_rss_mul_que_mul_int = 4,
|
||||
};
|
||||
|
||||
enum atl1c_rss_type {
|
||||
atl1c_rss_disable = 0,
|
||||
atl1c_rss_ipv4 = 1,
|
||||
atl1c_rss_ipv4_tcp = 2,
|
||||
atl1c_rss_ipv6 = 4,
|
||||
atl1c_rss_ipv6_tcp = 8
|
||||
};
|
||||
|
||||
enum atl1c_nic_type {
|
||||
athr_l1c = 0,
|
||||
athr_l2c = 1,
|
||||
};
|
||||
|
||||
enum atl1c_trans_queue {
|
||||
atl1c_trans_normal = 0,
|
||||
atl1c_trans_high = 1
|
||||
};
|
||||
|
||||
struct atl1c_hw_stats {
|
||||
/* rx */
|
||||
unsigned long rx_ok; /* The number of good packet received. */
|
||||
unsigned long rx_bcast; /* The number of good broadcast packet received. */
|
||||
unsigned long rx_mcast; /* The number of good multicast packet received. */
|
||||
unsigned long rx_pause; /* The number of Pause packet received. */
|
||||
unsigned long rx_ctrl; /* The number of Control packet received other than Pause frame. */
|
||||
unsigned long rx_fcs_err; /* The number of packets with bad FCS. */
|
||||
unsigned long rx_len_err; /* The number of packets with mismatch of length field and actual size. */
|
||||
unsigned long rx_byte_cnt; /* The number of bytes of good packet received. FCS is NOT included. */
|
||||
unsigned long rx_runt; /* The number of packets received that are less than 64 byte long and with good FCS. */
|
||||
unsigned long rx_frag; /* The number of packets received that are less than 64 byte long and with bad FCS. */
|
||||
unsigned long rx_sz_64; /* The number of good and bad packets received that are 64 byte long. */
|
||||
unsigned long rx_sz_65_127; /* The number of good and bad packets received that are between 65 and 127-byte long. */
|
||||
unsigned long rx_sz_128_255; /* The number of good and bad packets received that are between 128 and 255-byte long. */
|
||||
unsigned long rx_sz_256_511; /* The number of good and bad packets received that are between 256 and 511-byte long. */
|
||||
unsigned long rx_sz_512_1023; /* The number of good and bad packets received that are between 512 and 1023-byte long. */
|
||||
unsigned long rx_sz_1024_1518; /* The number of good and bad packets received that are between 1024 and 1518-byte long. */
|
||||
unsigned long rx_sz_1519_max; /* The number of good and bad packets received that are between 1519-byte and MTU. */
|
||||
unsigned long rx_sz_ov; /* The number of good and bad packets received that are more than MTU size truncated by Selene. */
|
||||
unsigned long rx_rxf_ov; /* The number of frame dropped due to occurrence of RX FIFO overflow. */
|
||||
unsigned long rx_rrd_ov; /* The number of frame dropped due to occurrence of RRD overflow. */
|
||||
unsigned long rx_align_err; /* Alignment Error */
|
||||
unsigned long rx_bcast_byte_cnt; /* The byte count of broadcast packet received, excluding FCS. */
|
||||
unsigned long rx_mcast_byte_cnt; /* The byte count of multicast packet received, excluding FCS. */
|
||||
unsigned long rx_err_addr; /* The number of packets dropped due to address filtering. */
|
||||
|
||||
/* tx */
|
||||
unsigned long tx_ok; /* The number of good packet transmitted. */
|
||||
unsigned long tx_bcast; /* The number of good broadcast packet transmitted. */
|
||||
unsigned long tx_mcast; /* The number of good multicast packet transmitted. */
|
||||
unsigned long tx_pause; /* The number of Pause packet transmitted. */
|
||||
unsigned long tx_exc_defer; /* The number of packets transmitted with excessive deferral. */
|
||||
unsigned long tx_ctrl; /* The number of packets transmitted is a control frame, excluding Pause frame. */
|
||||
unsigned long tx_defer; /* The number of packets transmitted that is deferred. */
|
||||
unsigned long tx_byte_cnt; /* The number of bytes of data transmitted. FCS is NOT included. */
|
||||
unsigned long tx_sz_64; /* The number of good and bad packets transmitted that are 64 byte long. */
|
||||
unsigned long tx_sz_65_127; /* The number of good and bad packets transmitted that are between 65 and 127-byte long. */
|
||||
unsigned long tx_sz_128_255; /* The number of good and bad packets transmitted that are between 128 and 255-byte long. */
|
||||
unsigned long tx_sz_256_511; /* The number of good and bad packets transmitted that are between 256 and 511-byte long. */
|
||||
unsigned long tx_sz_512_1023; /* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */
|
||||
unsigned long tx_sz_1024_1518; /* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */
|
||||
unsigned long tx_sz_1519_max; /* The number of good and bad packets transmitted that are between 1519-byte and MTU. */
|
||||
unsigned long tx_1_col; /* The number of packets subsequently transmitted successfully with a single prior collision. */
|
||||
unsigned long tx_2_col; /* The number of packets subsequently transmitted successfully with multiple prior collisions. */
|
||||
unsigned long tx_late_col; /* The number of packets transmitted with late collisions. */
|
||||
unsigned long tx_abort_col; /* The number of transmit packets aborted due to excessive collisions. */
|
||||
unsigned long tx_underrun; /* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
|
||||
unsigned long tx_rd_eop; /* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */
|
||||
unsigned long tx_len_err; /* The number of transmit packets with length field does NOT match the actual frame size. */
|
||||
unsigned long tx_trunc; /* The number of transmit packets truncated due to size exceeding MTU. */
|
||||
unsigned long tx_bcast_byte; /* The byte count of broadcast packet transmitted, excluding FCS. */
|
||||
unsigned long tx_mcast_byte; /* The byte count of multicast packet transmitted, excluding FCS. */
|
||||
};
|
||||
|
||||
struct atl1c_hw {
|
||||
u8 __iomem *hw_addr; /* inner register address */
|
||||
struct atl1c_adapter *adapter;
|
||||
enum atl1c_nic_type nic_type;
|
||||
enum atl1c_dma_order dma_order;
|
||||
enum atl1c_dma_rcb rcb_value;
|
||||
enum atl1c_dma_req_block dmar_block;
|
||||
enum atl1c_dma_req_block dmaw_block;
|
||||
|
||||
u16 device_id;
|
||||
u16 vendor_id;
|
||||
u16 subsystem_id;
|
||||
u16 subsystem_vendor_id;
|
||||
u8 revision_id;
|
||||
|
||||
u32 intr_mask;
|
||||
u8 dmaw_dly_cnt;
|
||||
u8 dmar_dly_cnt;
|
||||
|
||||
u8 preamble_len;
|
||||
u16 max_frame_size;
|
||||
u16 min_frame_size;
|
||||
|
||||
enum atl1c_mac_speed mac_speed;
|
||||
bool mac_duplex;
|
||||
bool hibernate;
|
||||
u16 media_type;
|
||||
#define MEDIA_TYPE_AUTO_SENSOR 0
|
||||
#define MEDIA_TYPE_100M_FULL 1
|
||||
#define MEDIA_TYPE_100M_HALF 2
|
||||
#define MEDIA_TYPE_10M_FULL 3
|
||||
#define MEDIA_TYPE_10M_HALF 4
|
||||
|
||||
u16 autoneg_advertised;
|
||||
u16 mii_autoneg_adv_reg;
|
||||
u16 mii_1000t_ctrl_reg;
|
||||
|
||||
u16 tx_imt; /* TX Interrupt Moderator timer ( 2us resolution) */
|
||||
u16 rx_imt; /* RX Interrupt Moderator timer ( 2us resolution) */
|
||||
u16 ict; /* Interrupt Clear timer (2us resolution) */
|
||||
u16 ctrl_flags;
|
||||
#define ATL1C_INTR_CLEAR_ON_READ 0x0001
|
||||
#define ATL1C_INTR_MODRT_ENABLE 0x0002
|
||||
#define ATL1C_CMB_ENABLE 0x0004
|
||||
#define ATL1C_SMB_ENABLE 0x0010
|
||||
#define ATL1C_TXQ_MODE_ENHANCE 0x0020
|
||||
#define ATL1C_RX_IPV6_CHKSUM 0x0040
|
||||
#define ATL1C_ASPM_L0S_SUPPORT 0x0080
|
||||
#define ATL1C_ASPM_L1_SUPPORT 0x0100
|
||||
#define ATL1C_ASPM_CTRL_MON 0x0200
|
||||
#define ATL1C_HIB_DISABLE 0x0400
|
||||
#define ATL1C_LINK_CAP_1000M 0x0800
|
||||
#define ATL1C_FPGA_VERSION 0x8000
|
||||
u16 cmb_tpd;
|
||||
u16 cmb_rrd;
|
||||
u16 cmb_rx_timer; /* 2us resolution */
|
||||
u16 cmb_tx_timer;
|
||||
u32 smb_timer;
|
||||
|
||||
u16 rrd_thresh; /* Threshold of number of RRD produced to trigger
|
||||
interrupt request */
|
||||
u16 tpd_thresh;
|
||||
u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. */
|
||||
u8 rfd_burst;
|
||||
enum atl1c_rss_type rss_type;
|
||||
enum atl1c_rss_mode rss_mode;
|
||||
u8 rss_hash_bits;
|
||||
u32 base_cpu;
|
||||
u32 indirect_tab;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u8 perm_mac_addr[ETH_ALEN];
|
||||
|
||||
bool phy_configured;
|
||||
bool re_autoneg;
|
||||
bool emi_ca;
|
||||
};
|
||||
|
||||
/*
|
||||
* atl1c_ring_header represents a single, contiguous block of DMA space
|
||||
* mapped for the three descriptor rings (tpd, rfd, rrd) and the two
|
||||
* message blocks (cmb, smb) described below
|
||||
*/
|
||||
struct atl1c_ring_header {
|
||||
void *desc; /* virtual address */
|
||||
dma_addr_t dma; /* physical address*/
|
||||
unsigned int size; /* length in bytes */
|
||||
};
|
||||
|
||||
/*
|
||||
* atl1c_buffer is wrapper around a pointer to a socket buffer
|
||||
* so a DMA handle can be stored along with the skb
|
||||
*/
|
||||
struct atl1c_buffer {
|
||||
struct sk_buff *skb; /* socket buffer */
|
||||
u16 length; /* rx buffer length */
|
||||
u16 state; /* state of buffer */
|
||||
#define ATL1_BUFFER_FREE 0
|
||||
#define ATL1_BUFFER_BUSY 1
|
||||
dma_addr_t dma;
|
||||
};
|
||||
|
||||
/* transimit packet descriptor (tpd) ring */
|
||||
struct atl1c_tpd_ring {
|
||||
void *desc; /* descriptor ring virtual address */
|
||||
dma_addr_t dma; /* descriptor ring physical address */
|
||||
u16 size; /* descriptor ring length in bytes */
|
||||
u16 count; /* number of descriptors in the ring */
|
||||
u16 next_to_use; /* this is protectd by adapter->tx_lock */
|
||||
atomic_t next_to_clean;
|
||||
struct atl1c_buffer *buffer_info;
|
||||
};
|
||||
|
||||
/* receive free descriptor (rfd) ring */
|
||||
struct atl1c_rfd_ring {
|
||||
void *desc; /* descriptor ring virtual address */
|
||||
dma_addr_t dma; /* descriptor ring physical address */
|
||||
u16 size; /* descriptor ring length in bytes */
|
||||
u16 count; /* number of descriptors in the ring */
|
||||
u16 next_to_use;
|
||||
u16 next_to_clean;
|
||||
struct atl1c_buffer *buffer_info;
|
||||
};
|
||||
|
||||
/* receive return desciptor (rrd) ring */
|
||||
struct atl1c_rrd_ring {
|
||||
void *desc; /* descriptor ring virtual address */
|
||||
dma_addr_t dma; /* descriptor ring physical address */
|
||||
u16 size; /* descriptor ring length in bytes */
|
||||
u16 count; /* number of descriptors in the ring */
|
||||
u16 next_to_use;
|
||||
u16 next_to_clean;
|
||||
};
|
||||
|
||||
struct atl1c_cmb {
|
||||
void *cmb;
|
||||
dma_addr_t dma;
|
||||
};
|
||||
|
||||
struct atl1c_smb {
|
||||
void *smb;
|
||||
dma_addr_t dma;
|
||||
};
|
||||
|
||||
/* board specific private data structure */
|
||||
struct atl1c_adapter {
|
||||
struct net_device *netdev;
|
||||
struct pci_dev *pdev;
|
||||
struct vlan_group *vlgrp;
|
||||
struct napi_struct napi;
|
||||
struct atl1c_hw hw;
|
||||
struct atl1c_hw_stats hw_stats;
|
||||
struct net_device_stats net_stats;
|
||||
struct mii_if_info mii; /* MII interface info */
|
||||
u16 rx_buffer_len;
|
||||
|
||||
unsigned long flags;
|
||||
#define __AT_TESTING 0x0001
|
||||
#define __AT_RESETTING 0x0002
|
||||
#define __AT_DOWN 0x0003
|
||||
u32 msg_enable;
|
||||
|
||||
bool have_msi;
|
||||
u32 wol;
|
||||
u16 link_speed;
|
||||
u16 link_duplex;
|
||||
|
||||
spinlock_t mdio_lock;
|
||||
spinlock_t tx_lock;
|
||||
atomic_t irq_sem;
|
||||
|
||||
struct work_struct reset_task;
|
||||
struct work_struct link_chg_task;
|
||||
struct timer_list watchdog_timer;
|
||||
struct timer_list phy_config_timer;
|
||||
|
||||
/* All Descriptor memory */
|
||||
struct atl1c_ring_header ring_header;
|
||||
struct atl1c_tpd_ring tpd_ring[AT_MAX_TRANSMIT_QUEUE];
|
||||
struct atl1c_rfd_ring rfd_ring[AT_MAX_RECEIVE_QUEUE];
|
||||
struct atl1c_rrd_ring rrd_ring[AT_MAX_RECEIVE_QUEUE];
|
||||
struct atl1c_cmb cmb;
|
||||
struct atl1c_smb smb;
|
||||
int num_rx_queues;
|
||||
u32 bd_number; /* board number;*/
|
||||
};
|
||||
|
||||
#define AT_WRITE_REG(a, reg, value) ( \
|
||||
writel((value), ((a)->hw_addr + reg)))
|
||||
|
||||
#define AT_WRITE_FLUSH(a) (\
|
||||
readl((a)->hw_addr))
|
||||
|
||||
#define AT_READ_REG(a, reg, pdata) do { \
|
||||
if (unlikely((a)->hibernate)) { \
|
||||
readl((a)->hw_addr + reg); \
|
||||
*(u32 *)pdata = readl((a)->hw_addr + reg); \
|
||||
} else { \
|
||||
*(u32 *)pdata = readl((a)->hw_addr + reg); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define AT_WRITE_REGB(a, reg, value) (\
|
||||
writeb((value), ((a)->hw_addr + reg)))
|
||||
|
||||
#define AT_READ_REGB(a, reg) (\
|
||||
readb((a)->hw_addr + reg))
|
||||
|
||||
#define AT_WRITE_REGW(a, reg, value) (\
|
||||
writew((value), ((a)->hw_addr + reg)))
|
||||
|
||||
#define AT_READ_REGW(a, reg) (\
|
||||
readw((a)->hw_addr + reg))
|
||||
|
||||
#define AT_WRITE_REG_ARRAY(a, reg, offset, value) ( \
|
||||
writel((value), (((a)->hw_addr + reg) + ((offset) << 2))))
|
||||
|
||||
#define AT_READ_REG_ARRAY(a, reg, offset) ( \
|
||||
readl(((a)->hw_addr + reg) + ((offset) << 2)))
|
||||
|
||||
extern char atl1c_driver_name[];
|
||||
extern char atl1c_driver_version[];
|
||||
|
||||
extern int atl1c_up(struct atl1c_adapter *adapter);
|
||||
extern void atl1c_down(struct atl1c_adapter *adapter);
|
||||
extern void atl1c_reinit_locked(struct atl1c_adapter *adapter);
|
||||
extern s32 atl1c_reset_hw(struct atl1c_hw *hw);
|
||||
extern void atl1c_set_ethtool_ops(struct net_device *netdev);
|
||||
#endif /* _ATL1C_H_ */
|
317
drivers/net/atl1c/atl1c_ethtool.c
Normal file
317
drivers/net/atl1c/atl1c_ethtool.c
Normal file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright(c) 2009 - 2009 Atheros Corporation. All rights reserved.
|
||||
*
|
||||
* Derived from Intel e1000 driver
|
||||
* Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#include "atl1c.h"
|
||||
|
||||
static int atl1c_get_settings(struct net_device *netdev,
|
||||
struct ethtool_cmd *ecmd)
|
||||
{
|
||||
struct atl1c_adapter *adapter = netdev_priv(netdev);
|
||||
struct atl1c_hw *hw = &adapter->hw;
|
||||
|
||||
ecmd->supported = (SUPPORTED_10baseT_Half |
|
||||
SUPPORTED_10baseT_Full |
|
||||
SUPPORTED_100baseT_Half |
|
||||
SUPPORTED_100baseT_Full |
|
||||
SUPPORTED_Autoneg |
|
||||
SUPPORTED_TP);
|
||||
if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M)
|
||||
ecmd->supported |= SUPPORTED_1000baseT_Full;
|
||||
|
||||
ecmd->advertising = ADVERTISED_TP;
|
||||
|
||||
ecmd->advertising |= hw->autoneg_advertised;
|
||||
|
||||
ecmd->port = PORT_TP;
|
||||
ecmd->phy_address = 0;
|
||||
ecmd->transceiver = XCVR_INTERNAL;
|
||||
|
||||
if (adapter->link_speed != SPEED_0) {
|
||||
ecmd->speed = adapter->link_speed;
|
||||
if (adapter->link_duplex == FULL_DUPLEX)
|
||||
ecmd->duplex = DUPLEX_FULL;
|
||||
else
|
||||
ecmd->duplex = DUPLEX_HALF;
|
||||
} else {
|
||||
ecmd->speed = -1;
|
||||
ecmd->duplex = -1;
|
||||
}
|
||||
|
||||
ecmd->autoneg = AUTONEG_ENABLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atl1c_set_settings(struct net_device *netdev,
|
||||
struct ethtool_cmd *ecmd)
|
||||
{
|
||||
struct atl1c_adapter *adapter = netdev_priv(netdev);
|
||||
struct atl1c_hw *hw = &adapter->hw;
|
||||
u16 autoneg_advertised;
|
||||
|
||||
while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
|
||||
msleep(1);
|
||||
|
||||
if (ecmd->autoneg == AUTONEG_ENABLE) {
|
||||
autoneg_advertised = ADVERTISED_Autoneg;
|
||||
} else {
|
||||
if (ecmd->speed == SPEED_1000) {
|
||||
if (ecmd->duplex != DUPLEX_FULL) {
|
||||
if (netif_msg_link(adapter))
|
||||
dev_warn(&adapter->pdev->dev,
|
||||
"1000M half is invalid\n");
|
||||
clear_bit(__AT_RESETTING, &adapter->flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
autoneg_advertised = ADVERTISED_1000baseT_Full;
|
||||
} else if (ecmd->speed == SPEED_100) {
|
||||
if (ecmd->duplex == DUPLEX_FULL)
|
||||
autoneg_advertised = ADVERTISED_100baseT_Full;
|
||||
else
|
||||
autoneg_advertised = ADVERTISED_100baseT_Half;
|
||||
} else {
|
||||
if (ecmd->duplex == DUPLEX_FULL)
|
||||
autoneg_advertised = ADVERTISED_10baseT_Full;
|
||||
else
|
||||
autoneg_advertised = ADVERTISED_10baseT_Half;
|
||||
}
|
||||
}
|
||||
|
||||
if (hw->autoneg_advertised != autoneg_advertised) {
|
||||
hw->autoneg_advertised = autoneg_advertised;
|
||||
if (atl1c_restart_autoneg(hw) != 0) {
|
||||
if (netif_msg_link(adapter))
|
||||
dev_warn(&adapter->pdev->dev,
|
||||
"ethtool speed/duplex setting failed\n");
|
||||
clear_bit(__AT_RESETTING, &adapter->flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
clear_bit(__AT_RESETTING, &adapter->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 atl1c_get_tx_csum(struct net_device *netdev)
|
||||
{
|
||||
return (netdev->features & NETIF_F_HW_CSUM) != 0;
|
||||
}
|
||||
|
||||
static u32 atl1c_get_msglevel(struct net_device *netdev)
|
||||
{
|
||||
struct atl1c_adapter *adapter = netdev_priv(netdev);
|
||||
return adapter->msg_enable;
|
||||
}
|
||||
|
||||
static void atl1c_set_msglevel(struct net_device *netdev, u32 data)
|
||||
{
|
||||
struct atl1c_adapter *adapter = netdev_priv(netdev);
|
||||
adapter->msg_enable = data;
|
||||
}
|
||||
|
||||
static int atl1c_get_regs_len(struct net_device *netdev)
|
||||
{
|
||||
return AT_REGS_LEN;
|
||||
}
|
||||
|
||||
static void atl1c_get_regs(struct net_device *netdev,
|
||||
struct ethtool_regs *regs, void *p)
|
||||
{
|
||||
struct atl1c_adapter *adapter = netdev_priv(netdev);
|
||||
struct atl1c_hw *hw = &adapter->hw;
|
||||
u32 *regs_buff = p;
|
||||
u16 phy_data;
|
||||
|
||||
memset(p, 0, AT_REGS_LEN);
|
||||
|
||||
regs->version = 0;
|
||||
AT_READ_REG(hw, REG_VPD_CAP, p++);
|
||||
AT_READ_REG(hw, REG_PM_CTRL, p++);
|
||||
AT_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL, p++);
|
||||
AT_READ_REG(hw, REG_TWSI_CTRL, p++);
|
||||
AT_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL, p++);
|
||||
AT_READ_REG(hw, REG_MASTER_CTRL, p++);
|
||||
AT_READ_REG(hw, REG_MANUAL_TIMER_INIT, p++);
|
||||
AT_READ_REG(hw, REG_IRQ_MODRT_TIMER_INIT, p++);
|
||||
AT_READ_REG(hw, REG_GPHY_CTRL, p++);
|
||||
AT_READ_REG(hw, REG_LINK_CTRL, p++);
|
||||
AT_READ_REG(hw, REG_IDLE_STATUS, p++);
|
||||
AT_READ_REG(hw, REG_MDIO_CTRL, p++);
|
||||
AT_READ_REG(hw, REG_SERDES_LOCK, p++);
|
||||
AT_READ_REG(hw, REG_MAC_CTRL, p++);
|
||||
AT_READ_REG(hw, REG_MAC_IPG_IFG, p++);
|
||||
AT_READ_REG(hw, REG_MAC_STA_ADDR, p++);
|
||||
AT_READ_REG(hw, REG_MAC_STA_ADDR+4, p++);
|
||||
AT_READ_REG(hw, REG_RX_HASH_TABLE, p++);
|
||||
AT_READ_REG(hw, REG_RX_HASH_TABLE+4, p++);
|
||||
AT_READ_REG(hw, REG_RXQ_CTRL, p++);
|
||||
AT_READ_REG(hw, REG_TXQ_CTRL, p++);
|
||||
AT_READ_REG(hw, REG_MTU, p++);
|
||||
AT_READ_REG(hw, REG_WOL_CTRL, p++);
|
||||
|
||||
atl1c_read_phy_reg(hw, MII_BMCR, &phy_data);
|
||||
regs_buff[73] = (u32) phy_data;
|
||||
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
|
||||
regs_buff[74] = (u32) phy_data;
|
||||
}
|
||||
|
||||
static int atl1c_get_eeprom_len(struct net_device *netdev)
|
||||
{
|
||||
struct atl1c_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
if (atl1c_check_eeprom_exist(&adapter->hw))
|
||||
return AT_EEPROM_LEN;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atl1c_get_eeprom(struct net_device *netdev,
|
||||
struct ethtool_eeprom *eeprom, u8 *bytes)
|
||||
{
|
||||
struct atl1c_adapter *adapter = netdev_priv(netdev);
|
||||
struct atl1c_hw *hw = &adapter->hw;
|
||||
u32 *eeprom_buff;
|
||||
int first_dword, last_dword;
|
||||
int ret_val = 0;
|
||||
int i;
|
||||
|
||||
if (eeprom->len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!atl1c_check_eeprom_exist(hw)) /* not exist */
|
||||
return -EINVAL;
|
||||
|
||||
eeprom->magic = adapter->pdev->vendor |
|
||||
(adapter->pdev->device << 16);
|
||||
|
||||
first_dword = eeprom->offset >> 2;
|
||||
last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
|
||||
|
||||
eeprom_buff = kmalloc(sizeof(u32) *
|
||||
(last_dword - first_dword + 1), GFP_KERNEL);
|
||||
if (eeprom_buff == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = first_dword; i < last_dword; i++) {
|
||||
if (!atl1c_read_eeprom(hw, i * 4, &(eeprom_buff[i-first_dword]))) {
|
||||
kfree(eeprom_buff);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3),
|
||||
eeprom->len);
|
||||
kfree(eeprom_buff);
|
||||
|
||||
return ret_val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atl1c_get_drvinfo(struct net_device *netdev,
|
||||
struct ethtool_drvinfo *drvinfo)
|
||||
{
|
||||
struct atl1c_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
strncpy(drvinfo->driver, atl1c_driver_name, sizeof(drvinfo->driver));
|
||||
strncpy(drvinfo->version, atl1c_driver_version,
|
||||
sizeof(drvinfo->version));
|
||||
strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
|
||||
strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
|
||||
sizeof(drvinfo->bus_info));
|
||||
drvinfo->n_stats = 0;
|
||||
drvinfo->testinfo_len = 0;
|
||||
drvinfo->regdump_len = atl1c_get_regs_len(netdev);
|
||||
drvinfo->eedump_len = atl1c_get_eeprom_len(netdev);
|
||||
}
|
||||
|
||||
static void atl1c_get_wol(struct net_device *netdev,
|
||||
struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct atl1c_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
wol->supported = WAKE_MAGIC | WAKE_PHY;
|
||||
wol->wolopts = 0;
|
||||
|
||||
if (adapter->wol & AT_WUFC_EX)
|
||||
wol->wolopts |= WAKE_UCAST;
|
||||
if (adapter->wol & AT_WUFC_MC)
|
||||
wol->wolopts |= WAKE_MCAST;
|
||||
if (adapter->wol & AT_WUFC_BC)
|
||||
wol->wolopts |= WAKE_BCAST;
|
||||
if (adapter->wol & AT_WUFC_MAG)
|
||||
wol->wolopts |= WAKE_MAGIC;
|
||||
if (adapter->wol & AT_WUFC_LNKC)
|
||||
wol->wolopts |= WAKE_PHY;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int atl1c_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct atl1c_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE |
|
||||
WAKE_MCAST | WAKE_BCAST | WAKE_MCAST))
|
||||
return -EOPNOTSUPP;
|
||||
/* these settings will always override what we currently have */
|
||||
adapter->wol = 0;
|
||||
|
||||
if (wol->wolopts & WAKE_MAGIC)
|
||||
adapter->wol |= AT_WUFC_MAG;
|
||||
if (wol->wolopts & WAKE_PHY)
|
||||
adapter->wol |= AT_WUFC_LNKC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atl1c_nway_reset(struct net_device *netdev)
|
||||
{
|
||||
struct atl1c_adapter *adapter = netdev_priv(netdev);
|
||||
if (netif_running(netdev))
|
||||
atl1c_reinit_locked(adapter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ethtool_ops atl1c_ethtool_ops = {
|
||||
.get_settings = atl1c_get_settings,
|
||||
.set_settings = atl1c_set_settings,
|
||||
.get_drvinfo = atl1c_get_drvinfo,
|
||||
.get_regs_len = atl1c_get_regs_len,
|
||||
.get_regs = atl1c_get_regs,
|
||||
.get_wol = atl1c_get_wol,
|
||||
.set_wol = atl1c_set_wol,
|
||||
.get_msglevel = atl1c_get_msglevel,
|
||||
.set_msglevel = atl1c_set_msglevel,
|
||||
.nway_reset = atl1c_nway_reset,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_eeprom_len = atl1c_get_eeprom_len,
|
||||
.get_eeprom = atl1c_get_eeprom,
|
||||
.get_tx_csum = atl1c_get_tx_csum,
|
||||
.get_sg = ethtool_op_get_sg,
|
||||
.set_sg = ethtool_op_set_sg,
|
||||
};
|
||||
|
||||
void atl1c_set_ethtool_ops(struct net_device *netdev)
|
||||
{
|
||||
SET_ETHTOOL_OPS(netdev, &atl1c_ethtool_ops);
|
||||
}
|
527
drivers/net/atl1c/atl1c_hw.c
Normal file
527
drivers/net/atl1c/atl1c_hw.c
Normal file
@ -0,0 +1,527 @@
|
||||
/*
|
||||
* Copyright(c) 2007 Atheros Corporation. All rights reserved.
|
||||
*
|
||||
* Derived from Intel e1000 driver
|
||||
* Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/crc32.h>
|
||||
|
||||
#include "atl1c.h"
|
||||
|
||||
/*
|
||||
* check_eeprom_exist
|
||||
* return 1 if eeprom exist
|
||||
*/
|
||||
int atl1c_check_eeprom_exist(struct atl1c_hw *hw)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
AT_READ_REG(hw, REG_TWSI_DEBUG, &data);
|
||||
if (data & TWSI_DEBUG_DEV_EXIST)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void atl1c_hw_set_mac_addr(struct atl1c_hw *hw)
|
||||
{
|
||||
u32 value;
|
||||
/*
|
||||
* 00-0B-6A-F6-00-DC
|
||||
* 0: 6AF600DC 1: 000B
|
||||
* low dword
|
||||
*/
|
||||
value = (((u32)hw->mac_addr[2]) << 24) |
|
||||
(((u32)hw->mac_addr[3]) << 16) |
|
||||
(((u32)hw->mac_addr[4]) << 8) |
|
||||
(((u32)hw->mac_addr[5])) ;
|
||||
AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value);
|
||||
/* hight dword */
|
||||
value = (((u32)hw->mac_addr[0]) << 8) |
|
||||
(((u32)hw->mac_addr[1])) ;
|
||||
AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* atl1c_get_permanent_address
|
||||
* return 0 if get valid mac address,
|
||||
*/
|
||||
static int atl1c_get_permanent_address(struct atl1c_hw *hw)
|
||||
{
|
||||
u32 addr[2];
|
||||
u32 i;
|
||||
u32 otp_ctrl_data;
|
||||
u32 twsi_ctrl_data;
|
||||
u8 eth_addr[ETH_ALEN];
|
||||
|
||||
/* init */
|
||||
addr[0] = addr[1] = 0;
|
||||
AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
|
||||
if (atl1c_check_eeprom_exist(hw)) {
|
||||
/* Enable OTP CLK */
|
||||
if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
|
||||
otp_ctrl_data |= OTP_CTRL_CLK_EN;
|
||||
AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
|
||||
AT_WRITE_FLUSH(hw);
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
|
||||
twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
|
||||
AT_WRITE_REG(hw, REG_TWSI_CTRL, twsi_ctrl_data);
|
||||
for (i = 0; i < AT_TWSI_EEPROM_TIMEOUT; i++) {
|
||||
msleep(10);
|
||||
AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
|
||||
if ((twsi_ctrl_data & TWSI_CTRL_SW_LDSTART) == 0)
|
||||
break;
|
||||
}
|
||||
if (i >= AT_TWSI_EEPROM_TIMEOUT)
|
||||
return -1;
|
||||
}
|
||||
/* Disable OTP_CLK */
|
||||
if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
|
||||
otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
|
||||
AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
|
||||
AT_WRITE_FLUSH(hw);
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
/* maybe MAC-address is from BIOS */
|
||||
AT_READ_REG(hw, REG_MAC_STA_ADDR, &addr[0]);
|
||||
AT_READ_REG(hw, REG_MAC_STA_ADDR + 4, &addr[1]);
|
||||
*(u32 *) ð_addr[2] = swab32(addr[0]);
|
||||
*(u16 *) ð_addr[0] = swab16(*(u16 *)&addr[1]);
|
||||
|
||||
if (is_valid_ether_addr(eth_addr)) {
|
||||
memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value)
|
||||
{
|
||||
int i;
|
||||
int ret = false;
|
||||
u32 otp_ctrl_data;
|
||||
u32 control;
|
||||
u32 data;
|
||||
|
||||
if (offset & 3)
|
||||
return ret; /* address do not align */
|
||||
|
||||
AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
|
||||
if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
|
||||
AT_WRITE_REG(hw, REG_OTP_CTRL,
|
||||
(otp_ctrl_data | OTP_CTRL_CLK_EN));
|
||||
|
||||
AT_WRITE_REG(hw, REG_EEPROM_DATA_LO, 0);
|
||||
control = (offset & EEPROM_CTRL_ADDR_MASK) << EEPROM_CTRL_ADDR_SHIFT;
|
||||
AT_WRITE_REG(hw, REG_EEPROM_CTRL, control);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
udelay(100);
|
||||
AT_READ_REG(hw, REG_EEPROM_CTRL, &control);
|
||||
if (control & EEPROM_CTRL_RW)
|
||||
break;
|
||||
}
|
||||
if (control & EEPROM_CTRL_RW) {
|
||||
AT_READ_REG(hw, REG_EEPROM_CTRL, &data);
|
||||
AT_READ_REG(hw, REG_EEPROM_DATA_LO, p_value);
|
||||
data = data & 0xFFFF;
|
||||
*p_value = swab32((data << 16) | (*p_value >> 16));
|
||||
ret = true;
|
||||
}
|
||||
if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
|
||||
AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Reads the adapter's MAC address from the EEPROM
|
||||
*
|
||||
* hw - Struct containing variables accessed by shared code
|
||||
*/
|
||||
int atl1c_read_mac_addr(struct atl1c_hw *hw)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err = atl1c_get_permanent_address(hw);
|
||||
if (err)
|
||||
random_ether_addr(hw->perm_mac_addr);
|
||||
|
||||
memcpy(hw->mac_addr, hw->perm_mac_addr, sizeof(hw->perm_mac_addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* atl1c_hash_mc_addr
|
||||
* purpose
|
||||
* set hash value for a multicast address
|
||||
* hash calcu processing :
|
||||
* 1. calcu 32bit CRC for multicast address
|
||||
* 2. reverse crc with MSB to LSB
|
||||
*/
|
||||
u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr)
|
||||
{
|
||||
u32 crc32;
|
||||
u32 value = 0;
|
||||
int i;
|
||||
|
||||
crc32 = ether_crc_le(6, mc_addr);
|
||||
for (i = 0; i < 32; i++)
|
||||
value |= (((crc32 >> i) & 1) << (31 - i));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the bit in the multicast table corresponding to the hash value.
|
||||
* hw - Struct containing variables accessed by shared code
|
||||
* hash_value - Multicast address hash value
|
||||
*/
|
||||
void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value)
|
||||
{
|
||||
u32 hash_bit, hash_reg;
|
||||
u32 mta;
|
||||
|
||||
/*
|
||||
* The HASH Table is a register array of 2 32-bit registers.
|
||||
* It is treated like an array of 64 bits. We want to set
|
||||
* bit BitArray[hash_value]. So we figure out what register
|
||||
* the bit is in, read it, OR in the new bit, then write
|
||||
* back the new value. The register is determined by the
|
||||
* upper bit of the hash value and the bit within that
|
||||
* register are determined by the lower 5 bits of the value.
|
||||
*/
|
||||
hash_reg = (hash_value >> 31) & 0x1;
|
||||
hash_bit = (hash_value >> 26) & 0x1F;
|
||||
|
||||
mta = AT_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg);
|
||||
|
||||
mta |= (1 << hash_bit);
|
||||
|
||||
AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads the value from a PHY register
|
||||
* hw - Struct containing variables accessed by shared code
|
||||
* reg_addr - address of the PHY register to read
|
||||
*/
|
||||
int atl1c_read_phy_reg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data)
|
||||
{
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
val = ((u32)(reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT |
|
||||
MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW |
|
||||
MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
|
||||
|
||||
AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
|
||||
|
||||
for (i = 0; i < MDIO_WAIT_TIMES; i++) {
|
||||
udelay(2);
|
||||
AT_READ_REG(hw, REG_MDIO_CTRL, &val);
|
||||
if (!(val & (MDIO_START | MDIO_BUSY)))
|
||||
break;
|
||||
}
|
||||
if (!(val & (MDIO_START | MDIO_BUSY))) {
|
||||
*phy_data = (u16)val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes a value to a PHY register
|
||||
* hw - Struct containing variables accessed by shared code
|
||||
* reg_addr - address of the PHY register to write
|
||||
* data - data to write to the PHY
|
||||
*/
|
||||
int atl1c_write_phy_reg(struct atl1c_hw *hw, u32 reg_addr, u16 phy_data)
|
||||
{
|
||||
int i;
|
||||
u32 val;
|
||||
|
||||
val = ((u32)(phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT |
|
||||
(reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT |
|
||||
MDIO_SUP_PREAMBLE | MDIO_START |
|
||||
MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
|
||||
|
||||
AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
|
||||
|
||||
for (i = 0; i < MDIO_WAIT_TIMES; i++) {
|
||||
udelay(2);
|
||||
AT_READ_REG(hw, REG_MDIO_CTRL, &val);
|
||||
if (!(val & (MDIO_START | MDIO_BUSY)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(val & (MDIO_START | MDIO_BUSY)))
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configures PHY autoneg and flow control advertisement settings
|
||||
*
|
||||
* hw - Struct containing variables accessed by shared code
|
||||
*/
|
||||
static int atl1c_phy_setup_adv(struct atl1c_hw *hw)
|
||||
{
|
||||
u16 mii_adv_data = ADVERTISE_DEFAULT_CAP & ~ADVERTISE_SPEED_MASK;
|
||||
u16 mii_giga_ctrl_data = GIGA_CR_1000T_DEFAULT_CAP &
|
||||
~GIGA_CR_1000T_SPEED_MASK;
|
||||
|
||||
if (hw->autoneg_advertised & ADVERTISED_10baseT_Half)
|
||||
mii_adv_data |= ADVERTISE_10HALF;
|
||||
if (hw->autoneg_advertised & ADVERTISED_10baseT_Full)
|
||||
mii_adv_data |= ADVERTISE_10FULL;
|
||||
if (hw->autoneg_advertised & ADVERTISED_100baseT_Half)
|
||||
mii_adv_data |= ADVERTISE_100HALF;
|
||||
if (hw->autoneg_advertised & ADVERTISED_100baseT_Full)
|
||||
mii_adv_data |= ADVERTISE_100FULL;
|
||||
|
||||
if (hw->autoneg_advertised & ADVERTISED_Autoneg)
|
||||
mii_adv_data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
|
||||
ADVERTISE_100HALF | ADVERTISE_100FULL;
|
||||
|
||||
if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M) {
|
||||
if (hw->autoneg_advertised & ADVERTISED_1000baseT_Half)
|
||||
mii_giga_ctrl_data |= ADVERTISE_1000HALF;
|
||||
if (hw->autoneg_advertised & ADVERTISED_1000baseT_Full)
|
||||
mii_giga_ctrl_data |= ADVERTISE_1000FULL;
|
||||
if (hw->autoneg_advertised & ADVERTISED_Autoneg)
|
||||
mii_giga_ctrl_data |= ADVERTISE_1000HALF |
|
||||
ADVERTISE_1000FULL;
|
||||
}
|
||||
|
||||
if (atl1c_write_phy_reg(hw, MII_ADVERTISE, mii_adv_data) != 0 ||
|
||||
atl1c_write_phy_reg(hw, MII_GIGA_CR, mii_giga_ctrl_data) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void atl1c_phy_disable(struct atl1c_hw *hw)
|
||||
{
|
||||
AT_WRITE_REGW(hw, REG_GPHY_CTRL,
|
||||
GPHY_CTRL_PW_WOL_DIS | GPHY_CTRL_EXT_RESET);
|
||||
}
|
||||
|
||||
static void atl1c_phy_magic_data(struct atl1c_hw *hw)
|
||||
{
|
||||
u16 data;
|
||||
|
||||
data = ANA_LOOP_SEL_10BT | ANA_EN_MASK_TB | ANA_EN_10BT_IDLE |
|
||||
((1 & ANA_INTERVAL_SEL_TIMER_MASK) <<
|
||||
ANA_INTERVAL_SEL_TIMER_SHIFT);
|
||||
|
||||
atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_18);
|
||||
atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
|
||||
|
||||
data = (2 & ANA_SERDES_CDR_BW_MASK) | ANA_MS_PAD_DBG |
|
||||
ANA_SERDES_EN_DEEM | ANA_SERDES_SEL_HSP | ANA_SERDES_EN_PLL |
|
||||
ANA_SERDES_EN_LCKDT;
|
||||
|
||||
atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_5);
|
||||
atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
|
||||
|
||||
data = (44 & ANA_LONG_CABLE_TH_100_MASK) |
|
||||
((33 & ANA_SHORT_CABLE_TH_100_MASK) <<
|
||||
ANA_SHORT_CABLE_TH_100_SHIFT) | ANA_BP_BAD_LINK_ACCUM |
|
||||
ANA_BP_SMALL_BW;
|
||||
|
||||
atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_54);
|
||||
atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
|
||||
|
||||
data = (11 & ANA_IECHO_ADJ_MASK) | ((11 & ANA_IECHO_ADJ_MASK) <<
|
||||
ANA_IECHO_ADJ_2_SHIFT) | ((8 & ANA_IECHO_ADJ_MASK) <<
|
||||
ANA_IECHO_ADJ_1_SHIFT) | ((8 & ANA_IECHO_ADJ_MASK) <<
|
||||
ANA_IECHO_ADJ_0_SHIFT);
|
||||
|
||||
atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_4);
|
||||
atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
|
||||
|
||||
data = ANA_RESTART_CAL | ((7 & ANA_MANUL_SWICH_ON_MASK) <<
|
||||
ANA_MANUL_SWICH_ON_SHIFT) | ANA_MAN_ENABLE |
|
||||
ANA_SEL_HSP | ANA_EN_HB | ANA_OEN_125M;
|
||||
|
||||
atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_0);
|
||||
atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
|
||||
|
||||
if (hw->ctrl_flags & ATL1C_HIB_DISABLE) {
|
||||
atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_41);
|
||||
if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0)
|
||||
return;
|
||||
data &= ~ANA_TOP_PS_EN;
|
||||
atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
|
||||
|
||||
atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_11);
|
||||
if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0)
|
||||
return;
|
||||
data &= ~ANA_PS_HIB_EN;
|
||||
atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
|
||||
}
|
||||
}
|
||||
|
||||
int atl1c_phy_reset(struct atl1c_hw *hw)
|
||||
{
|
||||
struct atl1c_adapter *adapter = hw->adapter;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
u32 phy_ctrl_data = GPHY_CTRL_DEFAULT;
|
||||
u32 mii_ier_data = IER_LINK_UP | IER_LINK_DOWN;
|
||||
int err;
|
||||
|
||||
if (hw->ctrl_flags & ATL1C_HIB_DISABLE)
|
||||
phy_ctrl_data &= ~GPHY_CTRL_HIB_EN;
|
||||
|
||||
AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data);
|
||||
AT_WRITE_FLUSH(hw);
|
||||
msleep(40);
|
||||
phy_ctrl_data |= GPHY_CTRL_EXT_RESET;
|
||||
AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data);
|
||||
AT_WRITE_FLUSH(hw);
|
||||
msleep(10);
|
||||
|
||||
/*Enable PHY LinkChange Interrupt */
|
||||
err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
|
||||
if (err) {
|
||||
if (netif_msg_hw(adapter))
|
||||
dev_err(&pdev->dev,
|
||||
"Error enable PHY linkChange Interrupt\n");
|
||||
return err;
|
||||
}
|
||||
if (!(hw->ctrl_flags & ATL1C_FPGA_VERSION))
|
||||
atl1c_phy_magic_data(hw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int atl1c_phy_init(struct atl1c_hw *hw)
|
||||
{
|
||||
struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
int ret_val;
|
||||
u16 mii_bmcr_data = BMCR_RESET;
|
||||
u16 phy_id1, phy_id2;
|
||||
|
||||
if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &phy_id1) != 0) ||
|
||||
(atl1c_read_phy_reg(hw, MII_PHYSID2, &phy_id2) != 0)) {
|
||||
if (netif_msg_link(adapter))
|
||||
dev_err(&pdev->dev, "Error get phy ID\n");
|
||||
return -1;
|
||||
}
|
||||
switch (hw->media_type) {
|
||||
case MEDIA_TYPE_AUTO_SENSOR:
|
||||
ret_val = atl1c_phy_setup_adv(hw);
|
||||
if (ret_val) {
|
||||
if (netif_msg_link(adapter))
|
||||
dev_err(&pdev->dev,
|
||||
"Error Setting up Auto-Negotiation\n");
|
||||
return ret_val;
|
||||
}
|
||||
mii_bmcr_data |= BMCR_AUTO_NEG_EN | BMCR_RESTART_AUTO_NEG;
|
||||
break;
|
||||
case MEDIA_TYPE_100M_FULL:
|
||||
mii_bmcr_data |= BMCR_SPEED_100 | BMCR_FULL_DUPLEX;
|
||||
break;
|
||||
case MEDIA_TYPE_100M_HALF:
|
||||
mii_bmcr_data |= BMCR_SPEED_100;
|
||||
break;
|
||||
case MEDIA_TYPE_10M_FULL:
|
||||
mii_bmcr_data |= BMCR_SPEED_10 | BMCR_FULL_DUPLEX;
|
||||
break;
|
||||
case MEDIA_TYPE_10M_HALF:
|
||||
mii_bmcr_data |= BMCR_SPEED_10;
|
||||
break;
|
||||
default:
|
||||
if (netif_msg_link(adapter))
|
||||
dev_err(&pdev->dev, "Wrong Media type %d\n",
|
||||
hw->media_type);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
ret_val = atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
hw->phy_configured = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Detects the current speed and duplex settings of the hardware.
|
||||
*
|
||||
* hw - Struct containing variables accessed by shared code
|
||||
* speed - Speed of the connection
|
||||
* duplex - Duplex setting of the connection
|
||||
*/
|
||||
int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
|
||||
{
|
||||
int err;
|
||||
u16 phy_data;
|
||||
|
||||
/* Read PHY Specific Status Register (17) */
|
||||
err = atl1c_read_phy_reg(hw, MII_GIGA_PSSR, &phy_data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!(phy_data & GIGA_PSSR_SPD_DPLX_RESOLVED))
|
||||
return -1;
|
||||
|
||||
switch (phy_data & GIGA_PSSR_SPEED) {
|
||||
case GIGA_PSSR_1000MBS:
|
||||
*speed = SPEED_1000;
|
||||
break;
|
||||
case GIGA_PSSR_100MBS:
|
||||
*speed = SPEED_100;
|
||||
break;
|
||||
case GIGA_PSSR_10MBS:
|
||||
*speed = SPEED_10;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (phy_data & GIGA_PSSR_DPLX)
|
||||
*duplex = FULL_DUPLEX;
|
||||
else
|
||||
*duplex = HALF_DUPLEX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int atl1c_restart_autoneg(struct atl1c_hw *hw)
|
||||
{
|
||||
int err = 0;
|
||||
u16 mii_bmcr_data = BMCR_RESET;
|
||||
|
||||
err = atl1c_phy_setup_adv(hw);
|
||||
if (err)
|
||||
return err;
|
||||
mii_bmcr_data |= BMCR_AUTO_NEG_EN | BMCR_RESTART_AUTO_NEG;
|
||||
|
||||
return atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data);
|
||||
}
|
859
drivers/net/atl1c/atl1c_hw.h
Normal file
859
drivers/net/atl1c/atl1c_hw.h
Normal file
@ -0,0 +1,859 @@
|
||||
/*
|
||||
* Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
|
||||
*
|
||||
* Derived from Intel e1000 driver
|
||||
* Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _ATL1C_HW_H_
|
||||
#define _ATL1C_HW_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mii.h>
|
||||
|
||||
struct atl1c_adapter;
|
||||
struct atl1c_hw;
|
||||
|
||||
/* function prototype */
|
||||
void atl1c_phy_disable(struct atl1c_hw *hw);
|
||||
void atl1c_hw_set_mac_addr(struct atl1c_hw *hw);
|
||||
int atl1c_phy_reset(struct atl1c_hw *hw);
|
||||
int atl1c_read_mac_addr(struct atl1c_hw *hw);
|
||||
int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex);
|
||||
u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr);
|
||||
void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value);
|
||||
int atl1c_read_phy_reg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data);
|
||||
int atl1c_write_phy_reg(struct atl1c_hw *hw, u32 reg_addr, u16 phy_data);
|
||||
bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value);
|
||||
int atl1c_phy_init(struct atl1c_hw *hw);
|
||||
int atl1c_check_eeprom_exist(struct atl1c_hw *hw);
|
||||
int atl1c_restart_autoneg(struct atl1c_hw *hw);
|
||||
|
||||
/* register definition */
|
||||
#define REG_DEVICE_CAP 0x5C
|
||||
#define DEVICE_CAP_MAX_PAYLOAD_MASK 0x7
|
||||
#define DEVICE_CAP_MAX_PAYLOAD_SHIFT 0
|
||||
|
||||
#define REG_DEVICE_CTRL 0x60
|
||||
#define DEVICE_CTRL_MAX_PAYLOAD_MASK 0x7
|
||||
#define DEVICE_CTRL_MAX_PAYLOAD_SHIFT 5
|
||||
#define DEVICE_CTRL_MAX_RREQ_SZ_MASK 0x7
|
||||
#define DEVICE_CTRL_MAX_RREQ_SZ_SHIFT 12
|
||||
|
||||
#define REG_LINK_CTRL 0x68
|
||||
#define LINK_CTRL_L0S_EN 0x01
|
||||
#define LINK_CTRL_L1_EN 0x02
|
||||
|
||||
#define REG_VPD_CAP 0x6C
|
||||
#define VPD_CAP_ID_MASK 0xff
|
||||
#define VPD_CAP_ID_SHIFT 0
|
||||
#define VPD_CAP_NEXT_PTR_MASK 0xFF
|
||||
#define VPD_CAP_NEXT_PTR_SHIFT 8
|
||||
#define VPD_CAP_VPD_ADDR_MASK 0x7FFF
|
||||
#define VPD_CAP_VPD_ADDR_SHIFT 16
|
||||
#define VPD_CAP_VPD_FLAG 0x80000000
|
||||
|
||||
#define REG_VPD_DATA 0x70
|
||||
|
||||
#define REG_PCIE_UC_SEVERITY 0x10C
|
||||
#define PCIE_UC_SERVRITY_TRN 0x00000001
|
||||
#define PCIE_UC_SERVRITY_DLP 0x00000010
|
||||
#define PCIE_UC_SERVRITY_PSN_TLP 0x00001000
|
||||
#define PCIE_UC_SERVRITY_FCP 0x00002000
|
||||
#define PCIE_UC_SERVRITY_CPL_TO 0x00004000
|
||||
#define PCIE_UC_SERVRITY_CA 0x00008000
|
||||
#define PCIE_UC_SERVRITY_UC 0x00010000
|
||||
#define PCIE_UC_SERVRITY_ROV 0x00020000
|
||||
#define PCIE_UC_SERVRITY_MLFP 0x00040000
|
||||
#define PCIE_UC_SERVRITY_ECRC 0x00080000
|
||||
#define PCIE_UC_SERVRITY_UR 0x00100000
|
||||
|
||||
#define REG_DEV_SERIALNUM_CTRL 0x200
|
||||
#define REG_DEV_MAC_SEL_MASK 0x0 /* 0:EUI; 1:MAC */
|
||||
#define REG_DEV_MAC_SEL_SHIFT 0
|
||||
#define REG_DEV_SERIAL_NUM_EN_MASK 0x1
|
||||
#define REG_DEV_SERIAL_NUM_EN_SHIFT 1
|
||||
|
||||
#define REG_TWSI_CTRL 0x218
|
||||
#define TWSI_CTRL_LD_OFFSET_MASK 0xFF
|
||||
#define TWSI_CTRL_LD_OFFSET_SHIFT 0
|
||||
#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7
|
||||
#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8
|
||||
#define TWSI_CTRL_SW_LDSTART 0x800
|
||||
#define TWSI_CTRL_HW_LDSTART 0x1000
|
||||
#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x7F
|
||||
#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15
|
||||
#define TWSI_CTRL_LD_EXIST 0x400000
|
||||
#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3
|
||||
#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23
|
||||
#define TWSI_CTRL_FREQ_SEL_100K 0
|
||||
#define TWSI_CTRL_FREQ_SEL_200K 1
|
||||
#define TWSI_CTRL_FREQ_SEL_300K 2
|
||||
#define TWSI_CTRL_FREQ_SEL_400K 3
|
||||
#define TWSI_CTRL_SMB_SLV_ADDR
|
||||
#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3
|
||||
#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24
|
||||
|
||||
|
||||
#define REG_PCIE_DEV_MISC_CTRL 0x21C
|
||||
#define PCIE_DEV_MISC_EXT_PIPE 0x2
|
||||
#define PCIE_DEV_MISC_RETRY_BUFDIS 0x1
|
||||
#define PCIE_DEV_MISC_SPIROM_EXIST 0x4
|
||||
#define PCIE_DEV_MISC_SERDES_ENDIAN 0x8
|
||||
#define PCIE_DEV_MISC_SERDES_SEL_DIN 0x10
|
||||
|
||||
#define REG_PCIE_PHYMISC 0x1000
|
||||
#define PCIE_PHYMISC_FORCE_RCV_DET 0x4
|
||||
|
||||
#define REG_TWSI_DEBUG 0x1108
|
||||
#define TWSI_DEBUG_DEV_EXIST 0x20000000
|
||||
|
||||
#define REG_EEPROM_CTRL 0x12C0
|
||||
#define EEPROM_CTRL_DATA_HI_MASK 0xFFFF
|
||||
#define EEPROM_CTRL_DATA_HI_SHIFT 0
|
||||
#define EEPROM_CTRL_ADDR_MASK 0x3FF
|
||||
#define EEPROM_CTRL_ADDR_SHIFT 16
|
||||
#define EEPROM_CTRL_ACK 0x40000000
|
||||
#define EEPROM_CTRL_RW 0x80000000
|
||||
|
||||
#define REG_EEPROM_DATA_LO 0x12C4
|
||||
|
||||
#define REG_OTP_CTRL 0x12F0
|
||||
#define OTP_CTRL_CLK_EN 0x0002
|
||||
|
||||
#define REG_PM_CTRL 0x12F8
|
||||
#define PM_CTRL_SDES_EN 0x00000001
|
||||
#define PM_CTRL_RBER_EN 0x00000002
|
||||
#define PM_CTRL_CLK_REQ_EN 0x00000004
|
||||
#define PM_CTRL_ASPM_L1_EN 0x00000008
|
||||
#define PM_CTRL_SERDES_L1_EN 0x00000010
|
||||
#define PM_CTRL_SERDES_PLL_L1_EN 0x00000020
|
||||
#define PM_CTRL_SERDES_PD_EX_L1 0x00000040
|
||||
#define PM_CTRL_SERDES_BUDS_RX_L1_EN 0x00000080
|
||||
#define PM_CTRL_L0S_ENTRY_TIMER_MASK 0xF
|
||||
#define PM_CTRL_L0S_ENTRY_TIMER_SHIFT 8
|
||||
#define PM_CTRL_ASPM_L0S_EN 0x00001000
|
||||
#define PM_CTRL_CLK_SWH_L1 0x00002000
|
||||
#define PM_CTRL_CLK_PWM_VER1_1 0x00004000
|
||||
#define PM_CTRL_PCIE_RECV 0x00008000
|
||||
#define PM_CTRL_L1_ENTRY_TIMER_MASK 0xF
|
||||
#define PM_CTRL_L1_ENTRY_TIMER_SHIFT 16
|
||||
#define PM_CTRL_PM_REQ_TIMER_MASK 0xF
|
||||
#define PM_CTRL_PM_REQ_TIMER_SHIFT 20
|
||||
#define PM_CTRL_LCKDET_TIMER_MASK 0x3F
|
||||
#define PM_CTRL_LCKDET_TIMER_SHIFT 24
|
||||
#define PM_CTRL_MAC_ASPM_CHK 0x40000000
|
||||
#define PM_CTRL_HOTRST 0x80000000
|
||||
|
||||
/* Selene Master Control Register */
|
||||
#define REG_MASTER_CTRL 0x1400
|
||||
#define MASTER_CTRL_SOFT_RST 0x1
|
||||
#define MASTER_CTRL_TEST_MODE_MASK 0x3
|
||||
#define MASTER_CTRL_TEST_MODE_SHIFT 2
|
||||
#define MASTER_CTRL_BERT_START 0x10
|
||||
#define MASTER_CTRL_MTIMER_EN 0x100
|
||||
#define MASTER_CTRL_MANUAL_INT 0x200
|
||||
#define MASTER_CTRL_TX_ITIMER_EN 0x400
|
||||
#define MASTER_CTRL_RX_ITIMER_EN 0x800
|
||||
#define MASTER_CTRL_CLK_SEL_DIS 0x1000
|
||||
#define MASTER_CTRL_CLK_SWH_MODE 0x2000
|
||||
#define MASTER_CTRL_INT_RDCLR 0x4000
|
||||
#define MASTER_CTRL_REV_NUM_SHIFT 16
|
||||
#define MASTER_CTRL_REV_NUM_MASK 0xff
|
||||
#define MASTER_CTRL_DEV_ID_SHIFT 24
|
||||
#define MASTER_CTRL_DEV_ID_MASK 0x7f
|
||||
#define MASTER_CTRL_OTP_SEL 0x80000000
|
||||
|
||||
/* Timer Initial Value Register */
|
||||
#define REG_MANUAL_TIMER_INIT 0x1404
|
||||
|
||||
/* IRQ ModeratorTimer Initial Value Register */
|
||||
#define REG_IRQ_MODRT_TIMER_INIT 0x1408
|
||||
#define IRQ_MODRT_TIMER_MASK 0xffff
|
||||
#define IRQ_MODRT_TX_TIMER_SHIFT 0
|
||||
#define IRQ_MODRT_RX_TIMER_SHIFT 16
|
||||
|
||||
#define REG_GPHY_CTRL 0x140C
|
||||
#define GPHY_CTRL_EXT_RESET 0x1
|
||||
#define GPHY_CTRL_RTL_MODE 0x2
|
||||
#define GPHY_CTRL_LED_MODE 0x4
|
||||
#define GPHY_CTRL_ANEG_NOW 0x8
|
||||
#define GPHY_CTRL_REV_ANEG 0x10
|
||||
#define GPHY_CTRL_GATE_25M_EN 0x20
|
||||
#define GPHY_CTRL_LPW_EXIT 0x40
|
||||
#define GPHY_CTRL_PHY_IDDQ 0x80
|
||||
#define GPHY_CTRL_PHY_IDDQ_DIS 0x100
|
||||
#define GPHY_CTRL_GIGA_DIS 0x200
|
||||
#define GPHY_CTRL_HIB_EN 0x400
|
||||
#define GPHY_CTRL_HIB_PULSE 0x800
|
||||
#define GPHY_CTRL_SEL_ANA_RST 0x1000
|
||||
#define GPHY_CTRL_PHY_PLL_ON 0x2000
|
||||
#define GPHY_CTRL_PWDOWN_HW 0x4000
|
||||
#define GPHY_CTRL_PHY_PLL_BYPASS 0x8000
|
||||
|
||||
#define GPHY_CTRL_DEFAULT ( \
|
||||
GPHY_CTRL_SEL_ANA_RST |\
|
||||
GPHY_CTRL_HIB_PULSE |\
|
||||
GPHY_CTRL_HIB_EN)
|
||||
|
||||
#define GPHY_CTRL_PW_WOL_DIS ( \
|
||||
GPHY_CTRL_SEL_ANA_RST |\
|
||||
GPHY_CTRL_HIB_PULSE |\
|
||||
GPHY_CTRL_HIB_EN |\
|
||||
GPHY_CTRL_PWDOWN_HW |\
|
||||
GPHY_CTRL_PHY_IDDQ)
|
||||
|
||||
/* Block IDLE Status Register */
|
||||
#define REG_IDLE_STATUS 0x1410
|
||||
#define IDLE_STATUS_MASK 0x00FF
|
||||
#define IDLE_STATUS_RXMAC_NO_IDLE 0x1
|
||||
#define IDLE_STATUS_TXMAC_NO_IDLE 0x2
|
||||
#define IDLE_STATUS_RXQ_NO_IDLE 0x4
|
||||
#define IDLE_STATUS_TXQ_NO_IDLE 0x8
|
||||
#define IDLE_STATUS_DMAR_NO_IDLE 0x10
|
||||
#define IDLE_STATUS_DMAW_NO_IDLE 0x20
|
||||
#define IDLE_STATUS_SMB_NO_IDLE 0x40
|
||||
#define IDLE_STATUS_CMB_NO_IDLE 0x80
|
||||
|
||||
/* MDIO Control Register */
|
||||
#define REG_MDIO_CTRL 0x1414
|
||||
#define MDIO_DATA_MASK 0xffff /* On MDIO write, the 16-bit
|
||||
* control data to write to PHY
|
||||
* MII management register */
|
||||
#define MDIO_DATA_SHIFT 0 /* On MDIO read, the 16-bit
|
||||
* status data that was read
|
||||
* from the PHY MII management register */
|
||||
#define MDIO_REG_ADDR_MASK 0x1f /* MDIO register address */
|
||||
#define MDIO_REG_ADDR_SHIFT 16
|
||||
#define MDIO_RW 0x200000 /* 1: read, 0: write */
|
||||
#define MDIO_SUP_PREAMBLE 0x400000 /* Suppress preamble */
|
||||
#define MDIO_START 0x800000 /* Write 1 to initiate the MDIO
|
||||
* master. And this bit is self
|
||||
* cleared after one cycle */
|
||||
#define MDIO_CLK_SEL_SHIFT 24
|
||||
#define MDIO_CLK_25_4 0
|
||||
#define MDIO_CLK_25_6 2
|
||||
#define MDIO_CLK_25_8 3
|
||||
#define MDIO_CLK_25_10 4
|
||||
#define MDIO_CLK_25_14 5
|
||||
#define MDIO_CLK_25_20 6
|
||||
#define MDIO_CLK_25_28 7
|
||||
#define MDIO_BUSY 0x8000000
|
||||
#define MDIO_AP_EN 0x10000000
|
||||
#define MDIO_WAIT_TIMES 10
|
||||
|
||||
/* MII PHY Status Register */
|
||||
#define REG_PHY_STATUS 0x1418
|
||||
#define PHY_GENERAL_STATUS_MASK 0xFFFF
|
||||
#define PHY_STATUS_RECV_ENABLE 0x0001
|
||||
#define PHY_OE_PWSP_STATUS_MASK 0x07FF
|
||||
#define PHY_OE_PWSP_STATUS_SHIFT 16
|
||||
#define PHY_STATUS_LPW_STATE 0x80000000
|
||||
/* BIST Control and Status Register0 (for the Packet Memory) */
|
||||
#define REG_BIST0_CTRL 0x141c
|
||||
#define BIST0_NOW 0x1
|
||||
#define BIST0_SRAM_FAIL 0x2 /* 1: The SRAM failure is
|
||||
* un-repairable because
|
||||
* it has address decoder
|
||||
* failure or more than 1 cell
|
||||
* stuck-to-x failure */
|
||||
#define BIST0_FUSE_FLAG 0x4
|
||||
|
||||
/* BIST Control and Status Register1(for the retry buffer of PCI Express) */
|
||||
#define REG_BIST1_CTRL 0x1420
|
||||
#define BIST1_NOW 0x1
|
||||
#define BIST1_SRAM_FAIL 0x2
|
||||
#define BIST1_FUSE_FLAG 0x4
|
||||
|
||||
/* SerDes Lock Detect Control and Status Register */
|
||||
#define REG_SERDES_LOCK 0x1424
|
||||
#define SERDES_LOCK_DETECT 0x1 /* SerDes lock detected. This signal
|
||||
* comes from Analog SerDes */
|
||||
#define SERDES_LOCK_DETECT_EN 0x2 /* 1: Enable SerDes Lock detect function */
|
||||
|
||||
/* MAC Control Register */
|
||||
#define REG_MAC_CTRL 0x1480
|
||||
#define MAC_CTRL_TX_EN 0x1
|
||||
#define MAC_CTRL_RX_EN 0x2
|
||||
#define MAC_CTRL_TX_FLOW 0x4
|
||||
#define MAC_CTRL_RX_FLOW 0x8
|
||||
#define MAC_CTRL_LOOPBACK 0x10
|
||||
#define MAC_CTRL_DUPLX 0x20
|
||||
#define MAC_CTRL_ADD_CRC 0x40
|
||||
#define MAC_CTRL_PAD 0x80
|
||||
#define MAC_CTRL_LENCHK 0x100
|
||||
#define MAC_CTRL_HUGE_EN 0x200
|
||||
#define MAC_CTRL_PRMLEN_SHIFT 10
|
||||
#define MAC_CTRL_PRMLEN_MASK 0xf
|
||||
#define MAC_CTRL_RMV_VLAN 0x4000
|
||||
#define MAC_CTRL_PROMIS_EN 0x8000
|
||||
#define MAC_CTRL_TX_PAUSE 0x10000
|
||||
#define MAC_CTRL_SCNT 0x20000
|
||||
#define MAC_CTRL_SRST_TX 0x40000
|
||||
#define MAC_CTRL_TX_SIMURST 0x80000
|
||||
#define MAC_CTRL_SPEED_SHIFT 20
|
||||
#define MAC_CTRL_SPEED_MASK 0x3
|
||||
#define MAC_CTRL_DBG_TX_BKPRESURE 0x400000
|
||||
#define MAC_CTRL_TX_HUGE 0x800000
|
||||
#define MAC_CTRL_RX_CHKSUM_EN 0x1000000
|
||||
#define MAC_CTRL_MC_ALL_EN 0x2000000
|
||||
#define MAC_CTRL_BC_EN 0x4000000
|
||||
#define MAC_CTRL_DBG 0x8000000
|
||||
#define MAC_CTRL_SINGLE_PAUSE_EN 0x10000000
|
||||
|
||||
/* MAC IPG/IFG Control Register */
|
||||
#define REG_MAC_IPG_IFG 0x1484
|
||||
#define MAC_IPG_IFG_IPGT_SHIFT 0 /* Desired back to back
|
||||
* inter-packet gap. The
|
||||
* default is 96-bit time */
|
||||
#define MAC_IPG_IFG_IPGT_MASK 0x7f
|
||||
#define MAC_IPG_IFG_MIFG_SHIFT 8 /* Minimum number of IFG to
|
||||
* enforce in between RX frames */
|
||||
#define MAC_IPG_IFG_MIFG_MASK 0xff /* Frame gap below such IFP is dropped */
|
||||
#define MAC_IPG_IFG_IPGR1_SHIFT 16 /* 64bit Carrier-Sense window */
|
||||
#define MAC_IPG_IFG_IPGR1_MASK 0x7f
|
||||
#define MAC_IPG_IFG_IPGR2_SHIFT 24 /* 96-bit IPG window */
|
||||
#define MAC_IPG_IFG_IPGR2_MASK 0x7f
|
||||
|
||||
/* MAC STATION ADDRESS */
|
||||
#define REG_MAC_STA_ADDR 0x1488
|
||||
|
||||
/* Hash table for multicast address */
|
||||
#define REG_RX_HASH_TABLE 0x1490
|
||||
|
||||
/* MAC Half-Duplex Control Register */
|
||||
#define REG_MAC_HALF_DUPLX_CTRL 0x1498
|
||||
#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT 0 /* Collision Window */
|
||||
#define MAC_HALF_DUPLX_CTRL_LCOL_MASK 0x3ff
|
||||
#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12
|
||||
#define MAC_HALF_DUPLX_CTRL_RETRY_MASK 0xf
|
||||
#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN 0x10000
|
||||
#define MAC_HALF_DUPLX_CTRL_NO_BACK_C 0x20000
|
||||
#define MAC_HALF_DUPLX_CTRL_NO_BACK_P 0x40000 /* No back-off on backpressure,
|
||||
* immediately start the
|
||||
* transmission after back pressure */
|
||||
#define MAC_HALF_DUPLX_CTRL_ABEBE 0x80000 /* 1: Alternative Binary Exponential Back-off Enabled */
|
||||
#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT 20 /* Maximum binary exponential number */
|
||||
#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK 0xf
|
||||
#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24 /* IPG to start JAM for collision based flow control in half-duplex */
|
||||
#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK 0xf /* mode. In unit of 8-bit time */
|
||||
|
||||
/* Maximum Frame Length Control Register */
|
||||
#define REG_MTU 0x149c
|
||||
|
||||
/* Wake-On-Lan control register */
|
||||
#define REG_WOL_CTRL 0x14a0
|
||||
#define WOL_PATTERN_EN 0x00000001
|
||||
#define WOL_PATTERN_PME_EN 0x00000002
|
||||
#define WOL_MAGIC_EN 0x00000004
|
||||
#define WOL_MAGIC_PME_EN 0x00000008
|
||||
#define WOL_LINK_CHG_EN 0x00000010
|
||||
#define WOL_LINK_CHG_PME_EN 0x00000020
|
||||
#define WOL_PATTERN_ST 0x00000100
|
||||
#define WOL_MAGIC_ST 0x00000200
|
||||
#define WOL_LINKCHG_ST 0x00000400
|
||||
#define WOL_CLK_SWITCH_EN 0x00008000
|
||||
#define WOL_PT0_EN 0x00010000
|
||||
#define WOL_PT1_EN 0x00020000
|
||||
#define WOL_PT2_EN 0x00040000
|
||||
#define WOL_PT3_EN 0x00080000
|
||||
#define WOL_PT4_EN 0x00100000
|
||||
#define WOL_PT5_EN 0x00200000
|
||||
#define WOL_PT6_EN 0x00400000
|
||||
|
||||
/* WOL Length ( 2 DWORD ) */
|
||||
#define REG_WOL_PATTERN_LEN 0x14a4
|
||||
#define WOL_PT_LEN_MASK 0x7f
|
||||
#define WOL_PT0_LEN_SHIFT 0
|
||||
#define WOL_PT1_LEN_SHIFT 8
|
||||
#define WOL_PT2_LEN_SHIFT 16
|
||||
#define WOL_PT3_LEN_SHIFT 24
|
||||
#define WOL_PT4_LEN_SHIFT 0
|
||||
#define WOL_PT5_LEN_SHIFT 8
|
||||
#define WOL_PT6_LEN_SHIFT 16
|
||||
|
||||
/* Internal SRAM Partition Register */
|
||||
#define RFDX_HEAD_ADDR_MASK 0x03FF
|
||||
#define RFDX_HARD_ADDR_SHIFT 0
|
||||
#define RFDX_TAIL_ADDR_MASK 0x03FF
|
||||
#define RFDX_TAIL_ADDR_SHIFT 16
|
||||
|
||||
#define REG_SRAM_RFD0_INFO 0x1500
|
||||
#define REG_SRAM_RFD1_INFO 0x1504
|
||||
#define REG_SRAM_RFD2_INFO 0x1508
|
||||
#define REG_SRAM_RFD3_INFO 0x150C
|
||||
|
||||
#define REG_RFD_NIC_LEN 0x1510 /* In 8-bytes */
|
||||
#define RFD_NIC_LEN_MASK 0x03FF
|
||||
|
||||
#define REG_SRAM_TRD_ADDR 0x1518
|
||||
#define TPD_HEAD_ADDR_MASK 0x03FF
|
||||
#define TPD_HEAD_ADDR_SHIFT 0
|
||||
#define TPD_TAIL_ADDR_MASK 0x03FF
|
||||
#define TPD_TAIL_ADDR_SHIFT 16
|
||||
|
||||
#define REG_SRAM_TRD_LEN 0x151C /* In 8-bytes */
|
||||
#define TPD_NIC_LEN_MASK 0x03FF
|
||||
|
||||
#define REG_SRAM_RXF_ADDR 0x1520
|
||||
#define REG_SRAM_RXF_LEN 0x1524
|
||||
#define REG_SRAM_TXF_ADDR 0x1528
|
||||
#define REG_SRAM_TXF_LEN 0x152C
|
||||
#define REG_SRAM_TCPH_ADDR 0x1530
|
||||
#define REG_SRAM_PKTH_ADDR 0x1532
|
||||
|
||||
/*
|
||||
* Load Ptr Register
|
||||
* Software sets this bit after the initialization of the head and tail */
|
||||
#define REG_LOAD_PTR 0x1534
|
||||
|
||||
/*
|
||||
* addresses of all descriptors, as well as the following descriptor
|
||||
* control register, which triggers each function block to load the head
|
||||
* pointer to prepare for the operation. This bit is then self-cleared
|
||||
* after one cycle.
|
||||
*/
|
||||
#define REG_RX_BASE_ADDR_HI 0x1540
|
||||
#define REG_TX_BASE_ADDR_HI 0x1544
|
||||
#define REG_SMB_BASE_ADDR_HI 0x1548
|
||||
#define REG_SMB_BASE_ADDR_LO 0x154C
|
||||
#define REG_RFD0_HEAD_ADDR_LO 0x1550
|
||||
#define REG_RFD1_HEAD_ADDR_LO 0x1554
|
||||
#define REG_RFD2_HEAD_ADDR_LO 0x1558
|
||||
#define REG_RFD3_HEAD_ADDR_LO 0x155C
|
||||
#define REG_RFD_RING_SIZE 0x1560
|
||||
#define RFD_RING_SIZE_MASK 0x0FFF
|
||||
#define REG_RX_BUF_SIZE 0x1564
|
||||
#define RX_BUF_SIZE_MASK 0xFFFF
|
||||
#define REG_RRD0_HEAD_ADDR_LO 0x1568
|
||||
#define REG_RRD1_HEAD_ADDR_LO 0x156C
|
||||
#define REG_RRD2_HEAD_ADDR_LO 0x1570
|
||||
#define REG_RRD3_HEAD_ADDR_LO 0x1574
|
||||
#define REG_RRD_RING_SIZE 0x1578
|
||||
#define RRD_RING_SIZE_MASK 0x0FFF
|
||||
#define REG_HTPD_HEAD_ADDR_LO 0x157C
|
||||
#define REG_NTPD_HEAD_ADDR_LO 0x1580
|
||||
#define REG_TPD_RING_SIZE 0x1584
|
||||
#define TPD_RING_SIZE_MASK 0xFFFF
|
||||
#define REG_CMB_BASE_ADDR_LO 0x1588
|
||||
|
||||
/* RSS about */
|
||||
#define REG_RSS_KEY0 0x14B0
|
||||
#define REG_RSS_KEY1 0x14B4
|
||||
#define REG_RSS_KEY2 0x14B8
|
||||
#define REG_RSS_KEY3 0x14BC
|
||||
#define REG_RSS_KEY4 0x14C0
|
||||
#define REG_RSS_KEY5 0x14C4
|
||||
#define REG_RSS_KEY6 0x14C8
|
||||
#define REG_RSS_KEY7 0x14CC
|
||||
#define REG_RSS_KEY8 0x14D0
|
||||
#define REG_RSS_KEY9 0x14D4
|
||||
#define REG_IDT_TABLE0 0x14E0
|
||||
#define REG_IDT_TABLE1 0x14E4
|
||||
#define REG_IDT_TABLE2 0x14E8
|
||||
#define REG_IDT_TABLE3 0x14EC
|
||||
#define REG_IDT_TABLE4 0x14F0
|
||||
#define REG_IDT_TABLE5 0x14F4
|
||||
#define REG_IDT_TABLE6 0x14F8
|
||||
#define REG_IDT_TABLE7 0x14FC
|
||||
#define REG_IDT_TABLE REG_IDT_TABLE0
|
||||
#define REG_RSS_HASH_VALUE 0x15B0
|
||||
#define REG_RSS_HASH_FLAG 0x15B4
|
||||
#define REG_BASE_CPU_NUMBER 0x15B8
|
||||
|
||||
/* TXQ Control Register */
|
||||
#define REG_TXQ_CTRL 0x1590
|
||||
#define TXQ_NUM_TPD_BURST_MASK 0xF
|
||||
#define TXQ_NUM_TPD_BURST_SHIFT 0
|
||||
#define TXQ_CTRL_IP_OPTION_EN 0x10
|
||||
#define TXQ_CTRL_EN 0x20
|
||||
#define TXQ_CTRL_ENH_MODE 0x40
|
||||
#define TXQ_CTRL_LS_8023_EN 0x80
|
||||
#define TXQ_TXF_BURST_NUM_SHIFT 16
|
||||
#define TXQ_TXF_BURST_NUM_MASK 0xFFFF
|
||||
|
||||
/* Jumbo packet Threshold for task offload */
|
||||
#define REG_TX_TSO_OFFLOAD_THRESH 0x1594 /* In 8-bytes */
|
||||
#define TX_TSO_OFFLOAD_THRESH_MASK 0x07FF
|
||||
|
||||
#define REG_TXF_WATER_MARK 0x1598 /* In 8-bytes */
|
||||
#define TXF_WATER_MARK_MASK 0x0FFF
|
||||
#define TXF_LOW_WATER_MARK_SHIFT 0
|
||||
#define TXF_HIGH_WATER_MARK_SHIFT 16
|
||||
#define TXQ_CTRL_BURST_MODE_EN 0x80000000
|
||||
|
||||
#define REG_THRUPUT_MON_CTRL 0x159C
|
||||
#define THRUPUT_MON_RATE_MASK 0x3
|
||||
#define THRUPUT_MON_RATE_SHIFT 0
|
||||
#define THRUPUT_MON_EN 0x80
|
||||
|
||||
/* RXQ Control Register */
|
||||
#define REG_RXQ_CTRL 0x15A0
|
||||
#define ASPM_THRUPUT_LIMIT_MASK 0x3
|
||||
#define ASPM_THRUPUT_LIMIT_SHIFT 0
|
||||
#define ASPM_THRUPUT_LIMIT_NO 0x00
|
||||
#define ASPM_THRUPUT_LIMIT_1M 0x01
|
||||
#define ASPM_THRUPUT_LIMIT_10M 0x02
|
||||
#define ASPM_THRUPUT_LIMIT_100M 0x04
|
||||
#define RXQ1_CTRL_EN 0x10
|
||||
#define RXQ2_CTRL_EN 0x20
|
||||
#define RXQ3_CTRL_EN 0x40
|
||||
#define IPV6_CHKSUM_CTRL_EN 0x80
|
||||
#define RSS_HASH_BITS_MASK 0x00FF
|
||||
#define RSS_HASH_BITS_SHIFT 8
|
||||
#define RSS_HASH_IPV4 0x10000
|
||||
#define RSS_HASH_IPV4_TCP 0x20000
|
||||
#define RSS_HASH_IPV6 0x40000
|
||||
#define RSS_HASH_IPV6_TCP 0x80000
|
||||
#define RXQ_RFD_BURST_NUM_MASK 0x003F
|
||||
#define RXQ_RFD_BURST_NUM_SHIFT 20
|
||||
#define RSS_MODE_MASK 0x0003
|
||||
#define RSS_MODE_SHIFT 26
|
||||
#define RSS_NIP_QUEUE_SEL_MASK 0x1
|
||||
#define RSS_NIP_QUEUE_SEL_SHIFT 28
|
||||
#define RRS_HASH_CTRL_EN 0x20000000
|
||||
#define RX_CUT_THRU_EN 0x40000000
|
||||
#define RXQ_CTRL_EN 0x80000000
|
||||
|
||||
#define REG_RFD_FREE_THRESH 0x15A4
|
||||
#define RFD_FREE_THRESH_MASK 0x003F
|
||||
#define RFD_FREE_HI_THRESH_SHIFT 0
|
||||
#define RFD_FREE_LO_THRESH_SHIFT 6
|
||||
|
||||
/* RXF flow control register */
|
||||
#define REG_RXQ_RXF_PAUSE_THRESH 0x15A8
|
||||
#define RXQ_RXF_PAUSE_TH_HI_SHIFT 0
|
||||
#define RXQ_RXF_PAUSE_TH_HI_MASK 0x0FFF
|
||||
#define RXQ_RXF_PAUSE_TH_LO_SHIFT 16
|
||||
#define RXQ_RXF_PAUSE_TH_LO_MASK 0x0FFF
|
||||
|
||||
#define REG_RXD_DMA_CTRL 0x15AC
|
||||
#define RXD_DMA_THRESH_MASK 0x0FFF /* In 8-bytes */
|
||||
#define RXD_DMA_THRESH_SHIFT 0
|
||||
#define RXD_DMA_DOWN_TIMER_MASK 0xFFFF
|
||||
#define RXD_DMA_DOWN_TIMER_SHIFT 16
|
||||
|
||||
/* DMA Engine Control Register */
|
||||
#define REG_DMA_CTRL 0x15C0
|
||||
#define DMA_CTRL_DMAR_IN_ORDER 0x1
|
||||
#define DMA_CTRL_DMAR_ENH_ORDER 0x2
|
||||
#define DMA_CTRL_DMAR_OUT_ORDER 0x4
|
||||
#define DMA_CTRL_RCB_VALUE 0x8
|
||||
#define DMA_CTRL_DMAR_BURST_LEN_MASK 0x0007
|
||||
#define DMA_CTRL_DMAR_BURST_LEN_SHIFT 4
|
||||
#define DMA_CTRL_DMAW_BURST_LEN_MASK 0x0007
|
||||
#define DMA_CTRL_DMAW_BURST_LEN_SHIFT 7
|
||||
#define DMA_CTRL_DMAR_REQ_PRI 0x400
|
||||
#define DMA_CTRL_DMAR_DLY_CNT_MASK 0x001F
|
||||
#define DMA_CTRL_DMAR_DLY_CNT_SHIFT 11
|
||||
#define DMA_CTRL_DMAW_DLY_CNT_MASK 0x000F
|
||||
#define DMA_CTRL_DMAW_DLY_CNT_SHIFT 16
|
||||
#define DMA_CTRL_CMB_EN 0x100000
|
||||
#define DMA_CTRL_SMB_EN 0x200000
|
||||
#define DMA_CTRL_CMB_NOW 0x400000
|
||||
#define MAC_CTRL_SMB_DIS 0x1000000
|
||||
#define DMA_CTRL_SMB_NOW 0x80000000
|
||||
|
||||
/* CMB/SMB Control Register */
|
||||
#define REG_SMB_STAT_TIMER 0x15C4 /* 2us resolution */
|
||||
#define SMB_STAT_TIMER_MASK 0xFFFFFF
|
||||
#define REG_CMB_TPD_THRESH 0x15C8
|
||||
#define CMB_TPD_THRESH_MASK 0xFFFF
|
||||
#define REG_CMB_TX_TIMER 0x15CC /* 2us resolution */
|
||||
#define CMB_TX_TIMER_MASK 0xFFFF
|
||||
|
||||
/* Mail box */
|
||||
#define MB_RFDX_PROD_IDX_MASK 0xFFFF
|
||||
#define REG_MB_RFD0_PROD_IDX 0x15E0
|
||||
#define REG_MB_RFD1_PROD_IDX 0x15E4
|
||||
#define REG_MB_RFD2_PROD_IDX 0x15E8
|
||||
#define REG_MB_RFD3_PROD_IDX 0x15EC
|
||||
|
||||
#define MB_PRIO_PROD_IDX_MASK 0xFFFF
|
||||
#define REG_MB_PRIO_PROD_IDX 0x15F0
|
||||
#define MB_HTPD_PROD_IDX_SHIFT 0
|
||||
#define MB_NTPD_PROD_IDX_SHIFT 16
|
||||
|
||||
#define MB_PRIO_CONS_IDX_MASK 0xFFFF
|
||||
#define REG_MB_PRIO_CONS_IDX 0x15F4
|
||||
#define MB_HTPD_CONS_IDX_SHIFT 0
|
||||
#define MB_NTPD_CONS_IDX_SHIFT 16
|
||||
|
||||
#define REG_MB_RFD01_CONS_IDX 0x15F8
|
||||
#define MB_RFD0_CONS_IDX_MASK 0x0000FFFF
|
||||
#define MB_RFD1_CONS_IDX_MASK 0xFFFF0000
|
||||
#define REG_MB_RFD23_CONS_IDX 0x15FC
|
||||
#define MB_RFD2_CONS_IDX_MASK 0x0000FFFF
|
||||
#define MB_RFD3_CONS_IDX_MASK 0xFFFF0000
|
||||
|
||||
/* Interrupt Status Register */
|
||||
#define REG_ISR 0x1600
|
||||
#define ISR_SMB 0x00000001
|
||||
#define ISR_TIMER 0x00000002
|
||||
/*
|
||||
* Software manual interrupt, for debug. Set when SW_MAN_INT_EN is set
|
||||
* in Table 51 Selene Master Control Register (Offset 0x1400).
|
||||
*/
|
||||
#define ISR_MANUAL 0x00000004
|
||||
#define ISR_HW_RXF_OV 0x00000008 /* RXF overflow interrupt */
|
||||
#define ISR_RFD0_UR 0x00000010 /* RFD0 under run */
|
||||
#define ISR_RFD1_UR 0x00000020
|
||||
#define ISR_RFD2_UR 0x00000040
|
||||
#define ISR_RFD3_UR 0x00000080
|
||||
#define ISR_TXF_UR 0x00000100
|
||||
#define ISR_DMAR_TO_RST 0x00000200
|
||||
#define ISR_DMAW_TO_RST 0x00000400
|
||||
#define ISR_TX_CREDIT 0x00000800
|
||||
#define ISR_GPHY 0x00001000
|
||||
/* GPHY low power state interrupt */
|
||||
#define ISR_GPHY_LPW 0x00002000
|
||||
#define ISR_TXQ_TO_RST 0x00004000
|
||||
#define ISR_TX_PKT 0x00008000
|
||||
#define ISR_RX_PKT_0 0x00010000
|
||||
#define ISR_RX_PKT_1 0x00020000
|
||||
#define ISR_RX_PKT_2 0x00040000
|
||||
#define ISR_RX_PKT_3 0x00080000
|
||||
#define ISR_MAC_RX 0x00100000
|
||||
#define ISR_MAC_TX 0x00200000
|
||||
#define ISR_UR_DETECTED 0x00400000
|
||||
#define ISR_FERR_DETECTED 0x00800000
|
||||
#define ISR_NFERR_DETECTED 0x01000000
|
||||
#define ISR_CERR_DETECTED 0x02000000
|
||||
#define ISR_PHY_LINKDOWN 0x04000000
|
||||
#define ISR_DIS_INT 0x80000000
|
||||
|
||||
/* Interrupt Mask Register */
|
||||
#define REG_IMR 0x1604
|
||||
|
||||
#define IMR_NORMAL_MASK (\
|
||||
ISR_MANUAL |\
|
||||
ISR_HW_RXF_OV |\
|
||||
ISR_RFD0_UR |\
|
||||
ISR_TXF_UR |\
|
||||
ISR_DMAR_TO_RST |\
|
||||
ISR_TXQ_TO_RST |\
|
||||
ISR_DMAW_TO_RST |\
|
||||
ISR_GPHY |\
|
||||
ISR_TX_PKT |\
|
||||
ISR_RX_PKT_0 |\
|
||||
ISR_GPHY_LPW |\
|
||||
ISR_PHY_LINKDOWN)
|
||||
|
||||
#define ISR_RX_PKT (\
|
||||
ISR_RX_PKT_0 |\
|
||||
ISR_RX_PKT_1 |\
|
||||
ISR_RX_PKT_2 |\
|
||||
ISR_RX_PKT_3)
|
||||
|
||||
#define ISR_OVER (\
|
||||
ISR_RFD0_UR |\
|
||||
ISR_RFD1_UR |\
|
||||
ISR_RFD2_UR |\
|
||||
ISR_RFD3_UR |\
|
||||
ISR_HW_RXF_OV |\
|
||||
ISR_TXF_UR)
|
||||
|
||||
#define ISR_ERROR (\
|
||||
ISR_DMAR_TO_RST |\
|
||||
ISR_TXQ_TO_RST |\
|
||||
ISR_DMAW_TO_RST |\
|
||||
ISR_PHY_LINKDOWN)
|
||||
|
||||
#define REG_INT_RETRIG_TIMER 0x1608
|
||||
#define INT_RETRIG_TIMER_MASK 0xFFFF
|
||||
|
||||
#define REG_HDS_CTRL 0x160C
|
||||
#define HDS_CTRL_EN 0x0001
|
||||
#define HDS_CTRL_BACKFILLSIZE_SHIFT 8
|
||||
#define HDS_CTRL_BACKFILLSIZE_MASK 0x0FFF
|
||||
#define HDS_CTRL_MAX_HDRSIZE_SHIFT 20
|
||||
#define HDS_CTRL_MAC_HDRSIZE_MASK 0x0FFF
|
||||
|
||||
#define REG_MAC_RX_STATUS_BIN 0x1700
|
||||
#define REG_MAC_RX_STATUS_END 0x175c
|
||||
#define REG_MAC_TX_STATUS_BIN 0x1760
|
||||
#define REG_MAC_TX_STATUS_END 0x17c0
|
||||
|
||||
/* DEBUG ADDR */
|
||||
#define REG_DEBUG_DATA0 0x1900
|
||||
#define REG_DEBUG_DATA1 0x1904
|
||||
|
||||
/* PHY Control Register */
|
||||
#define MII_BMCR 0x00
|
||||
#define BMCR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
|
||||
#define BMCR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
|
||||
#define BMCR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
|
||||
#define BMCR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
|
||||
#define BMCR_ISOLATE 0x0400 /* Isolate PHY from MII */
|
||||
#define BMCR_POWER_DOWN 0x0800 /* Power down */
|
||||
#define BMCR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
|
||||
#define BMCR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
|
||||
#define BMCR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
|
||||
#define BMCR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
|
||||
#define BMCR_SPEED_MASK 0x2040
|
||||
#define BMCR_SPEED_1000 0x0040
|
||||
#define BMCR_SPEED_100 0x2000
|
||||
#define BMCR_SPEED_10 0x0000
|
||||
|
||||
/* PHY Status Register */
|
||||
#define MII_BMSR 0x01
|
||||
#define BMMSR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
|
||||
#define BMSR_JABBER_DETECT 0x0002 /* Jabber Detected */
|
||||
#define BMSR_LINK_STATUS 0x0004 /* Link Status 1 = link */
|
||||
#define BMSR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
|
||||
#define BMSR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
|
||||
#define BMSR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
|
||||
#define BMSR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
|
||||
#define BMSR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
|
||||
#define BMSR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
|
||||
#define BMSR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
|
||||
#define BMSR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
|
||||
#define BMSR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
|
||||
#define BMSR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
|
||||
#define BMMII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
|
||||
#define BMMII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
|
||||
|
||||
#define MII_PHYSID1 0x02
|
||||
#define MII_PHYSID2 0x03
|
||||
|
||||
/* Autoneg Advertisement Register */
|
||||
#define MII_ADVERTISE 0x04
|
||||
#define ADVERTISE_SPEED_MASK 0x01E0
|
||||
#define ADVERTISE_DEFAULT_CAP 0x0DE0
|
||||
|
||||
/* 1000BASE-T Control Register */
|
||||
#define MII_GIGA_CR 0x09
|
||||
#define GIGA_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port 0=DTE device */
|
||||
|
||||
#define GIGA_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master 0=Configure PHY as Slave */
|
||||
#define GIGA_CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value 0=Automatic Master/Slave config */
|
||||
#define GIGA_CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
|
||||
#define GIGA_CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
|
||||
#define GIGA_CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
|
||||
#define GIGA_CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
|
||||
#define GIGA_CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
|
||||
#define GIGA_CR_1000T_SPEED_MASK 0x0300
|
||||
#define GIGA_CR_1000T_DEFAULT_CAP 0x0300
|
||||
|
||||
/* PHY Specific Status Register */
|
||||
#define MII_GIGA_PSSR 0x11
|
||||
#define GIGA_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
|
||||
#define GIGA_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
|
||||
#define GIGA_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
|
||||
#define GIGA_PSSR_10MBS 0x0000 /* 00=10Mbs */
|
||||
#define GIGA_PSSR_100MBS 0x4000 /* 01=100Mbs */
|
||||
#define GIGA_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
|
||||
|
||||
/* PHY Interrupt Enable Register */
|
||||
#define MII_IER 0x12
|
||||
#define IER_LINK_UP 0x0400
|
||||
#define IER_LINK_DOWN 0x0800
|
||||
|
||||
/* PHY Interrupt Status Register */
|
||||
#define MII_ISR 0x13
|
||||
#define ISR_LINK_UP 0x0400
|
||||
#define ISR_LINK_DOWN 0x0800
|
||||
|
||||
/* Cable-Detect-Test Control Register */
|
||||
#define MII_CDTC 0x16
|
||||
#define CDTC_EN_OFF 0 /* sc */
|
||||
#define CDTC_EN_BITS 1
|
||||
#define CDTC_PAIR_OFF 8
|
||||
#define CDTC_PAIR_BIT 2
|
||||
|
||||
/* Cable-Detect-Test Status Register */
|
||||
#define MII_CDTS 0x1C
|
||||
#define CDTS_STATUS_OFF 8
|
||||
#define CDTS_STATUS_BITS 2
|
||||
#define CDTS_STATUS_NORMAL 0
|
||||
#define CDTS_STATUS_SHORT 1
|
||||
#define CDTS_STATUS_OPEN 2
|
||||
#define CDTS_STATUS_INVALID 3
|
||||
|
||||
#define MII_DBG_ADDR 0x1D
|
||||
#define MII_DBG_DATA 0x1E
|
||||
|
||||
#define MII_ANA_CTRL_0 0x0
|
||||
#define ANA_RESTART_CAL 0x0001
|
||||
#define ANA_MANUL_SWICH_ON_SHIFT 0x1
|
||||
#define ANA_MANUL_SWICH_ON_MASK 0xF
|
||||
#define ANA_MAN_ENABLE 0x0020
|
||||
#define ANA_SEL_HSP 0x0040
|
||||
#define ANA_EN_HB 0x0080
|
||||
#define ANA_EN_HBIAS 0x0100
|
||||
#define ANA_OEN_125M 0x0200
|
||||
#define ANA_EN_LCKDT 0x0400
|
||||
#define ANA_LCKDT_PHY 0x0800
|
||||
#define ANA_AFE_MODE 0x1000
|
||||
#define ANA_VCO_SLOW 0x2000
|
||||
#define ANA_VCO_FAST 0x4000
|
||||
#define ANA_SEL_CLK125M_DSP 0x8000
|
||||
|
||||
#define MII_ANA_CTRL_4 0x4
|
||||
#define ANA_IECHO_ADJ_MASK 0xF
|
||||
#define ANA_IECHO_ADJ_3_SHIFT 0
|
||||
#define ANA_IECHO_ADJ_2_SHIFT 4
|
||||
#define ANA_IECHO_ADJ_1_SHIFT 8
|
||||
#define ANA_IECHO_ADJ_0_SHIFT 12
|
||||
|
||||
#define MII_ANA_CTRL_5 0x5
|
||||
#define ANA_SERDES_CDR_BW_SHIFT 0
|
||||
#define ANA_SERDES_CDR_BW_MASK 0x3
|
||||
#define ANA_MS_PAD_DBG 0x0004
|
||||
#define ANA_SPEEDUP_DBG 0x0008
|
||||
#define ANA_SERDES_TH_LOS_SHIFT 4
|
||||
#define ANA_SERDES_TH_LOS_MASK 0x3
|
||||
#define ANA_SERDES_EN_DEEM 0x0040
|
||||
#define ANA_SERDES_TXELECIDLE 0x0080
|
||||
#define ANA_SERDES_BEACON 0x0100
|
||||
#define ANA_SERDES_HALFTXDR 0x0200
|
||||
#define ANA_SERDES_SEL_HSP 0x0400
|
||||
#define ANA_SERDES_EN_PLL 0x0800
|
||||
#define ANA_SERDES_EN 0x1000
|
||||
#define ANA_SERDES_EN_LCKDT 0x2000
|
||||
|
||||
#define MII_ANA_CTRL_11 0xB
|
||||
#define ANA_PS_HIB_EN 0x8000
|
||||
|
||||
#define MII_ANA_CTRL_18 0x12
|
||||
#define ANA_TEST_MODE_10BT_01SHIFT 0
|
||||
#define ANA_TEST_MODE_10BT_01MASK 0x3
|
||||
#define ANA_LOOP_SEL_10BT 0x0004
|
||||
#define ANA_RGMII_MODE_SW 0x0008
|
||||
#define ANA_EN_LONGECABLE 0x0010
|
||||
#define ANA_TEST_MODE_10BT_2 0x0020
|
||||
#define ANA_EN_10BT_IDLE 0x0400
|
||||
#define ANA_EN_MASK_TB 0x0800
|
||||
#define ANA_TRIGGER_SEL_TIMER_SHIFT 12
|
||||
#define ANA_TRIGGER_SEL_TIMER_MASK 0x3
|
||||
#define ANA_INTERVAL_SEL_TIMER_SHIFT 14
|
||||
#define ANA_INTERVAL_SEL_TIMER_MASK 0x3
|
||||
|
||||
#define MII_ANA_CTRL_41 0x29
|
||||
#define ANA_TOP_PS_EN 0x8000
|
||||
|
||||
#define MII_ANA_CTRL_54 0x36
|
||||
#define ANA_LONG_CABLE_TH_100_SHIFT 0
|
||||
#define ANA_LONG_CABLE_TH_100_MASK 0x3F
|
||||
#define ANA_DESERVED 0x0040
|
||||
#define ANA_EN_LIT_CH 0x0080
|
||||
#define ANA_SHORT_CABLE_TH_100_SHIFT 8
|
||||
#define ANA_SHORT_CABLE_TH_100_MASK 0x3F
|
||||
#define ANA_BP_BAD_LINK_ACCUM 0x4000
|
||||
#define ANA_BP_SMALL_BW 0x8000
|
||||
|
||||
#endif /*_ATL1C_HW_H_*/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user