mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
ieee1394: remove the old IEEE 1394 driver stack
The drivers - ohci1394 (controller driver) - ieee1394 (core) - dv1394, raw1394, video1394 (userspace ABI) - eth1394, sbp2 (protocol drivers) are replaced by - firewire-ohci (controller driver) - firewire-core (core and userspace ABI) - firewire-net, firewire-sbp2 (protocol drivers) which are more featureful, better performing, and more secure than the older drivers; all with a smaller and more modern code base. The driver firedtv in drivers/media/dvb/firewire/ contains backends to both ieee1394 and firewire-core. Its ieee1394 backend code can be removed in an independent commit; firedtv as-is builds and works fine without ieee1394. The driver pcilynx (an incomplete controller driver) is deleted without replacement since PCILynx cards are extremely rare. Owners of these cards use them with the stand-alone bus sniffer driver nosy instead. The drivers nosy and init_ohci1394_dma which do not interact with either of the two IEEE 1394 stacks are not affected by the ieee1394 subsystem removal. There are still some issues with the newer firewire subsystem compared to the older one: - The rare and quirky controllers ALi M52xx, Apple UniNorth v1, NVIDIA NForce2 are even less well supported by firewire-ohci than by ohci1394. I am looking into the M52xx issue. - The experimental firewire-net is reportedly less stable than its experimental cousin eth1394. - Audio playback of a certain group of audio devices (ones based on DICE chipset with EAP; supported by prerelease FFADO code) does not work yet. This issue is still under investigation. - There were some ieee1394 based out-of-the-mainline drivers. Of them, only lisight, an audio driver for iSight webcams, seems still useful. Work is underway to reimplement it on top of firewire-core. All these remainig issues are minor; they should not stand in the way of overall better user experience of IEEE 1394 on Linux, together with a reduction in support efforts and maintenance burden. The coexistence of two IEEE 1394 kernel driver stacks in the mainline since 2.6.22 shall end now, as announced earlier this year. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
This commit is contained in:
parent
1ef5b816c0
commit
66fa12c571
@ -1,9 +0,0 @@
|
||||
What: dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
|
||||
Contact: linux1394-devel@lists.sourceforge.net
|
||||
Description:
|
||||
New application development should use raw1394 + userspace libraries
|
||||
instead, notably libiec61883 which is functionally equivalent.
|
||||
|
||||
Users:
|
||||
ffmpeg/libavformat (used by a variety of media players)
|
||||
dvgrab v1.x (replaced by dvgrab2 on top of raw1394 and resp. libraries)
|
14
Documentation/ABI/removed/dv1394
Normal file
14
Documentation/ABI/removed/dv1394
Normal file
@ -0,0 +1,14 @@
|
||||
What: dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
|
||||
Date: May 2010 (scheduled), finally removed in kernel v2.6.37
|
||||
Contact: linux1394-devel@lists.sourceforge.net
|
||||
Description:
|
||||
/dev/dv1394/* were character device files, one for each FireWire
|
||||
controller and for NTSC and PAL respectively, from which DV data
|
||||
could be received by read() or transmitted by write(). A few
|
||||
ioctl()s allowed limited control.
|
||||
This special-purpose interface has been superseded by libraw1394 +
|
||||
libiec61883 which are functionally equivalent, support HDV, and
|
||||
transparently work on top of the newer firewire kernel drivers.
|
||||
|
||||
Users:
|
||||
ffmpeg/libavformat (if configured for DV1394)
|
15
Documentation/ABI/removed/raw1394
Normal file
15
Documentation/ABI/removed/raw1394
Normal file
@ -0,0 +1,15 @@
|
||||
What: raw1394 (a.k.a. "Raw IEEE1394 I/O support" for FireWire)
|
||||
Date: May 2010 (scheduled), finally removed in kernel v2.6.37
|
||||
Contact: linux1394-devel@lists.sourceforge.net
|
||||
Description:
|
||||
/dev/raw1394 was a character device file that allowed low-level
|
||||
access to FireWire buses. Its major drawbacks were its inability
|
||||
to implement sensible device security policies, and its low level
|
||||
of abstraction that required userspace clients do duplicate much
|
||||
of the kernel's ieee1394 core functionality.
|
||||
Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
|
||||
firewire-core.
|
||||
|
||||
Users:
|
||||
libraw1394 (works with firewire-cdev too, transparent to library ABI
|
||||
users)
|
@ -1,16 +0,0 @@
|
||||
What: legacy isochronous ABI of raw1394 (1st generation iso ABI)
|
||||
Date: June 2007 (scheduled), removed in kernel v2.6.23
|
||||
Contact: linux1394-devel@lists.sourceforge.net
|
||||
Description:
|
||||
The two request types RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN have
|
||||
been deprecated for quite some time. They are very inefficient as they
|
||||
come with high interrupt load and several layers of callbacks for each
|
||||
packet. Because of these deficiencies, the video1394 and dv1394 drivers
|
||||
and the 3rd-generation isochronous ABI in raw1394 (rawiso) were created.
|
||||
|
||||
Users:
|
||||
libraw1394 users via the long deprecated API raw1394_iso_write,
|
||||
raw1394_start_iso_write, raw1394_start_iso_rcv, raw1394_stop_iso_rcv
|
||||
|
||||
libdc1394, which optionally uses these old libraw1394 calls
|
||||
alternatively to the more efficient video1394 ABI
|
16
Documentation/ABI/removed/video1394
Normal file
16
Documentation/ABI/removed/video1394
Normal file
@ -0,0 +1,16 @@
|
||||
What: video1394 (a.k.a. "OHCI-1394 Video support" for FireWire)
|
||||
Date: May 2010 (scheduled), finally removed in kernel v2.6.37
|
||||
Contact: linux1394-devel@lists.sourceforge.net
|
||||
Description:
|
||||
/dev/video1394/* were character device files, one for each FireWire
|
||||
controller, which were used for isochronous I/O. It was added as an
|
||||
alternative to raw1394's isochronous I/O functionality which had
|
||||
performance issues in its first generation. Any video1394 user had
|
||||
to use raw1394 + libraw1394 too because video1394 did not provide
|
||||
asynchronous I/O for device discovery and configuration.
|
||||
Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
|
||||
firewire-core.
|
||||
|
||||
Users:
|
||||
libdc1394 (works with firewire-cdev too, transparent to library ABI
|
||||
users)
|
@ -530,16 +530,6 @@ Who: Thomas Gleixner <tglx@linutronix.de>
|
||||
|
||||
----------------------------
|
||||
|
||||
What: old ieee1394 subsystem (CONFIG_IEEE1394)
|
||||
When: 2.6.37
|
||||
Files: drivers/ieee1394/ except init_ohci1394_dma.c
|
||||
Why: superseded by drivers/firewire/ (CONFIG_FIREWIRE) which offers more
|
||||
features, better performance, and better security, all with smaller
|
||||
and more modern code base
|
||||
Who: Stefan Richter <stefanr@s5r6.in-berlin.de>
|
||||
|
||||
----------------------------
|
||||
|
||||
What: The acpi_sleep=s4_nonvs command line option
|
||||
When: 2.6.37
|
||||
Files: arch/x86/kernel/acpi/sleep.c
|
||||
|
@ -51,7 +51,6 @@ obj-y += net/
|
||||
obj-$(CONFIG_ATM) += atm/
|
||||
obj-$(CONFIG_FUSION) += message/
|
||||
obj-y += firewire/
|
||||
obj-y += ieee1394/
|
||||
obj-$(CONFIG_UIO) += uio/
|
||||
obj-y += cdrom/
|
||||
obj-y += auxdisplay/
|
||||
|
@ -3,9 +3,6 @@ menu "IEEE 1394 (FireWire) support"
|
||||
# firewire-core does not depend on PCI but is
|
||||
# not useful without PCI controller driver
|
||||
|
||||
comment "You can enable one or both FireWire driver stacks."
|
||||
comment "The newer stack is recommended."
|
||||
|
||||
config FIREWIRE
|
||||
tristate "FireWire driver stack"
|
||||
select CRC_ITU_T
|
||||
@ -64,8 +61,6 @@ config FIREWIRE_NET
|
||||
To compile this driver as a module, say M here: The module will be
|
||||
called firewire-net.
|
||||
|
||||
source "drivers/ieee1394/Kconfig"
|
||||
|
||||
config FIREWIRE_NOSY
|
||||
tristate "Nosy - a FireWire traffic sniffer for PCILynx cards"
|
||||
depends on PCI
|
||||
|
@ -1,182 +0,0 @@
|
||||
config IEEE1394
|
||||
tristate "Legacy alternative FireWire driver stack"
|
||||
depends on PCI || BROKEN
|
||||
help
|
||||
IEEE 1394 describes a high performance serial bus, which is also
|
||||
known as FireWire(tm) or i.Link(tm) and is used for connecting all
|
||||
sorts of devices (most notably digital video cameras) to your
|
||||
computer.
|
||||
|
||||
If you have FireWire hardware and want to use it, say Y here. This
|
||||
is the core support only, you will also need to select a driver for
|
||||
your IEEE 1394 adapter.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called ieee1394.
|
||||
|
||||
NOTE:
|
||||
ieee1394 is superseded by the newer firewire-core driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
config IEEE1394_OHCI1394
|
||||
tristate "OHCI-1394 controllers"
|
||||
depends on PCI && IEEE1394
|
||||
help
|
||||
Enable this driver if you have an IEEE 1394 controller based on the
|
||||
OHCI-1394 specification. The current driver is only tested with OHCI
|
||||
chipsets made by Texas Instruments and NEC. Most third-party vendors
|
||||
use one of these chipsets. It should work with any OHCI-1394
|
||||
compliant card, however.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called ohci1394.
|
||||
|
||||
NOTE:
|
||||
ohci1394 is superseded by the newer firewire-ohci driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
If you want to install firewire-ohci and ohci1394 together, you
|
||||
should configure them only as modules and blacklist the driver(s)
|
||||
which you don't want to have auto-loaded. Add either
|
||||
|
||||
blacklist ohci1394
|
||||
blacklist video1394
|
||||
blacklist dv1394
|
||||
or
|
||||
blacklist firewire-ohci
|
||||
|
||||
to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf
|
||||
depending on your distribution.
|
||||
|
||||
comment "PCILynx controller requires I2C"
|
||||
depends on IEEE1394 && I2C=n
|
||||
|
||||
config IEEE1394_PCILYNX
|
||||
tristate "PCILynx controller"
|
||||
depends on PCI && IEEE1394 && I2C
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
Say Y here if you have an IEEE-1394 controller with the Texas
|
||||
Instruments PCILynx chip. Note: this driver is written for revision
|
||||
2 of this chip and may not work with revision 0.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called pcilynx.
|
||||
|
||||
Only some old and now very rare PCI and CardBus cards and
|
||||
PowerMacs G3 B&W contain the PCILynx controller. Therefore
|
||||
almost everybody can say N here.
|
||||
|
||||
comment "SBP-2 support (for storage devices) requires SCSI"
|
||||
depends on IEEE1394 && SCSI=n
|
||||
|
||||
config IEEE1394_SBP2
|
||||
tristate "Storage devices (SBP-2 protocol)"
|
||||
depends on IEEE1394 && SCSI
|
||||
help
|
||||
This option enables you to use SBP-2 devices connected to an IEEE
|
||||
1394 bus. SBP-2 devices include storage devices like harddisks and
|
||||
DVD drives, also some other FireWire devices like scanners.
|
||||
|
||||
You should also enable support for disks, CD-ROMs, etc. in the SCSI
|
||||
configuration section.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called sbp2.
|
||||
|
||||
NOTE:
|
||||
sbp2 is superseded by the newer firewire-sbp2 driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
config IEEE1394_SBP2_PHYS_DMA
|
||||
bool "Enable replacement for physical DMA in SBP2"
|
||||
depends on IEEE1394_SBP2 && VIRT_TO_BUS && EXPERIMENTAL
|
||||
help
|
||||
This builds sbp2 for use with non-OHCI host adapters which do not
|
||||
support physical DMA or for when ohci1394 is run with phys_dma=0.
|
||||
Physical DMA is data movement without assistance of the drivers'
|
||||
interrupt handlers. This option includes the interrupt handlers
|
||||
that are required in absence of this hardware feature.
|
||||
|
||||
This option is buggy and currently broken on some architectures.
|
||||
If unsure, say N.
|
||||
|
||||
config IEEE1394_ETH1394_ROM_ENTRY
|
||||
depends on IEEE1394
|
||||
bool
|
||||
default n
|
||||
|
||||
config IEEE1394_ETH1394
|
||||
tristate "IP networking over 1394 (experimental)"
|
||||
depends on IEEE1394 && EXPERIMENTAL && INET
|
||||
select IEEE1394_ETH1394_ROM_ENTRY
|
||||
help
|
||||
This driver implements a functional majority of RFC 2734: IPv4 over
|
||||
1394. It will provide IP connectivity with implementations of RFC
|
||||
2734 found on other operating systems. It will not communicate with
|
||||
older versions of this driver found in stock kernels prior to 2.6.3.
|
||||
This driver is still considered experimental. It does not yet support
|
||||
MCAP, therefore multicast support is significantly limited.
|
||||
|
||||
The module is called eth1394 although it does not emulate Ethernet.
|
||||
|
||||
NOTE:
|
||||
eth1394 is superseded by the newer firewire-net driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
config IEEE1394_RAWIO
|
||||
tristate "raw1394 userspace interface"
|
||||
depends on IEEE1394
|
||||
help
|
||||
This option adds support for the raw1394 device file which enables
|
||||
direct communication of user programs with IEEE 1394 devices
|
||||
(isochronous and asynchronous). Almost all application programs
|
||||
which access FireWire require this option.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called raw1394.
|
||||
|
||||
NOTE:
|
||||
raw1394 is superseded by the newer firewire-core driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
config IEEE1394_VIDEO1394
|
||||
tristate "video1394 userspace interface"
|
||||
depends on IEEE1394 && IEEE1394_OHCI1394
|
||||
help
|
||||
This option adds support for the video1394 device files which enable
|
||||
isochronous communication of user programs with IEEE 1394 devices,
|
||||
especially video capture or export. This interface is used by all
|
||||
libdc1394 based programs and by several other programs, in addition to
|
||||
the raw1394 interface. It is generally not required for DV capture.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called video1394.
|
||||
|
||||
NOTE:
|
||||
video1394 is superseded by the newer firewire-core driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
config IEEE1394_DV1394
|
||||
tristate "dv1394 userspace interface (deprecated)"
|
||||
depends on IEEE1394 && IEEE1394_OHCI1394
|
||||
help
|
||||
The dv1394 driver is unsupported and may be removed from Linux in a
|
||||
future release. Its functionality is now provided by either
|
||||
raw1394 or firewire-core together with libraries such as libiec61883.
|
||||
|
||||
config IEEE1394_VERBOSEDEBUG
|
||||
bool "Excessive debugging output"
|
||||
depends on IEEE1394
|
||||
help
|
||||
If you say Y here, you will get very verbose debugging logs from the
|
||||
ieee1394 drivers, including sent and received packet headers. This
|
||||
will quickly result in large amounts of data sent to the system log.
|
||||
|
||||
Say Y if you really need the debugging output. Everyone else says N.
|
@ -1,16 +0,0 @@
|
||||
#
|
||||
# Makefile for the Linux IEEE 1394 implementation
|
||||
#
|
||||
|
||||
ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
|
||||
highlevel.o csr.o nodemgr.o dma.o iso.o \
|
||||
csr1212.o config_roms.o
|
||||
|
||||
obj-$(CONFIG_IEEE1394) += ieee1394.o
|
||||
obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
|
||||
obj-$(CONFIG_IEEE1394_OHCI1394) += ohci1394.o
|
||||
obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o
|
||||
obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
|
||||
obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
|
||||
obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
|
||||
obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
|
@ -1,194 +0,0 @@
|
||||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* ConfigROM entries
|
||||
*
|
||||
* Copyright (C) 2004 Ben Collins
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "csr1212.h"
|
||||
#include "ieee1394.h"
|
||||
#include "ieee1394_types.h"
|
||||
#include "hosts.h"
|
||||
#include "ieee1394_core.h"
|
||||
#include "highlevel.h"
|
||||
#include "csr.h"
|
||||
#include "config_roms.h"
|
||||
|
||||
struct hpsb_config_rom_entry {
|
||||
const char *name;
|
||||
|
||||
/* Base initialization, called at module load */
|
||||
int (*init)(void);
|
||||
|
||||
/* Cleanup called at module exit */
|
||||
void (*cleanup)(void);
|
||||
|
||||
/* The flag added to host->config_roms */
|
||||
unsigned int flag;
|
||||
};
|
||||
|
||||
/* The default host entry. This must succeed. */
|
||||
int hpsb_default_host_entry(struct hpsb_host *host)
|
||||
{
|
||||
struct csr1212_keyval *root;
|
||||
struct csr1212_keyval *vend_id = NULL;
|
||||
struct csr1212_keyval *text = NULL;
|
||||
char csr_name[128];
|
||||
int ret;
|
||||
|
||||
sprintf(csr_name, "Linux - %s", host->driver->name);
|
||||
root = host->csr.rom->root_kv;
|
||||
|
||||
vend_id = csr1212_new_immediate(CSR1212_KV_ID_VENDOR, host->csr.guid_hi >> 8);
|
||||
text = csr1212_new_string_descriptor_leaf(csr_name);
|
||||
|
||||
if (!vend_id || !text) {
|
||||
if (vend_id)
|
||||
csr1212_release_keyval(vend_id);
|
||||
if (text)
|
||||
csr1212_release_keyval(text);
|
||||
csr1212_destroy_csr(host->csr.rom);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
csr1212_associate_keyval(vend_id, text);
|
||||
csr1212_release_keyval(text);
|
||||
ret = csr1212_attach_keyval_to_directory(root, vend_id);
|
||||
csr1212_release_keyval(vend_id);
|
||||
if (ret != CSR1212_SUCCESS) {
|
||||
csr1212_destroy_csr(host->csr.rom);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
host->update_config_rom = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
|
||||
#include "eth1394.h"
|
||||
|
||||
static struct csr1212_keyval *ip1394_ud;
|
||||
|
||||
static int config_rom_ip1394_init(void)
|
||||
{
|
||||
struct csr1212_keyval *spec_id = NULL;
|
||||
struct csr1212_keyval *spec_desc = NULL;
|
||||
struct csr1212_keyval *ver = NULL;
|
||||
struct csr1212_keyval *ver_desc = NULL;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
ip1394_ud = csr1212_new_directory(CSR1212_KV_ID_UNIT);
|
||||
|
||||
spec_id = csr1212_new_immediate(CSR1212_KV_ID_SPECIFIER_ID,
|
||||
ETHER1394_GASP_SPECIFIER_ID);
|
||||
spec_desc = csr1212_new_string_descriptor_leaf("IANA");
|
||||
ver = csr1212_new_immediate(CSR1212_KV_ID_VERSION,
|
||||
ETHER1394_GASP_VERSION);
|
||||
ver_desc = csr1212_new_string_descriptor_leaf("IPv4");
|
||||
|
||||
if (!ip1394_ud || !spec_id || !spec_desc || !ver || !ver_desc)
|
||||
goto ip1394_fail;
|
||||
|
||||
csr1212_associate_keyval(spec_id, spec_desc);
|
||||
csr1212_associate_keyval(ver, ver_desc);
|
||||
if (csr1212_attach_keyval_to_directory(ip1394_ud, spec_id)
|
||||
== CSR1212_SUCCESS &&
|
||||
csr1212_attach_keyval_to_directory(ip1394_ud, ver)
|
||||
== CSR1212_SUCCESS)
|
||||
ret = 0;
|
||||
|
||||
ip1394_fail:
|
||||
if (ret && ip1394_ud) {
|
||||
csr1212_release_keyval(ip1394_ud);
|
||||
ip1394_ud = NULL;
|
||||
}
|
||||
|
||||
if (spec_id)
|
||||
csr1212_release_keyval(spec_id);
|
||||
if (spec_desc)
|
||||
csr1212_release_keyval(spec_desc);
|
||||
if (ver)
|
||||
csr1212_release_keyval(ver);
|
||||
if (ver_desc)
|
||||
csr1212_release_keyval(ver_desc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void config_rom_ip1394_cleanup(void)
|
||||
{
|
||||
if (ip1394_ud) {
|
||||
csr1212_release_keyval(ip1394_ud);
|
||||
ip1394_ud = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int hpsb_config_rom_ip1394_add(struct hpsb_host *host)
|
||||
{
|
||||
if (!ip1394_ud)
|
||||
return -ENODEV;
|
||||
|
||||
if (csr1212_attach_keyval_to_directory(host->csr.rom->root_kv,
|
||||
ip1394_ud) != CSR1212_SUCCESS)
|
||||
return -ENOMEM;
|
||||
|
||||
host->config_roms |= HPSB_CONFIG_ROM_ENTRY_IP1394;
|
||||
host->update_config_rom = 1;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_add);
|
||||
|
||||
void hpsb_config_rom_ip1394_remove(struct hpsb_host *host)
|
||||
{
|
||||
csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, ip1394_ud);
|
||||
host->config_roms &= ~HPSB_CONFIG_ROM_ENTRY_IP1394;
|
||||
host->update_config_rom = 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_remove);
|
||||
|
||||
static struct hpsb_config_rom_entry ip1394_entry = {
|
||||
.name = "ip1394",
|
||||
.init = config_rom_ip1394_init,
|
||||
.cleanup = config_rom_ip1394_cleanup,
|
||||
.flag = HPSB_CONFIG_ROM_ENTRY_IP1394,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_IEEE1394_ETH1394_ROM_ENTRY */
|
||||
|
||||
static struct hpsb_config_rom_entry *const config_rom_entries[] = {
|
||||
#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
|
||||
&ip1394_entry,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Initialize all config roms */
|
||||
int hpsb_init_config_roms(void)
|
||||
{
|
||||
int i, error = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
|
||||
if (config_rom_entries[i]->init()) {
|
||||
HPSB_ERR("Failed to initialize config rom entry `%s'",
|
||||
config_rom_entries[i]->name);
|
||||
error = -1;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Cleanup all config roms */
|
||||
void hpsb_cleanup_config_roms(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
|
||||
config_rom_entries[i]->cleanup();
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
#ifndef _IEEE1394_CONFIG_ROMS_H
|
||||
#define _IEEE1394_CONFIG_ROMS_H
|
||||
|
||||
struct hpsb_host;
|
||||
|
||||
int hpsb_default_host_entry(struct hpsb_host *host);
|
||||
int hpsb_init_config_roms(void);
|
||||
void hpsb_cleanup_config_roms(void);
|
||||
|
||||
/* List of flags to check if a host contains a certain extra config rom
|
||||
* entry. Available in the host->config_roms member. */
|
||||
#define HPSB_CONFIG_ROM_ENTRY_IP1394 0x00000001
|
||||
|
||||
#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
|
||||
int hpsb_config_rom_ip1394_add(struct hpsb_host *host);
|
||||
void hpsb_config_rom_ip1394_remove(struct hpsb_host *host);
|
||||
#endif
|
||||
|
||||
#endif /* _IEEE1394_CONFIG_ROMS_H */
|
@ -1,843 +0,0 @@
|
||||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* CSR implementation, iso/bus manager implementation.
|
||||
*
|
||||
* Copyright (C) 1999 Andreas E. Bombe
|
||||
* 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*
|
||||
*
|
||||
* Contributions:
|
||||
*
|
||||
* Manfred Weihs <weihs@ict.tuwien.ac.at>
|
||||
* configuration ROM manipulation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "csr1212.h"
|
||||
#include "ieee1394_types.h"
|
||||
#include "hosts.h"
|
||||
#include "ieee1394.h"
|
||||
#include "highlevel.h"
|
||||
#include "ieee1394_core.h"
|
||||
|
||||
/* Module Parameters */
|
||||
/* this module parameter can be used to disable mapping of the FCP registers */
|
||||
|
||||
static int fcp = 1;
|
||||
module_param(fcp, int, 0444);
|
||||
MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0).");
|
||||
|
||||
static struct csr1212_keyval *node_cap = NULL;
|
||||
|
||||
static void add_host(struct hpsb_host *host);
|
||||
static void remove_host(struct hpsb_host *host);
|
||||
static void host_reset(struct hpsb_host *host);
|
||||
static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
|
||||
u64 addr, size_t length, u16 fl);
|
||||
static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
|
||||
quadlet_t *data, u64 addr, size_t length, u16 flags);
|
||||
static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
|
||||
u64 addr, size_t length, u16 flags);
|
||||
static int write_regs(struct hpsb_host *host, int nodeid, int destid,
|
||||
quadlet_t *data, u64 addr, size_t length, u16 flags);
|
||||
static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl);
|
||||
static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
|
||||
u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl);
|
||||
static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
|
||||
u64 addr, size_t length, u16 fl);
|
||||
static u64 allocate_addr_range(u64 size, u32 alignment, void *__host);
|
||||
static void release_addr_range(u64 addr, void *__host);
|
||||
|
||||
static struct hpsb_highlevel csr_highlevel = {
|
||||
.name = "standard registers",
|
||||
.add_host = add_host,
|
||||
.remove_host = remove_host,
|
||||
.host_reset = host_reset,
|
||||
};
|
||||
|
||||
static const struct hpsb_address_ops map_ops = {
|
||||
.read = read_maps,
|
||||
};
|
||||
|
||||
static const struct hpsb_address_ops fcp_ops = {
|
||||
.write = write_fcp,
|
||||
};
|
||||
|
||||
static const struct hpsb_address_ops reg_ops = {
|
||||
.read = read_regs,
|
||||
.write = write_regs,
|
||||
.lock = lock_regs,
|
||||
.lock64 = lock64_regs,
|
||||
};
|
||||
|
||||
static const struct hpsb_address_ops config_rom_ops = {
|
||||
.read = read_config_rom,
|
||||
};
|
||||
|
||||
struct csr1212_bus_ops csr_bus_ops = {
|
||||
.allocate_addr_range = allocate_addr_range,
|
||||
.release_addr = release_addr_range,
|
||||
};
|
||||
|
||||
|
||||
static u16 csr_crc16(unsigned *data, int length)
|
||||
{
|
||||
int check=0, i;
|
||||
int shift, sum, next=0;
|
||||
|
||||
for (i = length; i; i--) {
|
||||
for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
|
||||
sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
|
||||
next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
|
||||
}
|
||||
check = next & 0xffff;
|
||||
data++;
|
||||
}
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
static void host_reset(struct hpsb_host *host)
|
||||
{
|
||||
host->csr.state &= 0x300;
|
||||
|
||||
host->csr.bus_manager_id = 0x3f;
|
||||
host->csr.bandwidth_available = 4915;
|
||||
host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */
|
||||
host->csr.channels_available_lo = ~0;
|
||||
host->csr.broadcast_channel = 0x80000000 | 31;
|
||||
|
||||
if (host->is_irm) {
|
||||
if (host->driver->hw_csr_reg) {
|
||||
host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
|
||||
}
|
||||
}
|
||||
|
||||
host->csr.node_ids = host->node_id << 16;
|
||||
|
||||
if (!host->is_root) {
|
||||
/* clear cmstr bit */
|
||||
host->csr.state &= ~0x100;
|
||||
}
|
||||
|
||||
be32_add_cpu(&host->csr.topology_map[1], 1);
|
||||
host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16
|
||||
| host->selfid_count);
|
||||
host->csr.topology_map[0] =
|
||||
cpu_to_be32((host->selfid_count + 2) << 16
|
||||
| csr_crc16(host->csr.topology_map + 1,
|
||||
host->selfid_count + 2));
|
||||
|
||||
be32_add_cpu(&host->csr.speed_map[1], 1);
|
||||
host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16
|
||||
| csr_crc16(host->csr.speed_map+1,
|
||||
0x3f1));
|
||||
}
|
||||
|
||||
/*
|
||||
* HI == seconds (bits 0:2)
|
||||
* LO == fractions of a second in units of 125usec (bits 19:31)
|
||||
*
|
||||
* Convert SPLIT_TIMEOUT to jiffies.
|
||||
* The default and minimum as per 1394a-2000 clause 8.3.2.2.6 is 100ms.
|
||||
*/
|
||||
static inline void calculate_expire(struct csr_control *csr)
|
||||
{
|
||||
unsigned int usecs = (csr->split_timeout_hi & 7) * 1000000 +
|
||||
(csr->split_timeout_lo >> 19) * 125;
|
||||
|
||||
csr->expire = usecs_to_jiffies(usecs > 100000 ? usecs : 100000);
|
||||
HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%u", csr->expire, HZ);
|
||||
}
|
||||
|
||||
|
||||
static void add_host(struct hpsb_host *host)
|
||||
{
|
||||
struct csr1212_keyval *root;
|
||||
quadlet_t bus_info[CSR_BUS_INFO_SIZE];
|
||||
|
||||
hpsb_register_addrspace(&csr_highlevel, host, ®_ops,
|
||||
CSR_REGISTER_BASE,
|
||||
CSR_REGISTER_BASE + CSR_CONFIG_ROM);
|
||||
hpsb_register_addrspace(&csr_highlevel, host, &config_rom_ops,
|
||||
CSR_REGISTER_BASE + CSR_CONFIG_ROM,
|
||||
CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
|
||||
if (fcp) {
|
||||
hpsb_register_addrspace(&csr_highlevel, host, &fcp_ops,
|
||||
CSR_REGISTER_BASE + CSR_FCP_COMMAND,
|
||||
CSR_REGISTER_BASE + CSR_FCP_END);
|
||||
}
|
||||
hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
|
||||
CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
|
||||
CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
|
||||
hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
|
||||
CSR_REGISTER_BASE + CSR_SPEED_MAP,
|
||||
CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
|
||||
|
||||
spin_lock_init(&host->csr.lock);
|
||||
|
||||
host->csr.state = 0;
|
||||
host->csr.node_ids = 0;
|
||||
host->csr.split_timeout_hi = 0;
|
||||
host->csr.split_timeout_lo = 800 << 19;
|
||||
calculate_expire(&host->csr);
|
||||
host->csr.cycle_time = 0;
|
||||
host->csr.bus_time = 0;
|
||||
host->csr.bus_manager_id = 0x3f;
|
||||
host->csr.bandwidth_available = 4915;
|
||||
host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */
|
||||
host->csr.channels_available_lo = ~0;
|
||||
host->csr.broadcast_channel = 0x80000000 | 31;
|
||||
|
||||
if (host->is_irm) {
|
||||
if (host->driver->hw_csr_reg) {
|
||||
host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
|
||||
}
|
||||
}
|
||||
|
||||
if (host->csr.max_rec >= 9)
|
||||
host->csr.max_rom = 2;
|
||||
else if (host->csr.max_rec >= 5)
|
||||
host->csr.max_rom = 1;
|
||||
else
|
||||
host->csr.max_rom = 0;
|
||||
|
||||
host->csr.generation = 2;
|
||||
|
||||
bus_info[1] = IEEE1394_BUSID_MAGIC;
|
||||
bus_info[2] = cpu_to_be32((hpsb_disable_irm ? 0 : 1 << CSR_IRMC_SHIFT) |
|
||||
(1 << CSR_CMC_SHIFT) |
|
||||
(1 << CSR_ISC_SHIFT) |
|
||||
(0 << CSR_BMC_SHIFT) |
|
||||
(0 << CSR_PMC_SHIFT) |
|
||||
(host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
|
||||
(host->csr.max_rec << CSR_MAX_REC_SHIFT) |
|
||||
(host->csr.max_rom << CSR_MAX_ROM_SHIFT) |
|
||||
(host->csr.generation << CSR_GENERATION_SHIFT) |
|
||||
host->csr.lnk_spd);
|
||||
|
||||
bus_info[3] = cpu_to_be32(host->csr.guid_hi);
|
||||
bus_info[4] = cpu_to_be32(host->csr.guid_lo);
|
||||
|
||||
/* The hardware copy of the bus info block will be set later when a
|
||||
* bus reset is issued. */
|
||||
|
||||
csr1212_init_local_csr(host->csr.rom, bus_info, host->csr.max_rom);
|
||||
|
||||
root = host->csr.rom->root_kv;
|
||||
|
||||
if(csr1212_attach_keyval_to_directory(root, node_cap) != CSR1212_SUCCESS) {
|
||||
HPSB_ERR("Failed to attach Node Capabilities to root directory");
|
||||
}
|
||||
|
||||
host->update_config_rom = 1;
|
||||
}
|
||||
|
||||
static void remove_host(struct hpsb_host *host)
|
||||
{
|
||||
quadlet_t bus_info[CSR_BUS_INFO_SIZE];
|
||||
|
||||
bus_info[1] = IEEE1394_BUSID_MAGIC;
|
||||
bus_info[2] = cpu_to_be32((0 << CSR_IRMC_SHIFT) |
|
||||
(0 << CSR_CMC_SHIFT) |
|
||||
(0 << CSR_ISC_SHIFT) |
|
||||
(0 << CSR_BMC_SHIFT) |
|
||||
(0 << CSR_PMC_SHIFT) |
|
||||
(host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
|
||||
(host->csr.max_rec << CSR_MAX_REC_SHIFT) |
|
||||
(0 << CSR_MAX_ROM_SHIFT) |
|
||||
(0 << CSR_GENERATION_SHIFT) |
|
||||
host->csr.lnk_spd);
|
||||
|
||||
bus_info[3] = cpu_to_be32(host->csr.guid_hi);
|
||||
bus_info[4] = cpu_to_be32(host->csr.guid_lo);
|
||||
|
||||
csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, node_cap);
|
||||
|
||||
csr1212_init_local_csr(host->csr.rom, bus_info, 0);
|
||||
host->update_config_rom = 1;
|
||||
}
|
||||
|
||||
|
||||
int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
|
||||
size_t buffersize, unsigned char rom_version)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
HPSB_NOTICE("hpsb_update_config_rom() is deprecated");
|
||||
|
||||
spin_lock_irqsave(&host->csr.lock, flags);
|
||||
if (rom_version != host->csr.generation)
|
||||
ret = -1;
|
||||
else if (buffersize > host->csr.rom->cache_head->size)
|
||||
ret = -2;
|
||||
else {
|
||||
/* Just overwrite the generated ConfigROM image with new data,
|
||||
* it can be regenerated later. */
|
||||
memcpy(host->csr.rom->cache_head->data, new_rom, buffersize);
|
||||
host->csr.rom->cache_head->len = buffersize;
|
||||
|
||||
if (host->driver->set_hw_config_rom)
|
||||
host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data);
|
||||
/* Increment the generation number to keep some sort of sync
|
||||
* with the newer ConfigROM manipulation method. */
|
||||
host->csr.generation++;
|
||||
if (host->csr.generation > 0xf || host->csr.generation < 2)
|
||||
host->csr.generation = 2;
|
||||
ret=0;
|
||||
}
|
||||
spin_unlock_irqrestore(&host->csr.lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Read topology / speed maps and configuration ROM */
|
||||
static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
|
||||
u64 addr, size_t length, u16 fl)
|
||||
{
|
||||
unsigned long flags;
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
const char *src;
|
||||
|
||||
spin_lock_irqsave(&host->csr.lock, flags);
|
||||
|
||||
if (csraddr < CSR_SPEED_MAP) {
|
||||
src = ((char *)host->csr.topology_map) + csraddr
|
||||
- CSR_TOPOLOGY_MAP;
|
||||
} else {
|
||||
src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP;
|
||||
}
|
||||
|
||||
memcpy(buffer, src, length);
|
||||
spin_unlock_irqrestore(&host->csr.lock, flags);
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
|
||||
|
||||
#define out if (--length == 0) break
|
||||
|
||||
static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
|
||||
u64 addr, size_t length, u16 flags)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
int oldcycle;
|
||||
quadlet_t ret;
|
||||
|
||||
if ((csraddr | length) & 0x3)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
length /= 4;
|
||||
|
||||
switch (csraddr) {
|
||||
case CSR_STATE_CLEAR:
|
||||
*(buf++) = cpu_to_be32(host->csr.state);
|
||||
out;
|
||||
case CSR_STATE_SET:
|
||||
*(buf++) = cpu_to_be32(host->csr.state);
|
||||
out;
|
||||
case CSR_NODE_IDS:
|
||||
*(buf++) = cpu_to_be32(host->csr.node_ids);
|
||||
out;
|
||||
|
||||
case CSR_RESET_START:
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
/* address gap - handled by default below */
|
||||
|
||||
case CSR_SPLIT_TIMEOUT_HI:
|
||||
*(buf++) = cpu_to_be32(host->csr.split_timeout_hi);
|
||||
out;
|
||||
case CSR_SPLIT_TIMEOUT_LO:
|
||||
*(buf++) = cpu_to_be32(host->csr.split_timeout_lo);
|
||||
out;
|
||||
|
||||
/* address gap */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_CYCLE_TIME:
|
||||
oldcycle = host->csr.cycle_time;
|
||||
host->csr.cycle_time =
|
||||
host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
|
||||
|
||||
if (oldcycle > host->csr.cycle_time) {
|
||||
/* cycle time wrapped around */
|
||||
host->csr.bus_time += 1 << 7;
|
||||
}
|
||||
*(buf++) = cpu_to_be32(host->csr.cycle_time);
|
||||
out;
|
||||
case CSR_BUS_TIME:
|
||||
oldcycle = host->csr.cycle_time;
|
||||
host->csr.cycle_time =
|
||||
host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
|
||||
|
||||
if (oldcycle > host->csr.cycle_time) {
|
||||
/* cycle time wrapped around */
|
||||
host->csr.bus_time += (1 << 7);
|
||||
}
|
||||
*(buf++) = cpu_to_be32(host->csr.bus_time
|
||||
| (host->csr.cycle_time >> 25));
|
||||
out;
|
||||
|
||||
/* address gap */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_BUSY_TIMEOUT:
|
||||
/* not yet implemented */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_BUS_MANAGER_ID:
|
||||
if (host->driver->hw_csr_reg)
|
||||
ret = host->driver->hw_csr_reg(host, 0, 0, 0);
|
||||
else
|
||||
ret = host->csr.bus_manager_id;
|
||||
|
||||
*(buf++) = cpu_to_be32(ret);
|
||||
out;
|
||||
case CSR_BANDWIDTH_AVAILABLE:
|
||||
if (host->driver->hw_csr_reg)
|
||||
ret = host->driver->hw_csr_reg(host, 1, 0, 0);
|
||||
else
|
||||
ret = host->csr.bandwidth_available;
|
||||
|
||||
*(buf++) = cpu_to_be32(ret);
|
||||
out;
|
||||
case CSR_CHANNELS_AVAILABLE_HI:
|
||||
if (host->driver->hw_csr_reg)
|
||||
ret = host->driver->hw_csr_reg(host, 2, 0, 0);
|
||||
else
|
||||
ret = host->csr.channels_available_hi;
|
||||
|
||||
*(buf++) = cpu_to_be32(ret);
|
||||
out;
|
||||
case CSR_CHANNELS_AVAILABLE_LO:
|
||||
if (host->driver->hw_csr_reg)
|
||||
ret = host->driver->hw_csr_reg(host, 3, 0, 0);
|
||||
else
|
||||
ret = host->csr.channels_available_lo;
|
||||
|
||||
*(buf++) = cpu_to_be32(ret);
|
||||
out;
|
||||
|
||||
case CSR_BROADCAST_CHANNEL:
|
||||
*(buf++) = cpu_to_be32(host->csr.broadcast_channel);
|
||||
out;
|
||||
|
||||
/* address gap to end - fall through to default */
|
||||
default:
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
|
||||
static int write_regs(struct hpsb_host *host, int nodeid, int destid,
|
||||
quadlet_t *data, u64 addr, size_t length, u16 flags)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
|
||||
if ((csraddr | length) & 0x3)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
length /= 4;
|
||||
|
||||
switch (csraddr) {
|
||||
case CSR_STATE_CLEAR:
|
||||
/* FIXME FIXME FIXME */
|
||||
printk("doh, someone wants to mess with state clear\n");
|
||||
out;
|
||||
case CSR_STATE_SET:
|
||||
printk("doh, someone wants to mess with state set\n");
|
||||
out;
|
||||
|
||||
case CSR_NODE_IDS:
|
||||
host->csr.node_ids &= NODE_MASK << 16;
|
||||
host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
|
||||
host->node_id = host->csr.node_ids >> 16;
|
||||
host->driver->devctl(host, SET_BUS_ID, host->node_id >> 6);
|
||||
out;
|
||||
|
||||
case CSR_RESET_START:
|
||||
/* FIXME - perform command reset */
|
||||
out;
|
||||
|
||||
/* address gap */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_SPLIT_TIMEOUT_HI:
|
||||
host->csr.split_timeout_hi =
|
||||
be32_to_cpu(*(data++)) & 0x00000007;
|
||||
calculate_expire(&host->csr);
|
||||
out;
|
||||
case CSR_SPLIT_TIMEOUT_LO:
|
||||
host->csr.split_timeout_lo =
|
||||
be32_to_cpu(*(data++)) & 0xfff80000;
|
||||
calculate_expire(&host->csr);
|
||||
out;
|
||||
|
||||
/* address gap */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_CYCLE_TIME:
|
||||
/* should only be set by cycle start packet, automatically */
|
||||
host->csr.cycle_time = be32_to_cpu(*data);
|
||||
host->driver->devctl(host, SET_CYCLE_COUNTER,
|
||||
be32_to_cpu(*(data++)));
|
||||
out;
|
||||
case CSR_BUS_TIME:
|
||||
host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80;
|
||||
out;
|
||||
|
||||
/* address gap */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_BUSY_TIMEOUT:
|
||||
/* not yet implemented */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_BUS_MANAGER_ID:
|
||||
case CSR_BANDWIDTH_AVAILABLE:
|
||||
case CSR_CHANNELS_AVAILABLE_HI:
|
||||
case CSR_CHANNELS_AVAILABLE_LO:
|
||||
/* these are not writable, only lockable */
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
case CSR_BROADCAST_CHANNEL:
|
||||
/* only the valid bit can be written */
|
||||
host->csr.broadcast_channel = (host->csr.broadcast_channel & ~0x40000000)
|
||||
| (be32_to_cpu(*data) & 0x40000000);
|
||||
out;
|
||||
|
||||
/* address gap to end - fall through */
|
||||
default:
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
|
||||
#undef out
|
||||
|
||||
|
||||
static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
unsigned long flags;
|
||||
quadlet_t *regptr = NULL;
|
||||
|
||||
if (csraddr & 0x3)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
if (csraddr < CSR_BUS_MANAGER_ID || csraddr > CSR_CHANNELS_AVAILABLE_LO
|
||||
|| extcode != EXTCODE_COMPARE_SWAP)
|
||||
goto unsupported_lockreq;
|
||||
|
||||
data = be32_to_cpu(data);
|
||||
arg = be32_to_cpu(arg);
|
||||
|
||||
/* Is somebody releasing the broadcast_channel on us? */
|
||||
if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x1)) {
|
||||
/* Note: this is may not be the right way to handle
|
||||
* the problem, so we should look into the proper way
|
||||
* eventually. */
|
||||
HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
|
||||
"broadcast channel 31. Ignoring.",
|
||||
NODE_BUS_ARGS(host, nodeid));
|
||||
|
||||
data &= ~0x1; /* keep broadcast channel allocated */
|
||||
}
|
||||
|
||||
if (host->driver->hw_csr_reg) {
|
||||
quadlet_t old;
|
||||
|
||||
old = host->driver->
|
||||
hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
|
||||
data, arg);
|
||||
|
||||
*store = cpu_to_be32(old);
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&host->csr.lock, flags);
|
||||
|
||||
switch (csraddr) {
|
||||
case CSR_BUS_MANAGER_ID:
|
||||
regptr = &host->csr.bus_manager_id;
|
||||
*store = cpu_to_be32(*regptr);
|
||||
if (*regptr == arg)
|
||||
*regptr = data;
|
||||
break;
|
||||
|
||||
case CSR_BANDWIDTH_AVAILABLE:
|
||||
{
|
||||
quadlet_t bandwidth;
|
||||
quadlet_t old;
|
||||
quadlet_t new;
|
||||
|
||||
regptr = &host->csr.bandwidth_available;
|
||||
old = *regptr;
|
||||
|
||||
/* bandwidth available algorithm adapted from IEEE 1394a-2000 spec */
|
||||
if (arg > 0x1fff) {
|
||||
*store = cpu_to_be32(old); /* change nothing */
|
||||
break;
|
||||
}
|
||||
data &= 0x1fff;
|
||||
if (arg >= data) {
|
||||
/* allocate bandwidth */
|
||||
bandwidth = arg - data;
|
||||
if (old >= bandwidth) {
|
||||
new = old - bandwidth;
|
||||
*store = cpu_to_be32(arg);
|
||||
*regptr = new;
|
||||
} else {
|
||||
*store = cpu_to_be32(old);
|
||||
}
|
||||
} else {
|
||||
/* deallocate bandwidth */
|
||||
bandwidth = data - arg;
|
||||
if (old + bandwidth < 0x2000) {
|
||||
new = old + bandwidth;
|
||||
*store = cpu_to_be32(arg);
|
||||
*regptr = new;
|
||||
} else {
|
||||
*store = cpu_to_be32(old);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CSR_CHANNELS_AVAILABLE_HI:
|
||||
{
|
||||
/* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
|
||||
quadlet_t affected_channels = arg ^ data;
|
||||
|
||||
regptr = &host->csr.channels_available_hi;
|
||||
|
||||
if ((arg & affected_channels) == (*regptr & affected_channels)) {
|
||||
*regptr ^= affected_channels;
|
||||
*store = cpu_to_be32(arg);
|
||||
} else {
|
||||
*store = cpu_to_be32(*regptr);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CSR_CHANNELS_AVAILABLE_LO:
|
||||
{
|
||||
/* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
|
||||
quadlet_t affected_channels = arg ^ data;
|
||||
|
||||
regptr = &host->csr.channels_available_lo;
|
||||
|
||||
if ((arg & affected_channels) == (*regptr & affected_channels)) {
|
||||
*regptr ^= affected_channels;
|
||||
*store = cpu_to_be32(arg);
|
||||
} else {
|
||||
*store = cpu_to_be32(*regptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&host->csr.lock, flags);
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
|
||||
unsupported_lockreq:
|
||||
switch (csraddr) {
|
||||
case CSR_STATE_CLEAR:
|
||||
case CSR_STATE_SET:
|
||||
case CSR_RESET_START:
|
||||
case CSR_NODE_IDS:
|
||||
case CSR_SPLIT_TIMEOUT_HI:
|
||||
case CSR_SPLIT_TIMEOUT_LO:
|
||||
case CSR_CYCLE_TIME:
|
||||
case CSR_BUS_TIME:
|
||||
case CSR_BROADCAST_CHANNEL:
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
case CSR_BUSY_TIMEOUT:
|
||||
/* not yet implemented - fall through */
|
||||
default:
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
|
||||
u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
unsigned long flags;
|
||||
|
||||
data = be64_to_cpu(data);
|
||||
arg = be64_to_cpu(arg);
|
||||
|
||||
if (csraddr & 0x3)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
if (csraddr != CSR_CHANNELS_AVAILABLE
|
||||
|| extcode != EXTCODE_COMPARE_SWAP)
|
||||
goto unsupported_lock64req;
|
||||
|
||||
/* Is somebody releasing the broadcast_channel on us? */
|
||||
if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x100000000ULL)) {
|
||||
/* Note: this is may not be the right way to handle
|
||||
* the problem, so we should look into the proper way
|
||||
* eventually. */
|
||||
HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
|
||||
"broadcast channel 31. Ignoring.",
|
||||
NODE_BUS_ARGS(host, nodeid));
|
||||
|
||||
data &= ~0x100000000ULL; /* keep broadcast channel allocated */
|
||||
}
|
||||
|
||||
if (host->driver->hw_csr_reg) {
|
||||
quadlet_t data_hi, data_lo;
|
||||
quadlet_t arg_hi, arg_lo;
|
||||
quadlet_t old_hi, old_lo;
|
||||
|
||||
data_hi = data >> 32;
|
||||
data_lo = data & 0xFFFFFFFF;
|
||||
arg_hi = arg >> 32;
|
||||
arg_lo = arg & 0xFFFFFFFF;
|
||||
|
||||
old_hi = host->driver->hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
|
||||
data_hi, arg_hi);
|
||||
|
||||
old_lo = host->driver->hw_csr_reg(host, ((csraddr + 4) - CSR_BUS_MANAGER_ID) >> 2,
|
||||
data_lo, arg_lo);
|
||||
|
||||
*store = cpu_to_be64(((octlet_t)old_hi << 32) | old_lo);
|
||||
} else {
|
||||
octlet_t old;
|
||||
octlet_t affected_channels = arg ^ data;
|
||||
|
||||
spin_lock_irqsave(&host->csr.lock, flags);
|
||||
|
||||
old = ((octlet_t)host->csr.channels_available_hi << 32) | host->csr.channels_available_lo;
|
||||
|
||||
if ((arg & affected_channels) == (old & affected_channels)) {
|
||||
host->csr.channels_available_hi ^= (affected_channels >> 32);
|
||||
host->csr.channels_available_lo ^= (affected_channels & 0xffffffff);
|
||||
*store = cpu_to_be64(arg);
|
||||
} else {
|
||||
*store = cpu_to_be64(old);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&host->csr.lock, flags);
|
||||
}
|
||||
|
||||
/* Is somebody erroneously releasing the broadcast_channel on us? */
|
||||
if (host->csr.channels_available_hi & 0x1)
|
||||
host->csr.channels_available_hi &= ~0x1;
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
|
||||
unsupported_lock64req:
|
||||
switch (csraddr) {
|
||||
case CSR_STATE_CLEAR:
|
||||
case CSR_STATE_SET:
|
||||
case CSR_RESET_START:
|
||||
case CSR_NODE_IDS:
|
||||
case CSR_SPLIT_TIMEOUT_HI:
|
||||
case CSR_SPLIT_TIMEOUT_LO:
|
||||
case CSR_CYCLE_TIME:
|
||||
case CSR_BUS_TIME:
|
||||
case CSR_BUS_MANAGER_ID:
|
||||
case CSR_BROADCAST_CHANNEL:
|
||||
case CSR_BUSY_TIMEOUT:
|
||||
case CSR_BANDWIDTH_AVAILABLE:
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
default:
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
|
||||
quadlet_t *data, u64 addr, size_t length, u16 flags)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
|
||||
if (length > 512)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
switch (csraddr) {
|
||||
case CSR_FCP_COMMAND:
|
||||
highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length);
|
||||
break;
|
||||
case CSR_FCP_RESPONSE:
|
||||
highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length);
|
||||
break;
|
||||
default:
|
||||
return RCODE_TYPE_ERROR;
|
||||
}
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
|
||||
static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
|
||||
u64 addr, size_t length, u16 fl)
|
||||
{
|
||||
u32 offset = addr - CSR1212_REGISTER_SPACE_BASE;
|
||||
|
||||
if (csr1212_read(host->csr.rom, offset, buffer, length) == CSR1212_SUCCESS)
|
||||
return RCODE_COMPLETE;
|
||||
else
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
|
||||
static u64 allocate_addr_range(u64 size, u32 alignment, void *__host)
|
||||
{
|
||||
struct hpsb_host *host = (struct hpsb_host*)__host;
|
||||
|
||||
return hpsb_allocate_and_register_addrspace(&csr_highlevel,
|
||||
host,
|
||||
&config_rom_ops,
|
||||
size, alignment,
|
||||
CSR1212_UNITS_SPACE_BASE,
|
||||
CSR1212_UNITS_SPACE_END);
|
||||
}
|
||||
|
||||
static void release_addr_range(u64 addr, void *__host)
|
||||
{
|
||||
struct hpsb_host *host = (struct hpsb_host*)__host;
|
||||
hpsb_unregister_addrspace(&csr_highlevel, host, addr);
|
||||
}
|
||||
|
||||
|
||||
int init_csr(void)
|
||||
{
|
||||
node_cap = csr1212_new_immediate(CSR1212_KV_ID_NODE_CAPABILITIES, 0x0083c0);
|
||||
if (!node_cap) {
|
||||
HPSB_ERR("Failed to allocate memory for Node Capabilties ConfigROM entry!");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hpsb_register_highlevel(&csr_highlevel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_csr(void)
|
||||
{
|
||||
if (node_cap)
|
||||
csr1212_release_keyval(node_cap);
|
||||
hpsb_unregister_highlevel(&csr_highlevel);
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
#ifndef _IEEE1394_CSR_H
|
||||
#define _IEEE1394_CSR_H
|
||||
|
||||
#include <linux/spinlock_types.h>
|
||||
|
||||
#include "csr1212.h"
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
#define CSR_REGISTER_BASE 0xfffff0000000ULL
|
||||
|
||||
/* register offsets relative to CSR_REGISTER_BASE */
|
||||
#define CSR_STATE_CLEAR 0x0
|
||||
#define CSR_STATE_SET 0x4
|
||||
#define CSR_NODE_IDS 0x8
|
||||
#define CSR_RESET_START 0xc
|
||||
#define CSR_SPLIT_TIMEOUT_HI 0x18
|
||||
#define CSR_SPLIT_TIMEOUT_LO 0x1c
|
||||
#define CSR_CYCLE_TIME 0x200
|
||||
#define CSR_BUS_TIME 0x204
|
||||
#define CSR_BUSY_TIMEOUT 0x210
|
||||
#define CSR_BUS_MANAGER_ID 0x21c
|
||||
#define CSR_BANDWIDTH_AVAILABLE 0x220
|
||||
#define CSR_CHANNELS_AVAILABLE 0x224
|
||||
#define CSR_CHANNELS_AVAILABLE_HI 0x224
|
||||
#define CSR_CHANNELS_AVAILABLE_LO 0x228
|
||||
#define CSR_BROADCAST_CHANNEL 0x234
|
||||
#define CSR_CONFIG_ROM 0x400
|
||||
#define CSR_CONFIG_ROM_END 0x800
|
||||
#define CSR_FCP_COMMAND 0xB00
|
||||
#define CSR_FCP_RESPONSE 0xD00
|
||||
#define CSR_FCP_END 0xF00
|
||||
#define CSR_TOPOLOGY_MAP 0x1000
|
||||
#define CSR_TOPOLOGY_MAP_END 0x1400
|
||||
#define CSR_SPEED_MAP 0x2000
|
||||
#define CSR_SPEED_MAP_END 0x3000
|
||||
|
||||
/* IEEE 1394 bus specific Configuration ROM Key IDs */
|
||||
#define IEEE1394_KV_ID_POWER_REQUIREMENTS (0x30)
|
||||
|
||||
/* IEEE 1394 Bus Information Block specifics */
|
||||
#define CSR_BUS_INFO_SIZE (5 * sizeof(quadlet_t))
|
||||
|
||||
#define CSR_IRMC_SHIFT 31
|
||||
#define CSR_CMC_SHIFT 30
|
||||
#define CSR_ISC_SHIFT 29
|
||||
#define CSR_BMC_SHIFT 28
|
||||
#define CSR_PMC_SHIFT 27
|
||||
#define CSR_CYC_CLK_ACC_SHIFT 16
|
||||
#define CSR_MAX_REC_SHIFT 12
|
||||
#define CSR_MAX_ROM_SHIFT 8
|
||||
#define CSR_GENERATION_SHIFT 4
|
||||
|
||||
static inline void csr_set_bus_info_generation(struct csr1212_csr *csr, u8 gen)
|
||||
{
|
||||
csr->bus_info_data[2] &= ~cpu_to_be32(0xf << CSR_GENERATION_SHIFT);
|
||||
csr->bus_info_data[2] |= cpu_to_be32((u32)gen << CSR_GENERATION_SHIFT);
|
||||
}
|
||||
|
||||
struct csr_control {
|
||||
spinlock_t lock;
|
||||
|
||||
quadlet_t state;
|
||||
quadlet_t node_ids;
|
||||
quadlet_t split_timeout_hi, split_timeout_lo;
|
||||
unsigned long expire; /* Calculated from split_timeout */
|
||||
quadlet_t cycle_time;
|
||||
quadlet_t bus_time;
|
||||
quadlet_t bus_manager_id;
|
||||
quadlet_t bandwidth_available;
|
||||
quadlet_t channels_available_hi, channels_available_lo;
|
||||
quadlet_t broadcast_channel;
|
||||
|
||||
/* Bus Info */
|
||||
quadlet_t guid_hi, guid_lo;
|
||||
u8 cyc_clk_acc;
|
||||
u8 max_rec;
|
||||
u8 max_rom;
|
||||
u8 generation; /* Only use values between 0x2 and 0xf */
|
||||
u8 lnk_spd;
|
||||
|
||||
unsigned long gen_timestamp[16];
|
||||
|
||||
struct csr1212_csr *rom;
|
||||
|
||||
quadlet_t topology_map[256];
|
||||
quadlet_t speed_map[1024];
|
||||
};
|
||||
|
||||
extern struct csr1212_bus_ops csr_bus_ops;
|
||||
|
||||
int init_csr(void);
|
||||
void cleanup_csr(void);
|
||||
|
||||
/* hpsb_update_config_rom() is deprecated */
|
||||
struct hpsb_host;
|
||||
int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
|
||||
size_t size, unsigned char rom_version);
|
||||
|
||||
#endif /* _IEEE1394_CSR_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,383 +0,0 @@
|
||||
/*
|
||||
* csr1212.h -- IEEE 1212 Control and Status Register support for Linux
|
||||
*
|
||||
* Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
|
||||
* Steve Kinneberg <kinnebergsteve@acmsystems.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __CSR1212_H__
|
||||
#define __CSR1212_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#define CSR1212_MALLOC(size) kmalloc((size), GFP_KERNEL)
|
||||
#define CSR1212_FREE(ptr) kfree(ptr)
|
||||
|
||||
#define CSR1212_SUCCESS (0)
|
||||
|
||||
|
||||
/* CSR 1212 key types */
|
||||
#define CSR1212_KV_TYPE_IMMEDIATE 0
|
||||
#define CSR1212_KV_TYPE_CSR_OFFSET 1
|
||||
#define CSR1212_KV_TYPE_LEAF 2
|
||||
#define CSR1212_KV_TYPE_DIRECTORY 3
|
||||
|
||||
|
||||
/* CSR 1212 key ids */
|
||||
#define CSR1212_KV_ID_DESCRIPTOR 0x01
|
||||
#define CSR1212_KV_ID_BUS_DEPENDENT_INFO 0x02
|
||||
#define CSR1212_KV_ID_VENDOR 0x03
|
||||
#define CSR1212_KV_ID_HARDWARE_VERSION 0x04
|
||||
#define CSR1212_KV_ID_MODULE 0x07
|
||||
#define CSR1212_KV_ID_NODE_CAPABILITIES 0x0C
|
||||
#define CSR1212_KV_ID_EUI_64 0x0D
|
||||
#define CSR1212_KV_ID_UNIT 0x11
|
||||
#define CSR1212_KV_ID_SPECIFIER_ID 0x12
|
||||
#define CSR1212_KV_ID_VERSION 0x13
|
||||
#define CSR1212_KV_ID_DEPENDENT_INFO 0x14
|
||||
#define CSR1212_KV_ID_UNIT_LOCATION 0x15
|
||||
#define CSR1212_KV_ID_MODEL 0x17
|
||||
#define CSR1212_KV_ID_INSTANCE 0x18
|
||||
#define CSR1212_KV_ID_KEYWORD 0x19
|
||||
#define CSR1212_KV_ID_FEATURE 0x1A
|
||||
#define CSR1212_KV_ID_EXTENDED_ROM 0x1B
|
||||
#define CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID 0x1C
|
||||
#define CSR1212_KV_ID_EXTENDED_KEY 0x1D
|
||||
#define CSR1212_KV_ID_EXTENDED_DATA 0x1E
|
||||
#define CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR 0x1F
|
||||
#define CSR1212_KV_ID_DIRECTORY_ID 0x20
|
||||
#define CSR1212_KV_ID_REVISION 0x21
|
||||
|
||||
|
||||
/* IEEE 1212 Address space map */
|
||||
#define CSR1212_ALL_SPACE_BASE (0x000000000000ULL)
|
||||
#define CSR1212_ALL_SPACE_SIZE (1ULL << 48)
|
||||
#define CSR1212_ALL_SPACE_END (CSR1212_ALL_SPACE_BASE + CSR1212_ALL_SPACE_SIZE)
|
||||
|
||||
#define CSR1212_MEMORY_SPACE_BASE (0x000000000000ULL)
|
||||
#define CSR1212_MEMORY_SPACE_SIZE ((256ULL * (1ULL << 40)) - (512ULL * (1ULL << 20)))
|
||||
#define CSR1212_MEMORY_SPACE_END (CSR1212_MEMORY_SPACE_BASE + CSR1212_MEMORY_SPACE_SIZE)
|
||||
|
||||
#define CSR1212_PRIVATE_SPACE_BASE (0xffffe0000000ULL)
|
||||
#define CSR1212_PRIVATE_SPACE_SIZE (256ULL * (1ULL << 20))
|
||||
#define CSR1212_PRIVATE_SPACE_END (CSR1212_PRIVATE_SPACE_BASE + CSR1212_PRIVATE_SPACE_SIZE)
|
||||
|
||||
#define CSR1212_REGISTER_SPACE_BASE (0xfffff0000000ULL)
|
||||
#define CSR1212_REGISTER_SPACE_SIZE (256ULL * (1ULL << 20))
|
||||
#define CSR1212_REGISTER_SPACE_END (CSR1212_REGISTER_SPACE_BASE + CSR1212_REGISTER_SPACE_SIZE)
|
||||
|
||||
#define CSR1212_CSR_ARCH_REG_SPACE_BASE (0xfffff0000000ULL)
|
||||
#define CSR1212_CSR_ARCH_REG_SPACE_SIZE (512)
|
||||
#define CSR1212_CSR_ARCH_REG_SPACE_END (CSR1212_CSR_ARCH_REG_SPACE_BASE + CSR1212_CSR_ARCH_REG_SPACE_SIZE)
|
||||
#define CSR1212_CSR_ARCH_REG_SPACE_OFFSET (CSR1212_CSR_ARCH_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
|
||||
|
||||
#define CSR1212_CSR_BUS_DEP_REG_SPACE_BASE (0xfffff0000200ULL)
|
||||
#define CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE (512)
|
||||
#define CSR1212_CSR_BUS_DEP_REG_SPACE_END (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE + CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE)
|
||||
#define CSR1212_CSR_BUS_DEP_REG_SPACE_OFFSET (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
|
||||
|
||||
#define CSR1212_CONFIG_ROM_SPACE_BASE (0xfffff0000400ULL)
|
||||
#define CSR1212_CONFIG_ROM_SPACE_SIZE (1024)
|
||||
#define CSR1212_CONFIG_ROM_SPACE_END (CSR1212_CONFIG_ROM_SPACE_BASE + CSR1212_CONFIG_ROM_SPACE_SIZE)
|
||||
#define CSR1212_CONFIG_ROM_SPACE_OFFSET (CSR1212_CONFIG_ROM_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
|
||||
|
||||
#define CSR1212_UNITS_SPACE_BASE (0xfffff0000800ULL)
|
||||
#define CSR1212_UNITS_SPACE_SIZE ((256ULL * (1ULL << 20)) - 2048)
|
||||
#define CSR1212_UNITS_SPACE_END (CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE)
|
||||
#define CSR1212_UNITS_SPACE_OFFSET (CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
|
||||
|
||||
#define CSR1212_INVALID_ADDR_SPACE -1
|
||||
|
||||
|
||||
/* Config ROM image structures */
|
||||
struct csr1212_bus_info_block_img {
|
||||
u8 length;
|
||||
u8 crc_length;
|
||||
u16 crc;
|
||||
|
||||
/* Must be last */
|
||||
u32 data[0]; /* older gcc can't handle [] which is standard */
|
||||
};
|
||||
|
||||
struct csr1212_leaf {
|
||||
int len;
|
||||
u32 *data;
|
||||
};
|
||||
|
||||
struct csr1212_dentry {
|
||||
struct csr1212_dentry *next, *prev;
|
||||
struct csr1212_keyval *kv;
|
||||
};
|
||||
|
||||
struct csr1212_directory {
|
||||
int len;
|
||||
struct csr1212_dentry *dentries_head, *dentries_tail;
|
||||
};
|
||||
|
||||
struct csr1212_keyval {
|
||||
struct {
|
||||
u8 type;
|
||||
u8 id;
|
||||
} key;
|
||||
union {
|
||||
u32 immediate;
|
||||
u32 csr_offset;
|
||||
struct csr1212_leaf leaf;
|
||||
struct csr1212_directory directory;
|
||||
} value;
|
||||
struct csr1212_keyval *associate;
|
||||
atomic_t refcnt;
|
||||
|
||||
/* used in generating and/or parsing CSR image */
|
||||
struct csr1212_keyval *next, *prev; /* flat list of CSR elements */
|
||||
u32 offset; /* position in CSR from 0xffff f000 0000 */
|
||||
u8 valid; /* flag indicating keyval has valid data*/
|
||||
};
|
||||
|
||||
|
||||
struct csr1212_cache_region {
|
||||
struct csr1212_cache_region *next, *prev;
|
||||
u32 offset_start; /* inclusive */
|
||||
u32 offset_end; /* exclusive */
|
||||
};
|
||||
|
||||
struct csr1212_csr_rom_cache {
|
||||
struct csr1212_csr_rom_cache *next, *prev;
|
||||
struct csr1212_cache_region *filled_head, *filled_tail;
|
||||
struct csr1212_keyval *layout_head, *layout_tail;
|
||||
size_t size;
|
||||
u32 offset;
|
||||
struct csr1212_keyval *ext_rom;
|
||||
size_t len;
|
||||
|
||||
/* Must be last */
|
||||
u32 data[0]; /* older gcc can't handle [] which is standard */
|
||||
};
|
||||
|
||||
struct csr1212_csr {
|
||||
size_t bus_info_len; /* bus info block length in bytes */
|
||||
size_t crc_len; /* crc length in bytes */
|
||||
__be32 *bus_info_data; /* bus info data incl bus name and EUI */
|
||||
|
||||
void *private; /* private, bus specific data */
|
||||
struct csr1212_bus_ops *ops;
|
||||
|
||||
struct csr1212_keyval *root_kv;
|
||||
|
||||
int max_rom; /* max bytes readable in Config ROM region */
|
||||
|
||||
/* Items below used for image parsing and generation */
|
||||
struct csr1212_csr_rom_cache *cache_head, *cache_tail;
|
||||
};
|
||||
|
||||
struct csr1212_bus_ops {
|
||||
/* This function is used by csr1212 to read additional information
|
||||
* from remote nodes when parsing a Config ROM (i.e., read Config ROM
|
||||
* entries located in the Units Space. Must return 0 on success
|
||||
* anything else indicates an error. */
|
||||
int (*bus_read) (struct csr1212_csr *csr, u64 addr,
|
||||
void *buffer, void *private);
|
||||
|
||||
/* This function is used by csr1212 to allocate a region in units space
|
||||
* in the event that Config ROM entries don't all fit in the predefined
|
||||
* 1K region. The void *private parameter is private member of struct
|
||||
* csr1212_csr. */
|
||||
u64 (*allocate_addr_range) (u64 size, u32 alignment, void *private);
|
||||
|
||||
/* This function is used by csr1212 to release a region in units space
|
||||
* that is no longer needed. */
|
||||
void (*release_addr) (u64 addr, void *private);
|
||||
};
|
||||
|
||||
|
||||
/* Descriptor Leaf manipulation macros */
|
||||
#define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24
|
||||
#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff
|
||||
#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
|
||||
|
||||
#define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \
|
||||
(be32_to_cpu((kv)->value.leaf.data[0]) >> \
|
||||
CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
|
||||
#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \
|
||||
(be32_to_cpu((kv)->value.leaf.data[0]) & \
|
||||
CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)
|
||||
|
||||
|
||||
/* Text Descriptor Leaf manipulation macros */
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK 0xf /* after shift */
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff /* after shift */
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
|
||||
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \
|
||||
(be32_to_cpu((kv)->value.leaf.data[1]) >> \
|
||||
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \
|
||||
((be32_to_cpu((kv)->value.leaf.data[1]) >> \
|
||||
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
|
||||
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \
|
||||
(be32_to_cpu((kv)->value.leaf.data[1]) & \
|
||||
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \
|
||||
(&((kv)->value.leaf.data[2]))
|
||||
|
||||
|
||||
/* The following 2 function are for creating new Configuration ROM trees. The
|
||||
* first function is used for both creating local trees and parsing remote
|
||||
* trees. The second function adds pertinent information to local Configuration
|
||||
* ROM trees - namely data for the bus information block. */
|
||||
extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
|
||||
size_t bus_info_size,
|
||||
void *private);
|
||||
extern void csr1212_init_local_csr(struct csr1212_csr *csr,
|
||||
const u32 *bus_info_data, int max_rom);
|
||||
|
||||
|
||||
/* Destroy a Configuration ROM tree and release all memory taken by the tree. */
|
||||
extern void csr1212_destroy_csr(struct csr1212_csr *csr);
|
||||
|
||||
|
||||
/* The following set of functions are fore creating new keyvals for placement in
|
||||
* a Configuration ROM tree. Code that creates new keyvals with these functions
|
||||
* must release those keyvals with csr1212_release_keyval() when they are no
|
||||
* longer needed. */
|
||||
extern struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value);
|
||||
extern struct csr1212_keyval *csr1212_new_directory(u8 key);
|
||||
extern struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s);
|
||||
|
||||
|
||||
/* The following function manages association between keyvals. Typically,
|
||||
* Descriptor Leaves and Directories will be associated with another keyval and
|
||||
* it is desirable for the Descriptor keyval to be place immediately after the
|
||||
* keyval that it is associated with.
|
||||
* Take care with subsequent ROM modifications: There is no function to remove
|
||||
* previously specified associations.
|
||||
*/
|
||||
extern void csr1212_associate_keyval(struct csr1212_keyval *kv,
|
||||
struct csr1212_keyval *associate);
|
||||
|
||||
|
||||
/* The following functions manage the association of a keyval and directories.
|
||||
* A keyval may be attached to more than one directory. */
|
||||
extern int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
|
||||
struct csr1212_keyval *kv);
|
||||
extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
|
||||
struct csr1212_keyval *kv);
|
||||
|
||||
|
||||
/* Creates a complete Configuration ROM image in the list of caches available
|
||||
* via csr->cache_head. */
|
||||
extern int csr1212_generate_csr_image(struct csr1212_csr *csr);
|
||||
|
||||
|
||||
/* This is a convience function for reading a block of data out of one of the
|
||||
* caches in the csr->cache_head list. */
|
||||
extern int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer,
|
||||
u32 len);
|
||||
|
||||
|
||||
/* The following functions are in place for parsing Configuration ROM images.
|
||||
* csr1212_parse_keyval() is used should there be a need to directly parse a
|
||||
* Configuration ROM directly. */
|
||||
extern int csr1212_parse_keyval(struct csr1212_keyval *kv,
|
||||
struct csr1212_csr_rom_cache *cache);
|
||||
extern int csr1212_parse_csr(struct csr1212_csr *csr);
|
||||
|
||||
|
||||
/* This function allocates a new cache which may be used for either parsing or
|
||||
* generating sub-sets of Configuration ROM images. */
|
||||
static inline struct csr1212_csr_rom_cache *
|
||||
csr1212_rom_cache_malloc(u32 offset, size_t size)
|
||||
{
|
||||
struct csr1212_csr_rom_cache *cache;
|
||||
|
||||
cache = CSR1212_MALLOC(sizeof(*cache) + size);
|
||||
if (!cache)
|
||||
return NULL;
|
||||
|
||||
cache->next = NULL;
|
||||
cache->prev = NULL;
|
||||
cache->filled_head = NULL;
|
||||
cache->filled_tail = NULL;
|
||||
cache->layout_head = NULL;
|
||||
cache->layout_tail = NULL;
|
||||
cache->offset = offset;
|
||||
cache->size = size;
|
||||
cache->ext_rom = NULL;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
/* This function ensures that a keyval contains data when referencing a keyval
|
||||
* created by parsing a Configuration ROM. */
|
||||
extern struct csr1212_keyval *
|
||||
csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
|
||||
|
||||
|
||||
/* This function increments the reference count for a keyval should there be a
|
||||
* need for code to retain a keyval that has been parsed. */
|
||||
static inline void csr1212_keep_keyval(struct csr1212_keyval *kv)
|
||||
{
|
||||
atomic_inc(&kv->refcnt);
|
||||
smp_mb__after_atomic_inc();
|
||||
}
|
||||
|
||||
|
||||
/* This function decrements a keyval's reference count and will destroy the
|
||||
* keyval when there are no more users of the keyval. This should be called by
|
||||
* any code that calls csr1212_keep_keyval() or any of the keyval creation
|
||||
* routines csr1212_new_*(). */
|
||||
extern void csr1212_release_keyval(struct csr1212_keyval *kv);
|
||||
|
||||
|
||||
/*
|
||||
* This macro allows for looping over the keyval entries in a directory and it
|
||||
* ensures that keyvals from remote ConfigROMs are parsed properly.
|
||||
*
|
||||
* struct csr1212_csr *_csr points to the CSR associated with dir.
|
||||
* struct csr1212_keyval *_kv points to the current keyval (loop index).
|
||||
* struct csr1212_keyval *_dir points to the directory to be looped.
|
||||
* struct csr1212_dentry *_pos is used internally for indexing.
|
||||
*
|
||||
* kv will be NULL upon exit of the loop.
|
||||
*/
|
||||
#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \
|
||||
for (csr1212_get_keyval((_csr), (_dir)), \
|
||||
_pos = (_dir)->value.directory.dentries_head, \
|
||||
_kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;\
|
||||
(_kv) && (_pos); \
|
||||
(_kv->associate == NULL) ? \
|
||||
((_pos = _pos->next), (_kv = (_pos) ? \
|
||||
csr1212_get_keyval((_csr), _pos->kv) : \
|
||||
NULL)) : \
|
||||
(_kv = csr1212_get_keyval((_csr), _kv->associate)))
|
||||
|
||||
#endif /* __CSR1212_H__ */
|
@ -1,289 +0,0 @@
|
||||
/*
|
||||
* DMA region bookkeeping routines
|
||||
*
|
||||
* Copyright (C) 2002 Maas Digital LLC
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include "dma.h"
|
||||
|
||||
/* dma_prog_region */
|
||||
|
||||
void dma_prog_region_init(struct dma_prog_region *prog)
|
||||
{
|
||||
prog->kvirt = NULL;
|
||||
prog->dev = NULL;
|
||||
prog->n_pages = 0;
|
||||
prog->bus_addr = 0;
|
||||
}
|
||||
|
||||
int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
|
||||
struct pci_dev *dev)
|
||||
{
|
||||
/* round up to page size */
|
||||
n_bytes = PAGE_ALIGN(n_bytes);
|
||||
|
||||
prog->n_pages = n_bytes >> PAGE_SHIFT;
|
||||
|
||||
prog->kvirt = pci_alloc_consistent(dev, n_bytes, &prog->bus_addr);
|
||||
if (!prog->kvirt) {
|
||||
printk(KERN_ERR
|
||||
"dma_prog_region_alloc: pci_alloc_consistent() failed\n");
|
||||
dma_prog_region_free(prog);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
prog->dev = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dma_prog_region_free(struct dma_prog_region *prog)
|
||||
{
|
||||
if (prog->kvirt) {
|
||||
pci_free_consistent(prog->dev, prog->n_pages << PAGE_SHIFT,
|
||||
prog->kvirt, prog->bus_addr);
|
||||
}
|
||||
|
||||
prog->kvirt = NULL;
|
||||
prog->dev = NULL;
|
||||
prog->n_pages = 0;
|
||||
prog->bus_addr = 0;
|
||||
}
|
||||
|
||||
/* dma_region */
|
||||
|
||||
/**
|
||||
* dma_region_init - clear out all fields but do not allocate anything
|
||||
*/
|
||||
void dma_region_init(struct dma_region *dma)
|
||||
{
|
||||
dma->kvirt = NULL;
|
||||
dma->dev = NULL;
|
||||
dma->n_pages = 0;
|
||||
dma->n_dma_pages = 0;
|
||||
dma->sglist = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_region_alloc - allocate the buffer and map it to the IOMMU
|
||||
*/
|
||||
int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
|
||||
struct pci_dev *dev, int direction)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* round up to page size */
|
||||
n_bytes = PAGE_ALIGN(n_bytes);
|
||||
|
||||
dma->n_pages = n_bytes >> PAGE_SHIFT;
|
||||
|
||||
dma->kvirt = vmalloc_32(n_bytes);
|
||||
if (!dma->kvirt) {
|
||||
printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Clear the ram out, no junk to the user */
|
||||
memset(dma->kvirt, 0, n_bytes);
|
||||
|
||||
/* allocate scatter/gather list */
|
||||
dma->sglist = vmalloc(dma->n_pages * sizeof(*dma->sglist));
|
||||
if (!dma->sglist) {
|
||||
printk(KERN_ERR "dma_region_alloc: vmalloc(sglist) failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
sg_init_table(dma->sglist, dma->n_pages);
|
||||
|
||||
/* fill scatter/gather list with pages */
|
||||
for (i = 0; i < dma->n_pages; i++) {
|
||||
unsigned long va =
|
||||
(unsigned long)dma->kvirt + (i << PAGE_SHIFT);
|
||||
|
||||
sg_set_page(&dma->sglist[i], vmalloc_to_page((void *)va),
|
||||
PAGE_SIZE, 0);
|
||||
}
|
||||
|
||||
/* map sglist to the IOMMU */
|
||||
dma->n_dma_pages =
|
||||
pci_map_sg(dev, dma->sglist, dma->n_pages, direction);
|
||||
|
||||
if (dma->n_dma_pages == 0) {
|
||||
printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
dma->dev = dev;
|
||||
dma->direction = direction;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
dma_region_free(dma);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_region_free - unmap and free the buffer
|
||||
*/
|
||||
void dma_region_free(struct dma_region *dma)
|
||||
{
|
||||
if (dma->n_dma_pages) {
|
||||
pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages,
|
||||
dma->direction);
|
||||
dma->n_dma_pages = 0;
|
||||
dma->dev = NULL;
|
||||
}
|
||||
|
||||
vfree(dma->sglist);
|
||||
dma->sglist = NULL;
|
||||
|
||||
vfree(dma->kvirt);
|
||||
dma->kvirt = NULL;
|
||||
dma->n_pages = 0;
|
||||
}
|
||||
|
||||
/* find the scatterlist index and remaining offset corresponding to a
|
||||
given offset from the beginning of the buffer */
|
||||
static inline int dma_region_find(struct dma_region *dma, unsigned long offset,
|
||||
unsigned int start, unsigned long *rem)
|
||||
{
|
||||
int i;
|
||||
unsigned long off = offset;
|
||||
|
||||
for (i = start; i < dma->n_dma_pages; i++) {
|
||||
if (off < sg_dma_len(&dma->sglist[i])) {
|
||||
*rem = off;
|
||||
break;
|
||||
}
|
||||
|
||||
off -= sg_dma_len(&dma->sglist[i]);
|
||||
}
|
||||
|
||||
BUG_ON(i >= dma->n_dma_pages);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_region_offset_to_bus - get bus address of an offset within a DMA region
|
||||
*
|
||||
* Returns the DMA bus address of the byte with the given @offset relative to
|
||||
* the beginning of the @dma.
|
||||
*/
|
||||
dma_addr_t dma_region_offset_to_bus(struct dma_region * dma,
|
||||
unsigned long offset)
|
||||
{
|
||||
unsigned long rem = 0;
|
||||
|
||||
struct scatterlist *sg =
|
||||
&dma->sglist[dma_region_find(dma, offset, 0, &rem)];
|
||||
return sg_dma_address(sg) + rem;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_region_sync_for_cpu - sync the CPU's view of the buffer
|
||||
*/
|
||||
void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
|
||||
unsigned long len)
|
||||
{
|
||||
int first, last;
|
||||
unsigned long rem = 0;
|
||||
|
||||
if (!len)
|
||||
len = 1;
|
||||
|
||||
first = dma_region_find(dma, offset, 0, &rem);
|
||||
last = dma_region_find(dma, rem + len - 1, first, &rem);
|
||||
|
||||
pci_dma_sync_sg_for_cpu(dma->dev, &dma->sglist[first], last - first + 1,
|
||||
dma->direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_region_sync_for_device - sync the IO bus' view of the buffer
|
||||
*/
|
||||
void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
|
||||
unsigned long len)
|
||||
{
|
||||
int first, last;
|
||||
unsigned long rem = 0;
|
||||
|
||||
if (!len)
|
||||
len = 1;
|
||||
|
||||
first = dma_region_find(dma, offset, 0, &rem);
|
||||
last = dma_region_find(dma, rem + len - 1, first, &rem);
|
||||
|
||||
pci_dma_sync_sg_for_device(dma->dev, &dma->sglist[first],
|
||||
last - first + 1, dma->direction);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
|
||||
static int dma_region_pagefault(struct vm_area_struct *vma,
|
||||
struct vm_fault *vmf)
|
||||
{
|
||||
struct dma_region *dma = (struct dma_region *)vma->vm_private_data;
|
||||
|
||||
if (!dma->kvirt)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
if (vmf->pgoff >= dma->n_pages)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
vmf->page = vmalloc_to_page(dma->kvirt + (vmf->pgoff << PAGE_SHIFT));
|
||||
get_page(vmf->page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct dma_region_vm_ops = {
|
||||
.fault = dma_region_pagefault,
|
||||
};
|
||||
|
||||
/**
|
||||
* dma_region_mmap - map the buffer into a user space process
|
||||
*/
|
||||
int dma_region_mmap(struct dma_region *dma, struct file *file,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long size;
|
||||
|
||||
if (!dma->kvirt)
|
||||
return -EINVAL;
|
||||
|
||||
/* must be page-aligned (XXX: comment is wrong, we could allow pgoff) */
|
||||
if (vma->vm_pgoff != 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* check the length */
|
||||
size = vma->vm_end - vma->vm_start;
|
||||
if (size > (dma->n_pages << PAGE_SHIFT))
|
||||
return -EINVAL;
|
||||
|
||||
vma->vm_ops = &dma_region_vm_ops;
|
||||
vma->vm_private_data = dma;
|
||||
vma->vm_file = file;
|
||||
vma->vm_flags |= VM_RESERVED | VM_ALWAYSDUMP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* CONFIG_MMU */
|
||||
|
||||
int dma_region_mmap(struct dma_region *dma, struct file *file,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MMU */
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* DMA region bookkeeping routines
|
||||
*
|
||||
* Copyright (C) 2002 Maas Digital LLC
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#ifndef IEEE1394_DMA_H
|
||||
#define IEEE1394_DMA_H
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
struct file;
|
||||
struct pci_dev;
|
||||
struct scatterlist;
|
||||
struct vm_area_struct;
|
||||
|
||||
/**
|
||||
* struct dma_prog_region - small contiguous DMA buffer
|
||||
* @kvirt: kernel virtual address
|
||||
* @dev: PCI device
|
||||
* @n_pages: number of kernel pages
|
||||
* @bus_addr: base bus address
|
||||
*
|
||||
* a small, physically contiguous DMA buffer with random-access, synchronous
|
||||
* usage characteristics
|
||||
*/
|
||||
struct dma_prog_region {
|
||||
unsigned char *kvirt;
|
||||
struct pci_dev *dev;
|
||||
unsigned int n_pages;
|
||||
dma_addr_t bus_addr;
|
||||
};
|
||||
|
||||
/* clear out all fields but do not allocate any memory */
|
||||
void dma_prog_region_init(struct dma_prog_region *prog);
|
||||
int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
|
||||
struct pci_dev *dev);
|
||||
void dma_prog_region_free(struct dma_prog_region *prog);
|
||||
|
||||
static inline dma_addr_t dma_prog_region_offset_to_bus(
|
||||
struct dma_prog_region *prog, unsigned long offset)
|
||||
{
|
||||
return prog->bus_addr + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct dma_region - large non-contiguous DMA buffer
|
||||
* @virt: kernel virtual address
|
||||
* @dev: PCI device
|
||||
* @n_pages: number of kernel pages
|
||||
* @n_dma_pages: number of IOMMU pages
|
||||
* @sglist: IOMMU mapping
|
||||
* @direction: PCI_DMA_TODEVICE, etc.
|
||||
*
|
||||
* a large, non-physically-contiguous DMA buffer with streaming, asynchronous
|
||||
* usage characteristics
|
||||
*/
|
||||
struct dma_region {
|
||||
unsigned char *kvirt;
|
||||
struct pci_dev *dev;
|
||||
unsigned int n_pages;
|
||||
unsigned int n_dma_pages;
|
||||
struct scatterlist *sglist;
|
||||
int direction;
|
||||
};
|
||||
|
||||
void dma_region_init(struct dma_region *dma);
|
||||
int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
|
||||
struct pci_dev *dev, int direction);
|
||||
void dma_region_free(struct dma_region *dma);
|
||||
void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
|
||||
unsigned long len);
|
||||
void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
|
||||
unsigned long len);
|
||||
int dma_region_mmap(struct dma_region *dma, struct file *file,
|
||||
struct vm_area_struct *vma);
|
||||
dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
|
||||
unsigned long offset);
|
||||
|
||||
/**
|
||||
* dma_region_i - macro to index into a DMA region (or dma_prog_region)
|
||||
*/
|
||||
#define dma_region_i(_dma, _type, _index) \
|
||||
( ((_type*) ((_dma)->kvirt)) + (_index) )
|
||||
|
||||
#endif /* IEEE1394_DMA_H */
|
@ -1,587 +0,0 @@
|
||||
/*
|
||||
* dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips
|
||||
* Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
|
||||
* receive by Dan Dennedy <dan@dennedy.org>
|
||||
*
|
||||
* based on:
|
||||
* video1394.h - driver for OHCI 1394 boards
|
||||
* Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
|
||||
* Peter Schlaile <udbz@rz.uni-karlsruhe.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; 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 _DV_1394_PRIVATE_H
|
||||
#define _DV_1394_PRIVATE_H
|
||||
|
||||
#include "ieee1394.h"
|
||||
#include "ohci1394.h"
|
||||
#include "dma.h"
|
||||
|
||||
/* data structures private to the dv1394 driver */
|
||||
/* none of this is exposed to user-space */
|
||||
|
||||
|
||||
/*
|
||||
the 8-byte CIP (Common Isochronous Packet) header that precedes
|
||||
each packet of DV data.
|
||||
|
||||
See the IEC 61883 standard.
|
||||
*/
|
||||
|
||||
struct CIP_header { unsigned char b[8]; };
|
||||
|
||||
static inline void fill_cip_header(struct CIP_header *cip,
|
||||
unsigned char source_node_id,
|
||||
unsigned long counter,
|
||||
enum pal_or_ntsc format,
|
||||
unsigned long timestamp)
|
||||
{
|
||||
cip->b[0] = source_node_id;
|
||||
cip->b[1] = 0x78; /* packet size in quadlets (480/4) - even for empty packets! */
|
||||
cip->b[2] = 0x00;
|
||||
cip->b[3] = counter;
|
||||
|
||||
cip->b[4] = 0x80; /* const */
|
||||
|
||||
switch(format) {
|
||||
case DV1394_PAL:
|
||||
cip->b[5] = 0x80;
|
||||
break;
|
||||
case DV1394_NTSC:
|
||||
cip->b[5] = 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
cip->b[6] = timestamp >> 8;
|
||||
cip->b[7] = timestamp & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
DMA commands used to program the OHCI's DMA engine
|
||||
|
||||
See the Texas Instruments OHCI 1394 chipset documentation.
|
||||
*/
|
||||
|
||||
struct output_more_immediate { __le32 q[8]; };
|
||||
struct output_more { __le32 q[4]; };
|
||||
struct output_last { __le32 q[4]; };
|
||||
struct input_more { __le32 q[4]; };
|
||||
struct input_last { __le32 q[4]; };
|
||||
|
||||
/* outputs */
|
||||
|
||||
static inline void fill_output_more_immediate(struct output_more_immediate *omi,
|
||||
unsigned char tag,
|
||||
unsigned char channel,
|
||||
unsigned char sync_tag,
|
||||
unsigned int payload_size)
|
||||
{
|
||||
omi->q[0] = cpu_to_le32(0x02000000 | 8); /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
|
||||
omi->q[1] = cpu_to_le32(0);
|
||||
omi->q[2] = cpu_to_le32(0);
|
||||
omi->q[3] = cpu_to_le32(0);
|
||||
|
||||
/* IT packet header */
|
||||
omi->q[4] = cpu_to_le32( (0x0 << 16) /* IEEE1394_SPEED_100 */
|
||||
| (tag << 14)
|
||||
| (channel << 8)
|
||||
| (TCODE_ISO_DATA << 4)
|
||||
| (sync_tag) );
|
||||
|
||||
/* reserved field; mimic behavior of my Sony DSR-40 */
|
||||
omi->q[5] = cpu_to_le32((payload_size << 16) | (0x7F << 8) | 0xA0);
|
||||
|
||||
omi->q[6] = cpu_to_le32(0);
|
||||
omi->q[7] = cpu_to_le32(0);
|
||||
}
|
||||
|
||||
static inline void fill_output_more(struct output_more *om,
|
||||
unsigned int data_size,
|
||||
unsigned long data_phys_addr)
|
||||
{
|
||||
om->q[0] = cpu_to_le32(data_size);
|
||||
om->q[1] = cpu_to_le32(data_phys_addr);
|
||||
om->q[2] = cpu_to_le32(0);
|
||||
om->q[3] = cpu_to_le32(0);
|
||||
}
|
||||
|
||||
static inline void fill_output_last(struct output_last *ol,
|
||||
int want_timestamp,
|
||||
int want_interrupt,
|
||||
unsigned int data_size,
|
||||
unsigned long data_phys_addr)
|
||||
{
|
||||
u32 temp = 0;
|
||||
temp |= 1 << 28; /* OUTPUT_LAST */
|
||||
|
||||
if (want_timestamp) /* controller will update timestamp at DMA time */
|
||||
temp |= 1 << 27;
|
||||
|
||||
if (want_interrupt)
|
||||
temp |= 3 << 20;
|
||||
|
||||
temp |= 3 << 18; /* must take branch */
|
||||
temp |= data_size;
|
||||
|
||||
ol->q[0] = cpu_to_le32(temp);
|
||||
ol->q[1] = cpu_to_le32(data_phys_addr);
|
||||
ol->q[2] = cpu_to_le32(0);
|
||||
ol->q[3] = cpu_to_le32(0);
|
||||
}
|
||||
|
||||
/* inputs */
|
||||
|
||||
static inline void fill_input_more(struct input_more *im,
|
||||
int want_interrupt,
|
||||
unsigned int data_size,
|
||||
unsigned long data_phys_addr)
|
||||
{
|
||||
u32 temp = 2 << 28; /* INPUT_MORE */
|
||||
temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
|
||||
if (want_interrupt)
|
||||
temp |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */
|
||||
temp |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */
|
||||
/* disable wait on sync field, not used in DV :-( */
|
||||
temp |= data_size;
|
||||
|
||||
im->q[0] = cpu_to_le32(temp);
|
||||
im->q[1] = cpu_to_le32(data_phys_addr);
|
||||
im->q[2] = cpu_to_le32(0); /* branchAddress and Z not use in packet-per-buffer mode */
|
||||
im->q[3] = cpu_to_le32(0); /* xferStatus & resCount, resCount must be initialize to data_size */
|
||||
}
|
||||
|
||||
static inline void fill_input_last(struct input_last *il,
|
||||
int want_interrupt,
|
||||
unsigned int data_size,
|
||||
unsigned long data_phys_addr)
|
||||
{
|
||||
u32 temp = 3 << 28; /* INPUT_LAST */
|
||||
temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
|
||||
if (want_interrupt)
|
||||
temp |= 3 << 20; /* enable interrupts */
|
||||
temp |= 0xC << 16; /* enable branch to address */
|
||||
/* disable wait on sync field, not used in DV :-( */
|
||||
temp |= data_size;
|
||||
|
||||
il->q[0] = cpu_to_le32(temp);
|
||||
il->q[1] = cpu_to_le32(data_phys_addr);
|
||||
il->q[2] = cpu_to_le32(1); /* branchAddress (filled in later) and Z = 1 descriptor in next block */
|
||||
il->q[3] = cpu_to_le32(data_size); /* xferStatus & resCount, resCount must be initialize to data_size */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
A "DMA descriptor block" consists of several contiguous DMA commands.
|
||||
struct DMA_descriptor_block encapsulates all of the commands necessary
|
||||
to send one packet of DV data.
|
||||
|
||||
There are three different types of these blocks:
|
||||
|
||||
1) command to send an empty packet (CIP header only, no DV data):
|
||||
|
||||
OUTPUT_MORE-Immediate <-- contains the iso header in-line
|
||||
OUTPUT_LAST <-- points to the CIP header
|
||||
|
||||
2) command to send a full packet when the DV data payload does NOT
|
||||
cross a page boundary:
|
||||
|
||||
OUTPUT_MORE-Immediate <-- contains the iso header in-line
|
||||
OUTPUT_MORE <-- points to the CIP header
|
||||
OUTPUT_LAST <-- points to entire DV data payload
|
||||
|
||||
3) command to send a full packet when the DV payload DOES cross
|
||||
a page boundary:
|
||||
|
||||
OUTPUT_MORE-Immediate <-- contains the iso header in-line
|
||||
OUTPUT_MORE <-- points to the CIP header
|
||||
OUTPUT_MORE <-- points to first part of DV data payload
|
||||
OUTPUT_LAST <-- points to second part of DV data payload
|
||||
|
||||
This struct describes all three block types using unions.
|
||||
|
||||
!!! It is vital that an even number of these descriptor blocks fit on one
|
||||
page of memory, since a block cannot cross a page boundary !!!
|
||||
|
||||
*/
|
||||
|
||||
struct DMA_descriptor_block {
|
||||
|
||||
union {
|
||||
struct {
|
||||
/* iso header, common to all output block types */
|
||||
struct output_more_immediate omi;
|
||||
|
||||
union {
|
||||
/* empty packet */
|
||||
struct {
|
||||
struct output_last ol; /* CIP header */
|
||||
} empty;
|
||||
|
||||
/* full packet */
|
||||
struct {
|
||||
struct output_more om; /* CIP header */
|
||||
|
||||
union {
|
||||
/* payload does not cross page boundary */
|
||||
struct {
|
||||
struct output_last ol; /* data payload */
|
||||
} nocross;
|
||||
|
||||
/* payload crosses page boundary */
|
||||
struct {
|
||||
struct output_more om; /* data payload */
|
||||
struct output_last ol; /* data payload */
|
||||
} cross;
|
||||
} u;
|
||||
|
||||
} full;
|
||||
} u;
|
||||
} out;
|
||||
|
||||
struct {
|
||||
struct input_last il;
|
||||
} in;
|
||||
|
||||
} u;
|
||||
|
||||
/* ensure that PAGE_SIZE % sizeof(struct DMA_descriptor_block) == 0
|
||||
by padding out to 128 bytes */
|
||||
u32 __pad__[12];
|
||||
};
|
||||
|
||||
|
||||
/* struct frame contains all data associated with one frame in the
|
||||
ringbuffer these are allocated when the DMA context is initialized
|
||||
do_dv1394_init(). They are re-used after the card finishes
|
||||
transmitting the frame. */
|
||||
|
||||
struct video_card; /* forward declaration */
|
||||
|
||||
struct frame {
|
||||
|
||||
/* points to the struct video_card that owns this frame */
|
||||
struct video_card *video;
|
||||
|
||||
/* index of this frame in video_card->frames[] */
|
||||
unsigned int frame_num;
|
||||
|
||||
/* FRAME_CLEAR - DMA program not set up, waiting for data
|
||||
FRAME_READY - DMA program written, ready to transmit
|
||||
|
||||
Changes to these should be locked against the interrupt
|
||||
*/
|
||||
enum {
|
||||
FRAME_CLEAR = 0,
|
||||
FRAME_READY
|
||||
} state;
|
||||
|
||||
/* whether this frame has been DMA'ed already; used only from
|
||||
the IRQ handler to determine whether the frame can be reset */
|
||||
int done;
|
||||
|
||||
|
||||
/* kernel virtual pointer to the start of this frame's data in
|
||||
the user ringbuffer. Use only for CPU access; to get the DMA
|
||||
bus address you must go through the video->user_dma mapping */
|
||||
unsigned long data;
|
||||
|
||||
/* Max # of packets per frame */
|
||||
#define MAX_PACKETS 500
|
||||
|
||||
|
||||
/* a PAGE_SIZE memory pool for allocating CIP headers
|
||||
!header_pool must be aligned to PAGE_SIZE! */
|
||||
struct CIP_header *header_pool;
|
||||
dma_addr_t header_pool_dma;
|
||||
|
||||
|
||||
/* a physically contiguous memory pool for allocating DMA
|
||||
descriptor blocks; usually around 64KB in size
|
||||
!descriptor_pool must be aligned to PAGE_SIZE! */
|
||||
struct DMA_descriptor_block *descriptor_pool;
|
||||
dma_addr_t descriptor_pool_dma;
|
||||
unsigned long descriptor_pool_size;
|
||||
|
||||
|
||||
/* # of packets allocated for this frame */
|
||||
unsigned int n_packets;
|
||||
|
||||
|
||||
/* below are several pointers (kernel virtual addresses, not
|
||||
DMA bus addresses) to parts of the DMA program. These are
|
||||
set each time the DMA program is written in
|
||||
frame_prepare(). They are used later on, e.g. from the
|
||||
interrupt handler, to check the status of the frame */
|
||||
|
||||
/* points to status/timestamp field of first DMA packet */
|
||||
/* (we'll check it later to monitor timestamp accuracy) */
|
||||
__le32 *frame_begin_timestamp;
|
||||
|
||||
/* the timestamp we assigned to the first packet in the frame */
|
||||
u32 assigned_timestamp;
|
||||
|
||||
/* pointer to the first packet's CIP header (where the timestamp goes) */
|
||||
struct CIP_header *cip_syt1;
|
||||
|
||||
/* pointer to the second packet's CIP header
|
||||
(only set if the first packet was empty) */
|
||||
struct CIP_header *cip_syt2;
|
||||
|
||||
/* in order to figure out what caused an interrupt,
|
||||
store pointers to the status fields of the two packets
|
||||
that can cause interrupts. We'll check these from the
|
||||
interrupt handler.
|
||||
*/
|
||||
__le32 *mid_frame_timestamp;
|
||||
__le32 *frame_end_timestamp;
|
||||
|
||||
/* branch address field of final packet. This is effectively
|
||||
the "tail" in the chain of DMA descriptor blocks.
|
||||
We will fill it with the address of the first DMA descriptor
|
||||
block in the subsequent frame, once it is ready.
|
||||
*/
|
||||
__le32 *frame_end_branch;
|
||||
|
||||
/* the number of descriptors in the first descriptor block
|
||||
of the frame. Needed to start DMA */
|
||||
int first_n_descriptors;
|
||||
};
|
||||
|
||||
|
||||
struct packet {
|
||||
__le16 timestamp;
|
||||
u16 invalid;
|
||||
u16 iso_header;
|
||||
__le16 data_length;
|
||||
u32 cip_h1;
|
||||
u32 cip_h2;
|
||||
unsigned char data[480];
|
||||
unsigned char padding[16]; /* force struct size =512 for page alignment */
|
||||
};
|
||||
|
||||
|
||||
/* allocate/free a frame */
|
||||
static struct frame* frame_new(unsigned int frame_num, struct video_card *video);
|
||||
static void frame_delete(struct frame *f);
|
||||
|
||||
/* reset f so that it can be used again */
|
||||
static void frame_reset(struct frame *f);
|
||||
|
||||
/* struct video_card contains all data associated with one instance
|
||||
of the dv1394 driver
|
||||
*/
|
||||
enum modes {
|
||||
MODE_RECEIVE,
|
||||
MODE_TRANSMIT
|
||||
};
|
||||
|
||||
struct video_card {
|
||||
|
||||
/* ohci card to which this instance corresponds */
|
||||
struct ti_ohci *ohci;
|
||||
|
||||
/* OHCI card id; the link between the VFS inode and a specific video_card
|
||||
(essentially the device minor number) */
|
||||
int id;
|
||||
|
||||
/* entry in dv1394_cards */
|
||||
struct list_head list;
|
||||
|
||||
/* OHCI card IT DMA context number, -1 if not in use */
|
||||
int ohci_it_ctx;
|
||||
struct ohci1394_iso_tasklet it_tasklet;
|
||||
|
||||
/* register offsets for current IT DMA context, 0 if not in use */
|
||||
u32 ohci_IsoXmitContextControlSet;
|
||||
u32 ohci_IsoXmitContextControlClear;
|
||||
u32 ohci_IsoXmitCommandPtr;
|
||||
|
||||
/* OHCI card IR DMA context number, -1 if not in use */
|
||||
struct ohci1394_iso_tasklet ir_tasklet;
|
||||
int ohci_ir_ctx;
|
||||
|
||||
/* register offsets for current IR DMA context, 0 if not in use */
|
||||
u32 ohci_IsoRcvContextControlSet;
|
||||
u32 ohci_IsoRcvContextControlClear;
|
||||
u32 ohci_IsoRcvCommandPtr;
|
||||
u32 ohci_IsoRcvContextMatch;
|
||||
|
||||
|
||||
/* CONCURRENCY CONTROL */
|
||||
|
||||
/* there are THREE levels of locking associated with video_card. */
|
||||
|
||||
/*
|
||||
1) the 'open' flag - this prevents more than one process from
|
||||
opening the device. (the driver currently assumes only one opener).
|
||||
This is a regular int, but use test_and_set_bit() (on bit zero)
|
||||
for atomicity.
|
||||
*/
|
||||
unsigned long open;
|
||||
|
||||
/*
|
||||
2) the spinlock - this provides mutual exclusion between the interrupt
|
||||
handler and process-context operations. Generally you must take the
|
||||
spinlock under the following conditions:
|
||||
1) DMA (and hence the interrupt handler) may be running
|
||||
AND
|
||||
2) you need to operate on the video_card, especially active_frame
|
||||
|
||||
It is OK to play with video_card without taking the spinlock if
|
||||
you are certain that DMA is not running. Even if DMA is running,
|
||||
it is OK to *read* active_frame with the lock, then drop it
|
||||
immediately. This is safe because the interrupt handler will never
|
||||
advance active_frame onto a frame that is not READY (and the spinlock
|
||||
must be held while marking a frame READY).
|
||||
|
||||
spinlock is also used to protect ohci_it_ctx and ohci_ir_ctx,
|
||||
which can be accessed from both process and interrupt context
|
||||
*/
|
||||
spinlock_t spinlock;
|
||||
|
||||
/* flag to prevent spurious interrupts (which OHCI seems to
|
||||
generate a lot :) from accessing the struct */
|
||||
int dma_running;
|
||||
|
||||
/*
|
||||
3) the sleeping mutex 'mtx' - this is used from process context only,
|
||||
to serialize various operations on the video_card. Even though only one
|
||||
open() is allowed, we still need to prevent multiple threads of execution
|
||||
from entering calls like read, write, ioctl, etc.
|
||||
|
||||
I honestly can't think of a good reason to use dv1394 from several threads
|
||||
at once, but we need to serialize anyway to prevent oopses =).
|
||||
|
||||
NOTE: if you need both spinlock and mtx, take mtx first to avoid deadlock!
|
||||
*/
|
||||
struct mutex mtx;
|
||||
|
||||
/* people waiting for buffer space, please form a line here... */
|
||||
wait_queue_head_t waitq;
|
||||
|
||||
/* support asynchronous I/O signals (SIGIO) */
|
||||
struct fasync_struct *fasync;
|
||||
|
||||
/* the large, non-contiguous (rvmalloc()) ringbuffer for DV
|
||||
data, exposed to user-space via mmap() */
|
||||
unsigned long dv_buf_size;
|
||||
struct dma_region dv_buf;
|
||||
|
||||
/* next byte in the ringbuffer that a write() call will fill */
|
||||
size_t write_off;
|
||||
|
||||
struct frame *frames[DV1394_MAX_FRAMES];
|
||||
|
||||
/* n_frames also serves as an indicator that this struct video_card is
|
||||
initialized and ready to run DMA buffers */
|
||||
|
||||
int n_frames;
|
||||
|
||||
/* this is the frame that is currently "owned" by the OHCI DMA controller
|
||||
(set to -1 iff DMA is not running)
|
||||
|
||||
! must lock against the interrupt handler when accessing it !
|
||||
|
||||
RULES:
|
||||
|
||||
Only the interrupt handler may change active_frame if DMA
|
||||
is running; if not, process may change it
|
||||
|
||||
If the next frame is READY, the interrupt handler will advance
|
||||
active_frame when the current frame is finished.
|
||||
|
||||
If the next frame is CLEAR, the interrupt handler will re-transmit
|
||||
the current frame, and the dropped_frames counter will be incremented.
|
||||
|
||||
The interrupt handler will NEVER advance active_frame to a
|
||||
frame that is not READY.
|
||||
*/
|
||||
int active_frame;
|
||||
int first_run;
|
||||
|
||||
/* the same locking rules apply to these three fields also: */
|
||||
|
||||
/* altered ONLY from process context. Must check first_clear_frame->state;
|
||||
if it's READY, that means the ringbuffer is full with READY frames;
|
||||
if it's CLEAR, that means one or more ringbuffer frames are CLEAR */
|
||||
unsigned int first_clear_frame;
|
||||
|
||||
/* altered both by process and interrupt */
|
||||
unsigned int n_clear_frames;
|
||||
|
||||
/* only altered by the interrupt */
|
||||
unsigned int dropped_frames;
|
||||
|
||||
|
||||
|
||||
/* the CIP accumulator and continuity counter are properties
|
||||
of the DMA stream as a whole (not a single frame), so they
|
||||
are stored here in the video_card */
|
||||
|
||||
unsigned long cip_accum;
|
||||
unsigned long cip_n, cip_d;
|
||||
unsigned int syt_offset;
|
||||
unsigned int continuity_counter;
|
||||
|
||||
enum pal_or_ntsc pal_or_ntsc;
|
||||
|
||||
/* redundant, but simplifies the code somewhat */
|
||||
unsigned int frame_size; /* in bytes */
|
||||
|
||||
/* the isochronous channel to use, -1 if video card is inactive */
|
||||
int channel;
|
||||
|
||||
|
||||
/* physically contiguous packet ringbuffer for receive */
|
||||
struct dma_region packet_buf;
|
||||
unsigned long packet_buf_size;
|
||||
|
||||
unsigned int current_packet;
|
||||
int first_frame; /* received first start frame marker? */
|
||||
enum modes mode;
|
||||
};
|
||||
|
||||
/*
|
||||
if the video_card is not initialized, then the ONLY fields that are valid are:
|
||||
ohci
|
||||
open
|
||||
n_frames
|
||||
*/
|
||||
|
||||
static inline int video_card_initialized(struct video_card *v)
|
||||
{
|
||||
return v->n_frames > 0;
|
||||
}
|
||||
|
||||
static int do_dv1394_init(struct video_card *video, struct dv1394_init *init);
|
||||
static int do_dv1394_init_default(struct video_card *video);
|
||||
static void do_dv1394_shutdown(struct video_card *video, int free_user_buf);
|
||||
|
||||
|
||||
/* NTSC empty packet rate accurate to within 0.01%,
|
||||
calibrated against a Sony DSR-40 DVCAM deck */
|
||||
|
||||
#define CIP_N_NTSC 68000000
|
||||
#define CIP_D_NTSC 1068000000
|
||||
|
||||
#define CIP_N_PAL 1
|
||||
#define CIP_D_PAL 16
|
||||
|
||||
#endif /* _DV_1394_PRIVATE_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,305 +0,0 @@
|
||||
/*
|
||||
* dv1394.h - DV input/output over IEEE 1394 on OHCI chips
|
||||
* Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
|
||||
* receive by Dan Dennedy <dan@dennedy.org>
|
||||
*
|
||||
* based on:
|
||||
* video1394.h - driver for OHCI 1394 boards
|
||||
* Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
|
||||
* Peter Schlaile <udbz@rz.uni-karlsruhe.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; 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 _DV_1394_H
|
||||
#define _DV_1394_H
|
||||
|
||||
/* This is the public user-space interface. Try not to break it. */
|
||||
|
||||
#define DV1394_API_VERSION 0x20011127
|
||||
|
||||
/* ********************
|
||||
** **
|
||||
** DV1394 API **
|
||||
** **
|
||||
********************
|
||||
|
||||
There are two methods of operating the DV1394 DV output device.
|
||||
|
||||
1)
|
||||
|
||||
The simplest is an interface based on write(): simply write
|
||||
full DV frames of data to the device, and they will be transmitted
|
||||
as quickly as possible. The FD may be set for non-blocking I/O,
|
||||
in which case you can use select() or poll() to wait for output
|
||||
buffer space.
|
||||
|
||||
To set the DV output parameters (e.g. whether you want NTSC or PAL
|
||||
video), use the DV1394_INIT ioctl, passing in the parameters you
|
||||
want in a struct dv1394_init.
|
||||
|
||||
Example 1:
|
||||
To play a raw .DV file: cat foo.DV > /dev/dv1394
|
||||
(cat will use write() internally)
|
||||
|
||||
Example 2:
|
||||
static struct dv1394_init init = {
|
||||
0x63, (broadcast channel)
|
||||
4, (four-frame ringbuffer)
|
||||
DV1394_NTSC, (send NTSC video)
|
||||
0, 0 (default empty packet rate)
|
||||
}
|
||||
|
||||
ioctl(fd, DV1394_INIT, &init);
|
||||
|
||||
while (1) {
|
||||
read( <a raw DV file>, buf, DV1394_NTSC_FRAME_SIZE );
|
||||
write( <the dv1394 FD>, buf, DV1394_NTSC_FRAME_SIZE );
|
||||
}
|
||||
|
||||
2)
|
||||
|
||||
For more control over buffering, and to avoid unnecessary copies
|
||||
of the DV data, you can use the more sophisticated the mmap() interface.
|
||||
First, call the DV1394_INIT ioctl to specify your parameters,
|
||||
including the number of frames in the ringbuffer. Then, calling mmap()
|
||||
on the dv1394 device will give you direct access to the ringbuffer
|
||||
from which the DV card reads your frame data.
|
||||
|
||||
The ringbuffer is simply one large, contiguous region of memory
|
||||
containing two or more frames of packed DV data. Each frame of DV data
|
||||
is 120000 bytes (NTSC) or 144000 bytes (PAL).
|
||||
|
||||
Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES
|
||||
ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl
|
||||
or select()/poll() to wait until the frames are transmitted. Next, you'll
|
||||
need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer
|
||||
frames are clear (ready to be filled with new DV data). Finally, use
|
||||
DV1394_SUBMIT_FRAMES again to send the new data to the DV output.
|
||||
|
||||
|
||||
Example: here is what a four-frame ringbuffer might look like
|
||||
during DV transmission:
|
||||
|
||||
|
||||
frame 0 frame 1 frame 2 frame 3
|
||||
|
||||
*--------------------------------------*
|
||||
| CLEAR | DV data | DV data | CLEAR |
|
||||
*--------------------------------------*
|
||||
<ACTIVE>
|
||||
|
||||
transmission goes in this direction --->>>
|
||||
|
||||
|
||||
The DV hardware is currently transmitting the data in frame 1.
|
||||
Once frame 1 is finished, it will automatically transmit frame 2.
|
||||
(if frame 2 finishes before frame 3 is submitted, the device
|
||||
will continue to transmit frame 2, and will increase the dropped_frames
|
||||
counter each time it repeats the transmission).
|
||||
|
||||
|
||||
If you called DV1394_GET_STATUS at this instant, you would
|
||||
receive the following values:
|
||||
|
||||
n_frames = 4
|
||||
active_frame = 1
|
||||
first_clear_frame = 3
|
||||
n_clear_frames = 2
|
||||
|
||||
At this point, you should write new DV data into frame 3 and optionally
|
||||
frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
|
||||
it may transmit the new frames.
|
||||
|
||||
ERROR HANDLING
|
||||
|
||||
An error (buffer underflow/overflow or a break in the DV stream due
|
||||
to a 1394 bus reset) can be detected by checking the dropped_frames
|
||||
field of struct dv1394_status (obtained through the
|
||||
DV1394_GET_STATUS ioctl).
|
||||
|
||||
The best way to recover from such an error is to re-initialize
|
||||
dv1394, either by using the DV1394_INIT ioctl call, or closing the
|
||||
file descriptor and opening it again. (note that you must unmap all
|
||||
ringbuffer mappings when closing the file descriptor, or else
|
||||
dv1394 will still be considered 'in use').
|
||||
|
||||
MAIN LOOP
|
||||
|
||||
For maximum efficiency and robustness against bus errors, you are
|
||||
advised to model the main loop of your application after the
|
||||
following pseudo-code example:
|
||||
|
||||
(checks of system call return values omitted for brevity; always
|
||||
check return values in your code!)
|
||||
|
||||
while ( frames left ) {
|
||||
|
||||
struct pollfd *pfd = ...;
|
||||
|
||||
pfd->fd = dv1394_fd;
|
||||
pfd->revents = 0;
|
||||
pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive)
|
||||
|
||||
(add other sources of I/O here)
|
||||
|
||||
poll(pfd, 1, -1); (or select(); add a timeout if you want)
|
||||
|
||||
if (pfd->revents) {
|
||||
struct dv1394_status status;
|
||||
|
||||
ioctl(dv1394_fd, DV1394_GET_STATUS, &status);
|
||||
|
||||
if (status.dropped_frames > 0) {
|
||||
reset_dv1394();
|
||||
} else {
|
||||
for (int i = 0; i < status.n_clear_frames; i++) {
|
||||
copy_DV_frame();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
where copy_DV_frame() reads or writes on the dv1394 file descriptor
|
||||
(read/write mode) or copies data to/from the mmap ringbuffer and
|
||||
then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new
|
||||
frames are availble (mmap mode).
|
||||
|
||||
reset_dv1394() is called in the event of a buffer
|
||||
underflow/overflow or a halt in the DV stream (e.g. due to a 1394
|
||||
bus reset). To guarantee recovery from the error, this function
|
||||
should close the dv1394 file descriptor (and munmap() all
|
||||
ringbuffer mappings, if you are using them), then re-open the
|
||||
dv1394 device (and re-map the ringbuffer).
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* maximum number of frames in the ringbuffer */
|
||||
#define DV1394_MAX_FRAMES 32
|
||||
|
||||
/* number of *full* isochronous packets per DV frame */
|
||||
#define DV1394_NTSC_PACKETS_PER_FRAME 250
|
||||
#define DV1394_PAL_PACKETS_PER_FRAME 300
|
||||
|
||||
/* size of one frame's worth of DV data, in bytes */
|
||||
#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME)
|
||||
#define DV1394_PAL_FRAME_SIZE (480 * DV1394_PAL_PACKETS_PER_FRAME)
|
||||
|
||||
|
||||
/* ioctl() commands */
|
||||
#include "ieee1394-ioctl.h"
|
||||
|
||||
|
||||
enum pal_or_ntsc {
|
||||
DV1394_NTSC = 0,
|
||||
DV1394_PAL
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* this is the argument to DV1394_INIT */
|
||||
struct dv1394_init {
|
||||
/* DV1394_API_VERSION */
|
||||
unsigned int api_version;
|
||||
|
||||
/* isochronous transmission channel to use */
|
||||
unsigned int channel;
|
||||
|
||||
/* number of frames in the ringbuffer. Must be at least 2
|
||||
and at most DV1394_MAX_FRAMES. */
|
||||
unsigned int n_frames;
|
||||
|
||||
/* send/receive PAL or NTSC video format */
|
||||
enum pal_or_ntsc format;
|
||||
|
||||
/* the following are used only for transmission */
|
||||
|
||||
/* set these to zero unless you want a
|
||||
non-default empty packet rate (see below) */
|
||||
unsigned long cip_n;
|
||||
unsigned long cip_d;
|
||||
|
||||
/* set this to zero unless you want a
|
||||
non-default SYT cycle offset (default = 3 cycles) */
|
||||
unsigned int syt_offset;
|
||||
};
|
||||
|
||||
/* NOTE: you may only allocate the DV frame ringbuffer once each time
|
||||
you open the dv1394 device. DV1394_INIT will fail if you call it a
|
||||
second time with different 'n_frames' or 'format' arguments (which
|
||||
would imply a different size for the ringbuffer). If you need a
|
||||
different buffer size, simply close and re-open the device, then
|
||||
initialize it with your new settings. */
|
||||
|
||||
/* Q: What are cip_n and cip_d? */
|
||||
|
||||
/*
|
||||
A: DV video streams do not utilize 100% of the potential bandwidth offered
|
||||
by IEEE 1394 (FireWire). To achieve the correct rate of data transmission,
|
||||
DV devices must periodically insert empty packets into the 1394 data stream.
|
||||
Typically there is one empty packet per 14-16 data-carrying packets.
|
||||
|
||||
Some DV devices will accept a wide range of empty packet rates, while others
|
||||
require a precise rate. If the dv1394 driver produces empty packets at
|
||||
a rate that your device does not accept, you may see ugly patterns on the
|
||||
DV output, or even no output at all.
|
||||
|
||||
The default empty packet insertion rate seems to work for many people; if
|
||||
your DV output is stable, you can simply ignore this discussion. However,
|
||||
we have exposed the empty packet rate as a parameter to support devices that
|
||||
do not work with the default rate.
|
||||
|
||||
The decision to insert an empty packet is made with a numerator/denominator
|
||||
algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D.
|
||||
You can alter the empty packet rate by passing non-zero values for cip_n
|
||||
and cip_d to the INIT ioctl.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
struct dv1394_status {
|
||||
/* this embedded init struct returns the current dv1394
|
||||
parameters in use */
|
||||
struct dv1394_init init;
|
||||
|
||||
/* the ringbuffer frame that is currently being
|
||||
displayed. (-1 if the device is not transmitting anything) */
|
||||
int active_frame;
|
||||
|
||||
/* index of the first buffer (ahead of active_frame) that
|
||||
is ready to be filled with data */
|
||||
unsigned int first_clear_frame;
|
||||
|
||||
/* how many buffers, including first_clear_buffer, are
|
||||
ready to be filled with data */
|
||||
unsigned int n_clear_frames;
|
||||
|
||||
/* how many times the DV stream has underflowed, overflowed,
|
||||
or otherwise encountered an error, since the previous call
|
||||
to DV1394_GET_STATUS */
|
||||
unsigned int dropped_frames;
|
||||
|
||||
/* N.B. The dropped_frames counter is only a lower bound on the actual
|
||||
number of dropped frames, with the special case that if dropped_frames
|
||||
is zero, then it is guaranteed that NO frames have been dropped
|
||||
since the last call to DV1394_GET_STATUS.
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
#endif /* _DV_1394_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,234 +0,0 @@
|
||||
/*
|
||||
* eth1394.h -- Ethernet driver for Linux IEEE-1394 Subsystem
|
||||
*
|
||||
* Copyright (C) 2000 Bonin Franck <boninf@free.fr>
|
||||
* (C) 2001 Ben Collins <bcollins@debian.org>
|
||||
*
|
||||
* Mainly based on work by Emanuel Pirker and Andreas E. Bombe
|
||||
*
|
||||
* 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 __ETH1394_H
|
||||
#define __ETH1394_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "ieee1394.h"
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
/* Register for incoming packets. This is 4096 bytes, which supports up to
|
||||
* S3200 (per Table 16-3 of IEEE 1394b-2002). */
|
||||
#define ETHER1394_REGION_ADDR_LEN 4096
|
||||
|
||||
/* GASP identifier numbers for IPv4 over IEEE 1394 */
|
||||
#define ETHER1394_GASP_SPECIFIER_ID 0x00005E
|
||||
#define ETHER1394_GASP_SPECIFIER_ID_HI ((0x00005E >> 8) & 0xffff)
|
||||
#define ETHER1394_GASP_SPECIFIER_ID_LO (0x00005E & 0xff)
|
||||
#define ETHER1394_GASP_VERSION 1
|
||||
|
||||
#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* for GASP header */
|
||||
|
||||
#define ETHER1394_GASP_BUFFERS 16
|
||||
|
||||
#define NODE_SET (ALL_NODES + 1) /* Node set == 64 */
|
||||
|
||||
enum eth1394_bc_states { ETHER1394_BC_ERROR,
|
||||
ETHER1394_BC_RUNNING,
|
||||
ETHER1394_BC_STOPPED };
|
||||
|
||||
|
||||
/* Private structure for our ethernet driver */
|
||||
struct eth1394_priv {
|
||||
struct hpsb_host *host; /* The card for this dev */
|
||||
u16 bc_maxpayload; /* Max broadcast payload */
|
||||
u8 bc_sspd; /* Max broadcast speed */
|
||||
u64 local_fifo; /* Local FIFO Address */
|
||||
spinlock_t lock; /* Private lock */
|
||||
int broadcast_channel; /* Async stream Broadcast Channel */
|
||||
enum eth1394_bc_states bc_state; /* broadcast channel state */
|
||||
struct hpsb_iso *iso; /* Async stream recv handle */
|
||||
int bc_dgl; /* Outgoing broadcast datagram label */
|
||||
struct list_head ip_node_list; /* List of IP capable nodes */
|
||||
struct unit_directory *ud_list[ALL_NODES]; /* Cached unit dir list */
|
||||
|
||||
struct work_struct wake; /* Wake up after xmit failure */
|
||||
struct net_device *wake_dev; /* Stupid backlink for .wake */
|
||||
nodeid_t wake_node; /* Destination of failed xmit */
|
||||
};
|
||||
|
||||
|
||||
/* Define a fake hardware header format for the networking core. Note that
|
||||
* header size cannot exceed 16 bytes as that is the size of the header cache.
|
||||
* Also, we do not need the source address in the header so we omit it and
|
||||
* keep the header to under 16 bytes */
|
||||
#define ETH1394_ALEN (8)
|
||||
#define ETH1394_HLEN (10)
|
||||
|
||||
struct eth1394hdr {
|
||||
unsigned char h_dest[ETH1394_ALEN]; /* destination eth1394 addr */
|
||||
__be16 h_proto; /* packet type ID field */
|
||||
} __attribute__((packed));
|
||||
|
||||
static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (struct eth1394hdr *)skb_mac_header(skb);
|
||||
}
|
||||
|
||||
typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
|
||||
|
||||
/* IP1394 headers */
|
||||
|
||||
/* Unfragmented */
|
||||
#if defined __BIG_ENDIAN_BITFIELD
|
||||
struct eth1394_uf_hdr {
|
||||
u16 lf:2;
|
||||
u16 res:14;
|
||||
__be16 ether_type; /* Ethernet packet type */
|
||||
} __attribute__((packed));
|
||||
#elif defined __LITTLE_ENDIAN_BITFIELD
|
||||
struct eth1394_uf_hdr {
|
||||
u16 res:14;
|
||||
u16 lf:2;
|
||||
__be16 ether_type;
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
#error Unknown bit field type
|
||||
#endif
|
||||
|
||||
/* First fragment */
|
||||
#if defined __BIG_ENDIAN_BITFIELD
|
||||
struct eth1394_ff_hdr {
|
||||
u16 lf:2;
|
||||
u16 res1:2;
|
||||
u16 dg_size:12; /* Datagram size */
|
||||
__be16 ether_type; /* Ethernet packet type */
|
||||
u16 dgl; /* Datagram label */
|
||||
u16 res2;
|
||||
} __attribute__((packed));
|
||||
#elif defined __LITTLE_ENDIAN_BITFIELD
|
||||
struct eth1394_ff_hdr {
|
||||
u16 dg_size:12;
|
||||
u16 res1:2;
|
||||
u16 lf:2;
|
||||
__be16 ether_type;
|
||||
u16 dgl;
|
||||
u16 res2;
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
#error Unknown bit field type
|
||||
#endif
|
||||
|
||||
/* XXX: Subsequent fragments, including last */
|
||||
#if defined __BIG_ENDIAN_BITFIELD
|
||||
struct eth1394_sf_hdr {
|
||||
u16 lf:2;
|
||||
u16 res1:2;
|
||||
u16 dg_size:12; /* Datagram size */
|
||||
u16 res2:4;
|
||||
u16 fg_off:12; /* Fragment offset */
|
||||
u16 dgl; /* Datagram label */
|
||||
u16 res3;
|
||||
} __attribute__((packed));
|
||||
#elif defined __LITTLE_ENDIAN_BITFIELD
|
||||
struct eth1394_sf_hdr {
|
||||
u16 dg_size:12;
|
||||
u16 res1:2;
|
||||
u16 lf:2;
|
||||
u16 fg_off:12;
|
||||
u16 res2:4;
|
||||
u16 dgl;
|
||||
u16 res3;
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
#error Unknown bit field type
|
||||
#endif
|
||||
|
||||
#if defined __BIG_ENDIAN_BITFIELD
|
||||
struct eth1394_common_hdr {
|
||||
u16 lf:2;
|
||||
u16 pad1:14;
|
||||
} __attribute__((packed));
|
||||
#elif defined __LITTLE_ENDIAN_BITFIELD
|
||||
struct eth1394_common_hdr {
|
||||
u16 pad1:14;
|
||||
u16 lf:2;
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
#error Unknown bit field type
|
||||
#endif
|
||||
|
||||
struct eth1394_hdr_words {
|
||||
u16 word1;
|
||||
u16 word2;
|
||||
u16 word3;
|
||||
u16 word4;
|
||||
};
|
||||
|
||||
union eth1394_hdr {
|
||||
struct eth1394_common_hdr common;
|
||||
struct eth1394_uf_hdr uf;
|
||||
struct eth1394_ff_hdr ff;
|
||||
struct eth1394_sf_hdr sf;
|
||||
struct eth1394_hdr_words words;
|
||||
};
|
||||
|
||||
/* End of IP1394 headers */
|
||||
|
||||
/* Fragment types */
|
||||
#define ETH1394_HDR_LF_UF 0 /* unfragmented */
|
||||
#define ETH1394_HDR_LF_FF 1 /* first fragment */
|
||||
#define ETH1394_HDR_LF_LF 2 /* last fragment */
|
||||
#define ETH1394_HDR_LF_IF 3 /* interior fragment */
|
||||
|
||||
#define IP1394_HW_ADDR_LEN 16 /* As per RFC */
|
||||
|
||||
/* Our arp packet (ARPHRD_IEEE1394) */
|
||||
struct eth1394_arp {
|
||||
u16 hw_type; /* 0x0018 */
|
||||
u16 proto_type; /* 0x0806 */
|
||||
u8 hw_addr_len; /* 16 */
|
||||
u8 ip_addr_len; /* 4 */
|
||||
u16 opcode; /* ARP Opcode */
|
||||
/* Above is exactly the same format as struct arphdr */
|
||||
|
||||
__be64 s_uniq_id; /* Sender's 64bit EUI */
|
||||
u8 max_rec; /* Sender's max packet size */
|
||||
u8 sspd; /* Sender's max speed */
|
||||
__be16 fifo_hi; /* hi 16bits of sender's FIFO addr */
|
||||
__be32 fifo_lo; /* lo 32bits of sender's FIFO addr */
|
||||
u32 sip; /* Sender's IP Address */
|
||||
u32 tip; /* IP Address of requested hw addr */
|
||||
};
|
||||
|
||||
/* Network timeout */
|
||||
#define ETHER1394_TIMEOUT 100000
|
||||
|
||||
/* This is our task struct. It's used for the packet complete callback. */
|
||||
struct packet_task {
|
||||
struct sk_buff *skb;
|
||||
int outstanding_pkts;
|
||||
eth1394_tx_type tx_type;
|
||||
int max_payload;
|
||||
struct hpsb_packet *packet;
|
||||
struct eth1394_priv *priv;
|
||||
union eth1394_hdr hdr;
|
||||
u64 addr;
|
||||
u16 dest_node;
|
||||
};
|
||||
|
||||
#endif /* __ETH1394_H */
|
@ -1,691 +0,0 @@
|
||||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* Copyright (C) 1999 Andreas E. Bombe
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*
|
||||
*
|
||||
* Contributions:
|
||||
*
|
||||
* Christian Toegel <christian.toegel@gmx.at>
|
||||
* unregister address space
|
||||
*
|
||||
* Manfred Weihs <weihs@ict.tuwien.ac.at>
|
||||
* unregister address space
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include "ieee1394.h"
|
||||
#include "ieee1394_types.h"
|
||||
#include "hosts.h"
|
||||
#include "ieee1394_core.h"
|
||||
#include "highlevel.h"
|
||||
#include "nodemgr.h"
|
||||
|
||||
|
||||
struct hl_host_info {
|
||||
struct list_head list;
|
||||
struct hpsb_host *host;
|
||||
size_t size;
|
||||
unsigned long key;
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
||||
static LIST_HEAD(hl_drivers);
|
||||
static DECLARE_RWSEM(hl_drivers_sem);
|
||||
|
||||
static LIST_HEAD(hl_irqs);
|
||||
static DEFINE_RWLOCK(hl_irqs_lock);
|
||||
|
||||
static DEFINE_RWLOCK(addr_space_lock);
|
||||
|
||||
|
||||
static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
|
||||
struct hpsb_host *host)
|
||||
{
|
||||
struct hl_host_info *hi = NULL;
|
||||
|
||||
if (!hl || !host)
|
||||
return NULL;
|
||||
|
||||
read_lock(&hl->host_info_lock);
|
||||
list_for_each_entry(hi, &hl->host_info_list, list) {
|
||||
if (hi->host == host) {
|
||||
read_unlock(&hl->host_info_lock);
|
||||
return hi;
|
||||
}
|
||||
}
|
||||
read_unlock(&hl->host_info_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host
|
||||
*
|
||||
* Returns a per @host and @hl driver data structure that was previously stored
|
||||
* by hpsb_create_hostinfo.
|
||||
*/
|
||||
void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
|
||||
{
|
||||
struct hl_host_info *hi = hl_get_hostinfo(hl, host);
|
||||
|
||||
return hi ? hi->data : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host
|
||||
*
|
||||
* Allocate a hostinfo pointer backed by memory with @data_size and bind it to
|
||||
* to this @hl driver and @host. If @data_size is zero, then the return here is
|
||||
* only valid for error checking.
|
||||
*/
|
||||
void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
size_t data_size)
|
||||
{
|
||||
struct hl_host_info *hi;
|
||||
void *data;
|
||||
unsigned long flags;
|
||||
|
||||
hi = hl_get_hostinfo(hl, host);
|
||||
if (hi) {
|
||||
HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already"
|
||||
" exists", hl->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hi = kzalloc(sizeof(*hi) + data_size, GFP_ATOMIC);
|
||||
if (!hi)
|
||||
return NULL;
|
||||
|
||||
if (data_size) {
|
||||
data = hi->data = hi + 1;
|
||||
hi->size = data_size;
|
||||
} else
|
||||
data = hi;
|
||||
|
||||
hi->host = host;
|
||||
|
||||
write_lock_irqsave(&hl->host_info_lock, flags);
|
||||
list_add_tail(&hi->list, &hl->host_info_list);
|
||||
write_unlock_irqrestore(&hl->host_info_lock, flags);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_set_hostinfo - set the hostinfo pointer to something useful
|
||||
*
|
||||
* Usually follows a call to hpsb_create_hostinfo, where the size is 0.
|
||||
*/
|
||||
int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
void *data)
|
||||
{
|
||||
struct hl_host_info *hi;
|
||||
|
||||
hi = hl_get_hostinfo(hl, host);
|
||||
if (hi) {
|
||||
if (!hi->size && !hi->data) {
|
||||
hi->data = data;
|
||||
return 0;
|
||||
} else
|
||||
HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo "
|
||||
"already has data", hl->name);
|
||||
} else
|
||||
HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
|
||||
hl->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_destroy_hostinfo - free and remove a hostinfo pointer
|
||||
*
|
||||
* Free and remove the hostinfo pointer bound to this @hl driver and @host.
|
||||
*/
|
||||
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
|
||||
{
|
||||
struct hl_host_info *hi;
|
||||
|
||||
hi = hl_get_hostinfo(hl, host);
|
||||
if (hi) {
|
||||
unsigned long flags;
|
||||
write_lock_irqsave(&hl->host_info_lock, flags);
|
||||
list_del(&hi->list);
|
||||
write_unlock_irqrestore(&hl->host_info_lock, flags);
|
||||
kfree(hi);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo
|
||||
*
|
||||
* Sets an alternate lookup key for the hostinfo bound to this @hl driver and
|
||||
* @host.
|
||||
*/
|
||||
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
unsigned long key)
|
||||
{
|
||||
struct hl_host_info *hi;
|
||||
|
||||
hi = hl_get_hostinfo(hl, host);
|
||||
if (hi)
|
||||
hi->key = key;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key
|
||||
*/
|
||||
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
|
||||
{
|
||||
struct hl_host_info *hi;
|
||||
void *data = NULL;
|
||||
|
||||
if (!hl)
|
||||
return NULL;
|
||||
|
||||
read_lock(&hl->host_info_lock);
|
||||
list_for_each_entry(hi, &hl->host_info_list, list) {
|
||||
if (hi->key == key) {
|
||||
data = hi->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&hl->host_info_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
|
||||
{
|
||||
struct hpsb_highlevel *hl = __data;
|
||||
|
||||
hl->add_host(host);
|
||||
|
||||
if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
|
||||
HPSB_ERR("Failed to generate Configuration ROM image for host "
|
||||
"%s-%d", hl->name, host->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_register_highlevel - register highlevel driver
|
||||
*
|
||||
* The name pointer in @hl has to stay valid at all times because the string is
|
||||
* not copied.
|
||||
*/
|
||||
void hpsb_register_highlevel(struct hpsb_highlevel *hl)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
hpsb_init_highlevel(hl);
|
||||
INIT_LIST_HEAD(&hl->addr_list);
|
||||
|
||||
down_write(&hl_drivers_sem);
|
||||
list_add_tail(&hl->hl_list, &hl_drivers);
|
||||
up_write(&hl_drivers_sem);
|
||||
|
||||
write_lock_irqsave(&hl_irqs_lock, flags);
|
||||
list_add_tail(&hl->irq_list, &hl_irqs);
|
||||
write_unlock_irqrestore(&hl_irqs_lock, flags);
|
||||
|
||||
if (hl->add_host)
|
||||
nodemgr_for_each_host(hl, highlevel_for_each_host_reg);
|
||||
return;
|
||||
}
|
||||
|
||||
static void __delete_addr(struct hpsb_address_serve *as)
|
||||
{
|
||||
list_del(&as->host_list);
|
||||
list_del(&as->hl_list);
|
||||
kfree(as);
|
||||
}
|
||||
|
||||
static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
int update_cr)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct list_head *lh, *next;
|
||||
struct hpsb_address_serve *as;
|
||||
|
||||
/* First, let the highlevel driver unreg */
|
||||
if (hl->remove_host)
|
||||
hl->remove_host(host);
|
||||
|
||||
/* Remove any addresses that are matched for this highlevel driver
|
||||
* and this particular host. */
|
||||
write_lock_irqsave(&addr_space_lock, flags);
|
||||
list_for_each_safe (lh, next, &hl->addr_list) {
|
||||
as = list_entry(lh, struct hpsb_address_serve, hl_list);
|
||||
if (as->host == host)
|
||||
__delete_addr(as);
|
||||
}
|
||||
write_unlock_irqrestore(&addr_space_lock, flags);
|
||||
|
||||
/* Now update the config-rom to reflect anything removed by the
|
||||
* highlevel driver. */
|
||||
if (update_cr && host->update_config_rom &&
|
||||
hpsb_update_config_rom_image(host) < 0)
|
||||
HPSB_ERR("Failed to generate Configuration ROM image for host "
|
||||
"%s-%d", hl->name, host->id);
|
||||
|
||||
/* Finally remove all the host info associated between these two. */
|
||||
hpsb_destroy_hostinfo(hl, host);
|
||||
}
|
||||
|
||||
static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
|
||||
{
|
||||
struct hpsb_highlevel *hl = __data;
|
||||
|
||||
__unregister_host(hl, host, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_unregister_highlevel - unregister highlevel driver
|
||||
*/
|
||||
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
write_lock_irqsave(&hl_irqs_lock, flags);
|
||||
list_del(&hl->irq_list);
|
||||
write_unlock_irqrestore(&hl_irqs_lock, flags);
|
||||
|
||||
down_write(&hl_drivers_sem);
|
||||
list_del(&hl->hl_list);
|
||||
up_write(&hl_drivers_sem);
|
||||
|
||||
nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space
|
||||
*
|
||||
* @start and @end are 48 bit pointers and have to be quadlet aligned.
|
||||
* @end points to the first address behind the handled addresses. This
|
||||
* function can be called multiple times for a single hpsb_highlevel @hl to
|
||||
* implement sparse register sets. The requested region must not overlap any
|
||||
* previously allocated region, otherwise registering will fail.
|
||||
*
|
||||
* It returns true for successful allocation. Address spaces can be
|
||||
* unregistered with hpsb_unregister_addrspace. All remaining address spaces
|
||||
* are automatically deallocated together with the hpsb_highlevel @hl.
|
||||
*/
|
||||
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
|
||||
struct hpsb_host *host,
|
||||
const struct hpsb_address_ops *ops,
|
||||
u64 size, u64 alignment,
|
||||
u64 start, u64 end)
|
||||
{
|
||||
struct hpsb_address_serve *as, *a1, *a2;
|
||||
struct list_head *entry;
|
||||
u64 retval = CSR1212_INVALID_ADDR_SPACE;
|
||||
unsigned long flags;
|
||||
u64 align_mask = ~(alignment - 1);
|
||||
|
||||
if ((alignment & 3) || (alignment > 0x800000000000ULL) ||
|
||||
(hweight64(alignment) != 1)) {
|
||||
HPSB_ERR("%s called with invalid alignment: 0x%048llx",
|
||||
__func__, (unsigned long long)alignment);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* default range,
|
||||
* avoids controller's posted write area (see OHCI 1.1 clause 1.5) */
|
||||
if (start == CSR1212_INVALID_ADDR_SPACE &&
|
||||
end == CSR1212_INVALID_ADDR_SPACE) {
|
||||
start = host->middle_addr_space;
|
||||
end = CSR1212_ALL_SPACE_END;
|
||||
}
|
||||
|
||||
if (((start|end) & ~align_mask) || (start >= end) ||
|
||||
(end > CSR1212_ALL_SPACE_END)) {
|
||||
HPSB_ERR("%s called with invalid addresses "
|
||||
"(start = %012Lx end = %012Lx)", __func__,
|
||||
(unsigned long long)start,(unsigned long long)end);
|
||||
return retval;
|
||||
}
|
||||
|
||||
as = kmalloc(sizeof(*as), GFP_KERNEL);
|
||||
if (!as)
|
||||
return retval;
|
||||
|
||||
INIT_LIST_HEAD(&as->host_list);
|
||||
INIT_LIST_HEAD(&as->hl_list);
|
||||
as->op = ops;
|
||||
as->host = host;
|
||||
|
||||
write_lock_irqsave(&addr_space_lock, flags);
|
||||
list_for_each(entry, &host->addr_space) {
|
||||
u64 a1sa, a1ea;
|
||||
u64 a2sa, a2ea;
|
||||
|
||||
a1 = list_entry(entry, struct hpsb_address_serve, host_list);
|
||||
a2 = list_entry(entry->next, struct hpsb_address_serve,
|
||||
host_list);
|
||||
|
||||
a1sa = a1->start & align_mask;
|
||||
a1ea = (a1->end + alignment -1) & align_mask;
|
||||
a2sa = a2->start & align_mask;
|
||||
a2ea = (a2->end + alignment -1) & align_mask;
|
||||
|
||||
if ((a2sa - a1ea >= size) && (a2sa - start >= size) &&
|
||||
(a2sa > start)) {
|
||||
as->start = max(start, a1ea);
|
||||
as->end = as->start + size;
|
||||
list_add(&as->host_list, entry);
|
||||
list_add_tail(&as->hl_list, &hl->addr_list);
|
||||
retval = as->start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
write_unlock_irqrestore(&addr_space_lock, flags);
|
||||
|
||||
if (retval == CSR1212_INVALID_ADDR_SPACE)
|
||||
kfree(as);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_register_addrspace - register a host address space
|
||||
*
|
||||
* @start and @end are 48 bit pointers and have to be quadlet aligned.
|
||||
* @end points to the first address behind the handled addresses. This
|
||||
* function can be called multiple times for a single hpsb_highlevel @hl to
|
||||
* implement sparse register sets. The requested region must not overlap any
|
||||
* previously allocated region, otherwise registering will fail.
|
||||
*
|
||||
* It returns true for successful allocation. Address spaces can be
|
||||
* unregistered with hpsb_unregister_addrspace. All remaining address spaces
|
||||
* are automatically deallocated together with the hpsb_highlevel @hl.
|
||||
*/
|
||||
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
const struct hpsb_address_ops *ops,
|
||||
u64 start, u64 end)
|
||||
{
|
||||
struct hpsb_address_serve *as;
|
||||
struct list_head *lh;
|
||||
int retval = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (((start|end) & 3) || (start >= end) ||
|
||||
(end > CSR1212_ALL_SPACE_END)) {
|
||||
HPSB_ERR("%s called with invalid addresses", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
as = kmalloc(sizeof(*as), GFP_KERNEL);
|
||||
if (!as)
|
||||
return 0;
|
||||
|
||||
INIT_LIST_HEAD(&as->host_list);
|
||||
INIT_LIST_HEAD(&as->hl_list);
|
||||
as->op = ops;
|
||||
as->start = start;
|
||||
as->end = end;
|
||||
as->host = host;
|
||||
|
||||
write_lock_irqsave(&addr_space_lock, flags);
|
||||
list_for_each(lh, &host->addr_space) {
|
||||
struct hpsb_address_serve *as_this =
|
||||
list_entry(lh, struct hpsb_address_serve, host_list);
|
||||
struct hpsb_address_serve *as_next =
|
||||
list_entry(lh->next, struct hpsb_address_serve,
|
||||
host_list);
|
||||
|
||||
if (as_this->end > as->start)
|
||||
break;
|
||||
|
||||
if (as_next->start >= as->end) {
|
||||
list_add(&as->host_list, lh);
|
||||
list_add_tail(&as->hl_list, &hl->addr_list);
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
write_unlock_irqrestore(&addr_space_lock, flags);
|
||||
|
||||
if (retval == 0)
|
||||
kfree(as);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
u64 start)
|
||||
{
|
||||
int retval = 0;
|
||||
struct hpsb_address_serve *as;
|
||||
struct list_head *lh, *next;
|
||||
unsigned long flags;
|
||||
|
||||
write_lock_irqsave(&addr_space_lock, flags);
|
||||
list_for_each_safe (lh, next, &hl->addr_list) {
|
||||
as = list_entry(lh, struct hpsb_address_serve, hl_list);
|
||||
if (as->start == start && as->host == host) {
|
||||
__delete_addr(as);
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
write_unlock_irqrestore(&addr_space_lock, flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct hpsb_address_ops dummy_ops;
|
||||
|
||||
/* dummy address spaces as lower and upper bounds of the host's a.s. list */
|
||||
static void init_hpsb_highlevel(struct hpsb_host *host)
|
||||
{
|
||||
INIT_LIST_HEAD(&host->dummy_zero_addr.host_list);
|
||||
INIT_LIST_HEAD(&host->dummy_zero_addr.hl_list);
|
||||
INIT_LIST_HEAD(&host->dummy_max_addr.host_list);
|
||||
INIT_LIST_HEAD(&host->dummy_max_addr.hl_list);
|
||||
|
||||
host->dummy_zero_addr.op = host->dummy_max_addr.op = &dummy_ops;
|
||||
|
||||
host->dummy_zero_addr.start = host->dummy_zero_addr.end = 0;
|
||||
host->dummy_max_addr.start = host->dummy_max_addr.end = ((u64) 1) << 48;
|
||||
|
||||
list_add_tail(&host->dummy_zero_addr.host_list, &host->addr_space);
|
||||
list_add_tail(&host->dummy_max_addr.host_list, &host->addr_space);
|
||||
}
|
||||
|
||||
void highlevel_add_host(struct hpsb_host *host)
|
||||
{
|
||||
struct hpsb_highlevel *hl;
|
||||
|
||||
init_hpsb_highlevel(host);
|
||||
|
||||
down_read(&hl_drivers_sem);
|
||||
list_for_each_entry(hl, &hl_drivers, hl_list) {
|
||||
if (hl->add_host)
|
||||
hl->add_host(host);
|
||||
}
|
||||
up_read(&hl_drivers_sem);
|
||||
if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
|
||||
HPSB_ERR("Failed to generate Configuration ROM image for host "
|
||||
"%s-%d", hl->name, host->id);
|
||||
}
|
||||
|
||||
void highlevel_remove_host(struct hpsb_host *host)
|
||||
{
|
||||
struct hpsb_highlevel *hl;
|
||||
|
||||
down_read(&hl_drivers_sem);
|
||||
list_for_each_entry(hl, &hl_drivers, hl_list)
|
||||
__unregister_host(hl, host, 0);
|
||||
up_read(&hl_drivers_sem);
|
||||
}
|
||||
|
||||
void highlevel_host_reset(struct hpsb_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct hpsb_highlevel *hl;
|
||||
|
||||
read_lock_irqsave(&hl_irqs_lock, flags);
|
||||
list_for_each_entry(hl, &hl_irqs, irq_list) {
|
||||
if (hl->host_reset)
|
||||
hl->host_reset(host);
|
||||
}
|
||||
read_unlock_irqrestore(&hl_irqs_lock, flags);
|
||||
}
|
||||
|
||||
void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
|
||||
void *data, size_t length)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct hpsb_highlevel *hl;
|
||||
int cts = ((quadlet_t *)data)[0] >> 4;
|
||||
|
||||
read_lock_irqsave(&hl_irqs_lock, flags);
|
||||
list_for_each_entry(hl, &hl_irqs, irq_list) {
|
||||
if (hl->fcp_request)
|
||||
hl->fcp_request(host, nodeid, direction, cts, data,
|
||||
length);
|
||||
}
|
||||
read_unlock_irqrestore(&hl_irqs_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64:
|
||||
*
|
||||
* These functions are called to handle transactions. They are called when a
|
||||
* packet arrives. The flags argument contains the second word of the first
|
||||
* header quadlet of the incoming packet (containing transaction label, retry
|
||||
* code, transaction code and priority). These functions either return a
|
||||
* response code or a negative number. In the first case a response will be
|
||||
* generated. In the latter case, no response will be sent and the driver which
|
||||
* handled the request will send the response itself.
|
||||
*/
|
||||
int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
|
||||
unsigned int length, u16 flags)
|
||||
{
|
||||
struct hpsb_address_serve *as;
|
||||
unsigned int partlength;
|
||||
int rcode = RCODE_ADDRESS_ERROR;
|
||||
|
||||
read_lock(&addr_space_lock);
|
||||
list_for_each_entry(as, &host->addr_space, host_list) {
|
||||
if (as->start > addr)
|
||||
break;
|
||||
|
||||
if (as->end > addr) {
|
||||
partlength = min(as->end - addr, (u64) length);
|
||||
|
||||
if (as->op->read)
|
||||
rcode = as->op->read(host, nodeid, data,
|
||||
addr, partlength, flags);
|
||||
else
|
||||
rcode = RCODE_TYPE_ERROR;
|
||||
|
||||
data += partlength;
|
||||
length -= partlength;
|
||||
addr += partlength;
|
||||
|
||||
if ((rcode != RCODE_COMPLETE) || !length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&addr_space_lock);
|
||||
|
||||
if (length && (rcode == RCODE_COMPLETE))
|
||||
rcode = RCODE_ADDRESS_ERROR;
|
||||
return rcode;
|
||||
}
|
||||
|
||||
int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
|
||||
u64 addr, unsigned int length, u16 flags)
|
||||
{
|
||||
struct hpsb_address_serve *as;
|
||||
unsigned int partlength;
|
||||
int rcode = RCODE_ADDRESS_ERROR;
|
||||
|
||||
read_lock(&addr_space_lock);
|
||||
list_for_each_entry(as, &host->addr_space, host_list) {
|
||||
if (as->start > addr)
|
||||
break;
|
||||
|
||||
if (as->end > addr) {
|
||||
partlength = min(as->end - addr, (u64) length);
|
||||
|
||||
if (as->op->write)
|
||||
rcode = as->op->write(host, nodeid, destid,
|
||||
data, addr, partlength,
|
||||
flags);
|
||||
else
|
||||
rcode = RCODE_TYPE_ERROR;
|
||||
|
||||
data += partlength;
|
||||
length -= partlength;
|
||||
addr += partlength;
|
||||
|
||||
if ((rcode != RCODE_COMPLETE) || !length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&addr_space_lock);
|
||||
|
||||
if (length && (rcode == RCODE_COMPLETE))
|
||||
rcode = RCODE_ADDRESS_ERROR;
|
||||
return rcode;
|
||||
}
|
||||
|
||||
int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
|
||||
u16 flags)
|
||||
{
|
||||
struct hpsb_address_serve *as;
|
||||
int rcode = RCODE_ADDRESS_ERROR;
|
||||
|
||||
read_lock(&addr_space_lock);
|
||||
list_for_each_entry(as, &host->addr_space, host_list) {
|
||||
if (as->start > addr)
|
||||
break;
|
||||
|
||||
if (as->end > addr) {
|
||||
if (as->op->lock)
|
||||
rcode = as->op->lock(host, nodeid, store, addr,
|
||||
data, arg, ext_tcode,
|
||||
flags);
|
||||
else
|
||||
rcode = RCODE_TYPE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&addr_space_lock);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
|
||||
u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
|
||||
u16 flags)
|
||||
{
|
||||
struct hpsb_address_serve *as;
|
||||
int rcode = RCODE_ADDRESS_ERROR;
|
||||
|
||||
read_lock(&addr_space_lock);
|
||||
|
||||
list_for_each_entry(as, &host->addr_space, host_list) {
|
||||
if (as->start > addr)
|
||||
break;
|
||||
|
||||
if (as->end > addr) {
|
||||
if (as->op->lock64)
|
||||
rcode = as->op->lock64(host, nodeid, store,
|
||||
addr, data, arg,
|
||||
ext_tcode, flags);
|
||||
else
|
||||
rcode = RCODE_TYPE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&addr_space_lock);
|
||||
return rcode;
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
#ifndef IEEE1394_HIGHLEVEL_H
|
||||
#define IEEE1394_HIGHLEVEL_H
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct module;
|
||||
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
struct hpsb_host;
|
||||
|
||||
/* internal to ieee1394 core */
|
||||
struct hpsb_address_serve {
|
||||
struct list_head host_list; /* per host list */
|
||||
struct list_head hl_list; /* hpsb_highlevel list */
|
||||
const struct hpsb_address_ops *op;
|
||||
struct hpsb_host *host;
|
||||
u64 start; /* first address handled, quadlet aligned */
|
||||
u64 end; /* first address behind, quadlet aligned */
|
||||
};
|
||||
|
||||
/* Only the following structures are of interest to actual highlevel drivers. */
|
||||
|
||||
struct hpsb_highlevel {
|
||||
const char *name;
|
||||
|
||||
/* Any of the following pointers can legally be NULL. */
|
||||
|
||||
/* New host initialized. Will also be called during
|
||||
* hpsb_register_highlevel for all hosts already installed. */
|
||||
void (*add_host)(struct hpsb_host *host);
|
||||
|
||||
/* Host about to be removed. Will also be called during
|
||||
* hpsb_unregister_highlevel once for each host. */
|
||||
void (*remove_host)(struct hpsb_host *host);
|
||||
|
||||
/* Host experienced bus reset with possible configuration changes.
|
||||
* Note that this one may occur during interrupt/bottom half handling.
|
||||
* You can not expect to be able to do stock hpsb_reads. */
|
||||
void (*host_reset)(struct hpsb_host *host);
|
||||
|
||||
/* A write request was received on either the FCP_COMMAND (direction =
|
||||
* 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
|
||||
* contains the cts field (first byte of data). */
|
||||
void (*fcp_request)(struct hpsb_host *host, int nodeid, int direction,
|
||||
int cts, u8 *data, size_t length);
|
||||
|
||||
/* These are initialized by the subsystem when the
|
||||
* hpsb_higlevel is registered. */
|
||||
struct list_head hl_list;
|
||||
struct list_head irq_list;
|
||||
struct list_head addr_list;
|
||||
|
||||
struct list_head host_info_list;
|
||||
rwlock_t host_info_lock;
|
||||
};
|
||||
|
||||
struct hpsb_address_ops {
|
||||
/*
|
||||
* Null function pointers will make the respective operation complete
|
||||
* with RCODE_TYPE_ERROR. Makes for easy to implement read-only
|
||||
* registers (just leave everything but read NULL).
|
||||
*
|
||||
* All functions shall return appropriate IEEE 1394 rcodes.
|
||||
*/
|
||||
|
||||
/* These functions have to implement block reads for themselves.
|
||||
*
|
||||
* These functions either return a response code or a negative number.
|
||||
* In the first case a response will be generated. In the latter case,
|
||||
* no response will be sent and the driver which handled the request
|
||||
* will send the response itself. */
|
||||
int (*read)(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
|
||||
u64 addr, size_t length, u16 flags);
|
||||
int (*write)(struct hpsb_host *host, int nodeid, int destid,
|
||||
quadlet_t *data, u64 addr, size_t length, u16 flags);
|
||||
|
||||
/* Lock transactions: write results of ext_tcode operation into
|
||||
* *store. */
|
||||
int (*lock)(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
|
||||
u16 flags);
|
||||
int (*lock64)(struct hpsb_host *host, int nodeid, octlet_t *store,
|
||||
u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
|
||||
u16 flags);
|
||||
};
|
||||
|
||||
void highlevel_add_host(struct hpsb_host *host);
|
||||
void highlevel_remove_host(struct hpsb_host *host);
|
||||
void highlevel_host_reset(struct hpsb_host *host);
|
||||
int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
|
||||
unsigned int length, u16 flags);
|
||||
int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
|
||||
u64 addr, unsigned int length, u16 flags);
|
||||
int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
|
||||
u16 flags);
|
||||
int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
|
||||
u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
|
||||
u16 flags);
|
||||
void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
|
||||
void *data, size_t length);
|
||||
|
||||
/**
|
||||
* hpsb_init_highlevel - initialize a struct hpsb_highlevel
|
||||
*
|
||||
* This is only necessary if hpsb_get_hostinfo_bykey can be called
|
||||
* before hpsb_register_highlevel.
|
||||
*/
|
||||
static inline void hpsb_init_highlevel(struct hpsb_highlevel *hl)
|
||||
{
|
||||
rwlock_init(&hl->host_info_lock);
|
||||
INIT_LIST_HEAD(&hl->host_info_list);
|
||||
}
|
||||
void hpsb_register_highlevel(struct hpsb_highlevel *hl);
|
||||
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
|
||||
|
||||
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
|
||||
struct hpsb_host *host,
|
||||
const struct hpsb_address_ops *ops,
|
||||
u64 size, u64 alignment,
|
||||
u64 start, u64 end);
|
||||
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
const struct hpsb_address_ops *ops,
|
||||
u64 start, u64 end);
|
||||
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
u64 start);
|
||||
|
||||
void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
|
||||
void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
size_t data_size);
|
||||
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
|
||||
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
unsigned long key);
|
||||
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
|
||||
int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
void *data);
|
||||
|
||||
#endif /* IEEE1394_HIGHLEVEL_H */
|
@ -1,249 +0,0 @@
|
||||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* Low level (host adapter) management.
|
||||
*
|
||||
* Copyright (C) 1999 Andreas E. Bombe
|
||||
* Copyright (C) 1999 Emanuel Pirker
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "csr1212.h"
|
||||
#include "ieee1394.h"
|
||||
#include "ieee1394_types.h"
|
||||
#include "hosts.h"
|
||||
#include "ieee1394_core.h"
|
||||
#include "highlevel.h"
|
||||
#include "nodemgr.h"
|
||||
#include "csr.h"
|
||||
#include "config_roms.h"
|
||||
|
||||
|
||||
static void delayed_reset_bus(struct work_struct *work)
|
||||
{
|
||||
struct hpsb_host *host =
|
||||
container_of(work, struct hpsb_host, delayed_reset.work);
|
||||
u8 generation = host->csr.generation + 1;
|
||||
|
||||
/* The generation field rolls over to 2 rather than 0 per IEEE
|
||||
* 1394a-2000. */
|
||||
if (generation > 0xf || generation < 2)
|
||||
generation = 2;
|
||||
|
||||
csr_set_bus_info_generation(host->csr.rom, generation);
|
||||
if (csr1212_generate_csr_image(host->csr.rom) != CSR1212_SUCCESS) {
|
||||
/* CSR image creation failed.
|
||||
* Reset generation field and do not issue a bus reset. */
|
||||
csr_set_bus_info_generation(host->csr.rom,
|
||||
host->csr.generation);
|
||||
return;
|
||||
}
|
||||
|
||||
host->csr.generation = generation;
|
||||
|
||||
host->update_config_rom = 0;
|
||||
if (host->driver->set_hw_config_rom)
|
||||
host->driver->set_hw_config_rom(host,
|
||||
host->csr.rom->bus_info_data);
|
||||
|
||||
host->csr.gen_timestamp[host->csr.generation] = jiffies;
|
||||
hpsb_reset_bus(host, SHORT_RESET);
|
||||
}
|
||||
|
||||
static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dummy_isoctl(struct hpsb_iso *iso, enum isoctl_cmd command,
|
||||
unsigned long arg)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct hpsb_host_driver dummy_driver = {
|
||||
.transmit_packet = dummy_transmit_packet,
|
||||
.devctl = dummy_devctl,
|
||||
.isoctl = dummy_isoctl
|
||||
};
|
||||
|
||||
static int alloc_hostnum_cb(struct hpsb_host *host, void *__data)
|
||||
{
|
||||
int *hostnum = __data;
|
||||
|
||||
if (host->id == *hostnum)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_MUTEX(host_num_alloc);
|
||||
|
||||
/**
|
||||
* hpsb_alloc_host - allocate a new host controller.
|
||||
* @drv: the driver that will manage the host controller
|
||||
* @extra: number of extra bytes to allocate for the driver
|
||||
*
|
||||
* Allocate a &hpsb_host and initialize the general subsystem specific
|
||||
* fields. If the driver needs to store per host data, as drivers
|
||||
* usually do, the amount of memory required can be specified by the
|
||||
* @extra parameter. Once allocated, the driver should initialize the
|
||||
* driver specific parts, enable the controller and make it available
|
||||
* to the general subsystem using hpsb_add_host().
|
||||
*
|
||||
* Return Value: a pointer to the &hpsb_host if successful, %NULL if
|
||||
* no memory was available.
|
||||
*/
|
||||
struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
|
||||
struct device *dev)
|
||||
{
|
||||
struct hpsb_host *h;
|
||||
int i;
|
||||
int hostnum = 0;
|
||||
|
||||
h = kzalloc(sizeof(*h) + extra, GFP_KERNEL);
|
||||
if (!h)
|
||||
return NULL;
|
||||
|
||||
h->csr.rom = csr1212_create_csr(&csr_bus_ops, CSR_BUS_INFO_SIZE, h);
|
||||
if (!h->csr.rom)
|
||||
goto fail;
|
||||
|
||||
h->hostdata = h + 1;
|
||||
h->driver = drv;
|
||||
|
||||
INIT_LIST_HEAD(&h->pending_packets);
|
||||
INIT_LIST_HEAD(&h->addr_space);
|
||||
|
||||
for (i = 2; i < 16; i++)
|
||||
h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
|
||||
|
||||
atomic_set(&h->generation, 0);
|
||||
|
||||
INIT_DELAYED_WORK(&h->delayed_reset, delayed_reset_bus);
|
||||
|
||||
init_timer(&h->timeout);
|
||||
h->timeout.data = (unsigned long) h;
|
||||
h->timeout.function = abort_timedouts;
|
||||
h->timeout_interval = HZ / 20; /* 50ms, half of minimum SPLIT_TIMEOUT */
|
||||
|
||||
h->topology_map = h->csr.topology_map + 3;
|
||||
h->speed_map = (u8 *)(h->csr.speed_map + 2);
|
||||
|
||||
mutex_lock(&host_num_alloc);
|
||||
while (nodemgr_for_each_host(&hostnum, alloc_hostnum_cb))
|
||||
hostnum++;
|
||||
mutex_unlock(&host_num_alloc);
|
||||
h->id = hostnum;
|
||||
|
||||
memcpy(&h->device, &nodemgr_dev_template_host, sizeof(h->device));
|
||||
h->device.parent = dev;
|
||||
set_dev_node(&h->device, dev_to_node(dev));
|
||||
dev_set_name(&h->device, "fw-host%d", h->id);
|
||||
|
||||
h->host_dev.parent = &h->device;
|
||||
h->host_dev.class = &hpsb_host_class;
|
||||
dev_set_name(&h->host_dev, "fw-host%d", h->id);
|
||||
|
||||
if (device_register(&h->device))
|
||||
goto fail;
|
||||
if (device_register(&h->host_dev)) {
|
||||
device_unregister(&h->device);
|
||||
goto fail;
|
||||
}
|
||||
get_device(&h->device);
|
||||
|
||||
return h;
|
||||
|
||||
fail:
|
||||
kfree(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hpsb_add_host(struct hpsb_host *host)
|
||||
{
|
||||
if (hpsb_default_host_entry(host))
|
||||
return -ENOMEM;
|
||||
|
||||
highlevel_add_host(host);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hpsb_resume_host(struct hpsb_host *host)
|
||||
{
|
||||
if (host->driver->set_hw_config_rom)
|
||||
host->driver->set_hw_config_rom(host,
|
||||
host->csr.rom->bus_info_data);
|
||||
host->driver->devctl(host, RESET_BUS, SHORT_RESET);
|
||||
}
|
||||
|
||||
void hpsb_remove_host(struct hpsb_host *host)
|
||||
{
|
||||
host->is_shutdown = 1;
|
||||
|
||||
cancel_delayed_work(&host->delayed_reset);
|
||||
flush_scheduled_work();
|
||||
|
||||
host->driver = &dummy_driver;
|
||||
highlevel_remove_host(host);
|
||||
|
||||
device_unregister(&host->host_dev);
|
||||
device_unregister(&host->device);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_update_config_rom_image - updates configuration ROM image of a host
|
||||
*
|
||||
* Updates the configuration ROM image of a host. rom_version must be the
|
||||
* current version, otherwise it will fail with return value -1. If this
|
||||
* host does not support config-rom-update, it will return -%EINVAL.
|
||||
* Return value 0 indicates success.
|
||||
*/
|
||||
int hpsb_update_config_rom_image(struct hpsb_host *host)
|
||||
{
|
||||
unsigned long reset_delay;
|
||||
int next_gen = host->csr.generation + 1;
|
||||
|
||||
if (!host->update_config_rom)
|
||||
return -EINVAL;
|
||||
|
||||
if (next_gen > 0xf)
|
||||
next_gen = 2;
|
||||
|
||||
/* Stop the delayed interrupt, we're about to change the config rom and
|
||||
* it would be a waste to do a bus reset twice. */
|
||||
cancel_delayed_work(&host->delayed_reset);
|
||||
|
||||
/* IEEE 1394a-2000 prohibits using the same generation number
|
||||
* twice in a 60 second period. */
|
||||
if (time_before(jiffies, host->csr.gen_timestamp[next_gen] + 60 * HZ))
|
||||
/* Wait 60 seconds from the last time this generation number was
|
||||
* used. */
|
||||
reset_delay =
|
||||
(60 * HZ) + host->csr.gen_timestamp[next_gen] - jiffies;
|
||||
else
|
||||
/* Wait 1 second in case some other code wants to change the
|
||||
* Config ROM in the near future. */
|
||||
reset_delay = HZ;
|
||||
|
||||
PREPARE_DELAYED_WORK(&host->delayed_reset, delayed_reset_bus);
|
||||
schedule_delayed_work(&host->delayed_reset, reset_delay);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,201 +0,0 @@
|
||||
#ifndef _IEEE1394_HOSTS_H
|
||||
#define _IEEE1394_HOSTS_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
struct pci_dev;
|
||||
struct module;
|
||||
|
||||
#include "ieee1394_types.h"
|
||||
#include "csr.h"
|
||||
#include "highlevel.h"
|
||||
|
||||
struct hpsb_packet;
|
||||
struct hpsb_iso;
|
||||
|
||||
struct hpsb_host {
|
||||
struct list_head host_list;
|
||||
|
||||
void *hostdata;
|
||||
|
||||
atomic_t generation;
|
||||
|
||||
struct list_head pending_packets;
|
||||
struct timer_list timeout;
|
||||
unsigned long timeout_interval;
|
||||
|
||||
int node_count; /* number of identified nodes on this bus */
|
||||
int selfid_count; /* total number of SelfIDs received */
|
||||
int nodes_active; /* number of nodes with active link layer */
|
||||
|
||||
nodeid_t node_id; /* node ID of this host */
|
||||
nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
|
||||
nodeid_t busmgr_id; /* ID of this bus' bus manager */
|
||||
|
||||
/* this nodes state */
|
||||
unsigned in_bus_reset:1;
|
||||
unsigned is_shutdown:1;
|
||||
unsigned resume_packet_sent:1;
|
||||
|
||||
/* this nodes' duties on the bus */
|
||||
unsigned is_root:1;
|
||||
unsigned is_cycmst:1;
|
||||
unsigned is_irm:1;
|
||||
unsigned is_busmgr:1;
|
||||
|
||||
int reset_retries;
|
||||
quadlet_t *topology_map;
|
||||
u8 *speed_map;
|
||||
|
||||
int id;
|
||||
struct hpsb_host_driver *driver;
|
||||
struct pci_dev *pdev;
|
||||
struct device device;
|
||||
struct device host_dev;
|
||||
|
||||
struct delayed_work delayed_reset;
|
||||
unsigned config_roms:31;
|
||||
unsigned update_config_rom:1;
|
||||
|
||||
struct list_head addr_space;
|
||||
u64 low_addr_space; /* upper bound of physical DMA area */
|
||||
u64 middle_addr_space; /* upper bound of posted write area */
|
||||
|
||||
u8 speed[ALL_NODES]; /* speed between each node and local node */
|
||||
|
||||
/* per node tlabel allocation */
|
||||
u8 next_tl[ALL_NODES];
|
||||
struct { DECLARE_BITMAP(map, 64); } tl_pool[ALL_NODES];
|
||||
|
||||
struct csr_control csr;
|
||||
|
||||
struct hpsb_address_serve dummy_zero_addr;
|
||||
struct hpsb_address_serve dummy_max_addr;
|
||||
};
|
||||
|
||||
enum devctl_cmd {
|
||||
/* Host is requested to reset its bus and cancel all outstanding async
|
||||
* requests. If arg == 1, it shall also attempt to become root on the
|
||||
* bus. Return void. */
|
||||
RESET_BUS,
|
||||
|
||||
/* Arg is void, return value is the hardware cycle counter value. */
|
||||
GET_CYCLE_COUNTER,
|
||||
|
||||
/* Set the hardware cycle counter to the value in arg, return void.
|
||||
* FIXME - setting is probably not required. */
|
||||
SET_CYCLE_COUNTER,
|
||||
|
||||
/* Configure hardware for new bus ID in arg, return void. */
|
||||
SET_BUS_ID,
|
||||
|
||||
/* If arg true, start sending cycle start packets, stop if arg == 0.
|
||||
* Return void. */
|
||||
ACT_CYCLE_MASTER,
|
||||
|
||||
/* Cancel all outstanding async requests without resetting the bus.
|
||||
* Return void. */
|
||||
CANCEL_REQUESTS,
|
||||
};
|
||||
|
||||
enum isoctl_cmd {
|
||||
/* rawiso API - see iso.h for the meanings of these commands
|
||||
* (they correspond exactly to the hpsb_iso_* API functions)
|
||||
* INIT = allocate resources
|
||||
* START = begin transmission/reception
|
||||
* STOP = halt transmission/reception
|
||||
* QUEUE/RELEASE = produce/consume packets
|
||||
* SHUTDOWN = deallocate resources
|
||||
*/
|
||||
|
||||
XMIT_INIT,
|
||||
XMIT_START,
|
||||
XMIT_STOP,
|
||||
XMIT_QUEUE,
|
||||
XMIT_SHUTDOWN,
|
||||
|
||||
RECV_INIT,
|
||||
RECV_LISTEN_CHANNEL, /* multi-channel only */
|
||||
RECV_UNLISTEN_CHANNEL, /* multi-channel only */
|
||||
RECV_SET_CHANNEL_MASK, /* multi-channel only; arg is a *u64 */
|
||||
RECV_START,
|
||||
RECV_STOP,
|
||||
RECV_RELEASE,
|
||||
RECV_SHUTDOWN,
|
||||
RECV_FLUSH
|
||||
};
|
||||
|
||||
enum reset_types {
|
||||
/* 166 microsecond reset -- only type of reset available on
|
||||
non-1394a capable controllers */
|
||||
LONG_RESET,
|
||||
|
||||
/* Short (arbitrated) reset -- only available on 1394a capable
|
||||
controllers */
|
||||
SHORT_RESET,
|
||||
|
||||
/* Variants that set force_root before issueing the bus reset */
|
||||
LONG_RESET_FORCE_ROOT, SHORT_RESET_FORCE_ROOT,
|
||||
|
||||
/* Variants that clear force_root before issueing the bus reset */
|
||||
LONG_RESET_NO_FORCE_ROOT, SHORT_RESET_NO_FORCE_ROOT
|
||||
};
|
||||
|
||||
struct hpsb_host_driver {
|
||||
struct module *owner;
|
||||
const char *name;
|
||||
|
||||
/* The hardware driver may optionally support a function that is used
|
||||
* to set the hardware ConfigROM if the hardware supports handling
|
||||
* reads to the ConfigROM on its own. */
|
||||
void (*set_hw_config_rom)(struct hpsb_host *host,
|
||||
__be32 *config_rom);
|
||||
|
||||
/* This function shall implement packet transmission based on
|
||||
* packet->type. It shall CRC both parts of the packet (unless
|
||||
* packet->type == raw) and do byte-swapping as necessary or instruct
|
||||
* the hardware to do so. It can return immediately after the packet
|
||||
* was queued for sending. After sending, hpsb_sent_packet() has to be
|
||||
* called. Return 0 on success, negative errno on failure.
|
||||
* NOTE: The function must be callable in interrupt context.
|
||||
*/
|
||||
int (*transmit_packet)(struct hpsb_host *host,
|
||||
struct hpsb_packet *packet);
|
||||
|
||||
/* This function requests miscellanous services from the driver, see
|
||||
* above for command codes and expected actions. Return -1 for unknown
|
||||
* command, though that should never happen.
|
||||
*/
|
||||
int (*devctl)(struct hpsb_host *host, enum devctl_cmd command, int arg);
|
||||
|
||||
/* ISO transmission/reception functions. Return 0 on success, -1
|
||||
* (or -EXXX errno code) on failure. If the low-level driver does not
|
||||
* support the new ISO API, set isoctl to NULL.
|
||||
*/
|
||||
int (*isoctl)(struct hpsb_iso *iso, enum isoctl_cmd command,
|
||||
unsigned long arg);
|
||||
|
||||
/* This function is mainly to redirect local CSR reads/locks to the iso
|
||||
* management registers (bus manager id, bandwidth available, channels
|
||||
* available) to the hardware registers in OHCI. reg is 0,1,2,3 for bus
|
||||
* mgr, bwdth avail, ch avail hi, ch avail lo respectively (the same ids
|
||||
* as OHCI uses). data and compare are the new data and expected data
|
||||
* respectively, return value is the old value.
|
||||
*/
|
||||
quadlet_t (*hw_csr_reg) (struct hpsb_host *host, int reg,
|
||||
quadlet_t data, quadlet_t compare);
|
||||
};
|
||||
|
||||
struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
|
||||
struct device *dev);
|
||||
int hpsb_add_host(struct hpsb_host *host);
|
||||
void hpsb_resume_host(struct hpsb_host *host);
|
||||
void hpsb_remove_host(struct hpsb_host *host);
|
||||
int hpsb_update_config_rom_image(struct hpsb_host *host);
|
||||
|
||||
#endif /* _IEEE1394_HOSTS_H */
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Base file for all ieee1394 ioctl's.
|
||||
* Linux-1394 has allocated base '#' with a range of 0x00-0x3f.
|
||||
*/
|
||||
|
||||
#ifndef __IEEE1394_IOCTL_H
|
||||
#define __IEEE1394_IOCTL_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* DV1394 Gets 10 */
|
||||
|
||||
/* Get the driver ready to transmit video. pass a struct dv1394_init* as
|
||||
* the parameter (see below), or NULL to get default parameters */
|
||||
#define DV1394_IOC_INIT _IOW('#', 0x06, struct dv1394_init)
|
||||
|
||||
/* Stop transmitting video and free the ringbuffer */
|
||||
#define DV1394_IOC_SHUTDOWN _IO ('#', 0x07)
|
||||
|
||||
/* Submit N new frames to be transmitted, where the index of the first new
|
||||
* frame is first_clear_buffer, and the index of the last new frame is
|
||||
* (first_clear_buffer + N) % n_frames */
|
||||
#define DV1394_IOC_SUBMIT_FRAMES _IO ('#', 0x08)
|
||||
|
||||
/* Block until N buffers are clear (pass N as the parameter) Because we
|
||||
* re-transmit the last frame on underrun, there will at most be n_frames
|
||||
* - 1 clear frames at any time */
|
||||
#define DV1394_IOC_WAIT_FRAMES _IO ('#', 0x09)
|
||||
|
||||
/* Capture new frames that have been received, where the index of the
|
||||
* first new frame is first_clear_buffer, and the index of the last new
|
||||
* frame is (first_clear_buffer + N) % n_frames */
|
||||
#define DV1394_IOC_RECEIVE_FRAMES _IO ('#', 0x0a)
|
||||
|
||||
/* Tell card to start receiving DMA */
|
||||
#define DV1394_IOC_START_RECEIVE _IO ('#', 0x0b)
|
||||
|
||||
/* Pass a struct dv1394_status* as the parameter */
|
||||
#define DV1394_IOC_GET_STATUS _IOR('#', 0x0c, struct dv1394_status)
|
||||
|
||||
|
||||
/* Video1394 Gets 10 */
|
||||
|
||||
#define VIDEO1394_IOC_LISTEN_CHANNEL \
|
||||
_IOWR('#', 0x10, struct video1394_mmap)
|
||||
#define VIDEO1394_IOC_UNLISTEN_CHANNEL \
|
||||
_IOW ('#', 0x11, int)
|
||||
#define VIDEO1394_IOC_LISTEN_QUEUE_BUFFER \
|
||||
_IOW ('#', 0x12, struct video1394_wait)
|
||||
#define VIDEO1394_IOC_LISTEN_WAIT_BUFFER \
|
||||
_IOWR('#', 0x13, struct video1394_wait)
|
||||
#define VIDEO1394_IOC_TALK_CHANNEL \
|
||||
_IOWR('#', 0x14, struct video1394_mmap)
|
||||
#define VIDEO1394_IOC_UNTALK_CHANNEL \
|
||||
_IOW ('#', 0x15, int)
|
||||
/*
|
||||
* This one is broken: it really wanted
|
||||
* "sizeof (struct video1394_wait) + sizeof (struct video1394_queue_variable)"
|
||||
* but got just a "size_t"
|
||||
*/
|
||||
#define VIDEO1394_IOC_TALK_QUEUE_BUFFER \
|
||||
_IOW ('#', 0x16, size_t)
|
||||
#define VIDEO1394_IOC_TALK_WAIT_BUFFER \
|
||||
_IOW ('#', 0x17, struct video1394_wait)
|
||||
#define VIDEO1394_IOC_LISTEN_POLL_BUFFER \
|
||||
_IOWR('#', 0x18, struct video1394_wait)
|
||||
|
||||
|
||||
/* Raw1394's ISO interface */
|
||||
#define RAW1394_IOC_ISO_XMIT_INIT \
|
||||
_IOW ('#', 0x1a, struct raw1394_iso_status)
|
||||
#define RAW1394_IOC_ISO_RECV_INIT \
|
||||
_IOWR('#', 0x1b, struct raw1394_iso_status)
|
||||
#define RAW1394_IOC_ISO_RECV_START \
|
||||
_IOC (_IOC_WRITE, '#', 0x1c, sizeof(int) * 3)
|
||||
#define RAW1394_IOC_ISO_XMIT_START \
|
||||
_IOC (_IOC_WRITE, '#', 0x1d, sizeof(int) * 2)
|
||||
#define RAW1394_IOC_ISO_XMIT_RECV_STOP \
|
||||
_IO ('#', 0x1e)
|
||||
#define RAW1394_IOC_ISO_GET_STATUS \
|
||||
_IOR ('#', 0x1f, struct raw1394_iso_status)
|
||||
#define RAW1394_IOC_ISO_SHUTDOWN \
|
||||
_IO ('#', 0x20)
|
||||
#define RAW1394_IOC_ISO_QUEUE_ACTIVITY \
|
||||
_IO ('#', 0x21)
|
||||
#define RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL \
|
||||
_IOW ('#', 0x22, unsigned char)
|
||||
#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL \
|
||||
_IOW ('#', 0x23, unsigned char)
|
||||
#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK \
|
||||
_IOW ('#', 0x24, __u64)
|
||||
#define RAW1394_IOC_ISO_RECV_PACKETS \
|
||||
_IOW ('#', 0x25, struct raw1394_iso_packets)
|
||||
#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS \
|
||||
_IOW ('#', 0x26, unsigned int)
|
||||
#define RAW1394_IOC_ISO_XMIT_PACKETS \
|
||||
_IOW ('#', 0x27, struct raw1394_iso_packets)
|
||||
#define RAW1394_IOC_ISO_XMIT_SYNC \
|
||||
_IO ('#', 0x28)
|
||||
#define RAW1394_IOC_ISO_RECV_FLUSH \
|
||||
_IO ('#', 0x29)
|
||||
#define RAW1394_IOC_GET_CYCLE_TIMER \
|
||||
_IOR ('#', 0x30, struct raw1394_cycle_timer)
|
||||
|
||||
#endif /* __IEEE1394_IOCTL_H */
|
@ -1,220 +0,0 @@
|
||||
/*
|
||||
* Generic IEEE 1394 definitions
|
||||
*/
|
||||
|
||||
#ifndef _IEEE1394_IEEE1394_H
|
||||
#define _IEEE1394_IEEE1394_H
|
||||
|
||||
#define TCODE_WRITEQ 0x0
|
||||
#define TCODE_WRITEB 0x1
|
||||
#define TCODE_WRITE_RESPONSE 0x2
|
||||
#define TCODE_READQ 0x4
|
||||
#define TCODE_READB 0x5
|
||||
#define TCODE_READQ_RESPONSE 0x6
|
||||
#define TCODE_READB_RESPONSE 0x7
|
||||
#define TCODE_CYCLE_START 0x8
|
||||
#define TCODE_LOCK_REQUEST 0x9
|
||||
#define TCODE_ISO_DATA 0xa
|
||||
#define TCODE_STREAM_DATA 0xa
|
||||
#define TCODE_LOCK_RESPONSE 0xb
|
||||
|
||||
#define RCODE_COMPLETE 0x0
|
||||
#define RCODE_CONFLICT_ERROR 0x4
|
||||
#define RCODE_DATA_ERROR 0x5
|
||||
#define RCODE_TYPE_ERROR 0x6
|
||||
#define RCODE_ADDRESS_ERROR 0x7
|
||||
|
||||
#define EXTCODE_MASK_SWAP 0x1
|
||||
#define EXTCODE_COMPARE_SWAP 0x2
|
||||
#define EXTCODE_FETCH_ADD 0x3
|
||||
#define EXTCODE_LITTLE_ADD 0x4
|
||||
#define EXTCODE_BOUNDED_ADD 0x5
|
||||
#define EXTCODE_WRAP_ADD 0x6
|
||||
|
||||
#define ACK_COMPLETE 0x1
|
||||
#define ACK_PENDING 0x2
|
||||
#define ACK_BUSY_X 0x4
|
||||
#define ACK_BUSY_A 0x5
|
||||
#define ACK_BUSY_B 0x6
|
||||
#define ACK_TARDY 0xb
|
||||
#define ACK_CONFLICT_ERROR 0xc
|
||||
#define ACK_DATA_ERROR 0xd
|
||||
#define ACK_TYPE_ERROR 0xe
|
||||
#define ACK_ADDRESS_ERROR 0xf
|
||||
|
||||
/* Non-standard "ACK codes" for internal use */
|
||||
#define ACKX_NONE (-1)
|
||||
#define ACKX_SEND_ERROR (-2)
|
||||
#define ACKX_ABORTED (-3)
|
||||
#define ACKX_TIMEOUT (-4)
|
||||
|
||||
#define IEEE1394_SPEED_100 0x00
|
||||
#define IEEE1394_SPEED_200 0x01
|
||||
#define IEEE1394_SPEED_400 0x02
|
||||
#define IEEE1394_SPEED_800 0x03
|
||||
#define IEEE1394_SPEED_1600 0x04
|
||||
#define IEEE1394_SPEED_3200 0x05
|
||||
#define IEEE1394_SPEED_MAX IEEE1394_SPEED_3200
|
||||
|
||||
/* Maps speed values above to a string representation */
|
||||
extern const char *hpsb_speedto_str[];
|
||||
|
||||
/* 1394a cable PHY packets */
|
||||
#define SELFID_PWRCL_NO_POWER 0x0
|
||||
#define SELFID_PWRCL_PROVIDE_15W 0x1
|
||||
#define SELFID_PWRCL_PROVIDE_30W 0x2
|
||||
#define SELFID_PWRCL_PROVIDE_45W 0x3
|
||||
#define SELFID_PWRCL_USE_1W 0x4
|
||||
#define SELFID_PWRCL_USE_3W 0x5
|
||||
#define SELFID_PWRCL_USE_6W 0x6
|
||||
#define SELFID_PWRCL_USE_10W 0x7
|
||||
|
||||
#define SELFID_PORT_CHILD 0x3
|
||||
#define SELFID_PORT_PARENT 0x2
|
||||
#define SELFID_PORT_NCONN 0x1
|
||||
#define SELFID_PORT_NONE 0x0
|
||||
|
||||
#define SELFID_SPEED_UNKNOWN 0x3 /* 1394b PHY */
|
||||
|
||||
#define PHYPACKET_LINKON 0x40000000
|
||||
#define PHYPACKET_PHYCONFIG_R 0x00800000
|
||||
#define PHYPACKET_PHYCONFIG_T 0x00400000
|
||||
#define EXTPHYPACKET_TYPE_PING 0x00000000
|
||||
#define EXTPHYPACKET_TYPE_REMOTEACCESS_BASE 0x00040000
|
||||
#define EXTPHYPACKET_TYPE_REMOTEACCESS_PAGED 0x00140000
|
||||
#define EXTPHYPACKET_TYPE_REMOTEREPLY_BASE 0x000C0000
|
||||
#define EXTPHYPACKET_TYPE_REMOTEREPLY_PAGED 0x001C0000
|
||||
#define EXTPHYPACKET_TYPE_REMOTECOMMAND 0x00200000
|
||||
#define EXTPHYPACKET_TYPE_REMOTECONFIRMATION 0x00280000
|
||||
#define EXTPHYPACKET_TYPE_RESUME 0x003C0000
|
||||
|
||||
#define EXTPHYPACKET_TYPEMASK 0xC0FC0000
|
||||
|
||||
#define PHYPACKET_PORT_SHIFT 24
|
||||
#define PHYPACKET_GAPCOUNT_SHIFT 16
|
||||
|
||||
/* 1394a PHY register map bitmasks */
|
||||
#define PHY_00_PHYSICAL_ID 0xFC
|
||||
#define PHY_00_R 0x02 /* Root */
|
||||
#define PHY_00_PS 0x01 /* Power Status*/
|
||||
#define PHY_01_RHB 0x80 /* Root Hold-Off */
|
||||
#define PHY_01_IBR 0x80 /* Initiate Bus Reset */
|
||||
#define PHY_01_GAP_COUNT 0x3F
|
||||
#define PHY_02_EXTENDED 0xE0 /* 0x7 for 1394a-compliant PHY */
|
||||
#define PHY_02_TOTAL_PORTS 0x1F
|
||||
#define PHY_03_MAX_SPEED 0xE0
|
||||
#define PHY_03_DELAY 0x0F
|
||||
#define PHY_04_LCTRL 0x80 /* Link Active Report Control */
|
||||
#define PHY_04_CONTENDER 0x40
|
||||
#define PHY_04_JITTER 0x38
|
||||
#define PHY_04_PWR_CLASS 0x07 /* Power Class */
|
||||
#define PHY_05_WATCHDOG 0x80
|
||||
#define PHY_05_ISBR 0x40 /* Initiate Short Bus Reset */
|
||||
#define PHY_05_LOOP 0x20 /* Loop Detect */
|
||||
#define PHY_05_PWR_FAIL 0x10 /* Cable Power Failure Detect */
|
||||
#define PHY_05_TIMEOUT 0x08 /* Arbitration State Machine Timeout */
|
||||
#define PHY_05_PORT_EVENT 0x04 /* Port Event Detect */
|
||||
#define PHY_05_ENAB_ACCEL 0x02 /* Enable Arbitration Acceleration */
|
||||
#define PHY_05_ENAB_MULTI 0x01 /* Ena. Multispeed Packet Concatenation */
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/* '1' '3' '9' '4' in ASCII */
|
||||
#define IEEE1394_BUSID_MAGIC cpu_to_be32(0x31333934)
|
||||
|
||||
#ifdef __BIG_ENDIAN_BITFIELD
|
||||
|
||||
struct selfid {
|
||||
u32 packet_identifier:2; /* always binary 10 */
|
||||
u32 phy_id:6;
|
||||
/* byte */
|
||||
u32 extended:1; /* if true is struct ext_selfid */
|
||||
u32 link_active:1;
|
||||
u32 gap_count:6;
|
||||
/* byte */
|
||||
u32 speed:2;
|
||||
u32 phy_delay:2;
|
||||
u32 contender:1;
|
||||
u32 power_class:3;
|
||||
/* byte */
|
||||
u32 port0:2;
|
||||
u32 port1:2;
|
||||
u32 port2:2;
|
||||
u32 initiated_reset:1;
|
||||
u32 more_packets:1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ext_selfid {
|
||||
u32 packet_identifier:2; /* always binary 10 */
|
||||
u32 phy_id:6;
|
||||
/* byte */
|
||||
u32 extended:1; /* if false is struct selfid */
|
||||
u32 seq_nr:3;
|
||||
u32 reserved:2;
|
||||
u32 porta:2;
|
||||
/* byte */
|
||||
u32 portb:2;
|
||||
u32 portc:2;
|
||||
u32 portd:2;
|
||||
u32 porte:2;
|
||||
/* byte */
|
||||
u32 portf:2;
|
||||
u32 portg:2;
|
||||
u32 porth:2;
|
||||
u32 reserved2:1;
|
||||
u32 more_packets:1;
|
||||
} __attribute__((packed));
|
||||
|
||||
#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */
|
||||
|
||||
/*
|
||||
* Note: these mean to be bit fields of a big endian SelfID as seen on a little
|
||||
* endian machine. Without swapping.
|
||||
*/
|
||||
|
||||
struct selfid {
|
||||
u32 phy_id:6;
|
||||
u32 packet_identifier:2; /* always binary 10 */
|
||||
/* byte */
|
||||
u32 gap_count:6;
|
||||
u32 link_active:1;
|
||||
u32 extended:1; /* if true is struct ext_selfid */
|
||||
/* byte */
|
||||
u32 power_class:3;
|
||||
u32 contender:1;
|
||||
u32 phy_delay:2;
|
||||
u32 speed:2;
|
||||
/* byte */
|
||||
u32 more_packets:1;
|
||||
u32 initiated_reset:1;
|
||||
u32 port2:2;
|
||||
u32 port1:2;
|
||||
u32 port0:2;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ext_selfid {
|
||||
u32 phy_id:6;
|
||||
u32 packet_identifier:2; /* always binary 10 */
|
||||
/* byte */
|
||||
u32 porta:2;
|
||||
u32 reserved:2;
|
||||
u32 seq_nr:3;
|
||||
u32 extended:1; /* if false is struct selfid */
|
||||
/* byte */
|
||||
u32 porte:2;
|
||||
u32 portd:2;
|
||||
u32 portc:2;
|
||||
u32 portb:2;
|
||||
/* byte */
|
||||
u32 more_packets:1;
|
||||
u32 reserved2:1;
|
||||
u32 porth:2;
|
||||
u32 portg:2;
|
||||
u32 portf:2;
|
||||
} __attribute__((packed));
|
||||
|
||||
#else
|
||||
#error What? PDP endian?
|
||||
#endif /* __BIG_ENDIAN_BITFIELD */
|
||||
|
||||
#endif /* _IEEE1394_IEEE1394_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,172 +0,0 @@
|
||||
#ifndef _IEEE1394_CORE_H
|
||||
#define _IEEE1394_CORE_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "hosts.h"
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
struct hpsb_packet {
|
||||
/* This struct is basically read-only for hosts with the exception of
|
||||
* the data buffer contents and driver_list. */
|
||||
|
||||
/* This can be used for host driver internal linking.
|
||||
*
|
||||
* NOTE: This must be left in init state when the driver is done
|
||||
* with it (e.g. by using list_del_init()), since the core does
|
||||
* some sanity checks to make sure the packet is not on a
|
||||
* driver_list when free'ing it. */
|
||||
struct list_head driver_list;
|
||||
|
||||
nodeid_t node_id;
|
||||
|
||||
/* hpsb_raw = send as-is, do not CRC (but still byte-swap it) */
|
||||
enum { hpsb_async, hpsb_raw } __attribute__((packed)) type;
|
||||
|
||||
/* Okay, this is core internal and a no care for hosts.
|
||||
* queued = queued for sending
|
||||
* pending = sent, waiting for response
|
||||
* complete = processing completed, successful or not
|
||||
*/
|
||||
enum {
|
||||
hpsb_unused, hpsb_queued, hpsb_pending, hpsb_complete
|
||||
} __attribute__((packed)) state;
|
||||
|
||||
/* These are core-internal. */
|
||||
signed char tlabel;
|
||||
signed char ack_code;
|
||||
unsigned char tcode;
|
||||
|
||||
unsigned expect_response:1;
|
||||
unsigned no_waiter:1;
|
||||
|
||||
/* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
|
||||
unsigned speed_code:2;
|
||||
|
||||
struct hpsb_host *host;
|
||||
unsigned int generation;
|
||||
|
||||
atomic_t refcnt;
|
||||
struct list_head queue;
|
||||
|
||||
/* Function (and possible data to pass to it) to call when this
|
||||
* packet is completed. */
|
||||
void (*complete_routine)(void *);
|
||||
void *complete_data;
|
||||
|
||||
/* Store jiffies for implementing bus timeouts. */
|
||||
unsigned long sendtime;
|
||||
|
||||
/* Core-internal. */
|
||||
size_t allocated_data_size; /* as allocated */
|
||||
|
||||
/* Sizes are in bytes. To be set by caller of hpsb_alloc_packet. */
|
||||
size_t data_size; /* as filled in */
|
||||
size_t header_size; /* as filled in, not counting the CRC */
|
||||
|
||||
/* Buffers */
|
||||
quadlet_t *data; /* can be DMA-mapped */
|
||||
quadlet_t header[5];
|
||||
quadlet_t embedded_data[0]; /* keep as last member */
|
||||
};
|
||||
|
||||
void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
|
||||
void (*routine)(void *), void *data);
|
||||
static inline struct hpsb_packet *driver_packet(struct list_head *l)
|
||||
{
|
||||
return list_entry(l, struct hpsb_packet, driver_list);
|
||||
}
|
||||
void abort_timedouts(unsigned long __opaque);
|
||||
struct hpsb_packet *hpsb_alloc_packet(size_t data_size);
|
||||
void hpsb_free_packet(struct hpsb_packet *packet);
|
||||
|
||||
/**
|
||||
* get_hpsb_generation - generation counter for the complete 1394 subsystem
|
||||
*
|
||||
* Generation gets incremented on every change in the subsystem (notably on bus
|
||||
* resets). Use the functions, not the variable.
|
||||
*/
|
||||
static inline unsigned int get_hpsb_generation(struct hpsb_host *host)
|
||||
{
|
||||
return atomic_read(&host->generation);
|
||||
}
|
||||
|
||||
int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt);
|
||||
int hpsb_send_packet(struct hpsb_packet *packet);
|
||||
int hpsb_send_packet_and_wait(struct hpsb_packet *packet);
|
||||
int hpsb_reset_bus(struct hpsb_host *host, int type);
|
||||
int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
|
||||
u64 *local_time);
|
||||
|
||||
int hpsb_bus_reset(struct hpsb_host *host);
|
||||
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
|
||||
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
|
||||
void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
|
||||
int ackcode);
|
||||
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
|
||||
int write_acked);
|
||||
|
||||
/*
|
||||
* CHARACTER DEVICE DISPATCHING
|
||||
*
|
||||
* All ieee1394 character device drivers share the same major number
|
||||
* (major 171). The 256 minor numbers are allocated to the various
|
||||
* task-specific interfaces (raw1394, video1394, dv1394, etc) in
|
||||
* blocks of 16.
|
||||
*
|
||||
* The core ieee1394.o module allocates the device number region
|
||||
* 171:0-255, the various drivers must then cdev_add() their cdev
|
||||
* objects to handle their respective sub-regions.
|
||||
*
|
||||
* Minor device number block allocations:
|
||||
*
|
||||
* Block 0 ( 0- 15) raw1394
|
||||
* Block 1 ( 16- 31) video1394
|
||||
* Block 2 ( 32- 47) dv1394
|
||||
*
|
||||
* Blocks 3-14 free for future allocation
|
||||
*
|
||||
* Block 15 (240-255) reserved for drivers under development, etc.
|
||||
*/
|
||||
|
||||
#define IEEE1394_MAJOR 171
|
||||
|
||||
#define IEEE1394_MINOR_BLOCK_RAW1394 0
|
||||
#define IEEE1394_MINOR_BLOCK_VIDEO1394 1
|
||||
#define IEEE1394_MINOR_BLOCK_DV1394 2
|
||||
#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
|
||||
|
||||
#define IEEE1394_CORE_DEV MKDEV(IEEE1394_MAJOR, 0)
|
||||
#define IEEE1394_RAW1394_DEV MKDEV(IEEE1394_MAJOR, \
|
||||
IEEE1394_MINOR_BLOCK_RAW1394 * 16)
|
||||
#define IEEE1394_VIDEO1394_DEV MKDEV(IEEE1394_MAJOR, \
|
||||
IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
|
||||
#define IEEE1394_DV1394_DEV MKDEV(IEEE1394_MAJOR, \
|
||||
IEEE1394_MINOR_BLOCK_DV1394 * 16)
|
||||
#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \
|
||||
IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
|
||||
|
||||
/**
|
||||
* ieee1394_file_to_instance - get the index within a minor number block
|
||||
*/
|
||||
static inline unsigned char ieee1394_file_to_instance(struct file *file)
|
||||
{
|
||||
int idx = cdev_index(file->f_path.dentry->d_inode);
|
||||
if (idx < 0)
|
||||
idx = 0;
|
||||
return idx;
|
||||
}
|
||||
|
||||
extern int hpsb_disable_irm;
|
||||
|
||||
/* Our sysfs bus entry */
|
||||
extern struct bus_type ieee1394_bus_type;
|
||||
extern struct class hpsb_host_class;
|
||||
extern struct class *hpsb_protocol_class;
|
||||
|
||||
#endif /* _IEEE1394_CORE_H */
|
@ -1,19 +0,0 @@
|
||||
#ifndef _IEEE1394_HOTPLUG_H
|
||||
#define _IEEE1394_HOTPLUG_H
|
||||
|
||||
/* Unit spec id and sw version entry for some protocols */
|
||||
#define AVC_UNIT_SPEC_ID_ENTRY 0x0000A02D
|
||||
#define AVC_SW_VERSION_ENTRY 0x00010001
|
||||
#define CAMERA_UNIT_SPEC_ID_ENTRY 0x0000A02D
|
||||
#define CAMERA_SW_VERSION_ENTRY 0x00000100
|
||||
|
||||
/* /include/linux/mod_devicetable.h defines:
|
||||
* IEEE1394_MATCH_VENDOR_ID
|
||||
* IEEE1394_MATCH_MODEL_ID
|
||||
* IEEE1394_MATCH_SPECIFIER_ID
|
||||
* IEEE1394_MATCH_VERSION
|
||||
* struct ieee1394_device_id
|
||||
*/
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
#endif /* _IEEE1394_HOTPLUG_H */
|
@ -1,595 +0,0 @@
|
||||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* Transaction support.
|
||||
*
|
||||
* Copyright (C) 1999 Andreas E. Bombe
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sched.h> /* because linux/wait.h is broken if CONFIG_SMP=n */
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <asm/bug.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include "ieee1394.h"
|
||||
#include "ieee1394_types.h"
|
||||
#include "hosts.h"
|
||||
#include "ieee1394_core.h"
|
||||
#include "ieee1394_transactions.h"
|
||||
|
||||
#define PREP_ASYNC_HEAD_ADDRESS(tc) \
|
||||
packet->tcode = tc; \
|
||||
packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
|
||||
| (1 << 8) | (tc << 4); \
|
||||
packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
|
||||
packet->header[2] = addr & 0xffffffff
|
||||
|
||||
#ifndef HPSB_DEBUG_TLABELS
|
||||
static
|
||||
#endif
|
||||
DEFINE_SPINLOCK(hpsb_tlabel_lock);
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
|
||||
|
||||
static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
|
||||
{
|
||||
PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
|
||||
packet->header_size = 12;
|
||||
packet->data_size = 0;
|
||||
packet->expect_response = 1;
|
||||
}
|
||||
|
||||
static void fill_async_readblock(struct hpsb_packet *packet, u64 addr,
|
||||
int length)
|
||||
{
|
||||
PREP_ASYNC_HEAD_ADDRESS(TCODE_READB);
|
||||
packet->header[3] = length << 16;
|
||||
packet->header_size = 16;
|
||||
packet->data_size = 0;
|
||||
packet->expect_response = 1;
|
||||
}
|
||||
|
||||
static void fill_async_writequad(struct hpsb_packet *packet, u64 addr,
|
||||
quadlet_t data)
|
||||
{
|
||||
PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ);
|
||||
packet->header[3] = data;
|
||||
packet->header_size = 16;
|
||||
packet->data_size = 0;
|
||||
packet->expect_response = 1;
|
||||
}
|
||||
|
||||
static void fill_async_writeblock(struct hpsb_packet *packet, u64 addr,
|
||||
int length)
|
||||
{
|
||||
PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
|
||||
packet->header[3] = length << 16;
|
||||
packet->header_size = 16;
|
||||
packet->expect_response = 1;
|
||||
packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
|
||||
}
|
||||
|
||||
static void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode,
|
||||
int length)
|
||||
{
|
||||
PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST);
|
||||
packet->header[3] = (length << 16) | extcode;
|
||||
packet->header_size = 16;
|
||||
packet->data_size = length;
|
||||
packet->expect_response = 1;
|
||||
}
|
||||
|
||||
static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data)
|
||||
{
|
||||
packet->header[0] = data;
|
||||
packet->header[1] = ~data;
|
||||
packet->header_size = 8;
|
||||
packet->data_size = 0;
|
||||
packet->expect_response = 0;
|
||||
packet->type = hpsb_raw; /* No CRC added */
|
||||
packet->speed_code = IEEE1394_SPEED_100; /* Force speed to be 100Mbps */
|
||||
}
|
||||
|
||||
static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
|
||||
int channel, int tag, int sync)
|
||||
{
|
||||
packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
|
||||
| (TCODE_STREAM_DATA << 4) | sync;
|
||||
|
||||
packet->header_size = 4;
|
||||
packet->data_size = length;
|
||||
packet->type = hpsb_async;
|
||||
packet->tcode = TCODE_ISO_DATA;
|
||||
}
|
||||
|
||||
/* same as hpsb_get_tlabel, except that it returns immediately */
|
||||
static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
|
||||
{
|
||||
unsigned long flags, *tp;
|
||||
u8 *next;
|
||||
int tlabel, n = NODEID_TO_NODE(packet->node_id);
|
||||
|
||||
/* Broadcast transactions are complete once the request has been sent.
|
||||
* Use the same transaction label for all broadcast transactions. */
|
||||
if (unlikely(n == ALL_NODES)) {
|
||||
packet->tlabel = 0;
|
||||
return 0;
|
||||
}
|
||||
tp = packet->host->tl_pool[n].map;
|
||||
next = &packet->host->next_tl[n];
|
||||
|
||||
spin_lock_irqsave(&hpsb_tlabel_lock, flags);
|
||||
tlabel = find_next_zero_bit(tp, 64, *next);
|
||||
if (tlabel > 63)
|
||||
tlabel = find_first_zero_bit(tp, 64);
|
||||
if (tlabel > 63) {
|
||||
spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
|
||||
return -EAGAIN;
|
||||
}
|
||||
__set_bit(tlabel, tp);
|
||||
*next = (tlabel + 1) & 63;
|
||||
spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
|
||||
|
||||
packet->tlabel = tlabel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_get_tlabel - allocate a transaction label
|
||||
* @packet: the packet whose tlabel and tl_pool we set
|
||||
*
|
||||
* Every asynchronous transaction on the 1394 bus needs a transaction
|
||||
* label to match the response to the request. This label has to be
|
||||
* different from any other transaction label in an outstanding request to
|
||||
* the same node to make matching possible without ambiguity.
|
||||
*
|
||||
* There are 64 different tlabels, so an allocated tlabel has to be freed
|
||||
* with hpsb_free_tlabel() after the transaction is complete (unless it's
|
||||
* reused again for the same target node).
|
||||
*
|
||||
* Return value: Zero on success, otherwise non-zero. A non-zero return
|
||||
* generally means there are no available tlabels. If this is called out
|
||||
* of interrupt or atomic context, then it will sleep until can return a
|
||||
* tlabel or a signal is received.
|
||||
*/
|
||||
int hpsb_get_tlabel(struct hpsb_packet *packet)
|
||||
{
|
||||
if (irqs_disabled() || in_atomic())
|
||||
return hpsb_get_tlabel_atomic(packet);
|
||||
|
||||
/* NB: The macro wait_event_interruptible() is called with a condition
|
||||
* argument with side effect. This is only possible because the side
|
||||
* effect does not occur until the condition became true, and
|
||||
* wait_event_interruptible() won't evaluate the condition again after
|
||||
* that. */
|
||||
return wait_event_interruptible(tlabel_wq,
|
||||
!hpsb_get_tlabel_atomic(packet));
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_free_tlabel - free an allocated transaction label
|
||||
* @packet: packet whose tlabel and tl_pool needs to be cleared
|
||||
*
|
||||
* Frees the transaction label allocated with hpsb_get_tlabel(). The
|
||||
* tlabel has to be freed after the transaction is complete (i.e. response
|
||||
* was received for a split transaction or packet was sent for a unified
|
||||
* transaction).
|
||||
*
|
||||
* A tlabel must not be freed twice.
|
||||
*/
|
||||
void hpsb_free_tlabel(struct hpsb_packet *packet)
|
||||
{
|
||||
unsigned long flags, *tp;
|
||||
int tlabel, n = NODEID_TO_NODE(packet->node_id);
|
||||
|
||||
if (unlikely(n == ALL_NODES))
|
||||
return;
|
||||
tp = packet->host->tl_pool[n].map;
|
||||
tlabel = packet->tlabel;
|
||||
BUG_ON(tlabel > 63 || tlabel < 0);
|
||||
|
||||
spin_lock_irqsave(&hpsb_tlabel_lock, flags);
|
||||
BUG_ON(!__test_and_clear_bit(tlabel, tp));
|
||||
spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
|
||||
|
||||
wake_up_interruptible(&tlabel_wq);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_packet_success - Make sense of the ack and reply codes
|
||||
*
|
||||
* Make sense of the ack and reply codes and return more convenient error codes:
|
||||
* 0 = success. -%EBUSY = node is busy, try again. -%EAGAIN = error which can
|
||||
* probably resolved by retry. -%EREMOTEIO = node suffers from an internal
|
||||
* error. -%EACCES = this transaction is not allowed on requested address.
|
||||
* -%EINVAL = invalid address at node.
|
||||
*/
|
||||
int hpsb_packet_success(struct hpsb_packet *packet)
|
||||
{
|
||||
switch (packet->ack_code) {
|
||||
case ACK_PENDING:
|
||||
switch ((packet->header[1] >> 12) & 0xf) {
|
||||
case RCODE_COMPLETE:
|
||||
return 0;
|
||||
case RCODE_CONFLICT_ERROR:
|
||||
return -EAGAIN;
|
||||
case RCODE_DATA_ERROR:
|
||||
return -EREMOTEIO;
|
||||
case RCODE_TYPE_ERROR:
|
||||
return -EACCES;
|
||||
case RCODE_ADDRESS_ERROR:
|
||||
return -EINVAL;
|
||||
default:
|
||||
HPSB_ERR("received reserved rcode %d from node %d",
|
||||
(packet->header[1] >> 12) & 0xf,
|
||||
packet->node_id);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
case ACK_BUSY_X:
|
||||
case ACK_BUSY_A:
|
||||
case ACK_BUSY_B:
|
||||
return -EBUSY;
|
||||
|
||||
case ACK_TYPE_ERROR:
|
||||
return -EACCES;
|
||||
|
||||
case ACK_COMPLETE:
|
||||
if (packet->tcode == TCODE_WRITEQ
|
||||
|| packet->tcode == TCODE_WRITEB) {
|
||||
return 0;
|
||||
} else {
|
||||
HPSB_ERR("impossible ack_complete from node %d "
|
||||
"(tcode %d)", packet->node_id, packet->tcode);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
case ACK_DATA_ERROR:
|
||||
if (packet->tcode == TCODE_WRITEB
|
||||
|| packet->tcode == TCODE_LOCK_REQUEST) {
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
HPSB_ERR("impossible ack_data_error from node %d "
|
||||
"(tcode %d)", packet->node_id, packet->tcode);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
case ACK_ADDRESS_ERROR:
|
||||
return -EINVAL;
|
||||
|
||||
case ACK_TARDY:
|
||||
case ACK_CONFLICT_ERROR:
|
||||
case ACKX_NONE:
|
||||
case ACKX_SEND_ERROR:
|
||||
case ACKX_ABORTED:
|
||||
case ACKX_TIMEOUT:
|
||||
/* error while sending */
|
||||
return -EAGAIN;
|
||||
|
||||
default:
|
||||
HPSB_ERR("got invalid ack %d from node %d (tcode %d)",
|
||||
packet->ack_code, packet->node_id, packet->tcode);
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
|
||||
u64 addr, size_t length)
|
||||
{
|
||||
struct hpsb_packet *packet;
|
||||
|
||||
if (length == 0)
|
||||
return NULL;
|
||||
|
||||
packet = hpsb_alloc_packet(length);
|
||||
if (!packet)
|
||||
return NULL;
|
||||
|
||||
packet->host = host;
|
||||
packet->node_id = node;
|
||||
|
||||
if (hpsb_get_tlabel(packet)) {
|
||||
hpsb_free_packet(packet);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (length == 4)
|
||||
fill_async_readquad(packet, addr);
|
||||
else
|
||||
fill_async_readblock(packet, addr, length);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host, nodeid_t node,
|
||||
u64 addr, quadlet_t * buffer,
|
||||
size_t length)
|
||||
{
|
||||
struct hpsb_packet *packet;
|
||||
|
||||
if (length == 0)
|
||||
return NULL;
|
||||
|
||||
packet = hpsb_alloc_packet(length);
|
||||
if (!packet)
|
||||
return NULL;
|
||||
|
||||
if (length % 4) { /* zero padding bytes */
|
||||
packet->data[length >> 2] = 0;
|
||||
}
|
||||
packet->host = host;
|
||||
packet->node_id = node;
|
||||
|
||||
if (hpsb_get_tlabel(packet)) {
|
||||
hpsb_free_packet(packet);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (length == 4) {
|
||||
fill_async_writequad(packet, addr, buffer ? *buffer : 0);
|
||||
} else {
|
||||
fill_async_writeblock(packet, addr, length);
|
||||
if (buffer)
|
||||
memcpy(packet->data, buffer, length);
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer,
|
||||
int length, int channel, int tag,
|
||||
int sync)
|
||||
{
|
||||
struct hpsb_packet *packet;
|
||||
|
||||
if (length == 0)
|
||||
return NULL;
|
||||
|
||||
packet = hpsb_alloc_packet(length);
|
||||
if (!packet)
|
||||
return NULL;
|
||||
|
||||
if (length % 4) { /* zero padding bytes */
|
||||
packet->data[length >> 2] = 0;
|
||||
}
|
||||
packet->host = host;
|
||||
|
||||
/* Because it is too difficult to determine all PHY speeds and link
|
||||
* speeds here, we use S100... */
|
||||
packet->speed_code = IEEE1394_SPEED_100;
|
||||
|
||||
/* ...and prevent hpsb_send_packet() from overriding it. */
|
||||
packet->node_id = LOCAL_BUS | ALL_NODES;
|
||||
|
||||
if (hpsb_get_tlabel(packet)) {
|
||||
hpsb_free_packet(packet);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fill_async_stream_packet(packet, length, channel, tag, sync);
|
||||
if (buffer)
|
||||
memcpy(packet->data, buffer, length);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
|
||||
u64 addr, int extcode,
|
||||
quadlet_t * data, quadlet_t arg)
|
||||
{
|
||||
struct hpsb_packet *p;
|
||||
u32 length;
|
||||
|
||||
p = hpsb_alloc_packet(8);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
p->host = host;
|
||||
p->node_id = node;
|
||||
if (hpsb_get_tlabel(p)) {
|
||||
hpsb_free_packet(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (extcode) {
|
||||
case EXTCODE_FETCH_ADD:
|
||||
case EXTCODE_LITTLE_ADD:
|
||||
length = 4;
|
||||
if (data)
|
||||
p->data[0] = *data;
|
||||
break;
|
||||
default:
|
||||
length = 8;
|
||||
if (data) {
|
||||
p->data[0] = arg;
|
||||
p->data[1] = *data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fill_async_lock(p, addr, extcode, length);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
|
||||
nodeid_t node, u64 addr, int extcode,
|
||||
octlet_t * data, octlet_t arg)
|
||||
{
|
||||
struct hpsb_packet *p;
|
||||
u32 length;
|
||||
|
||||
p = hpsb_alloc_packet(16);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
p->host = host;
|
||||
p->node_id = node;
|
||||
if (hpsb_get_tlabel(p)) {
|
||||
hpsb_free_packet(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (extcode) {
|
||||
case EXTCODE_FETCH_ADD:
|
||||
case EXTCODE_LITTLE_ADD:
|
||||
length = 8;
|
||||
if (data) {
|
||||
p->data[0] = *data >> 32;
|
||||
p->data[1] = *data & 0xffffffff;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
length = 16;
|
||||
if (data) {
|
||||
p->data[0] = arg >> 32;
|
||||
p->data[1] = arg & 0xffffffff;
|
||||
p->data[2] = *data >> 32;
|
||||
p->data[3] = *data & 0xffffffff;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fill_async_lock(p, addr, extcode, length);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data)
|
||||
{
|
||||
struct hpsb_packet *p;
|
||||
|
||||
p = hpsb_alloc_packet(0);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
p->host = host;
|
||||
fill_phy_packet(p, data);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME - these functions should probably read from / write to user space to
|
||||
* avoid in kernel buffers for user space callers
|
||||
*/
|
||||
|
||||
/**
|
||||
* hpsb_read - generic read function
|
||||
*
|
||||
* Recognizes the local node ID and act accordingly. Automatically uses a
|
||||
* quadlet read request if @length == 4 and and a block read request otherwise.
|
||||
* It does not yet support lengths that are not a multiple of 4.
|
||||
*
|
||||
* You must explicitly specifiy the @generation for which the node ID is valid,
|
||||
* to avoid sending packets to the wrong nodes when we race with a bus reset.
|
||||
*/
|
||||
int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
|
||||
u64 addr, quadlet_t * buffer, size_t length)
|
||||
{
|
||||
struct hpsb_packet *packet;
|
||||
int retval = 0;
|
||||
|
||||
if (length == 0)
|
||||
return -EINVAL;
|
||||
|
||||
packet = hpsb_make_readpacket(host, node, addr, length);
|
||||
|
||||
if (!packet) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
packet->generation = generation;
|
||||
retval = hpsb_send_packet_and_wait(packet);
|
||||
if (retval < 0)
|
||||
goto hpsb_read_fail;
|
||||
|
||||
retval = hpsb_packet_success(packet);
|
||||
|
||||
if (retval == 0) {
|
||||
if (length == 4) {
|
||||
*buffer = packet->header[3];
|
||||
} else {
|
||||
memcpy(buffer, packet->data, length);
|
||||
}
|
||||
}
|
||||
|
||||
hpsb_read_fail:
|
||||
hpsb_free_tlabel(packet);
|
||||
hpsb_free_packet(packet);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_write - generic write function
|
||||
*
|
||||
* Recognizes the local node ID and act accordingly. Automatically uses a
|
||||
* quadlet write request if @length == 4 and and a block write request
|
||||
* otherwise. It does not yet support lengths that are not a multiple of 4.
|
||||
*
|
||||
* You must explicitly specifiy the @generation for which the node ID is valid,
|
||||
* to avoid sending packets to the wrong nodes when we race with a bus reset.
|
||||
*/
|
||||
int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
|
||||
u64 addr, quadlet_t * buffer, size_t length)
|
||||
{
|
||||
struct hpsb_packet *packet;
|
||||
int retval;
|
||||
|
||||
if (length == 0)
|
||||
return -EINVAL;
|
||||
|
||||
packet = hpsb_make_writepacket(host, node, addr, buffer, length);
|
||||
|
||||
if (!packet)
|
||||
return -ENOMEM;
|
||||
|
||||
packet->generation = generation;
|
||||
retval = hpsb_send_packet_and_wait(packet);
|
||||
if (retval < 0)
|
||||
goto hpsb_write_fail;
|
||||
|
||||
retval = hpsb_packet_success(packet);
|
||||
|
||||
hpsb_write_fail:
|
||||
hpsb_free_tlabel(packet);
|
||||
hpsb_free_packet(packet);
|
||||
|
||||
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;
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
#ifndef _IEEE1394_TRANSACTIONS_H
|
||||
#define _IEEE1394_TRANSACTIONS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
struct hpsb_packet;
|
||||
struct hpsb_host;
|
||||
|
||||
int hpsb_get_tlabel(struct hpsb_packet *packet);
|
||||
void hpsb_free_tlabel(struct hpsb_packet *packet);
|
||||
struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
|
||||
u64 addr, size_t length);
|
||||
struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
|
||||
u64 addr, int extcode, quadlet_t *data,
|
||||
quadlet_t arg);
|
||||
struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
|
||||
nodeid_t node, u64 addr, int extcode,
|
||||
octlet_t *data, octlet_t arg);
|
||||
struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data);
|
||||
struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host,
|
||||
nodeid_t node, u64 addr,
|
||||
quadlet_t *buffer, size_t length);
|
||||
struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
|
||||
int length, int channel, int tag,
|
||||
int sync);
|
||||
int hpsb_packet_success(struct hpsb_packet *packet);
|
||||
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;
|
||||
#endif
|
||||
|
||||
#endif /* _IEEE1394_TRANSACTIONS_H */
|
@ -1,69 +0,0 @@
|
||||
#ifndef _IEEE1394_TYPES_H
|
||||
#define _IEEE1394_TYPES_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
typedef u32 quadlet_t;
|
||||
typedef u64 octlet_t;
|
||||
typedef u16 nodeid_t;
|
||||
|
||||
typedef u8 byte_t;
|
||||
typedef u64 nodeaddr_t;
|
||||
typedef u16 arm_length_t;
|
||||
|
||||
#define BUS_MASK 0xffc0
|
||||
#define BUS_SHIFT 6
|
||||
#define NODE_MASK 0x003f
|
||||
#define LOCAL_BUS 0xffc0
|
||||
#define ALL_NODES 0x003f
|
||||
|
||||
#define NODEID_TO_BUS(nodeid) ((nodeid & BUS_MASK) >> BUS_SHIFT)
|
||||
#define NODEID_TO_NODE(nodeid) (nodeid & NODE_MASK)
|
||||
|
||||
/* Can be used to consistently print a node/bus ID. */
|
||||
#define NODE_BUS_FMT "%d-%02d:%04d"
|
||||
#define NODE_BUS_ARGS(__host, __nodeid) \
|
||||
__host->id, NODEID_TO_NODE(__nodeid), NODEID_TO_BUS(__nodeid)
|
||||
|
||||
#define HPSB_PRINT(level, fmt, args...) \
|
||||
printk(level "ieee1394: " fmt "\n" , ## args)
|
||||
|
||||
#define HPSB_DEBUG(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
|
||||
#define HPSB_INFO(fmt, args...) HPSB_PRINT(KERN_INFO, fmt , ## args)
|
||||
#define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args)
|
||||
#define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args)
|
||||
#define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args)
|
||||
|
||||
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
|
||||
#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
|
||||
#define HPSB_DEBUG_TLABELS
|
||||
#else
|
||||
#define HPSB_VERBOSE(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
|
||||
static inline void *memcpy_le32(u32 *dest, const u32 *__src, size_t count)
|
||||
{
|
||||
void *tmp = dest;
|
||||
u32 *src = (u32 *)__src;
|
||||
|
||||
count /= 4;
|
||||
while (count--)
|
||||
*dest++ = swab32p(src++);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count)
|
||||
{
|
||||
return memcpy(dest, src, count);
|
||||
}
|
||||
|
||||
#endif /* __BIG_ENDIAN */
|
||||
|
||||
#endif /* _IEEE1394_TYPES_H */
|
@ -1,568 +0,0 @@
|
||||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* kernel ISO transmission/reception
|
||||
*
|
||||
* Copyright (C) 2002 Maas Digital LLC
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "hosts.h"
|
||||
#include "iso.h"
|
||||
|
||||
/**
|
||||
* hpsb_iso_stop - stop DMA
|
||||
*/
|
||||
void hpsb_iso_stop(struct hpsb_iso *iso)
|
||||
{
|
||||
if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
|
||||
return;
|
||||
|
||||
iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
|
||||
XMIT_STOP : RECV_STOP, 0);
|
||||
iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_shutdown - deallocate buffer and DMA context
|
||||
*/
|
||||
void hpsb_iso_shutdown(struct hpsb_iso *iso)
|
||||
{
|
||||
if (iso->flags & HPSB_ISO_DRIVER_INIT) {
|
||||
hpsb_iso_stop(iso);
|
||||
iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
|
||||
XMIT_SHUTDOWN : RECV_SHUTDOWN, 0);
|
||||
iso->flags &= ~HPSB_ISO_DRIVER_INIT;
|
||||
}
|
||||
|
||||
dma_region_free(&iso->data_buf);
|
||||
kfree(iso);
|
||||
}
|
||||
|
||||
static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host,
|
||||
enum hpsb_iso_type type,
|
||||
unsigned int data_buf_size,
|
||||
unsigned int buf_packets,
|
||||
int channel, int dma_mode,
|
||||
int irq_interval,
|
||||
void (*callback) (struct hpsb_iso
|
||||
*))
|
||||
{
|
||||
struct hpsb_iso *iso;
|
||||
int dma_direction;
|
||||
|
||||
/* make sure driver supports the ISO API */
|
||||
if (!host->driver->isoctl) {
|
||||
printk(KERN_INFO
|
||||
"ieee1394: host driver '%s' does not support the rawiso API\n",
|
||||
host->driver->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* sanitize parameters */
|
||||
|
||||
if (buf_packets < 2)
|
||||
buf_packets = 2;
|
||||
|
||||
if ((dma_mode < HPSB_ISO_DMA_DEFAULT)
|
||||
|| (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER))
|
||||
dma_mode = HPSB_ISO_DMA_DEFAULT;
|
||||
|
||||
if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
|
||||
irq_interval = buf_packets / 4;
|
||||
if (irq_interval == 0) /* really interrupt for each packet */
|
||||
irq_interval = 1;
|
||||
|
||||
if (channel < -1 || channel >= 64)
|
||||
return NULL;
|
||||
|
||||
/* channel = -1 is OK for multi-channel recv but not for xmit */
|
||||
if (type == HPSB_ISO_XMIT && channel < 0)
|
||||
return NULL;
|
||||
|
||||
/* allocate and write the struct hpsb_iso */
|
||||
|
||||
iso =
|
||||
kmalloc(sizeof(*iso) +
|
||||
buf_packets * sizeof(struct hpsb_iso_packet_info),
|
||||
GFP_KERNEL);
|
||||
if (!iso)
|
||||
return NULL;
|
||||
|
||||
iso->infos = (struct hpsb_iso_packet_info *)(iso + 1);
|
||||
|
||||
iso->type = type;
|
||||
iso->host = host;
|
||||
iso->hostdata = NULL;
|
||||
iso->callback = callback;
|
||||
init_waitqueue_head(&iso->waitq);
|
||||
iso->channel = channel;
|
||||
iso->irq_interval = irq_interval;
|
||||
iso->dma_mode = dma_mode;
|
||||
dma_region_init(&iso->data_buf);
|
||||
iso->buf_size = PAGE_ALIGN(data_buf_size);
|
||||
iso->buf_packets = buf_packets;
|
||||
iso->pkt_dma = 0;
|
||||
iso->first_packet = 0;
|
||||
spin_lock_init(&iso->lock);
|
||||
|
||||
if (iso->type == HPSB_ISO_XMIT) {
|
||||
iso->n_ready_packets = iso->buf_packets;
|
||||
dma_direction = PCI_DMA_TODEVICE;
|
||||
} else {
|
||||
iso->n_ready_packets = 0;
|
||||
dma_direction = PCI_DMA_FROMDEVICE;
|
||||
}
|
||||
|
||||
atomic_set(&iso->overflows, 0);
|
||||
iso->bytes_discarded = 0;
|
||||
iso->flags = 0;
|
||||
iso->prebuffer = 0;
|
||||
|
||||
/* allocate the packet buffer */
|
||||
if (dma_region_alloc
|
||||
(&iso->data_buf, iso->buf_size, host->pdev, dma_direction))
|
||||
goto err;
|
||||
|
||||
return iso;
|
||||
|
||||
err:
|
||||
hpsb_iso_shutdown(iso);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_n_ready - returns number of packets ready to send or receive
|
||||
*/
|
||||
int hpsb_iso_n_ready(struct hpsb_iso *iso)
|
||||
{
|
||||
unsigned long flags;
|
||||
int val;
|
||||
|
||||
spin_lock_irqsave(&iso->lock, flags);
|
||||
val = iso->n_ready_packets;
|
||||
spin_unlock_irqrestore(&iso->lock, flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_xmit_init - allocate the buffer and DMA context
|
||||
*/
|
||||
struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
|
||||
unsigned int data_buf_size,
|
||||
unsigned int buf_packets,
|
||||
int channel,
|
||||
int speed,
|
||||
int irq_interval,
|
||||
void (*callback) (struct hpsb_iso *))
|
||||
{
|
||||
struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT,
|
||||
data_buf_size, buf_packets,
|
||||
channel,
|
||||
HPSB_ISO_DMA_DEFAULT,
|
||||
irq_interval, callback);
|
||||
if (!iso)
|
||||
return NULL;
|
||||
|
||||
iso->speed = speed;
|
||||
|
||||
/* tell the driver to start working */
|
||||
if (host->driver->isoctl(iso, XMIT_INIT, 0))
|
||||
goto err;
|
||||
|
||||
iso->flags |= HPSB_ISO_DRIVER_INIT;
|
||||
return iso;
|
||||
|
||||
err:
|
||||
hpsb_iso_shutdown(iso);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_init - allocate the buffer and DMA context
|
||||
*
|
||||
* Note, if channel = -1, multi-channel receive is enabled.
|
||||
*/
|
||||
struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
|
||||
unsigned int data_buf_size,
|
||||
unsigned int buf_packets,
|
||||
int channel,
|
||||
int dma_mode,
|
||||
int irq_interval,
|
||||
void (*callback) (struct hpsb_iso *))
|
||||
{
|
||||
struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV,
|
||||
data_buf_size, buf_packets,
|
||||
channel, dma_mode,
|
||||
irq_interval, callback);
|
||||
if (!iso)
|
||||
return NULL;
|
||||
|
||||
/* tell the driver to start working */
|
||||
if (host->driver->isoctl(iso, RECV_INIT, 0))
|
||||
goto err;
|
||||
|
||||
iso->flags |= HPSB_ISO_DRIVER_INIT;
|
||||
return iso;
|
||||
|
||||
err:
|
||||
hpsb_iso_shutdown(iso);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_listen_channel
|
||||
*
|
||||
* multi-channel only
|
||||
*/
|
||||
int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
|
||||
return -EINVAL;
|
||||
return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_unlisten_channel
|
||||
*
|
||||
* multi-channel only
|
||||
*/
|
||||
int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
|
||||
return -EINVAL;
|
||||
return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_set_channel_mask
|
||||
*
|
||||
* multi-channel only
|
||||
*/
|
||||
int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
|
||||
return -EINVAL;
|
||||
return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK,
|
||||
(unsigned long)&mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_flush - check for arrival of new packets
|
||||
*
|
||||
* check for arrival of new packets immediately (even if irq_interval
|
||||
* has not yet been reached)
|
||||
*/
|
||||
int hpsb_iso_recv_flush(struct hpsb_iso *iso)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_RECV)
|
||||
return -EINVAL;
|
||||
return iso->host->driver->isoctl(iso, RECV_FLUSH, 0);
|
||||
}
|
||||
|
||||
static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle)
|
||||
{
|
||||
int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
iso->flags |= HPSB_ISO_DRIVER_STARTED;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_xmit_start - start DMA
|
||||
*/
|
||||
int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_XMIT)
|
||||
return -1;
|
||||
|
||||
if (iso->flags & HPSB_ISO_DRIVER_STARTED)
|
||||
return 0;
|
||||
|
||||
if (cycle < -1)
|
||||
cycle = -1;
|
||||
else if (cycle >= 8000)
|
||||
cycle %= 8000;
|
||||
|
||||
iso->xmit_cycle = cycle;
|
||||
|
||||
if (prebuffer < 0)
|
||||
prebuffer = iso->buf_packets - 1;
|
||||
else if (prebuffer == 0)
|
||||
prebuffer = 1;
|
||||
|
||||
if (prebuffer >= iso->buf_packets)
|
||||
prebuffer = iso->buf_packets - 1;
|
||||
|
||||
iso->prebuffer = prebuffer;
|
||||
|
||||
/* remember the starting cycle; DMA will commence from xmit_queue_packets()
|
||||
once enough packets have been buffered */
|
||||
iso->start_cycle = cycle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_start - start DMA
|
||||
*/
|
||||
int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
|
||||
{
|
||||
int retval = 0;
|
||||
int isoctl_args[3];
|
||||
|
||||
if (iso->type != HPSB_ISO_RECV)
|
||||
return -1;
|
||||
|
||||
if (iso->flags & HPSB_ISO_DRIVER_STARTED)
|
||||
return 0;
|
||||
|
||||
if (cycle < -1)
|
||||
cycle = -1;
|
||||
else if (cycle >= 8000)
|
||||
cycle %= 8000;
|
||||
|
||||
isoctl_args[0] = cycle;
|
||||
|
||||
if (tag_mask < 0)
|
||||
/* match all tags */
|
||||
tag_mask = 0xF;
|
||||
isoctl_args[1] = tag_mask;
|
||||
|
||||
isoctl_args[2] = sync;
|
||||
|
||||
retval =
|
||||
iso->host->driver->isoctl(iso, RECV_START,
|
||||
(unsigned long)&isoctl_args[0]);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
iso->flags |= HPSB_ISO_DRIVER_STARTED;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* check to make sure the user has not supplied bogus values of offset/len
|
||||
* that would cause the kernel to access memory outside the buffer */
|
||||
static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
|
||||
unsigned int offset, unsigned short len,
|
||||
unsigned int *out_offset,
|
||||
unsigned short *out_len)
|
||||
{
|
||||
if (offset >= iso->buf_size)
|
||||
return -EFAULT;
|
||||
|
||||
/* make sure the packet does not go beyond the end of the buffer */
|
||||
if (offset + len > iso->buf_size)
|
||||
return -EFAULT;
|
||||
|
||||
/* check for wrap-around */
|
||||
if (offset + len < offset)
|
||||
return -EFAULT;
|
||||
|
||||
/* now we can trust 'offset' and 'length' */
|
||||
*out_offset = offset;
|
||||
*out_len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_xmit_queue_packet - queue a packet for transmission.
|
||||
*
|
||||
* @offset is relative to the beginning of the DMA buffer, where the packet's
|
||||
* data payload should already have been placed.
|
||||
*/
|
||||
int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
|
||||
u8 tag, u8 sy)
|
||||
{
|
||||
struct hpsb_iso_packet_info *info;
|
||||
unsigned long flags;
|
||||
int rv;
|
||||
|
||||
if (iso->type != HPSB_ISO_XMIT)
|
||||
return -EINVAL;
|
||||
|
||||
/* is there space in the buffer? */
|
||||
if (iso->n_ready_packets <= 0) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
info = &iso->infos[iso->first_packet];
|
||||
|
||||
/* check for bogus offset/length */
|
||||
if (hpsb_iso_check_offset_len
|
||||
(iso, offset, len, &info->offset, &info->len))
|
||||
return -EFAULT;
|
||||
|
||||
info->tag = tag;
|
||||
info->sy = sy;
|
||||
|
||||
spin_lock_irqsave(&iso->lock, flags);
|
||||
|
||||
rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long)info);
|
||||
if (rv)
|
||||
goto out;
|
||||
|
||||
/* increment cursors */
|
||||
iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
|
||||
iso->xmit_cycle = (iso->xmit_cycle + 1) % 8000;
|
||||
iso->n_ready_packets--;
|
||||
|
||||
if (iso->prebuffer != 0) {
|
||||
iso->prebuffer--;
|
||||
if (iso->prebuffer <= 0) {
|
||||
iso->prebuffer = 0;
|
||||
rv = do_iso_xmit_start(iso, iso->start_cycle);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&iso->lock, flags);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_xmit_sync - wait until all queued packets have been transmitted
|
||||
*/
|
||||
int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_XMIT)
|
||||
return -EINVAL;
|
||||
|
||||
return wait_event_interruptible(iso->waitq,
|
||||
hpsb_iso_n_ready(iso) ==
|
||||
iso->buf_packets);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_packet_sent
|
||||
*
|
||||
* Available to low-level drivers.
|
||||
*
|
||||
* Call after a packet has been transmitted to the bus (interrupt context is
|
||||
* OK). @cycle is the _exact_ cycle the packet was sent on. @error should be
|
||||
* non-zero if some sort of error occurred when sending the packet.
|
||||
*/
|
||||
void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&iso->lock, flags);
|
||||
|
||||
/* predict the cycle of the next packet to be queued */
|
||||
|
||||
/* jump ahead by the number of packets that are already buffered */
|
||||
cycle += iso->buf_packets - iso->n_ready_packets;
|
||||
cycle %= 8000;
|
||||
|
||||
iso->xmit_cycle = cycle;
|
||||
iso->n_ready_packets++;
|
||||
iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
|
||||
|
||||
if (iso->n_ready_packets == iso->buf_packets || error != 0) {
|
||||
/* the buffer has run empty! */
|
||||
atomic_inc(&iso->overflows);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&iso->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_packet_received
|
||||
*
|
||||
* Available to low-level drivers.
|
||||
*
|
||||
* Call after a packet has been received (interrupt context is OK).
|
||||
*/
|
||||
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
|
||||
u16 total_len, u16 cycle, u8 channel, u8 tag,
|
||||
u8 sy)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&iso->lock, flags);
|
||||
|
||||
if (iso->n_ready_packets == iso->buf_packets) {
|
||||
/* overflow! */
|
||||
atomic_inc(&iso->overflows);
|
||||
/* Record size of this discarded packet */
|
||||
iso->bytes_discarded += total_len;
|
||||
} else {
|
||||
struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma];
|
||||
info->offset = offset;
|
||||
info->len = len;
|
||||
info->total_len = total_len;
|
||||
info->cycle = cycle;
|
||||
info->channel = channel;
|
||||
info->tag = tag;
|
||||
info->sy = sy;
|
||||
|
||||
iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
|
||||
iso->n_ready_packets++;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&iso->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_release_packets - release packets, reuse buffer
|
||||
*
|
||||
* @n_packets have been read out of the buffer, re-use the buffer space
|
||||
*/
|
||||
int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int i;
|
||||
int rv = 0;
|
||||
|
||||
if (iso->type != HPSB_ISO_RECV)
|
||||
return -1;
|
||||
|
||||
spin_lock_irqsave(&iso->lock, flags);
|
||||
for (i = 0; i < n_packets; i++) {
|
||||
rv = iso->host->driver->isoctl(iso, RECV_RELEASE,
|
||||
(unsigned long)&iso->infos[iso->
|
||||
first_packet]);
|
||||
if (rv)
|
||||
break;
|
||||
|
||||
iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
|
||||
iso->n_ready_packets--;
|
||||
|
||||
/* release memory from packets discarded when queue was full */
|
||||
if (iso->n_ready_packets == 0) { /* Release only after all prior packets handled */
|
||||
if (iso->bytes_discarded != 0) {
|
||||
struct hpsb_iso_packet_info inf;
|
||||
inf.total_len = iso->bytes_discarded;
|
||||
iso->host->driver->isoctl(iso, RECV_RELEASE,
|
||||
(unsigned long)&inf);
|
||||
iso->bytes_discarded = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&iso->lock, flags);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_wake
|
||||
*
|
||||
* Available to low-level drivers.
|
||||
*
|
||||
* Call to wake waiting processes after buffer space has opened up.
|
||||
*/
|
||||
void hpsb_iso_wake(struct hpsb_iso *iso)
|
||||
{
|
||||
wake_up_interruptible(&iso->waitq);
|
||||
|
||||
if (iso->callback)
|
||||
iso->callback(iso);
|
||||
}
|
@ -1,195 +0,0 @@
|
||||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* kernel ISO transmission/reception
|
||||
*
|
||||
* Copyright (C) 2002 Maas Digital LLC
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#ifndef IEEE1394_ISO_H
|
||||
#define IEEE1394_ISO_H
|
||||
|
||||
#include <linux/spinlock_types.h>
|
||||
#include <linux/wait.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#include "dma.h"
|
||||
|
||||
struct hpsb_host;
|
||||
|
||||
/* high-level ISO interface */
|
||||
|
||||
/*
|
||||
* This API sends and receives isochronous packets on a large,
|
||||
* virtually-contiguous kernel memory buffer. The buffer may be mapped
|
||||
* into a user-space process for zero-copy transmission and reception.
|
||||
*
|
||||
* There are no explicit boundaries between packets in the buffer. A
|
||||
* packet may be transmitted or received at any location. However,
|
||||
* low-level drivers may impose certain restrictions on alignment or
|
||||
* size of packets. (e.g. in OHCI no packet may cross a page boundary,
|
||||
* and packets should be quadlet-aligned)
|
||||
*/
|
||||
|
||||
/* Packet descriptor - the API maintains a ring buffer of these packet
|
||||
* descriptors in kernel memory (hpsb_iso.infos[]). */
|
||||
struct hpsb_iso_packet_info {
|
||||
/* offset of data payload relative to the first byte of the buffer */
|
||||
__u32 offset;
|
||||
|
||||
/* length of the data payload, in bytes (not including the isochronous
|
||||
* header) */
|
||||
__u16 len;
|
||||
|
||||
/* (recv only) the cycle number (mod 8000) on which the packet was
|
||||
* received */
|
||||
__u16 cycle;
|
||||
|
||||
/* (recv only) channel on which the packet was received */
|
||||
__u8 channel;
|
||||
|
||||
/* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */
|
||||
__u8 tag;
|
||||
__u8 sy;
|
||||
|
||||
/* length in bytes of the packet including header/trailer.
|
||||
* MUST be at structure end, since the first part of this structure is
|
||||
* also defined in raw1394.h (i.e. struct raw1394_iso_packet_info), is
|
||||
* copied to userspace and is accessed there through libraw1394. */
|
||||
__u16 total_len;
|
||||
};
|
||||
|
||||
enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 };
|
||||
|
||||
/* The mode of the dma when receiving iso data. Must be supported by chip */
|
||||
enum raw1394_iso_dma_recv_mode {
|
||||
HPSB_ISO_DMA_DEFAULT = -1,
|
||||
HPSB_ISO_DMA_OLD_ABI = 0,
|
||||
HPSB_ISO_DMA_BUFFERFILL = 1,
|
||||
HPSB_ISO_DMA_PACKET_PER_BUFFER = 2
|
||||
};
|
||||
|
||||
struct hpsb_iso {
|
||||
enum hpsb_iso_type type;
|
||||
|
||||
/* pointer to low-level driver and its private data */
|
||||
struct hpsb_host *host;
|
||||
void *hostdata;
|
||||
|
||||
/* a function to be called (from interrupt context) after
|
||||
* outgoing packets have been sent, or incoming packets have
|
||||
* arrived */
|
||||
void (*callback)(struct hpsb_iso*);
|
||||
|
||||
/* wait for buffer space */
|
||||
wait_queue_head_t waitq;
|
||||
|
||||
int speed; /* IEEE1394_SPEED_100, 200, or 400 */
|
||||
int channel; /* -1 if multichannel */
|
||||
int dma_mode; /* dma receive mode */
|
||||
|
||||
|
||||
/* greatest # of packets between interrupts - controls
|
||||
* the maximum latency of the buffer */
|
||||
int irq_interval;
|
||||
|
||||
/* the buffer for packet data payloads */
|
||||
struct dma_region data_buf;
|
||||
|
||||
/* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */
|
||||
unsigned int buf_size;
|
||||
|
||||
/* # of packets in the ringbuffer */
|
||||
unsigned int buf_packets;
|
||||
|
||||
/* protects packet cursors */
|
||||
spinlock_t lock;
|
||||
|
||||
/* the index of the next packet that will be produced
|
||||
or consumed by the user */
|
||||
int first_packet;
|
||||
|
||||
/* the index of the next packet that will be transmitted
|
||||
or received by the 1394 hardware */
|
||||
int pkt_dma;
|
||||
|
||||
/* how many packets, starting at first_packet:
|
||||
* (transmit) are ready to be filled with data
|
||||
* (receive) contain received data */
|
||||
int n_ready_packets;
|
||||
|
||||
/* how many times the buffer has overflowed or underflowed */
|
||||
atomic_t overflows;
|
||||
/* how many cycles were skipped for a given context */
|
||||
atomic_t skips;
|
||||
|
||||
/* Current number of bytes lost in discarded packets */
|
||||
int bytes_discarded;
|
||||
|
||||
/* private flags to track initialization progress */
|
||||
#define HPSB_ISO_DRIVER_INIT (1<<0)
|
||||
#define HPSB_ISO_DRIVER_STARTED (1<<1)
|
||||
unsigned int flags;
|
||||
|
||||
/* # of packets left to prebuffer (xmit only) */
|
||||
int prebuffer;
|
||||
|
||||
/* starting cycle for DMA (xmit only) */
|
||||
int start_cycle;
|
||||
|
||||
/* cycle at which next packet will be transmitted,
|
||||
* -1 if not known */
|
||||
int xmit_cycle;
|
||||
|
||||
/* ringbuffer of packet descriptors in regular kernel memory
|
||||
* XXX Keep this last, since we use over-allocated memory from
|
||||
* this entry to fill this field. */
|
||||
struct hpsb_iso_packet_info *infos;
|
||||
};
|
||||
|
||||
/* functions available to high-level drivers (e.g. raw1394) */
|
||||
|
||||
struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
|
||||
unsigned int data_buf_size,
|
||||
unsigned int buf_packets,
|
||||
int channel,
|
||||
int speed,
|
||||
int irq_interval,
|
||||
void (*callback)(struct hpsb_iso*));
|
||||
struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
|
||||
unsigned int data_buf_size,
|
||||
unsigned int buf_packets,
|
||||
int channel,
|
||||
int dma_mode,
|
||||
int irq_interval,
|
||||
void (*callback)(struct hpsb_iso*));
|
||||
int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel);
|
||||
int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel);
|
||||
int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask);
|
||||
int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle,
|
||||
int prebuffer);
|
||||
int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle,
|
||||
int tag_mask, int sync);
|
||||
void hpsb_iso_stop(struct hpsb_iso *iso);
|
||||
void hpsb_iso_shutdown(struct hpsb_iso *iso);
|
||||
int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
|
||||
u8 tag, u8 sy);
|
||||
int hpsb_iso_xmit_sync(struct hpsb_iso *iso);
|
||||
int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
|
||||
unsigned int n_packets);
|
||||
int hpsb_iso_recv_flush(struct hpsb_iso *iso);
|
||||
int hpsb_iso_n_ready(struct hpsb_iso *iso);
|
||||
|
||||
/* the following are callbacks available to low-level drivers */
|
||||
|
||||
void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error);
|
||||
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
|
||||
u16 total_len, u16 cycle, u8 channel, u8 tag,
|
||||
u8 sy);
|
||||
void hpsb_iso_wake(struct hpsb_iso *iso);
|
||||
|
||||
#endif /* IEEE1394_ISO_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2000 Andreas E. Bombe
|
||||
* 2001 Ben Collins <bcollins@debian.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _IEEE1394_NODEMGR_H
|
||||
#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;
|
||||
struct csr1212_keyval;
|
||||
struct hpsb_host;
|
||||
struct ieee1394_device_id;
|
||||
|
||||
/* This is the start of a Node entry structure. It should be a stable API
|
||||
* for which to gather info from the Node Manager about devices attached
|
||||
* to the bus. */
|
||||
struct bus_options {
|
||||
u8 irmc; /* Iso Resource Manager Capable */
|
||||
u8 cmc; /* Cycle Master Capable */
|
||||
u8 isc; /* Iso Capable */
|
||||
u8 bmc; /* Bus Master Capable */
|
||||
u8 pmc; /* Power Manager Capable (PNP spec) */
|
||||
u8 cyc_clk_acc; /* Cycle clock accuracy */
|
||||
u8 max_rom; /* Maximum block read supported in the CSR */
|
||||
u8 generation; /* Incremented when configrom changes */
|
||||
u8 lnkspd; /* Link speed */
|
||||
u16 max_rec; /* Maximum packet size node can receive */
|
||||
};
|
||||
|
||||
#define UNIT_DIRECTORY_VENDOR_ID 0x01
|
||||
#define UNIT_DIRECTORY_MODEL_ID 0x02
|
||||
#define UNIT_DIRECTORY_SPECIFIER_ID 0x04
|
||||
#define UNIT_DIRECTORY_VERSION 0x08
|
||||
#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY 0x10
|
||||
#define UNIT_DIRECTORY_LUN_DIRECTORY 0x20
|
||||
#define UNIT_DIRECTORY_HAS_LUN 0x40
|
||||
|
||||
/*
|
||||
* A unit directory corresponds to a protocol supported by the
|
||||
* node. If a node supports eg. IP/1394 and AV/C, its config rom has a
|
||||
* unit directory for each of these protocols.
|
||||
*/
|
||||
struct unit_directory {
|
||||
struct node_entry *ne; /* The node which this directory belongs to */
|
||||
octlet_t address; /* Address of the unit directory on the node */
|
||||
u8 flags; /* Indicates which entries were read */
|
||||
|
||||
quadlet_t vendor_id;
|
||||
struct csr1212_keyval *vendor_name_kv;
|
||||
|
||||
quadlet_t model_id;
|
||||
struct csr1212_keyval *model_name_kv;
|
||||
quadlet_t specifier_id;
|
||||
quadlet_t version;
|
||||
quadlet_t directory_id;
|
||||
|
||||
unsigned int id;
|
||||
|
||||
int ignore_driver;
|
||||
|
||||
int length; /* Number of quadlets */
|
||||
|
||||
struct device device;
|
||||
struct device unit_dev;
|
||||
|
||||
struct csr1212_keyval *ud_kv;
|
||||
u32 lun; /* logical unit number immediate value */
|
||||
};
|
||||
|
||||
struct node_entry {
|
||||
u64 guid; /* GUID of this node */
|
||||
u32 guid_vendor_id; /* Top 24bits of guid */
|
||||
|
||||
struct hpsb_host *host; /* Host this node is attached to */
|
||||
nodeid_t nodeid; /* NodeID */
|
||||
struct bus_options busopt; /* Bus Options */
|
||||
bool needs_probe;
|
||||
unsigned int generation; /* Synced with hpsb generation */
|
||||
|
||||
/* The following is read from the config rom */
|
||||
u32 vendor_id;
|
||||
struct csr1212_keyval *vendor_name_kv;
|
||||
|
||||
u32 capabilities;
|
||||
|
||||
struct device device;
|
||||
struct device node_dev;
|
||||
|
||||
/* Means this node is not attached anymore */
|
||||
bool in_limbo;
|
||||
|
||||
struct csr1212_csr *csr;
|
||||
};
|
||||
|
||||
struct hpsb_protocol_driver {
|
||||
/* The name of the driver, e.g. SBP2 or IP1394 */
|
||||
const char *name;
|
||||
|
||||
/*
|
||||
* The device id table describing the protocols and/or devices
|
||||
* supported by this driver. This is used by the nodemgr to
|
||||
* decide if a driver could support a given node, but the
|
||||
* probe function below can implement further protocol
|
||||
* dependent or vendor dependent checking.
|
||||
*/
|
||||
const struct ieee1394_device_id *id_table;
|
||||
|
||||
/*
|
||||
* The update function is called when the node has just
|
||||
* survived a bus reset, i.e. it is still present on the bus.
|
||||
* However, it may be necessary to reestablish the connection
|
||||
* or login into the node again, depending on the protocol. If the
|
||||
* probe fails (returns non-zero), we unbind the driver from this
|
||||
* device.
|
||||
*/
|
||||
int (*update)(struct unit_directory *ud);
|
||||
|
||||
/* Our LDM structure */
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
int __hpsb_register_protocol(struct hpsb_protocol_driver *, struct module *);
|
||||
static inline int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
|
||||
{
|
||||
return __hpsb_register_protocol(driver, THIS_MODULE);
|
||||
}
|
||||
|
||||
void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver);
|
||||
|
||||
static inline int hpsb_node_entry_valid(struct node_entry *ne)
|
||||
{
|
||||
return ne->generation == get_hpsb_generation(ne->host);
|
||||
}
|
||||
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);
|
||||
void cleanup_ieee1394_nodemgr(void);
|
||||
|
||||
/* The template for a host device */
|
||||
extern struct device nodemgr_dev_template_host;
|
||||
|
||||
/* Bus attributes we export */
|
||||
extern struct bus_attribute *const fw_bus_attrs[];
|
||||
|
||||
#endif /* _IEEE1394_NODEMGR_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,453 +0,0 @@
|
||||
/*
|
||||
* ohci1394.h - driver for OHCI 1394 boards
|
||||
* Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
|
||||
* Gord Peters <GordPeters@smarttech.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _OHCI1394_H
|
||||
#define _OHCI1394_H
|
||||
|
||||
#include "ieee1394_types.h"
|
||||
#include <asm/io.h>
|
||||
|
||||
#define OHCI1394_DRIVER_NAME "ohci1394"
|
||||
|
||||
#define OHCI1394_MAX_AT_REQ_RETRIES 0xf
|
||||
#define OHCI1394_MAX_AT_RESP_RETRIES 0x2
|
||||
#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
|
||||
#define OHCI1394_MAX_SELF_ID_ERRORS 16
|
||||
|
||||
#define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */
|
||||
#define AR_REQ_BUF_SIZE PAGE_SIZE /* size of AR req buffers */
|
||||
#define AR_REQ_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
|
||||
|
||||
#define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */
|
||||
#define AR_RESP_BUF_SIZE PAGE_SIZE /* size of AR resp buffers */
|
||||
#define AR_RESP_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
|
||||
|
||||
#define IR_NUM_DESC 16 /* number of IR descriptors */
|
||||
#define IR_BUF_SIZE PAGE_SIZE /* 4096 bytes/buffer */
|
||||
#define IR_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
|
||||
|
||||
#define IT_NUM_DESC 16 /* number of IT descriptors */
|
||||
|
||||
#define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */
|
||||
#define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */
|
||||
|
||||
#define OHCI_LOOP_COUNT 100 /* Number of loops for reg read waits */
|
||||
|
||||
#define OHCI_CONFIG_ROM_LEN 1024 /* Length of the mapped configrom space */
|
||||
|
||||
#define OHCI1394_SI_DMA_BUF_SIZE 8192 /* length of the selfid buffer */
|
||||
|
||||
/* PCI configuration space addresses */
|
||||
#define OHCI1394_PCI_HCI_Control 0x40
|
||||
|
||||
struct dma_cmd {
|
||||
u32 control;
|
||||
u32 address;
|
||||
u32 branchAddress;
|
||||
u32 status;
|
||||
};
|
||||
|
||||
/*
|
||||
* FIXME:
|
||||
* It is important that a single at_dma_prg does not cross a page boundary
|
||||
* The proper way to do it would be to do the check dynamically as the
|
||||
* programs are inserted into the AT fifo.
|
||||
*/
|
||||
struct at_dma_prg {
|
||||
struct dma_cmd begin;
|
||||
quadlet_t data[4];
|
||||
struct dma_cmd end;
|
||||
quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
|
||||
};
|
||||
|
||||
/* identify whether a DMA context is asynchronous or isochronous */
|
||||
enum context_type { DMA_CTX_ASYNC_REQ, DMA_CTX_ASYNC_RESP, DMA_CTX_ISO };
|
||||
|
||||
/* DMA receive context */
|
||||
struct dma_rcv_ctx {
|
||||
struct ti_ohci *ohci;
|
||||
enum context_type type;
|
||||
int ctx;
|
||||
unsigned int num_desc;
|
||||
|
||||
unsigned int buf_size;
|
||||
unsigned int split_buf_size;
|
||||
|
||||
/* dma block descriptors */
|
||||
struct dma_cmd **prg_cpu;
|
||||
dma_addr_t *prg_bus;
|
||||
struct pci_pool *prg_pool;
|
||||
|
||||
/* dma buffers */
|
||||
quadlet_t **buf_cpu;
|
||||
dma_addr_t *buf_bus;
|
||||
|
||||
unsigned int buf_ind;
|
||||
unsigned int buf_offset;
|
||||
quadlet_t *spb;
|
||||
spinlock_t lock;
|
||||
struct tasklet_struct task;
|
||||
int ctrlClear;
|
||||
int ctrlSet;
|
||||
int cmdPtr;
|
||||
int ctxtMatch;
|
||||
};
|
||||
|
||||
/* DMA transmit context */
|
||||
struct dma_trm_ctx {
|
||||
struct ti_ohci *ohci;
|
||||
enum context_type type;
|
||||
int ctx;
|
||||
unsigned int num_desc;
|
||||
|
||||
/* dma block descriptors */
|
||||
struct at_dma_prg **prg_cpu;
|
||||
dma_addr_t *prg_bus;
|
||||
struct pci_pool *prg_pool;
|
||||
|
||||
unsigned int prg_ind;
|
||||
unsigned int sent_ind;
|
||||
int free_prgs;
|
||||
quadlet_t *branchAddrPtr;
|
||||
|
||||
/* list of packets inserted in the AT FIFO */
|
||||
struct list_head fifo_list;
|
||||
|
||||
/* list of pending packets to be inserted in the AT FIFO */
|
||||
struct list_head pending_list;
|
||||
|
||||
spinlock_t lock;
|
||||
struct tasklet_struct task;
|
||||
int ctrlClear;
|
||||
int ctrlSet;
|
||||
int cmdPtr;
|
||||
};
|
||||
|
||||
struct ohci1394_iso_tasklet {
|
||||
struct tasklet_struct tasklet;
|
||||
struct list_head link;
|
||||
int context;
|
||||
enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE,
|
||||
OHCI_ISO_MULTICHANNEL_RECEIVE } type;
|
||||
};
|
||||
|
||||
struct ti_ohci {
|
||||
struct pci_dev *dev;
|
||||
|
||||
enum {
|
||||
OHCI_INIT_ALLOC_HOST,
|
||||
OHCI_INIT_HAVE_MEM_REGION,
|
||||
OHCI_INIT_HAVE_IOMAPPING,
|
||||
OHCI_INIT_HAVE_CONFIG_ROM_BUFFER,
|
||||
OHCI_INIT_HAVE_SELFID_BUFFER,
|
||||
OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE,
|
||||
OHCI_INIT_HAVE_IRQ,
|
||||
OHCI_INIT_DONE,
|
||||
} init_state;
|
||||
|
||||
/* remapped memory spaces */
|
||||
void __iomem *registers;
|
||||
|
||||
/* dma buffer for self-id packets */
|
||||
quadlet_t *selfid_buf_cpu;
|
||||
dma_addr_t selfid_buf_bus;
|
||||
|
||||
/* buffer for csr config rom */
|
||||
quadlet_t *csr_config_rom_cpu;
|
||||
dma_addr_t csr_config_rom_bus;
|
||||
int csr_config_rom_length;
|
||||
|
||||
unsigned int max_packet_size;
|
||||
|
||||
/* async receive */
|
||||
struct dma_rcv_ctx ar_resp_context;
|
||||
struct dma_rcv_ctx ar_req_context;
|
||||
|
||||
/* async transmit */
|
||||
struct dma_trm_ctx at_resp_context;
|
||||
struct dma_trm_ctx at_req_context;
|
||||
|
||||
/* iso receive */
|
||||
int nb_iso_rcv_ctx;
|
||||
unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */
|
||||
unsigned long ir_multichannel_used; /* ditto */
|
||||
spinlock_t IR_channel_lock;
|
||||
|
||||
/* iso transmit */
|
||||
int nb_iso_xmit_ctx;
|
||||
unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
|
||||
|
||||
u64 ISO_channel_usage;
|
||||
|
||||
/* IEEE-1394 part follows */
|
||||
struct hpsb_host *host;
|
||||
|
||||
int phyid, isroot;
|
||||
|
||||
spinlock_t phy_reg_lock;
|
||||
spinlock_t event_lock;
|
||||
|
||||
int self_id_errors;
|
||||
|
||||
/* Tasklets for iso receive and transmit, used by video1394
|
||||
* and dv1394 */
|
||||
struct list_head iso_tasklet_list;
|
||||
spinlock_t iso_tasklet_list_lock;
|
||||
|
||||
/* Swap the selfid buffer? */
|
||||
unsigned int selfid_swap:1;
|
||||
/* Some Apple chipset seem to swap incoming headers for us */
|
||||
unsigned int no_swap_incoming:1;
|
||||
|
||||
/* Force extra paranoia checking on bus-reset handling */
|
||||
unsigned int check_busreset:1;
|
||||
};
|
||||
|
||||
static inline int cross_bound(unsigned long addr, unsigned int size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
if (size > PAGE_SIZE)
|
||||
return 1;
|
||||
|
||||
if (addr >> PAGE_SHIFT != (addr + size - 1) >> PAGE_SHIFT)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register read and write helper functions.
|
||||
*/
|
||||
static inline void reg_write(const struct ti_ohci *ohci, int offset, u32 data)
|
||||
{
|
||||
writel(data, ohci->registers + offset);
|
||||
}
|
||||
|
||||
static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
|
||||
{
|
||||
return readl(ohci->registers + offset);
|
||||
}
|
||||
|
||||
|
||||
/* 2 KiloBytes of register space */
|
||||
#define OHCI1394_REGISTER_SIZE 0x800
|
||||
|
||||
/* Offsets relative to context bases defined below */
|
||||
|
||||
#define OHCI1394_ContextControlSet 0x000
|
||||
#define OHCI1394_ContextControlClear 0x004
|
||||
#define OHCI1394_ContextCommandPtr 0x00C
|
||||
|
||||
/* register map */
|
||||
#define OHCI1394_Version 0x000
|
||||
#define OHCI1394_GUID_ROM 0x004
|
||||
#define OHCI1394_ATRetries 0x008
|
||||
#define OHCI1394_CSRData 0x00C
|
||||
#define OHCI1394_CSRCompareData 0x010
|
||||
#define OHCI1394_CSRControl 0x014
|
||||
#define OHCI1394_ConfigROMhdr 0x018
|
||||
#define OHCI1394_BusID 0x01C
|
||||
#define OHCI1394_BusOptions 0x020
|
||||
#define OHCI1394_GUIDHi 0x024
|
||||
#define OHCI1394_GUIDLo 0x028
|
||||
#define OHCI1394_ConfigROMmap 0x034
|
||||
#define OHCI1394_PostedWriteAddressLo 0x038
|
||||
#define OHCI1394_PostedWriteAddressHi 0x03C
|
||||
#define OHCI1394_VendorID 0x040
|
||||
#define OHCI1394_HCControlSet 0x050
|
||||
#define OHCI1394_HCControlClear 0x054
|
||||
#define OHCI1394_HCControl_noByteSwap 0x40000000
|
||||
#define OHCI1394_HCControl_programPhyEnable 0x00800000
|
||||
#define OHCI1394_HCControl_aPhyEnhanceEnable 0x00400000
|
||||
#define OHCI1394_HCControl_LPS 0x00080000
|
||||
#define OHCI1394_HCControl_postedWriteEnable 0x00040000
|
||||
#define OHCI1394_HCControl_linkEnable 0x00020000
|
||||
#define OHCI1394_HCControl_softReset 0x00010000
|
||||
#define OHCI1394_SelfIDBuffer 0x064
|
||||
#define OHCI1394_SelfIDCount 0x068
|
||||
#define OHCI1394_IRMultiChanMaskHiSet 0x070
|
||||
#define OHCI1394_IRMultiChanMaskHiClear 0x074
|
||||
#define OHCI1394_IRMultiChanMaskLoSet 0x078
|
||||
#define OHCI1394_IRMultiChanMaskLoClear 0x07C
|
||||
#define OHCI1394_IntEventSet 0x080
|
||||
#define OHCI1394_IntEventClear 0x084
|
||||
#define OHCI1394_IntMaskSet 0x088
|
||||
#define OHCI1394_IntMaskClear 0x08C
|
||||
#define OHCI1394_IsoXmitIntEventSet 0x090
|
||||
#define OHCI1394_IsoXmitIntEventClear 0x094
|
||||
#define OHCI1394_IsoXmitIntMaskSet 0x098
|
||||
#define OHCI1394_IsoXmitIntMaskClear 0x09C
|
||||
#define OHCI1394_IsoRecvIntEventSet 0x0A0
|
||||
#define OHCI1394_IsoRecvIntEventClear 0x0A4
|
||||
#define OHCI1394_IsoRecvIntMaskSet 0x0A8
|
||||
#define OHCI1394_IsoRecvIntMaskClear 0x0AC
|
||||
#define OHCI1394_InitialBandwidthAvailable 0x0B0
|
||||
#define OHCI1394_InitialChannelsAvailableHi 0x0B4
|
||||
#define OHCI1394_InitialChannelsAvailableLo 0x0B8
|
||||
#define OHCI1394_FairnessControl 0x0DC
|
||||
#define OHCI1394_LinkControlSet 0x0E0
|
||||
#define OHCI1394_LinkControlClear 0x0E4
|
||||
#define OHCI1394_LinkControl_RcvSelfID 0x00000200
|
||||
#define OHCI1394_LinkControl_RcvPhyPkt 0x00000400
|
||||
#define OHCI1394_LinkControl_CycleTimerEnable 0x00100000
|
||||
#define OHCI1394_LinkControl_CycleMaster 0x00200000
|
||||
#define OHCI1394_LinkControl_CycleSource 0x00400000
|
||||
#define OHCI1394_NodeID 0x0E8
|
||||
#define OHCI1394_PhyControl 0x0EC
|
||||
#define OHCI1394_IsochronousCycleTimer 0x0F0
|
||||
#define OHCI1394_AsReqFilterHiSet 0x100
|
||||
#define OHCI1394_AsReqFilterHiClear 0x104
|
||||
#define OHCI1394_AsReqFilterLoSet 0x108
|
||||
#define OHCI1394_AsReqFilterLoClear 0x10C
|
||||
#define OHCI1394_PhyReqFilterHiSet 0x110
|
||||
#define OHCI1394_PhyReqFilterHiClear 0x114
|
||||
#define OHCI1394_PhyReqFilterLoSet 0x118
|
||||
#define OHCI1394_PhyReqFilterLoClear 0x11C
|
||||
#define OHCI1394_PhyUpperBound 0x120
|
||||
|
||||
#define OHCI1394_AsReqTrContextBase 0x180
|
||||
#define OHCI1394_AsReqTrContextControlSet 0x180
|
||||
#define OHCI1394_AsReqTrContextControlClear 0x184
|
||||
#define OHCI1394_AsReqTrCommandPtr 0x18C
|
||||
|
||||
#define OHCI1394_AsRspTrContextBase 0x1A0
|
||||
#define OHCI1394_AsRspTrContextControlSet 0x1A0
|
||||
#define OHCI1394_AsRspTrContextControlClear 0x1A4
|
||||
#define OHCI1394_AsRspTrCommandPtr 0x1AC
|
||||
|
||||
#define OHCI1394_AsReqRcvContextBase 0x1C0
|
||||
#define OHCI1394_AsReqRcvContextControlSet 0x1C0
|
||||
#define OHCI1394_AsReqRcvContextControlClear 0x1C4
|
||||
#define OHCI1394_AsReqRcvCommandPtr 0x1CC
|
||||
|
||||
#define OHCI1394_AsRspRcvContextBase 0x1E0
|
||||
#define OHCI1394_AsRspRcvContextControlSet 0x1E0
|
||||
#define OHCI1394_AsRspRcvContextControlClear 0x1E4
|
||||
#define OHCI1394_AsRspRcvCommandPtr 0x1EC
|
||||
|
||||
/* Isochronous transmit registers */
|
||||
/* Add (16 * n) for context n */
|
||||
#define OHCI1394_IsoXmitContextBase 0x200
|
||||
#define OHCI1394_IsoXmitContextControlSet 0x200
|
||||
#define OHCI1394_IsoXmitContextControlClear 0x204
|
||||
#define OHCI1394_IsoXmitCommandPtr 0x20C
|
||||
|
||||
/* Isochronous receive registers */
|
||||
/* Add (32 * n) for context n */
|
||||
#define OHCI1394_IsoRcvContextBase 0x400
|
||||
#define OHCI1394_IsoRcvContextControlSet 0x400
|
||||
#define OHCI1394_IsoRcvContextControlClear 0x404
|
||||
#define OHCI1394_IsoRcvCommandPtr 0x40C
|
||||
#define OHCI1394_IsoRcvContextMatch 0x410
|
||||
|
||||
/* Interrupts Mask/Events */
|
||||
|
||||
#define OHCI1394_reqTxComplete 0x00000001
|
||||
#define OHCI1394_respTxComplete 0x00000002
|
||||
#define OHCI1394_ARRQ 0x00000004
|
||||
#define OHCI1394_ARRS 0x00000008
|
||||
#define OHCI1394_RQPkt 0x00000010
|
||||
#define OHCI1394_RSPkt 0x00000020
|
||||
#define OHCI1394_isochTx 0x00000040
|
||||
#define OHCI1394_isochRx 0x00000080
|
||||
#define OHCI1394_postedWriteErr 0x00000100
|
||||
#define OHCI1394_lockRespErr 0x00000200
|
||||
#define OHCI1394_selfIDComplete 0x00010000
|
||||
#define OHCI1394_busReset 0x00020000
|
||||
#define OHCI1394_phy 0x00080000
|
||||
#define OHCI1394_cycleSynch 0x00100000
|
||||
#define OHCI1394_cycle64Seconds 0x00200000
|
||||
#define OHCI1394_cycleLost 0x00400000
|
||||
#define OHCI1394_cycleInconsistent 0x00800000
|
||||
#define OHCI1394_unrecoverableError 0x01000000
|
||||
#define OHCI1394_cycleTooLong 0x02000000
|
||||
#define OHCI1394_phyRegRcvd 0x04000000
|
||||
#define OHCI1394_masterIntEnable 0x80000000
|
||||
|
||||
/* DMA Control flags */
|
||||
#define DMA_CTL_OUTPUT_MORE 0x00000000
|
||||
#define DMA_CTL_OUTPUT_LAST 0x10000000
|
||||
#define DMA_CTL_INPUT_MORE 0x20000000
|
||||
#define DMA_CTL_INPUT_LAST 0x30000000
|
||||
#define DMA_CTL_UPDATE 0x08000000
|
||||
#define DMA_CTL_IMMEDIATE 0x02000000
|
||||
#define DMA_CTL_IRQ 0x00300000
|
||||
#define DMA_CTL_BRANCH 0x000c0000
|
||||
#define DMA_CTL_WAIT 0x00030000
|
||||
|
||||
/* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */
|
||||
#define EVT_NO_STATUS 0x0 /* No event status */
|
||||
#define EVT_RESERVED_A 0x1 /* Reserved, not used !!! */
|
||||
#define EVT_LONG_PACKET 0x2 /* The revc data was longer than the buf */
|
||||
#define EVT_MISSING_ACK 0x3 /* A subaction gap was detected before an ack
|
||||
arrived, or recv'd ack had a parity error */
|
||||
#define EVT_UNDERRUN 0x4 /* Underrun on corresponding FIFO, packet
|
||||
truncated */
|
||||
#define EVT_OVERRUN 0x5 /* A recv FIFO overflowed on reception of ISO
|
||||
packet */
|
||||
#define EVT_DESCRIPTOR_READ 0x6 /* An unrecoverable error occurred while host was
|
||||
reading a descriptor block */
|
||||
#define EVT_DATA_READ 0x7 /* An error occurred while host controller was
|
||||
attempting to read from host memory in the data
|
||||
stage of descriptor processing */
|
||||
#define EVT_DATA_WRITE 0x8 /* An error occurred while host controller was
|
||||
attempting to write either during the data stage
|
||||
of descriptor processing, or when processing a single
|
||||
16-bit host memory write */
|
||||
#define EVT_BUS_RESET 0x9 /* Identifies a PHY packet in the recv buffer as
|
||||
being a synthesized bus reset packet */
|
||||
#define EVT_TIMEOUT 0xa /* Indicates that the asynchronous transmit response
|
||||
packet expired and was not transmitted, or that an
|
||||
IT DMA context experienced a skip processing overflow */
|
||||
#define EVT_TCODE_ERR 0xb /* A bad tCode is associated with this packet.
|
||||
The packet was flushed */
|
||||
#define EVT_RESERVED_B 0xc /* Reserved, not used !!! */
|
||||
#define EVT_RESERVED_C 0xd /* Reserved, not used !!! */
|
||||
#define EVT_UNKNOWN 0xe /* An error condition has occurred that cannot be
|
||||
represented by any other event codes defined herein. */
|
||||
#define EVT_FLUSHED 0xf /* Send by the link side of output FIFO when asynchronous
|
||||
packets are being flushed due to a bus reset. */
|
||||
|
||||
#define OHCI1394_TCODE_PHY 0xE
|
||||
|
||||
/* Node offset map (phys DMA area, posted write area).
|
||||
* The value of OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED may be modified but must
|
||||
* be lower than OHCI1394_MIDDLE_ADDRESS_SPACE.
|
||||
* OHCI1394_PHYS_UPPER_BOUND_FIXED and OHCI1394_MIDDLE_ADDRESS_SPACE are
|
||||
* constants given by the OHCI spec.
|
||||
*/
|
||||
#define OHCI1394_PHYS_UPPER_BOUND_FIXED 0x000100000000ULL /* 4 GB */
|
||||
#define OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED 0x010000000000ULL /* 1 TB */
|
||||
#define OHCI1394_MIDDLE_ADDRESS_SPACE 0xffff00000000ULL
|
||||
|
||||
void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet,
|
||||
int type,
|
||||
void (*func)(unsigned long),
|
||||
unsigned long data);
|
||||
int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
|
||||
struct ohci1394_iso_tasklet *tasklet);
|
||||
void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
|
||||
struct ohci1394_iso_tasklet *tasklet);
|
||||
int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
|
||||
struct ti_ohci *ohci1394_get_struct(int card_num);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,468 +0,0 @@
|
||||
#ifndef __PCILYNX_H__
|
||||
#define __PCILYNX_H__
|
||||
|
||||
|
||||
#define PCILYNX_DRIVER_NAME "pcilynx"
|
||||
#define PCILYNX_MAJOR 177
|
||||
|
||||
#define PCILYNX_MINOR_AUX_START 0
|
||||
#define PCILYNX_MINOR_ROM_START 16
|
||||
#define PCILYNX_MINOR_RAM_START 32
|
||||
|
||||
#define PCILYNX_MAX_REGISTER 0xfff
|
||||
#define PCILYNX_MAX_MEMORY 0xffff
|
||||
|
||||
#define PCI_DEVICE_ID_TI_PCILYNX 0x8000
|
||||
#define MAX_PCILYNX_CARDS 4
|
||||
#define LOCALRAM_SIZE 4096
|
||||
|
||||
#define NUM_ISORCV_PCL 4
|
||||
#define MAX_ISORCV_SIZE 2048
|
||||
#define ISORCV_PER_PAGE (PAGE_SIZE / MAX_ISORCV_SIZE)
|
||||
#define ISORCV_PAGES (NUM_ISORCV_PCL / ISORCV_PER_PAGE)
|
||||
|
||||
#define CHANNEL_LOCALBUS 0
|
||||
#define CHANNEL_ASYNC_RCV 1
|
||||
#define CHANNEL_ISO_RCV 2
|
||||
#define CHANNEL_ASYNC_SEND 3
|
||||
#define CHANNEL_ISO_SEND 4
|
||||
|
||||
#define PCILYNX_CONFIG_ROM_LENGTH 1024
|
||||
|
||||
typedef int pcl_t;
|
||||
|
||||
struct ti_lynx {
|
||||
int id; /* sequential card number */
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
struct pci_dev *dev;
|
||||
|
||||
struct {
|
||||
unsigned reg_1394a:1;
|
||||
u32 vendor;
|
||||
u32 product;
|
||||
} phyic;
|
||||
|
||||
enum { clear, have_intr, have_aux_buf, have_pcl_mem,
|
||||
have_1394_buffers, have_iomappings, is_host } state;
|
||||
|
||||
/* remapped memory spaces */
|
||||
void __iomem *registers;
|
||||
void __iomem *local_rom;
|
||||
void __iomem *local_ram;
|
||||
void __iomem *aux_port;
|
||||
__be32 bus_info_block[5];
|
||||
|
||||
/*
|
||||
* use local RAM of LOCALRAM_SIZE bytes for PCLs, which allows for
|
||||
* LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes);
|
||||
* the following is an allocation bitmap
|
||||
*/
|
||||
u8 pcl_bmap[LOCALRAM_SIZE / 1024];
|
||||
|
||||
/* point to PCLs memory area if needed */
|
||||
void *pcl_mem;
|
||||
dma_addr_t pcl_mem_dma;
|
||||
|
||||
/* PCLs for local mem / aux transfers */
|
||||
pcl_t dmem_pcl;
|
||||
|
||||
/* IEEE-1394 part follows */
|
||||
struct hpsb_host *host;
|
||||
|
||||
int phyid, isroot;
|
||||
int selfid_size;
|
||||
int phy_reg0;
|
||||
|
||||
spinlock_t phy_reg_lock;
|
||||
|
||||
pcl_t rcv_pcl_start, rcv_pcl;
|
||||
void *rcv_page;
|
||||
dma_addr_t rcv_page_dma;
|
||||
int rcv_active;
|
||||
|
||||
struct lynx_send_data {
|
||||
pcl_t pcl_start, pcl;
|
||||
struct list_head queue;
|
||||
struct list_head pcl_queue; /* this queue contains at most one packet */
|
||||
spinlock_t queue_lock;
|
||||
dma_addr_t header_dma, data_dma;
|
||||
int channel;
|
||||
} async, iso_send;
|
||||
|
||||
struct {
|
||||
pcl_t pcl[NUM_ISORCV_PCL];
|
||||
u32 stat[NUM_ISORCV_PCL];
|
||||
void *page[ISORCV_PAGES];
|
||||
dma_addr_t page_dma[ISORCV_PAGES];
|
||||
pcl_t pcl_start;
|
||||
int chan_count;
|
||||
int next, last, used, running;
|
||||
struct tasklet_struct tq;
|
||||
spinlock_t lock;
|
||||
} iso_rcv;
|
||||
|
||||
u32 i2c_driven_state; /* the state we currently drive the Serial EEPROM Control register */
|
||||
};
|
||||
|
||||
/* the per-file data structure for mem space access */
|
||||
struct memdata {
|
||||
struct ti_lynx *lynx;
|
||||
int cid;
|
||||
atomic_t aux_intr_last_seen;
|
||||
/* enum values are the same as LBUS_ADDR_SEL_* values below */
|
||||
enum { rom = 0x10000, aux = 0x20000, ram = 0 } type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Register read and write helper functions.
|
||||
*/
|
||||
static inline void reg_write(const struct ti_lynx *lynx, int offset, u32 data)
|
||||
{
|
||||
writel(data, lynx->registers + offset);
|
||||
}
|
||||
|
||||
static inline u32 reg_read(const struct ti_lynx *lynx, int offset)
|
||||
{
|
||||
return readl(lynx->registers + offset);
|
||||
}
|
||||
|
||||
static inline void reg_set_bits(const struct ti_lynx *lynx, int offset,
|
||||
u32 mask)
|
||||
{
|
||||
reg_write(lynx, offset, (reg_read(lynx, offset) | mask));
|
||||
}
|
||||
|
||||
static inline void reg_clear_bits(const struct ti_lynx *lynx, int offset,
|
||||
u32 mask)
|
||||
{
|
||||
reg_write(lynx, offset, (reg_read(lynx, offset) & ~mask));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* chip register definitions follow */
|
||||
|
||||
#define PCI_LATENCY_CACHELINE 0x0c
|
||||
|
||||
#define MISC_CONTROL 0x40
|
||||
#define MISC_CONTROL_SWRESET (1<<0)
|
||||
|
||||
#define SERIAL_EEPROM_CONTROL 0x44
|
||||
|
||||
#define PCI_INT_STATUS 0x48
|
||||
#define PCI_INT_ENABLE 0x4c
|
||||
/* status and enable have identical bit numbers */
|
||||
#define PCI_INT_INT_PEND (1<<31)
|
||||
#define PCI_INT_FORCED_INT (1<<30)
|
||||
#define PCI_INT_SLV_ADR_PERR (1<<28)
|
||||
#define PCI_INT_SLV_DAT_PERR (1<<27)
|
||||
#define PCI_INT_MST_DAT_PERR (1<<26)
|
||||
#define PCI_INT_MST_DEV_TIMEOUT (1<<25)
|
||||
#define PCI_INT_INTERNAL_SLV_TIMEOUT (1<<23)
|
||||
#define PCI_INT_AUX_TIMEOUT (1<<18)
|
||||
#define PCI_INT_AUX_INT (1<<17)
|
||||
#define PCI_INT_1394 (1<<16)
|
||||
#define PCI_INT_DMA4_PCL (1<<9)
|
||||
#define PCI_INT_DMA4_HLT (1<<8)
|
||||
#define PCI_INT_DMA3_PCL (1<<7)
|
||||
#define PCI_INT_DMA3_HLT (1<<6)
|
||||
#define PCI_INT_DMA2_PCL (1<<5)
|
||||
#define PCI_INT_DMA2_HLT (1<<4)
|
||||
#define PCI_INT_DMA1_PCL (1<<3)
|
||||
#define PCI_INT_DMA1_HLT (1<<2)
|
||||
#define PCI_INT_DMA0_PCL (1<<1)
|
||||
#define PCI_INT_DMA0_HLT (1<<0)
|
||||
/* all DMA interrupts combined: */
|
||||
#define PCI_INT_DMA_ALL 0x3ff
|
||||
|
||||
#define PCI_INT_DMA_HLT(chan) (1 << (chan * 2))
|
||||
#define PCI_INT_DMA_PCL(chan) (1 << (chan * 2 + 1))
|
||||
|
||||
#define LBUS_ADDR 0xb4
|
||||
#define LBUS_ADDR_SEL_RAM (0x0<<16)
|
||||
#define LBUS_ADDR_SEL_ROM (0x1<<16)
|
||||
#define LBUS_ADDR_SEL_AUX (0x2<<16)
|
||||
#define LBUS_ADDR_SEL_ZV (0x3<<16)
|
||||
|
||||
#define GPIO_CTRL_A 0xb8
|
||||
#define GPIO_CTRL_B 0xbc
|
||||
#define GPIO_DATA_BASE 0xc0
|
||||
|
||||
#define DMA_BREG(base, chan) (base + chan * 0x20)
|
||||
#define DMA_SREG(base, chan) (base + chan * 0x10)
|
||||
|
||||
#define DMA0_PREV_PCL 0x100
|
||||
#define DMA1_PREV_PCL 0x120
|
||||
#define DMA2_PREV_PCL 0x140
|
||||
#define DMA3_PREV_PCL 0x160
|
||||
#define DMA4_PREV_PCL 0x180
|
||||
#define DMA_PREV_PCL(chan) (DMA_BREG(DMA0_PREV_PCL, chan))
|
||||
|
||||
#define DMA0_CURRENT_PCL 0x104
|
||||
#define DMA1_CURRENT_PCL 0x124
|
||||
#define DMA2_CURRENT_PCL 0x144
|
||||
#define DMA3_CURRENT_PCL 0x164
|
||||
#define DMA4_CURRENT_PCL 0x184
|
||||
#define DMA_CURRENT_PCL(chan) (DMA_BREG(DMA0_CURRENT_PCL, chan))
|
||||
|
||||
#define DMA0_CHAN_STAT 0x10c
|
||||
#define DMA1_CHAN_STAT 0x12c
|
||||
#define DMA2_CHAN_STAT 0x14c
|
||||
#define DMA3_CHAN_STAT 0x16c
|
||||
#define DMA4_CHAN_STAT 0x18c
|
||||
#define DMA_CHAN_STAT(chan) (DMA_BREG(DMA0_CHAN_STAT, chan))
|
||||
/* CHAN_STATUS registers share bits */
|
||||
#define DMA_CHAN_STAT_SELFID (1<<31)
|
||||
#define DMA_CHAN_STAT_ISOPKT (1<<30)
|
||||
#define DMA_CHAN_STAT_PCIERR (1<<29)
|
||||
#define DMA_CHAN_STAT_PKTERR (1<<28)
|
||||
#define DMA_CHAN_STAT_PKTCMPL (1<<27)
|
||||
#define DMA_CHAN_STAT_SPECIALACK (1<<14)
|
||||
|
||||
|
||||
#define DMA0_CHAN_CTRL 0x110
|
||||
#define DMA1_CHAN_CTRL 0x130
|
||||
#define DMA2_CHAN_CTRL 0x150
|
||||
#define DMA3_CHAN_CTRL 0x170
|
||||
#define DMA4_CHAN_CTRL 0x190
|
||||
#define DMA_CHAN_CTRL(chan) (DMA_BREG(DMA0_CHAN_CTRL, chan))
|
||||
/* CHAN_CTRL registers share bits */
|
||||
#define DMA_CHAN_CTRL_ENABLE (1<<31)
|
||||
#define DMA_CHAN_CTRL_BUSY (1<<30)
|
||||
#define DMA_CHAN_CTRL_LINK (1<<29)
|
||||
|
||||
#define DMA0_READY 0x114
|
||||
#define DMA1_READY 0x134
|
||||
#define DMA2_READY 0x154
|
||||
#define DMA3_READY 0x174
|
||||
#define DMA4_READY 0x194
|
||||
#define DMA_READY(chan) (DMA_BREG(DMA0_READY, chan))
|
||||
|
||||
#define DMA_GLOBAL_REGISTER 0x908
|
||||
|
||||
#define FIFO_SIZES 0xa00
|
||||
|
||||
#define FIFO_CONTROL 0xa10
|
||||
#define FIFO_CONTROL_GRF_FLUSH (1<<4)
|
||||
#define FIFO_CONTROL_ITF_FLUSH (1<<3)
|
||||
#define FIFO_CONTROL_ATF_FLUSH (1<<2)
|
||||
|
||||
#define FIFO_XMIT_THRESHOLD 0xa14
|
||||
|
||||
#define DMA0_WORD0_CMP_VALUE 0xb00
|
||||
#define DMA1_WORD0_CMP_VALUE 0xb10
|
||||
#define DMA2_WORD0_CMP_VALUE 0xb20
|
||||
#define DMA3_WORD0_CMP_VALUE 0xb30
|
||||
#define DMA4_WORD0_CMP_VALUE 0xb40
|
||||
#define DMA_WORD0_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD0_CMP_VALUE, chan))
|
||||
|
||||
#define DMA0_WORD0_CMP_ENABLE 0xb04
|
||||
#define DMA1_WORD0_CMP_ENABLE 0xb14
|
||||
#define DMA2_WORD0_CMP_ENABLE 0xb24
|
||||
#define DMA3_WORD0_CMP_ENABLE 0xb34
|
||||
#define DMA4_WORD0_CMP_ENABLE 0xb44
|
||||
#define DMA_WORD0_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD0_CMP_ENABLE,chan))
|
||||
|
||||
#define DMA0_WORD1_CMP_VALUE 0xb08
|
||||
#define DMA1_WORD1_CMP_VALUE 0xb18
|
||||
#define DMA2_WORD1_CMP_VALUE 0xb28
|
||||
#define DMA3_WORD1_CMP_VALUE 0xb38
|
||||
#define DMA4_WORD1_CMP_VALUE 0xb48
|
||||
#define DMA_WORD1_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD1_CMP_VALUE, chan))
|
||||
|
||||
#define DMA0_WORD1_CMP_ENABLE 0xb0c
|
||||
#define DMA1_WORD1_CMP_ENABLE 0xb1c
|
||||
#define DMA2_WORD1_CMP_ENABLE 0xb2c
|
||||
#define DMA3_WORD1_CMP_ENABLE 0xb3c
|
||||
#define DMA4_WORD1_CMP_ENABLE 0xb4c
|
||||
#define DMA_WORD1_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD1_CMP_ENABLE,chan))
|
||||
/* word 1 compare enable flags */
|
||||
#define DMA_WORD1_CMP_MATCH_OTHERBUS (1<<15)
|
||||
#define DMA_WORD1_CMP_MATCH_BROADCAST (1<<14)
|
||||
#define DMA_WORD1_CMP_MATCH_BUS_BCAST (1<<13)
|
||||
#define DMA_WORD1_CMP_MATCH_LOCAL_NODE (1<<12)
|
||||
#define DMA_WORD1_CMP_MATCH_EXACT (1<<11)
|
||||
#define DMA_WORD1_CMP_ENABLE_SELF_ID (1<<10)
|
||||
#define DMA_WORD1_CMP_ENABLE_MASTER (1<<8)
|
||||
|
||||
#define LINK_ID 0xf00
|
||||
#define LINK_ID_BUS(id) (id<<22)
|
||||
#define LINK_ID_NODE(id) (id<<16)
|
||||
|
||||
#define LINK_CONTROL 0xf04
|
||||
#define LINK_CONTROL_BUSY (1<<29)
|
||||
#define LINK_CONTROL_TX_ISO_EN (1<<26)
|
||||
#define LINK_CONTROL_RX_ISO_EN (1<<25)
|
||||
#define LINK_CONTROL_TX_ASYNC_EN (1<<24)
|
||||
#define LINK_CONTROL_RX_ASYNC_EN (1<<23)
|
||||
#define LINK_CONTROL_RESET_TX (1<<21)
|
||||
#define LINK_CONTROL_RESET_RX (1<<20)
|
||||
#define LINK_CONTROL_CYCMASTER (1<<11)
|
||||
#define LINK_CONTROL_CYCSOURCE (1<<10)
|
||||
#define LINK_CONTROL_CYCTIMEREN (1<<9)
|
||||
#define LINK_CONTROL_RCV_CMP_VALID (1<<7)
|
||||
#define LINK_CONTROL_SNOOP_ENABLE (1<<6)
|
||||
|
||||
#define CYCLE_TIMER 0xf08
|
||||
|
||||
#define LINK_PHY 0xf0c
|
||||
#define LINK_PHY_READ (1<<31)
|
||||
#define LINK_PHY_WRITE (1<<30)
|
||||
#define LINK_PHY_ADDR(addr) (addr<<24)
|
||||
#define LINK_PHY_WDATA(data) (data<<16)
|
||||
#define LINK_PHY_RADDR(addr) (addr<<8)
|
||||
|
||||
|
||||
#define LINK_INT_STATUS 0xf14
|
||||
#define LINK_INT_ENABLE 0xf18
|
||||
/* status and enable have identical bit numbers */
|
||||
#define LINK_INT_LINK_INT (1<<31)
|
||||
#define LINK_INT_PHY_TIMEOUT (1<<30)
|
||||
#define LINK_INT_PHY_REG_RCVD (1<<29)
|
||||
#define LINK_INT_PHY_BUSRESET (1<<28)
|
||||
#define LINK_INT_TX_RDY (1<<26)
|
||||
#define LINK_INT_RX_DATA_RDY (1<<25)
|
||||
#define LINK_INT_ISO_STUCK (1<<20)
|
||||
#define LINK_INT_ASYNC_STUCK (1<<19)
|
||||
#define LINK_INT_SENT_REJECT (1<<17)
|
||||
#define LINK_INT_HDR_ERR (1<<16)
|
||||
#define LINK_INT_TX_INVALID_TC (1<<15)
|
||||
#define LINK_INT_CYC_SECOND (1<<11)
|
||||
#define LINK_INT_CYC_START (1<<10)
|
||||
#define LINK_INT_CYC_DONE (1<<9)
|
||||
#define LINK_INT_CYC_PENDING (1<<8)
|
||||
#define LINK_INT_CYC_LOST (1<<7)
|
||||
#define LINK_INT_CYC_ARB_FAILED (1<<6)
|
||||
#define LINK_INT_GRF_OVERFLOW (1<<5)
|
||||
#define LINK_INT_ITF_UNDERFLOW (1<<4)
|
||||
#define LINK_INT_ATF_UNDERFLOW (1<<3)
|
||||
#define LINK_INT_ISOARB_FAILED (1<<0)
|
||||
|
||||
/* PHY specifics */
|
||||
#define PHY_VENDORID_TI 0x800028
|
||||
#define PHY_PRODUCTID_TSB41LV03 0x000000
|
||||
|
||||
|
||||
/* this is the physical layout of a PCL, its size is 128 bytes */
|
||||
struct ti_pcl {
|
||||
u32 next;
|
||||
u32 async_error_next;
|
||||
u32 user_data;
|
||||
u32 pcl_status;
|
||||
u32 remaining_transfer_count;
|
||||
u32 next_data_buffer;
|
||||
struct {
|
||||
u32 control;
|
||||
u32 pointer;
|
||||
} buffer[13] __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER))
|
||||
|
||||
|
||||
static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
const struct ti_pcl *pcl)
|
||||
{
|
||||
memcpy_le32((u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
|
||||
(u32 *)pcl, sizeof(struct ti_pcl));
|
||||
}
|
||||
|
||||
static inline void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
struct ti_pcl *pcl)
|
||||
{
|
||||
memcpy_le32((u32 *)pcl,
|
||||
(u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
|
||||
sizeof(struct ti_pcl));
|
||||
}
|
||||
|
||||
static inline u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
|
||||
{
|
||||
return lynx->pcl_mem_dma + pclid * sizeof(struct ti_pcl);
|
||||
}
|
||||
|
||||
|
||||
#if defined (__BIG_ENDIAN)
|
||||
typedef struct ti_pcl pcltmp_t;
|
||||
|
||||
static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
pcltmp_t *tmp)
|
||||
{
|
||||
get_pcl(lynx, pclid, tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
pcltmp_t *tmp)
|
||||
{
|
||||
put_pcl(lynx, pclid, tmp);
|
||||
}
|
||||
|
||||
#else
|
||||
typedef int pcltmp_t; /* just a dummy */
|
||||
|
||||
static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
pcltmp_t *tmp)
|
||||
{
|
||||
return lynx->pcl_mem + pclid * sizeof(struct ti_pcl);
|
||||
}
|
||||
|
||||
static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
pcltmp_t *tmp)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static inline void run_sub_pcl(const struct ti_lynx *lynx, pcl_t pclid, int idx,
|
||||
int dmachan)
|
||||
{
|
||||
reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20,
|
||||
pcl_bus(lynx, pclid) + idx * 4);
|
||||
reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20,
|
||||
DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK);
|
||||
}
|
||||
|
||||
static inline void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan)
|
||||
{
|
||||
run_sub_pcl(lynx, pclid, 0, dmachan);
|
||||
}
|
||||
|
||||
#define PCL_NEXT_INVALID (1<<0)
|
||||
|
||||
/* transfer commands */
|
||||
#define PCL_CMD_RCV (0x1<<24)
|
||||
#define PCL_CMD_RCV_AND_UPDATE (0xa<<24)
|
||||
#define PCL_CMD_XMT (0x2<<24)
|
||||
#define PCL_CMD_UNFXMT (0xc<<24)
|
||||
#define PCL_CMD_PCI_TO_LBUS (0x8<<24)
|
||||
#define PCL_CMD_LBUS_TO_PCI (0x9<<24)
|
||||
|
||||
/* aux commands */
|
||||
#define PCL_CMD_NOP (0x0<<24)
|
||||
#define PCL_CMD_LOAD (0x3<<24)
|
||||
#define PCL_CMD_STOREQ (0x4<<24)
|
||||
#define PCL_CMD_STORED (0xb<<24)
|
||||
#define PCL_CMD_STORE0 (0x5<<24)
|
||||
#define PCL_CMD_STORE1 (0x6<<24)
|
||||
#define PCL_CMD_COMPARE (0xe<<24)
|
||||
#define PCL_CMD_SWAP_COMPARE (0xf<<24)
|
||||
#define PCL_CMD_ADD (0xd<<24)
|
||||
#define PCL_CMD_BRANCH (0x7<<24)
|
||||
|
||||
/* BRANCH condition codes */
|
||||
#define PCL_COND_DMARDY_SET (0x1<<20)
|
||||
#define PCL_COND_DMARDY_CLEAR (0x2<<20)
|
||||
|
||||
#define PCL_GEN_INTR (1<<19)
|
||||
#define PCL_LAST_BUFF (1<<18)
|
||||
#define PCL_LAST_CMD (PCL_LAST_BUFF)
|
||||
#define PCL_WAITSTAT (1<<17)
|
||||
#define PCL_BIGENDIAN (1<<16)
|
||||
#define PCL_ISOMODE (1<<12)
|
||||
|
||||
#endif
|
@ -1,81 +0,0 @@
|
||||
#ifndef IEEE1394_RAW1394_PRIVATE_H
|
||||
#define IEEE1394_RAW1394_PRIVATE_H
|
||||
|
||||
/* header for definitions that are private to the raw1394 driver
|
||||
and not visible to user-space */
|
||||
|
||||
#define RAW1394_DEVICE_MAJOR 171
|
||||
#define RAW1394_DEVICE_NAME "raw1394"
|
||||
|
||||
#define RAW1394_MAX_USER_CSR_DIRS 16
|
||||
|
||||
struct iso_block_store {
|
||||
atomic_t refcount;
|
||||
size_t data_size;
|
||||
quadlet_t data[0];
|
||||
};
|
||||
|
||||
enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0,
|
||||
RAW1394_ISO_RECV = 1,
|
||||
RAW1394_ISO_XMIT = 2 };
|
||||
|
||||
struct file_info {
|
||||
struct list_head list;
|
||||
|
||||
struct mutex state_mutex;
|
||||
enum { opened, initialized, connected } state;
|
||||
unsigned int protocol_version;
|
||||
|
||||
struct hpsb_host *host;
|
||||
|
||||
struct list_head req_pending; /* protected by reqlists_lock */
|
||||
struct list_head req_complete; /* protected by reqlists_lock */
|
||||
spinlock_t reqlists_lock;
|
||||
wait_queue_head_t wait_complete;
|
||||
|
||||
struct list_head addr_list; /* protected by host_info_lock */
|
||||
|
||||
u8 __user *fcp_buffer;
|
||||
|
||||
u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
|
||||
|
||||
/* new rawiso API */
|
||||
enum raw1394_iso_state iso_state;
|
||||
struct hpsb_iso *iso_handle;
|
||||
|
||||
/* User space's CSR1212 dynamic ConfigROM directories */
|
||||
struct csr1212_keyval *csr1212_dirs[RAW1394_MAX_USER_CSR_DIRS];
|
||||
|
||||
/* Legacy ConfigROM update flag */
|
||||
u8 cfgrom_upd;
|
||||
};
|
||||
|
||||
struct arm_addr {
|
||||
struct list_head addr_list; /* file_info list */
|
||||
u64 start, end;
|
||||
u64 arm_tag;
|
||||
u8 access_rights;
|
||||
u8 notification_options;
|
||||
u8 client_transactions;
|
||||
u64 recvb;
|
||||
u16 rec_length;
|
||||
u8 *addr_space_buffer; /* accessed by read/write/lock requests */
|
||||
};
|
||||
|
||||
struct pending_request {
|
||||
struct list_head list;
|
||||
struct file_info *file_info;
|
||||
struct hpsb_packet *packet;
|
||||
struct iso_block_store *ibs;
|
||||
quadlet_t *data;
|
||||
int free_data;
|
||||
struct raw1394_request req;
|
||||
};
|
||||
|
||||
struct host_info {
|
||||
struct list_head list;
|
||||
struct hpsb_host *host;
|
||||
struct list_head file_info_list; /* protected by host_info_lock */
|
||||
};
|
||||
|
||||
#endif /* IEEE1394_RAW1394_PRIVATE_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,191 +0,0 @@
|
||||
#ifndef IEEE1394_RAW1394_H
|
||||
#define IEEE1394_RAW1394_H
|
||||
|
||||
/* header for the raw1394 API that is exported to user-space */
|
||||
|
||||
#define RAW1394_KERNELAPI_VERSION 4
|
||||
|
||||
/* state: opened */
|
||||
#define RAW1394_REQ_INITIALIZE 1
|
||||
|
||||
/* state: initialized */
|
||||
#define RAW1394_REQ_LIST_CARDS 2
|
||||
#define RAW1394_REQ_SET_CARD 3
|
||||
|
||||
/* state: connected */
|
||||
#define RAW1394_REQ_ASYNC_READ 100
|
||||
#define RAW1394_REQ_ASYNC_WRITE 101
|
||||
#define RAW1394_REQ_LOCK 102
|
||||
#define RAW1394_REQ_LOCK64 103
|
||||
#define RAW1394_REQ_ISO_SEND 104 /* removed ABI, now a no-op */
|
||||
#define RAW1394_REQ_ASYNC_SEND 105
|
||||
#define RAW1394_REQ_ASYNC_STREAM 106
|
||||
|
||||
#define RAW1394_REQ_ISO_LISTEN 200 /* removed ABI, now a no-op */
|
||||
#define RAW1394_REQ_FCP_LISTEN 201
|
||||
#define RAW1394_REQ_RESET_BUS 202
|
||||
#define RAW1394_REQ_GET_ROM 203
|
||||
#define RAW1394_REQ_UPDATE_ROM 204
|
||||
#define RAW1394_REQ_ECHO 205
|
||||
#define RAW1394_REQ_MODIFY_ROM 206
|
||||
|
||||
#define RAW1394_REQ_ARM_REGISTER 300
|
||||
#define RAW1394_REQ_ARM_UNREGISTER 301
|
||||
#define RAW1394_REQ_ARM_SET_BUF 302
|
||||
#define RAW1394_REQ_ARM_GET_BUF 303
|
||||
|
||||
#define RAW1394_REQ_RESET_NOTIFY 400
|
||||
|
||||
#define RAW1394_REQ_PHYPACKET 500
|
||||
|
||||
/* kernel to user */
|
||||
#define RAW1394_REQ_BUS_RESET 10000
|
||||
#define RAW1394_REQ_ISO_RECEIVE 10001
|
||||
#define RAW1394_REQ_FCP_REQUEST 10002
|
||||
#define RAW1394_REQ_ARM 10003
|
||||
#define RAW1394_REQ_RAWISO_ACTIVITY 10004
|
||||
|
||||
/* error codes */
|
||||
#define RAW1394_ERROR_NONE 0
|
||||
#define RAW1394_ERROR_COMPAT (-1001)
|
||||
#define RAW1394_ERROR_STATE_ORDER (-1002)
|
||||
#define RAW1394_ERROR_GENERATION (-1003)
|
||||
#define RAW1394_ERROR_INVALID_ARG (-1004)
|
||||
#define RAW1394_ERROR_MEMFAULT (-1005)
|
||||
#define RAW1394_ERROR_ALREADY (-1006)
|
||||
|
||||
#define RAW1394_ERROR_EXCESSIVE (-1020)
|
||||
#define RAW1394_ERROR_UNTIDY_LEN (-1021)
|
||||
|
||||
#define RAW1394_ERROR_SEND_ERROR (-1100)
|
||||
#define RAW1394_ERROR_ABORTED (-1101)
|
||||
#define RAW1394_ERROR_TIMEOUT (-1102)
|
||||
|
||||
/* arm_codes */
|
||||
#define ARM_READ 1
|
||||
#define ARM_WRITE 2
|
||||
#define ARM_LOCK 4
|
||||
|
||||
#define RAW1394_LONG_RESET 0
|
||||
#define RAW1394_SHORT_RESET 1
|
||||
|
||||
/* busresetnotify ... */
|
||||
#define RAW1394_NOTIFY_OFF 0
|
||||
#define RAW1394_NOTIFY_ON 1
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
struct raw1394_request {
|
||||
__u32 type;
|
||||
__s32 error;
|
||||
__u32 misc;
|
||||
|
||||
__u32 generation;
|
||||
__u32 length;
|
||||
|
||||
__u64 address;
|
||||
|
||||
__u64 tag;
|
||||
|
||||
__u64 sendb;
|
||||
__u64 recvb;
|
||||
};
|
||||
|
||||
struct raw1394_khost_list {
|
||||
__u32 nodes;
|
||||
__u8 name[32];
|
||||
};
|
||||
|
||||
typedef struct arm_request {
|
||||
__u16 destination_nodeid;
|
||||
__u16 source_nodeid;
|
||||
__u64 destination_offset;
|
||||
__u8 tlabel;
|
||||
__u8 tcode;
|
||||
__u8 extended_transaction_code;
|
||||
__u32 generation;
|
||||
__u16 buffer_length;
|
||||
__u8 __user *buffer;
|
||||
} *arm_request_t;
|
||||
|
||||
typedef struct arm_response {
|
||||
__s32 response_code;
|
||||
__u16 buffer_length;
|
||||
__u8 __user *buffer;
|
||||
} *arm_response_t;
|
||||
|
||||
typedef struct arm_request_response {
|
||||
struct arm_request __user *request;
|
||||
struct arm_response __user *response;
|
||||
} *arm_request_response_t;
|
||||
|
||||
/* rawiso API */
|
||||
#include "ieee1394-ioctl.h"
|
||||
|
||||
/* per-packet metadata embedded in the ringbuffer */
|
||||
/* must be identical to hpsb_iso_packet_info in iso.h! */
|
||||
struct raw1394_iso_packet_info {
|
||||
__u32 offset;
|
||||
__u16 len;
|
||||
__u16 cycle; /* recv only */
|
||||
__u8 channel; /* recv only */
|
||||
__u8 tag;
|
||||
__u8 sy;
|
||||
};
|
||||
|
||||
/* argument for RAW1394_ISO_RECV/XMIT_PACKETS ioctls */
|
||||
struct raw1394_iso_packets {
|
||||
__u32 n_packets;
|
||||
struct raw1394_iso_packet_info __user *infos;
|
||||
};
|
||||
|
||||
struct raw1394_iso_config {
|
||||
/* size of packet data buffer, in bytes (will be rounded up to PAGE_SIZE) */
|
||||
__u32 data_buf_size;
|
||||
|
||||
/* # of packets to buffer */
|
||||
__u32 buf_packets;
|
||||
|
||||
/* iso channel (set to -1 for multi-channel recv) */
|
||||
__s32 channel;
|
||||
|
||||
/* xmit only - iso transmission speed */
|
||||
__u8 speed;
|
||||
|
||||
/* The mode of the dma when receiving iso data. Must be supported by chip */
|
||||
__u8 dma_mode;
|
||||
|
||||
/* max. latency of buffer, in packets (-1 if you don't care) */
|
||||
__s32 irq_interval;
|
||||
};
|
||||
|
||||
/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */
|
||||
struct raw1394_iso_status {
|
||||
/* current settings */
|
||||
struct raw1394_iso_config config;
|
||||
|
||||
/* number of packets waiting to be filled with data (ISO transmission)
|
||||
or containing data received (ISO reception) */
|
||||
__u32 n_packets;
|
||||
|
||||
/* approximate number of packets dropped due to overflow or
|
||||
underflow of the packet buffer (a value of zero guarantees
|
||||
that no packets have been dropped) */
|
||||
__u32 overflows;
|
||||
|
||||
/* cycle number at which next packet will be transmitted;
|
||||
-1 if not known */
|
||||
__s16 xmit_cycle;
|
||||
};
|
||||
|
||||
/* argument to RAW1394_IOC_GET_CYCLE_TIMER ioctl */
|
||||
struct raw1394_cycle_timer {
|
||||
/* contents of Isochronous Cycle Timer register,
|
||||
as in OHCI 1.1 clause 5.13 (also with non-OHCI hosts) */
|
||||
__u32 cycle_timer;
|
||||
|
||||
/* local time in microseconds since Epoch,
|
||||
simultaneously read with cycle timer */
|
||||
__u64 local_time;
|
||||
};
|
||||
#endif /* IEEE1394_RAW1394_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,346 +0,0 @@
|
||||
/*
|
||||
* sbp2.h - Defines and prototypes for sbp2.c
|
||||
*
|
||||
* Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
|
||||
* jamesg@filanet.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef SBP2_H
|
||||
#define SBP2_H
|
||||
|
||||
#define SBP2_DEVICE_NAME "sbp2"
|
||||
|
||||
/*
|
||||
* There is no transport protocol limit to the CDB length, but we implement
|
||||
* a fixed length only. 16 bytes is enough for disks larger than 2 TB.
|
||||
*/
|
||||
#define SBP2_MAX_CDB_SIZE 16
|
||||
|
||||
/*
|
||||
* SBP-2 specific definitions
|
||||
*/
|
||||
|
||||
#define ORB_DIRECTION_WRITE_TO_MEDIA 0x0
|
||||
#define ORB_DIRECTION_READ_FROM_MEDIA 0x1
|
||||
#define ORB_DIRECTION_NO_DATA_TRANSFER 0x2
|
||||
|
||||
#define ORB_SET_NULL_PTR(v) (((v) & 0x1) << 31)
|
||||
#define ORB_SET_NOTIFY(v) (((v) & 0x1) << 31)
|
||||
#define ORB_SET_RQ_FMT(v) (((v) & 0x3) << 29)
|
||||
#define ORB_SET_NODE_ID(v) (((v) & 0xffff) << 16)
|
||||
#define ORB_SET_STATUS_FIFO_HI(v, id) ((v) >> 32 | ORB_SET_NODE_ID(id))
|
||||
#define ORB_SET_STATUS_FIFO_LO(v) ((v) & 0xffffffff)
|
||||
#define ORB_SET_DATA_SIZE(v) ((v) & 0xffff)
|
||||
#define ORB_SET_PAGE_SIZE(v) (((v) & 0x7) << 16)
|
||||
#define ORB_SET_PAGE_TABLE_PRESENT(v) (((v) & 0x1) << 19)
|
||||
#define ORB_SET_MAX_PAYLOAD(v) (((v) & 0xf) << 20)
|
||||
#define ORB_SET_SPEED(v) (((v) & 0x7) << 24)
|
||||
#define ORB_SET_DIRECTION(v) (((v) & 0x1) << 27)
|
||||
|
||||
struct sbp2_command_orb {
|
||||
u32 next_ORB_hi;
|
||||
u32 next_ORB_lo;
|
||||
u32 data_descriptor_hi;
|
||||
u32 data_descriptor_lo;
|
||||
u32 misc;
|
||||
u8 cdb[SBP2_MAX_CDB_SIZE];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SBP2_LOGIN_REQUEST 0x0
|
||||
#define SBP2_QUERY_LOGINS_REQUEST 0x1
|
||||
#define SBP2_RECONNECT_REQUEST 0x3
|
||||
#define SBP2_SET_PASSWORD_REQUEST 0x4
|
||||
#define SBP2_LOGOUT_REQUEST 0x7
|
||||
#define SBP2_ABORT_TASK_REQUEST 0xb
|
||||
#define SBP2_ABORT_TASK_SET 0xc
|
||||
#define SBP2_LOGICAL_UNIT_RESET 0xe
|
||||
#define SBP2_TARGET_RESET_REQUEST 0xf
|
||||
|
||||
#define ORB_SET_LUN(v) ((v) & 0xffff)
|
||||
#define ORB_SET_FUNCTION(v) (((v) & 0xf) << 16)
|
||||
#define ORB_SET_RECONNECT(v) (((v) & 0xf) << 20)
|
||||
#define ORB_SET_EXCLUSIVE(v) ((v) ? 1 << 28 : 0)
|
||||
#define ORB_SET_LOGIN_RESP_LENGTH(v) ((v) & 0xffff)
|
||||
#define ORB_SET_PASSWD_LENGTH(v) (((v) & 0xffff) << 16)
|
||||
|
||||
struct sbp2_login_orb {
|
||||
u32 password_hi;
|
||||
u32 password_lo;
|
||||
u32 login_response_hi;
|
||||
u32 login_response_lo;
|
||||
u32 lun_misc;
|
||||
u32 passwd_resp_lengths;
|
||||
u32 status_fifo_hi;
|
||||
u32 status_fifo_lo;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define RESPONSE_GET_LOGIN_ID(v) ((v) & 0xffff)
|
||||
#define RESPONSE_GET_LENGTH(v) (((v) >> 16) & 0xffff)
|
||||
#define RESPONSE_GET_RECONNECT_HOLD(v) ((v) & 0xffff)
|
||||
|
||||
struct sbp2_login_response {
|
||||
u32 length_login_ID;
|
||||
u32 command_block_agent_hi;
|
||||
u32 command_block_agent_lo;
|
||||
u32 reconnect_hold;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define ORB_SET_LOGIN_ID(v) ((v) & 0xffff)
|
||||
#define ORB_SET_QUERY_LOGINS_RESP_LENGTH(v) ((v) & 0xffff)
|
||||
|
||||
struct sbp2_query_logins_orb {
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 query_response_hi;
|
||||
u32 query_response_lo;
|
||||
u32 lun_misc;
|
||||
u32 reserved_resp_length;
|
||||
u32 status_fifo_hi;
|
||||
u32 status_fifo_lo;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define RESPONSE_GET_MAX_LOGINS(v) ((v) & 0xffff)
|
||||
#define RESPONSE_GET_ACTIVE_LOGINS(v) ((RESPONSE_GET_LENGTH((v)) - 4) / 12)
|
||||
|
||||
struct sbp2_query_logins_response {
|
||||
u32 length_max_logins;
|
||||
u32 misc_IDs;
|
||||
u32 initiator_misc_hi;
|
||||
u32 initiator_misc_lo;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sbp2_reconnect_orb {
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 reserved3;
|
||||
u32 reserved4;
|
||||
u32 login_ID_misc;
|
||||
u32 reserved5;
|
||||
u32 status_fifo_hi;
|
||||
u32 status_fifo_lo;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sbp2_logout_orb {
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 reserved3;
|
||||
u32 reserved4;
|
||||
u32 login_ID_misc;
|
||||
u32 reserved5;
|
||||
u32 status_fifo_hi;
|
||||
u32 status_fifo_lo;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sbp2_unrestricted_page_table {
|
||||
__be32 high;
|
||||
__be32 low;
|
||||
};
|
||||
|
||||
#define RESP_STATUS_REQUEST_COMPLETE 0x0
|
||||
#define RESP_STATUS_TRANSPORT_FAILURE 0x1
|
||||
#define RESP_STATUS_ILLEGAL_REQUEST 0x2
|
||||
#define RESP_STATUS_VENDOR_DEPENDENT 0x3
|
||||
|
||||
#define SBP2_STATUS_NO_ADDITIONAL_INFO 0x0
|
||||
#define SBP2_STATUS_REQ_TYPE_NOT_SUPPORTED 0x1
|
||||
#define SBP2_STATUS_SPEED_NOT_SUPPORTED 0x2
|
||||
#define SBP2_STATUS_PAGE_SIZE_NOT_SUPPORTED 0x3
|
||||
#define SBP2_STATUS_ACCESS_DENIED 0x4
|
||||
#define SBP2_STATUS_LU_NOT_SUPPORTED 0x5
|
||||
#define SBP2_STATUS_MAX_PAYLOAD_TOO_SMALL 0x6
|
||||
#define SBP2_STATUS_RESOURCES_UNAVAILABLE 0x8
|
||||
#define SBP2_STATUS_FUNCTION_REJECTED 0x9
|
||||
#define SBP2_STATUS_LOGIN_ID_NOT_RECOGNIZED 0xa
|
||||
#define SBP2_STATUS_DUMMY_ORB_COMPLETED 0xb
|
||||
#define SBP2_STATUS_REQUEST_ABORTED 0xc
|
||||
#define SBP2_STATUS_UNSPECIFIED_ERROR 0xff
|
||||
|
||||
#define SFMT_CURRENT_ERROR 0x0
|
||||
#define SFMT_DEFERRED_ERROR 0x1
|
||||
#define SFMT_VENDOR_DEPENDENT_STATUS 0x3
|
||||
|
||||
#define STATUS_GET_SRC(v) (((v) >> 30) & 0x3)
|
||||
#define STATUS_GET_RESP(v) (((v) >> 28) & 0x3)
|
||||
#define STATUS_GET_LEN(v) (((v) >> 24) & 0x7)
|
||||
#define STATUS_GET_SBP_STATUS(v) (((v) >> 16) & 0xff)
|
||||
#define STATUS_GET_ORB_OFFSET_HI(v) ((v) & 0x0000ffff)
|
||||
#define STATUS_TEST_DEAD(v) ((v) & 0x08000000)
|
||||
/* test 'resp' | 'dead' | 'sbp2_status' */
|
||||
#define STATUS_TEST_RDS(v) ((v) & 0x38ff0000)
|
||||
|
||||
struct sbp2_status_block {
|
||||
u32 ORB_offset_hi_misc;
|
||||
u32 ORB_offset_lo;
|
||||
u8 command_set_dependent[24];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/*
|
||||
* SBP2 related configuration ROM definitions
|
||||
*/
|
||||
|
||||
#define SBP2_UNIT_DIRECTORY_OFFSET_KEY 0xd1
|
||||
#define SBP2_CSR_OFFSET_KEY 0x54
|
||||
#define SBP2_UNIT_SPEC_ID_KEY 0x12
|
||||
#define SBP2_UNIT_SW_VERSION_KEY 0x13
|
||||
#define SBP2_COMMAND_SET_SPEC_ID_KEY 0x38
|
||||
#define SBP2_COMMAND_SET_KEY 0x39
|
||||
#define SBP2_UNIT_CHARACTERISTICS_KEY 0x3a
|
||||
#define SBP2_DEVICE_TYPE_AND_LUN_KEY 0x14
|
||||
#define SBP2_FIRMWARE_REVISION_KEY 0x3c
|
||||
|
||||
#define SBP2_AGENT_STATE_OFFSET 0x00ULL
|
||||
#define SBP2_AGENT_RESET_OFFSET 0x04ULL
|
||||
#define SBP2_ORB_POINTER_OFFSET 0x08ULL
|
||||
#define SBP2_DOORBELL_OFFSET 0x10ULL
|
||||
#define SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET 0x14ULL
|
||||
#define SBP2_UNSOLICITED_STATUS_VALUE 0xf
|
||||
|
||||
#define SBP2_BUSY_TIMEOUT_ADDRESS 0xfffff0000210ULL
|
||||
/* biggest possible value for Single Phase Retry count is 0xf */
|
||||
#define SBP2_BUSY_TIMEOUT_VALUE 0xf
|
||||
|
||||
#define SBP2_AGENT_RESET_DATA 0xf
|
||||
|
||||
#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e
|
||||
#define SBP2_SW_VERSION_ENTRY 0x00010483
|
||||
|
||||
/*
|
||||
* The default maximum s/g segment size of a FireWire controller is
|
||||
* usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
|
||||
* be quadlet-aligned, we set the length limit to 0xffff & ~3.
|
||||
*/
|
||||
#define SBP2_MAX_SEG_SIZE 0xfffc
|
||||
|
||||
/*
|
||||
* There is no real limitation of the queue depth (i.e. length of the linked
|
||||
* list of command ORBs) at the target. The chosen depth is merely an
|
||||
* implementation detail of the sbp2 driver.
|
||||
*/
|
||||
#define SBP2_MAX_CMDS 8
|
||||
|
||||
#define SBP2_SCSI_STATUS_GOOD 0x0
|
||||
#define SBP2_SCSI_STATUS_CHECK_CONDITION 0x2
|
||||
#define SBP2_SCSI_STATUS_CONDITION_MET 0x4
|
||||
#define SBP2_SCSI_STATUS_BUSY 0x8
|
||||
#define SBP2_SCSI_STATUS_RESERVATION_CONFLICT 0x18
|
||||
#define SBP2_SCSI_STATUS_COMMAND_TERMINATED 0x22
|
||||
#define SBP2_SCSI_STATUS_SELECTION_TIMEOUT 0xff
|
||||
|
||||
|
||||
/*
|
||||
* Representations of commands and devices
|
||||
*/
|
||||
|
||||
/* Per SCSI command */
|
||||
struct sbp2_command_info {
|
||||
struct list_head list;
|
||||
struct sbp2_command_orb command_orb;
|
||||
dma_addr_t command_orb_dma;
|
||||
struct scsi_cmnd *Current_SCpnt;
|
||||
void (*Current_done)(struct scsi_cmnd *);
|
||||
|
||||
/* Also need s/g structure for each sbp2 command */
|
||||
struct sbp2_unrestricted_page_table
|
||||
scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
|
||||
dma_addr_t sge_dma;
|
||||
};
|
||||
|
||||
/* Per FireWire host */
|
||||
struct sbp2_fwhost_info {
|
||||
struct hpsb_host *host;
|
||||
struct list_head logical_units;
|
||||
};
|
||||
|
||||
/* Per logical unit */
|
||||
struct sbp2_lu {
|
||||
/* Operation request blocks */
|
||||
struct sbp2_command_orb *last_orb;
|
||||
dma_addr_t last_orb_dma;
|
||||
struct sbp2_login_orb *login_orb;
|
||||
dma_addr_t login_orb_dma;
|
||||
struct sbp2_login_response *login_response;
|
||||
dma_addr_t login_response_dma;
|
||||
struct sbp2_query_logins_orb *query_logins_orb;
|
||||
dma_addr_t query_logins_orb_dma;
|
||||
struct sbp2_query_logins_response *query_logins_response;
|
||||
dma_addr_t query_logins_response_dma;
|
||||
struct sbp2_reconnect_orb *reconnect_orb;
|
||||
dma_addr_t reconnect_orb_dma;
|
||||
struct sbp2_logout_orb *logout_orb;
|
||||
dma_addr_t logout_orb_dma;
|
||||
struct sbp2_status_block status_block;
|
||||
|
||||
/* How to talk to the unit */
|
||||
u64 management_agent_addr;
|
||||
u64 command_block_agent_addr;
|
||||
u32 speed_code;
|
||||
u32 max_payload_size;
|
||||
u16 lun;
|
||||
|
||||
/* Address for the unit to write status blocks to */
|
||||
u64 status_fifo_addr;
|
||||
|
||||
/* Waitqueue flag for logins, reconnects, logouts, query logins */
|
||||
unsigned int access_complete:1;
|
||||
|
||||
/* Pool of command ORBs for this logical unit */
|
||||
spinlock_t cmd_orb_lock;
|
||||
struct list_head cmd_orb_inuse;
|
||||
struct list_head cmd_orb_completed;
|
||||
|
||||
/* Backlink to FireWire host; list of units attached to the host */
|
||||
struct sbp2_fwhost_info *hi;
|
||||
struct list_head lu_list;
|
||||
|
||||
/* IEEE 1394 core's device representations */
|
||||
struct node_entry *ne;
|
||||
struct unit_directory *ud;
|
||||
|
||||
/* SCSI core's device representations */
|
||||
struct scsi_device *sdev;
|
||||
struct Scsi_Host *shost;
|
||||
|
||||
/* Device specific workarounds/brokeness */
|
||||
unsigned workarounds;
|
||||
|
||||
/* Connection state */
|
||||
atomic_t state;
|
||||
|
||||
/* For deferred requests to the fetch agent */
|
||||
struct work_struct protocol_work;
|
||||
};
|
||||
|
||||
/* For use in sbp2_lu.state */
|
||||
enum sbp2lu_state_types {
|
||||
SBP2LU_STATE_RUNNING, /* all normal */
|
||||
SBP2LU_STATE_IN_RESET, /* between bus reset and reconnect */
|
||||
SBP2LU_STATE_IN_SHUTDOWN /* when sbp2_remove was called */
|
||||
};
|
||||
|
||||
/* For use in sbp2_lu.workarounds and in the corresponding
|
||||
* module load parameter */
|
||||
#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
|
||||
#define SBP2_WORKAROUND_INQUIRY_36 0x2
|
||||
#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
|
||||
#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
|
||||
#define SBP2_WORKAROUND_DELAY_INQUIRY 0x10
|
||||
#define SBP2_INQUIRY_DELAY 12
|
||||
#define SBP2_WORKAROUND_POWER_CONDITION 0x20
|
||||
#define SBP2_WORKAROUND_OVERRIDE 0x100
|
||||
|
||||
#endif /* SBP2_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* video1394.h - driver for OHCI 1394 boards
|
||||
* Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
|
||||
* Peter Schlaile <udbz@rz.uni-karlsruhe.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; 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 _VIDEO_1394_H
|
||||
#define _VIDEO_1394_H
|
||||
|
||||
#include "ieee1394-ioctl.h"
|
||||
|
||||
#define VIDEO1394_DRIVER_NAME "video1394"
|
||||
|
||||
#define VIDEO1394_MAX_SIZE 0x4000000
|
||||
|
||||
enum {
|
||||
VIDEO1394_BUFFER_FREE = 0,
|
||||
VIDEO1394_BUFFER_QUEUED,
|
||||
VIDEO1394_BUFFER_READY
|
||||
};
|
||||
|
||||
#define VIDEO1394_SYNC_FRAMES 0x00000001
|
||||
#define VIDEO1394_INCLUDE_ISO_HEADERS 0x00000002
|
||||
#define VIDEO1394_VARIABLE_PACKET_SIZE 0x00000004
|
||||
|
||||
struct video1394_mmap {
|
||||
int channel; /* -1 to find an open channel in LISTEN/TALK */
|
||||
unsigned int sync_tag;
|
||||
unsigned int nb_buffers;
|
||||
unsigned int buf_size;
|
||||
unsigned int packet_size; /* For VARIABLE_PACKET_SIZE:
|
||||
Maximum packet size */
|
||||
unsigned int fps;
|
||||
unsigned int syt_offset;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* For TALK_QUEUE_BUFFER with VIDEO1394_VARIABLE_PACKET_SIZE use */
|
||||
struct video1394_queue_variable {
|
||||
unsigned int channel;
|
||||
unsigned int buffer;
|
||||
unsigned int __user * packet_sizes; /* Buffer of size:
|
||||
buf_size / packet_size */
|
||||
};
|
||||
|
||||
struct video1394_wait {
|
||||
unsigned int channel;
|
||||
unsigned int buffer;
|
||||
struct timeval filltime; /* time of buffer full */
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user