diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-10-10 00:12:20 +0200 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-10-11 14:48:03 +0200 |
commit | 66fa12c571d35e3cd62574c65f1785a460105397 (patch) | |
tree | b4f8de3d5ca827d2b134ed628628a7bff46967ca | |
parent | 1ef5b816c0eaf84f91106cfc0893069c49e86113 (diff) |
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>
50 files changed, 45 insertions, 29313 deletions
diff --git a/Documentation/ABI/obsolete/dv1394 b/Documentation/ABI/obsolete/dv1394 deleted file mode 100644 index 2ee36864ca1..00000000000 --- a/Documentation/ABI/obsolete/dv1394 +++ /dev/null @@ -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) diff --git a/Documentation/ABI/removed/dv1394 b/Documentation/ABI/removed/dv1394 new file mode 100644 index 00000000000..c2310b6676f --- /dev/null +++ b/Documentation/ABI/removed/dv1394 @@ -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) diff --git a/Documentation/ABI/removed/raw1394 b/Documentation/ABI/removed/raw1394 new file mode 100644 index 00000000000..490aa1efc4a --- /dev/null +++ b/Documentation/ABI/removed/raw1394 @@ -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) diff --git a/Documentation/ABI/removed/raw1394_legacy_isochronous b/Documentation/ABI/removed/raw1394_legacy_isochronous deleted file mode 100644 index 1b629622d88..00000000000 --- a/Documentation/ABI/removed/raw1394_legacy_isochronous +++ /dev/null @@ -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 diff --git a/Documentation/ABI/removed/video1394 b/Documentation/ABI/removed/video1394 new file mode 100644 index 00000000000..c39c25aee77 --- /dev/null +++ b/Documentation/ABI/removed/video1394 @@ -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) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 842aa9de84a..1388eca94bb 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -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 diff --git a/drivers/Makefile b/drivers/Makefile index a2aea53a75e..ecde80a1de4 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -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/ diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index fcf3ea28340..40a222e19b2 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -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 diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig deleted file mode 100644 index e02096cf7d9..00000000000 --- a/drivers/ieee1394/Kconfig +++ /dev/null @@ -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. diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile deleted file mode 100644 index 427b86b8776..00000000000 --- a/drivers/ieee1394/Makefile +++ /dev/null @@ -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 diff --git a/drivers/ieee1394/config_roms.c b/drivers/ieee1394/config_roms.c deleted file mode 100644 index 1b981207fa7..00000000000 --- a/drivers/ieee1394/config_roms.c +++ /dev/null @@ -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(); -} diff --git a/drivers/ieee1394/config_roms.h b/drivers/ieee1394/config_roms.h deleted file mode 100644 index 1f5cd1f16c4..00000000000 --- a/drivers/ieee1394/config_roms.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c deleted file mode 100644 index d696f69ebce..00000000000 --- a/drivers/ieee1394/csr.c +++ /dev/null @@ -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); -} diff --git a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h deleted file mode 100644 index 90fb3f2192c..00000000000 --- a/drivers/ieee1394/csr.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c deleted file mode 100644 index e76cac64c53..00000000000 --- a/drivers/ieee1394/csr1212.c +++ /dev/null @@ -1,1467 +0,0 @@ -/* - * csr1212.c -- 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. - */ - - -/* TODO List: - * - Verify interface consistency: i.e., public functions that take a size - * parameter expect size to be in bytes. - */ - -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/kmemcheck.h> -#include <linux/string.h> -#include <asm/bug.h> -#include <asm/byteorder.h> - -#include "csr1212.h" - - -/* Permitted key type for each key id */ -#define __I (1 << CSR1212_KV_TYPE_IMMEDIATE) -#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET) -#define __D (1 << CSR1212_KV_TYPE_DIRECTORY) -#define __L (1 << CSR1212_KV_TYPE_LEAF) -static const u8 csr1212_key_id_type_map[0x30] = { - __C, /* used by Apple iSight */ - __D | __L, /* Descriptor */ - __I | __D | __L, /* Bus_Dependent_Info */ - __I | __D | __L, /* Vendor */ - __I, /* Hardware_Version */ - 0, 0, /* Reserved */ - __D | __L | __I, /* Module */ - __I, 0, 0, 0, /* used by Apple iSight, Reserved */ - __I, /* Node_Capabilities */ - __L, /* EUI_64 */ - 0, 0, 0, /* Reserved */ - __D, /* Unit */ - __I, /* Specifier_ID */ - __I, /* Version */ - __I | __C | __D | __L, /* Dependent_Info */ - __L, /* Unit_Location */ - 0, /* Reserved */ - __I, /* Model */ - __D, /* Instance */ - __L, /* Keyword */ - __D, /* Feature */ - __L, /* Extended_ROM */ - __I, /* Extended_Key_Specifier_ID */ - __I, /* Extended_Key */ - __I | __C | __D | __L, /* Extended_Data */ - __L, /* Modifiable_Descriptor */ - __I, /* Directory_ID */ - __I, /* Revision */ -}; -#undef __I -#undef __C -#undef __D -#undef __L - - -#define quads_to_bytes(_q) ((_q) * sizeof(u32)) -#define bytes_to_quads(_b) DIV_ROUND_UP(_b, sizeof(u32)) - -static void free_keyval(struct csr1212_keyval *kv) -{ - if ((kv->key.type == CSR1212_KV_TYPE_LEAF) && - (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)) - CSR1212_FREE(kv->value.leaf.data); - - CSR1212_FREE(kv); -} - -static u16 csr1212_crc16(const u32 *buffer, size_t length) -{ - int shift; - u32 data; - u16 sum, crc = 0; - - for (; length; length--) { - data = be32_to_cpu(*buffer); - buffer++; - for (shift = 28; shift >= 0; shift -= 4 ) { - sum = ((crc >> 12) ^ (data >> shift)) & 0xf; - crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum); - } - crc &= 0xffff; - } - - return cpu_to_be16(crc); -} - -/* Microsoft computes the CRC with the bytes in reverse order. */ -static u16 csr1212_msft_crc16(const u32 *buffer, size_t length) -{ - int shift; - u32 data; - u16 sum, crc = 0; - - for (; length; length--) { - data = le32_to_cpu(*buffer); - buffer++; - for (shift = 28; shift >= 0; shift -= 4 ) { - sum = ((crc >> 12) ^ (data >> shift)) & 0xf; - crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum); - } - crc &= 0xffff; - } - - return cpu_to_be16(crc); -} - -static struct csr1212_dentry * -csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv) -{ - struct csr1212_dentry *pos; - - for (pos = dir->value.directory.dentries_head; - pos != NULL; pos = pos->next) - if (pos->kv == kv) - return pos; - return NULL; -} - -static struct csr1212_keyval * -csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset) -{ - struct csr1212_keyval *kv; - - for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next) - if (kv->offset == offset) - return kv; - return NULL; -} - - -/* Creation Routines */ - -struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops, - size_t bus_info_size, void *private) -{ - struct csr1212_csr *csr; - - csr = CSR1212_MALLOC(sizeof(*csr)); - if (!csr) - return NULL; - - csr->cache_head = - csr1212_rom_cache_malloc(CSR1212_CONFIG_ROM_SPACE_OFFSET, - CSR1212_CONFIG_ROM_SPACE_SIZE); - if (!csr->cache_head) { - CSR1212_FREE(csr); - return NULL; - } - - /* The keyval key id is not used for the root node, but a valid key id - * that can be used for a directory needs to be passed to - * csr1212_new_directory(). */ - csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR); - if (!csr->root_kv) { - CSR1212_FREE(csr->cache_head); - CSR1212_FREE(csr); - return NULL; - } - - csr->bus_info_data = csr->cache_head->data; - csr->bus_info_len = bus_info_size; - csr->crc_len = bus_info_size; - csr->ops = ops; - csr->private = private; - csr->cache_tail = csr->cache_head; - - return csr; -} - -void csr1212_init_local_csr(struct csr1212_csr *csr, - const u32 *bus_info_data, int max_rom) -{ - static const int mr_map[] = { 4, 64, 1024, 0 }; - - BUG_ON(max_rom & ~0x3); - csr->max_rom = mr_map[max_rom]; - memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len); -} - -static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key) -{ - struct csr1212_keyval *kv; - - if (key < 0x30 && ((csr1212_key_id_type_map[key] & (1 << type)) == 0)) - return NULL; - - kv = CSR1212_MALLOC(sizeof(*kv)); - if (!kv) - return NULL; - - atomic_set(&kv->refcnt, 1); - kv->key.type = type; - kv->key.id = key; - kv->associate = NULL; - kv->next = NULL; - kv->prev = NULL; - kv->offset = 0; - kv->valid = 0; - return kv; -} - -struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value) -{ - struct csr1212_keyval *kv; - - kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key); - if (!kv) - return NULL; - - kv->value.immediate = value; - kv->valid = 1; - return kv; -} - -static struct csr1212_keyval * -csr1212_new_leaf(u8 key, const void *data, size_t data_len) -{ - struct csr1212_keyval *kv; - - kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key); - if (!kv) - return NULL; - - if (data_len > 0) { - kv->value.leaf.data = CSR1212_MALLOC(data_len); - if (!kv->value.leaf.data) { - CSR1212_FREE(kv); - return NULL; - } - - if (data) - memcpy(kv->value.leaf.data, data, data_len); - } else { - kv->value.leaf.data = NULL; - } - - kv->value.leaf.len = bytes_to_quads(data_len); - kv->offset = 0; - kv->valid = 1; - - return kv; -} - -static struct csr1212_keyval * -csr1212_new_csr_offset(u8 key, u32 csr_offset) -{ - struct csr1212_keyval *kv; - - kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key); - if (!kv) - return NULL; - - kv->value.csr_offset = csr_offset; - - kv->offset = 0; - kv->valid = 1; - return kv; -} - -struct csr1212_keyval *csr1212_new_directory(u8 key) -{ - struct csr1212_keyval *kv; - - kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key); - if (!kv) - return NULL; - - kv->value.directory.len = 0; - kv->offset = 0; - kv->value.directory.dentries_head = NULL; - kv->value.directory.dentries_tail = NULL; - kv->valid = 1; - return kv; -} - -void csr1212_associate_keyval(struct csr1212_keyval *kv, - struct csr1212_keyval *associate) -{ - BUG_ON(!kv || !associate || kv->key.id == CSR1212_KV_ID_DESCRIPTOR || - (associate->key.id != CSR1212_KV_ID_DESCRIPTOR && - associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO && - associate->key.id != CSR1212_KV_ID_EXTENDED_KEY && - associate->key.id != CSR1212_KV_ID_EXTENDED_DATA && - associate->key.id < 0x30) || - (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID && - associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) || - (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY && - associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) || - (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY && - kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) || - (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA && - kv->key.id != CSR1212_KV_ID_EXTENDED_KEY)); - - if (kv->associate) - csr1212_release_keyval(kv->associate); - - csr1212_keep_keyval(associate); - kv->associate = associate; -} - -static int __csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, - struct csr1212_keyval *kv, - bool keep_keyval) -{ - struct csr1212_dentry *dentry; - - BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY); - - dentry = CSR1212_MALLOC(sizeof(*dentry)); - if (!dentry) - return -ENOMEM; - - if (keep_keyval) - csr1212_keep_keyval(kv); - dentry->kv = kv; - - dentry->next = NULL; - dentry->prev = dir->value.directory.dentries_tail; - - if (!dir->value.directory.dentries_head) - dir->value.directory.dentries_head = dentry; - - if (dir->value.directory.dentries_tail) - dir->value.directory.dentries_tail->next = dentry; - dir->value.directory.dentries_tail = dentry; - - return CSR1212_SUCCESS; -} - -int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, - struct csr1212_keyval *kv) -{ - return __csr1212_attach_keyval_to_directory(dir, kv, true); -} - -#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \ - (&((kv)->value.leaf.data[1])) - -#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \ - ((kv)->value.leaf.data[0] = \ - cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \ - ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT))) -#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \ - ((kv)->value.leaf.data[0] = \ - cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \ - CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \ - ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK))) - -static struct csr1212_keyval * -csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id, - const void *data, size_t data_len) -{ - struct csr1212_keyval *kv; - - kv = csr1212_new_leaf(CSR1212_KV_ID_DESCRIPTOR, NULL, - data_len + CSR1212_DESCRIPTOR_LEAF_OVERHEAD); - if (!kv) - return NULL; - - kmemcheck_annotate_variable(kv->value.leaf.data[0]); - CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype); - CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id); - - if (data) - memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len); - - return kv; -} - -/* Check if string conforms to minimal ASCII as per IEEE 1212 clause 7.4 */ -static int csr1212_check_minimal_ascii(const char *s) -{ - static const char minimal_ascii_table[] = { - /* 1 2 4 8 16 32 64 128 */ - 128, /* --, --, --, --, --, --, --, 07, */ - 4 + 16 + 32, /* --, --, 0a, --, 0C, 0D, --, --, */ - 0, /* --, --, --, --, --, --, --, --, */ - 0, /* --, --, --, --, --, --, --, --, */ - 255 - 8 - 16, /* 20, 21, 22, --, --, 25, 26, 27, */ - 255, /* 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, */ - 255, /* 30, 31, 32, 33, 34, 35, 36, 37, */ - 255, /* 38, 39, 3a, 3b, 3c, 3d, 3e, 3f, */ - 255, /* 40, 41, 42, 43, 44, 45, 46, 47, */ - 255, /* 48, 49, 4a, 4b, 4c, 4d, 4e, 4f, */ - 255, /* 50, 51, 52, 53, 54, 55, 56, 57, */ - 1 + 2 + 4 + 128, /* 58, 59, 5a, --, --, --, --, 5f, */ - 255 - 1, /* --, 61, 62, 63, 64, 65, 66, 67, */ - 255, /* 68, 69, 6a, 6b, 6c, 6d, 6e, 6f, */ - 255, /* 70, 71, 72, 73, 74, 75, 76, 77, */ - 1 + 2 + 4, /* 78, 79, 7a, --, --, --, --, --, */ - }; - int i, j; - - for (; *s; s++) { - i = *s >> 3; /* i = *s / 8; */ - j = 1 << (*s & 3); /* j = 1 << (*s % 8); */ - - if (i >= ARRAY_SIZE(minimal_ascii_table) || - !(minimal_ascii_table[i] & j)) - return -EINVAL; - } - return 0; -} - -/* IEEE 1212 clause 7.5.4.1 textual descriptors (English, minimal ASCII) */ -struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s) -{ - struct csr1212_keyval *kv; - u32 *text; - size_t str_len, quads; - - if (!s || !*s || csr1212_check_minimal_ascii(s)) - return NULL; - - str_len = strlen(s); - quads = bytes_to_quads(str_len); - kv = csr1212_new_descriptor_leaf(0, 0, NULL, quads_to_bytes(quads) + - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD); - if (!kv) - return NULL; - - kv->value.leaf.data[1] = 0; /* width, character_set, language */ - text = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv); - text[quads - 1] = 0; /* padding */ - memcpy(text, s, str_len); - - return kv; -} - - -/* Destruction Routines */ - -void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir, - struct csr1212_keyval *kv) -{ - struct csr1212_dentry *dentry; - - if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY) - return; - - dentry = csr1212_find_keyval(dir, kv); - - if (!dentry) - return; - - if (dentry->prev) - dentry->prev->next = dentry->next; - if (dentry->next) - dentry->next->prev = dentry->prev; - if (dir->value.directory.dentries_head == dentry) - dir->value.directory.dentries_head = dentry->next; - if (dir->value.directory.dentries_tail == dentry) - dir->value.directory.dentries_tail = dentry->prev; - - CSR1212_FREE(dentry); - - csr1212_release_keyval(kv); -} - -/* This function is used to free the memory taken by a keyval. If the given - * keyval is a directory type, then any keyvals contained in that directory - * will be destroyed as well if noone holds a reference on them. By means of - * list manipulation, this routine will descend a directory structure in a - * non-recursive manner. */ -void csr1212_release_keyval(struct csr1212_keyval *kv) -{ - struct csr1212_keyval *k, *a; - struct csr1212_dentry dentry; - struct csr1212_dentry *head, *tail; - - if (!atomic_dec_and_test(&kv->refcnt)) - return; - - dentry.kv = kv; - dentry.next = NULL; - dentry.prev = NULL; - - head = &dentry; - tail = head; - - while (head) { - k = head->kv; - - while (k) { - /* must not dec_and_test kv->refcnt again */ - if (k != kv && !atomic_dec_and_test(&k->refcnt)) - break; - - a = k->associate; - - if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) { - /* If the current entry is a directory, move all - * the entries to the destruction list. */ - if (k->value.directory.dentries_head) { - tail->next = - k->value.directory.dentries_head; - k->value.directory.dentries_head->prev = - tail; - tail = k->value.directory.dentries_tail; - } - } - free_keyval(k); - k = a; - } - - head = head->next; - if (head) { - if (head->prev && head->prev != &dentry) - CSR1212_FREE(head->prev); - head->prev = NULL; - } else if (tail != &dentry) { - CSR1212_FREE(tail); - } - } -} - -void csr1212_destroy_csr(struct csr1212_csr *csr) -{ - struct csr1212_csr_rom_cache *c, *oc; - struct csr1212_cache_region *cr, *ocr; - - csr1212_release_keyval(csr->root_kv); - - c = csr->cache_head; - while (c) { - oc = c; - cr = c->filled_head; - while (cr) { - ocr = cr; - cr = cr->next; - CSR1212_FREE(ocr); - } - c = c->next; - CSR1212_FREE(oc); - } - - CSR1212_FREE(csr); -} - - -/* CSR Image Creation */ - -static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize) -{ - struct csr1212_csr_rom_cache *cache; - u64 csr_addr; - - BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range || - !csr->ops->release_addr || csr->max_rom < 1); - - /* ROM size must be a multiple of csr->max_rom */ - romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1); - - csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, - csr->private); - if (csr_addr == CSR1212_INVALID_ADDR_SPACE) - return -ENOMEM; - - if (csr_addr < CSR1212_REGISTER_SPACE_BASE) { - /* Invalid address returned from allocate_addr_range(). */ - csr->ops->release_addr(csr_addr, csr->private); - return -ENOMEM; - } - - cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, - romsize); - if (!cache) { - csr->ops->release_addr(csr_addr, csr->private); - return -ENOMEM; - } - - cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, - CSR1212_KV_ID_EXTENDED_ROM); - if (!cache->ext_rom) { - csr->ops->release_addr(csr_addr, csr->private); - CSR1212_FREE(cache); - return -ENOMEM; - } - - if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != - CSR1212_SUCCESS) { - csr1212_release_keyval(cache->ext_rom); - csr->ops->release_addr(csr_addr, csr->private); - CSR1212_FREE(cache); - return -ENOMEM; - } - cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE; - cache->ext_rom->value.leaf.len = -1; - cache->ext_rom->value.leaf.data = cache->data; - - /* Add cache to tail of cache list */ - cache->prev = csr->cache_tail; - csr->cache_tail->next = cache; - csr->cache_tail = cache; - return CSR1212_SUCCESS; -} - -static void csr1212_remove_cache(struct csr1212_csr *csr, - struct csr1212_csr_rom_cache *cache) -{ - if (csr->cache_head == cache) - csr->cache_head = cache->next; - if (csr->cache_tail == cache) - csr->cache_tail = cache->prev; - - if (cache->prev) - cache->prev->next = cache->next; - if (cache->next) - cache->next->prev = cache->prev; - - if (cache->ext_rom) { - csr1212_detach_keyval_from_directory(csr->root_kv, - cache->ext_rom); - csr1212_release_keyval(cache->ext_rom); - } - - CSR1212_FREE(cache); -} - -static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir, - struct csr1212_keyval **layout_tail) -{ - struct csr1212_dentry *dentry; - struct csr1212_keyval *dkv; - struct csr1212_keyval *last_extkey_spec = NULL; - struct csr1212_keyval *last_extkey = NULL; - int num_entries = 0; - - for (dentry = dir->value.directory.dentries_head; dentry; - dentry = dentry->next) { - for (dkv = dentry->kv; dkv; dkv = dkv->associate) { - /* Special Case: Extended Key Specifier_ID */ - if (dkv->key.id == - CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { - if (last_extkey_spec == NULL) - last_extkey_spec = dkv; - else if (dkv->value.immediate != - last_extkey_spec->value.immediate) - last_extkey_spec = dkv; - else - continue; - /* Special Case: Extended Key */ - } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) { - if (last_extkey == NULL) - last_extkey = dkv; - else if (dkv->value.immediate != - last_extkey->value.immediate) - last_extkey = dkv; - else - continue; - } - - num_entries += 1; - - switch (dkv->key.type) { - default: - case CSR1212_KV_TYPE_IMMEDIATE: - case CSR1212_KV_TYPE_CSR_OFFSET: - break; - case CSR1212_KV_TYPE_LEAF: - case CSR1212_KV_TYPE_DIRECTORY: - /* Remove from list */ - if (dkv->prev && (dkv->prev->next == dkv)) - dkv->prev->next = dkv->next; - if (dkv->next && (dkv->next->prev == dkv)) - dkv->next->prev = dkv->prev; - //if (dkv == *layout_tail) - // *layout_tail = dkv->prev; - - /* Special case: Extended ROM leafs */ - if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) { - dkv->value.leaf.len = -1; - /* Don't add Extended ROM leafs in the - * layout list, they are handled - * differently. */ - break; - } - - /* Add to tail of list */ - dkv->next = NULL; - dkv->prev = *layout_tail; - (*layout_tail)->next = dkv; - *layout_tail = dkv; - break; - } - } - } - return num_entries; -} - -static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv) -{ - struct csr1212_keyval *ltail = kv; - size_t agg_size = 0; - - while (kv) { - switch (kv->key.type) { - case CSR1212_KV_TYPE_LEAF: - /* Add 1 quadlet for crc/len field */ - agg_size += kv->value.leaf.len + 1; - break; - - case CSR1212_KV_TYPE_DIRECTORY: - kv->value.directory.len = - csr1212_generate_layout_subdir(kv, <ail); - /* Add 1 quadlet for crc/len field */ - agg_size += kv->value.directory.len + 1; - break; - } - kv = kv->next; - } - return quads_to_bytes(agg_size); -} - -static struct csr1212_keyval * -csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, - struct csr1212_keyval *start_kv, int start_pos) -{ - struct csr1212_keyval *kv = start_kv; - struct csr1212_keyval *okv = start_kv; - int pos = start_pos; - int kv_len = 0, okv_len = 0; - - cache->layout_head = kv; - - while (kv && pos < cache->size) { - /* Special case: Extended ROM leafs */ - if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) - kv->offset = cache->offset + pos; - - switch (kv->key.type) { - case CSR1212_KV_TYPE_LEAF: - kv_len = kv->value.leaf.len; - break; - - case CSR1212_KV_TYPE_DIRECTORY: - kv_len = kv->value.directory.len; - break; - - default: - /* Should never get here */ - WARN_ON(1); - break; - } - - pos += quads_to_bytes(kv_len + 1); - - if (pos <= cache->size) { - okv = kv; - okv_len = kv_len; - kv = kv->next; - } - } - - cache->layout_tail = okv; - cache->len = okv->offset - cache->offset + quads_to_bytes(okv_len + 1); - - return kv; -} - -#define CSR1212_KV_KEY_SHIFT 24 -#define CSR1212_KV_KEY_TYPE_SHIFT 6 -#define CSR1212_KV_KEY_ID_MASK 0x3f -#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* after shift */ - -static void -csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer) -{ - struct csr1212_dentry *dentry; - struct csr1212_keyval *last_extkey_spec = NULL; - struct csr1212_keyval *last_extkey = NULL; - int index = 0; - - for (dentry = dir->value.directory.dentries_head; - dentry; - dentry = dentry->next) { - struct csr1212_keyval *a; - - for (a = dentry->kv; a; a = a->associate) { - u32 value = 0; - - /* Special Case: Extended Key Specifier_ID */ - if (a->key.id == - CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { - if (last_extkey_spec == NULL) - last_extkey_spec = a; - else if (a->value.immediate != - last_extkey_spec->value.immediate) - last_extkey_spec = a; - else - continue; - - /* Special Case: Extended Key */ - } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) { - if (last_extkey == NULL) - last_extkey = a; - else if (a->value.immediate != - last_extkey->value.immediate) - last_extkey = a; - else - continue; - } - - switch (a->key.type) { - case CSR1212_KV_TYPE_IMMEDIATE: - value = a->value.immediate; - break; - case CSR1212_KV_TYPE_CSR_OFFSET: - value = a->value.csr_offset; - break; - case CSR1212_KV_TYPE_LEAF: - value = a->offset; - value -= dir->offset + quads_to_bytes(1+index); - value = bytes_to_quads(value); - break; - case CSR1212_KV_TYPE_DIRECTORY: - value = a->offset; - value -= dir->offset + quads_to_bytes(1+index); - value = bytes_to_quads(value); - break; - default: - /* Should never get here */ - WARN_ON(1); - break; - } - - value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << - CSR1212_KV_KEY_SHIFT; - value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) << - (CSR1212_KV_KEY_SHIFT + - CSR1212_KV_KEY_TYPE_SHIFT); - data_buffer[index] = cpu_to_be32(value); - index++; - } - } -} - -struct csr1212_keyval_img { - u16 length; - u16 crc; - - /* Must be last */ - u32 data[0]; /* older gcc can't handle [] which is standard */ -}; - -static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache) -{ - struct csr1212_keyval *kv, *nkv; - struct csr1212_keyval_img *kvi; - - for (kv = cache->layout_head; - kv != cache->layout_tail->next; - kv = nkv) { - kvi = (struct csr1212_keyval_img *)(cache->data + - bytes_to_quads(kv->offset - cache->offset)); - switch (kv->key.type) { - default: - case CSR1212_KV_TYPE_IMMEDIATE: - case CSR1212_KV_TYPE_CSR_OFFSET: - /* Should never get here */ - WARN_ON(1); - break; - - case CSR1212_KV_TYPE_LEAF: - /* Don't copy over Extended ROM areas, they are - * already filled out! */ - if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) - memcpy(kvi->data, kv->value.leaf.data, - quads_to_bytes(kv->value.leaf.len)); - - kvi->length = cpu_to_be16(kv->value.leaf.len); - kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len); - break; - - case CSR1212_KV_TYPE_DIRECTORY: - csr1212_generate_tree_subdir(kv, kvi->data); - - kvi->length = cpu_to_be16(kv->value.directory.len); - kvi->crc = csr1212_crc16(kvi->data, - kv->value.directory.len); - break; - } - - nkv = kv->next; - if (kv->prev) - kv->prev->next = NULL; - if (kv->next) - kv->next->prev = NULL; - kv->prev = NULL; - kv->next = NULL; - } -} - -/* This size is arbitrarily chosen. - * The struct overhead is subtracted for more economic allocations. */ -#define CSR1212_EXTENDED_ROM_SIZE (2048 - sizeof(struct csr1212_csr_rom_cache)) - -int csr1212_generate_csr_image(struct csr1212_csr *csr) -{ - struct csr1212_bus_info_block_img *bi; - struct csr1212_csr_rom_cache *cache; - struct csr1212_keyval *kv; - size_t agg_size; - int ret; - int init_offset; - - BUG_ON(!csr); - - cache = csr->cache_head; - - bi = (struct csr1212_bus_info_block_img*)cache->data; - - bi->length = bytes_to_quads(csr->bus_info_len) - 1; - bi->crc_length = bi->length; - bi->crc = csr1212_crc16(bi->data, bi->crc_length); - - csr->root_kv->next = NULL; - csr->root_kv->prev = NULL; - - agg_size = csr1212_generate_layout_order(csr->root_kv); - - init_offset = csr->bus_info_len; - - for (kv = csr->root_kv, cache = csr->cache_head; - kv; - cache = cache->next) { - if (!cache) { - /* Estimate approximate number of additional cache - * regions needed (it assumes that the cache holding - * the first 1K Config ROM space always exists). */ - int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE - - (2 * sizeof(u32))) + 1; - - /* Add additional cache regions, extras will be - * removed later */ - for (; est_c; est_c--) { - ret = csr1212_append_new_cache(csr, - CSR1212_EXTENDED_ROM_SIZE); - if (ret != CSR1212_SUCCESS) - return ret; - } - /* Need to re-layout for additional cache regions */ - agg_size = csr1212_generate_layout_order(csr->root_kv); - kv = csr->root_kv; - cache = csr->cache_head; - init_offset = csr->bus_info_len; - } - kv = csr1212_generate_positions(cache, kv, init_offset); - agg_size -= cache->len; - init_offset = sizeof(u32); - } - - /* Remove unused, excess cache regions */ - while (cache) { - struct csr1212_csr_rom_cache *oc = cache; - - cache = cache->next; - csr1212_remove_cache(csr, oc); - } - - /* Go through the list backward so that when done, the correct CRC - * will be calculated for the Extended ROM areas. */ - for (cache = csr->cache_tail; cache; cache = cache->prev) { - /* Only Extended ROM caches should have this set. */ - if (cache->ext_rom) { - int leaf_size; - - /* Make sure the Extended ROM leaf is a multiple of - * max_rom in size. */ - BUG_ON(csr->max_rom < 1); - leaf_size = (cache->len + (csr->max_rom - 1)) & - ~(csr->max_rom - 1); - - /* Zero out the unused ROM region */ - memset(cache->data + bytes_to_quads(cache->len), 0x00, - leaf_size - cache->len); - - /* Subtract leaf header */ - leaf_size -= sizeof(u32); - - /* Update the Extended ROM leaf length */ - cache->ext_rom->value.leaf.len = - bytes_to_quads(leaf_size); - } else { - /* Zero out the unused ROM region */ - memset(cache->data + bytes_to_quads(cache->len), 0x00, - cache->size - cache->len); - } - - /* Copy the data into the cache buffer */ - csr1212_fill_cache(cache); - - if (cache != csr->cache_head) { - /* Set the length and CRC of the extended ROM. */ - struct csr1212_keyval_img *kvi = - (struct csr1212_keyval_img*)cache->data; - u16 len = bytes_to_quads(cache->len) - 1; - - kvi->length = cpu_to_be16(len); - kvi->crc = csr1212_crc16(kvi->data, len); - } - } - - return CSR1212_SUCCESS; -} - -int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len) -{ - struct csr1212_csr_rom_cache *cache; - - for (cache = csr->cache_head; cache; cache = cache->next) - if (offset >= cache->offset && - (offset + len) <= (cache->offset + cache->size)) { - memcpy(buffer, &cache->data[ - bytes_to_quads(offset - cache->offset)], - len); - return CSR1212_SUCCESS; - } - - return -ENOENT; -} - -/* - * Apparently there are many different wrong implementations of the CRC - * algorithm. We don't fail, we just warn... approximately once per GUID. - */ -static void -csr1212_check_crc(const u32 *buffer, size_t length, u16 crc, __be32 *guid) -{ - static u64 last_bad_eui64; - u64 eui64 = ((u64)be32_to_cpu(guid[0]) << 32) | be32_to_cpu(guid[1]); - - if (csr1212_crc16(buffer, length) == crc || - csr1212_msft_crc16(buffer, length) == crc || - eui64 == last_bad_eui64) - return; - - printk(KERN_DEBUG "ieee1394: config ROM CRC error\n"); - last_bad_eui64 = eui64; -} - -/* Parse a chunk of data as a Config ROM */ - -static int csr1212_parse_bus_info_block(struct csr1212_csr *csr) -{ - struct csr1212_bus_info_block_img *bi; - struct csr1212_cache_region *cr; - int i; - int ret; - - for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) { - ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i, - &csr->cache_head->data[bytes_to_quads(i)], - csr->private); - if (ret != CSR1212_SUCCESS) - return ret; - - /* check ROM header's info_length */ - if (i == 0 && - be32_to_cpu(csr->cache_head->data[0]) >> 24 != - bytes_to_quads(csr->bus_info_len) - 1) - return -EINVAL; - } - - bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data; - csr->crc_len = quads_to_bytes(bi->crc_length); - - /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that - * is not always the case, so read the rest of the crc area 1 quadlet at - * a time. */ - for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) { - ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i, - &csr->cache_head->data[bytes_to_quads(i)], - csr->private); - if (ret != CSR1212_SUCCESS) - return ret; - } - - csr1212_check_crc(bi->data, bi->crc_length, bi->crc, - &csr->bus_info_data[3]); - - cr = CSR1212_MALLOC(sizeof(*cr)); - if (!cr) - return -ENOMEM; - - cr->next = NULL; - cr->prev = NULL; - cr->offset_start = 0; - cr->offset_end = csr->crc_len + 4; - - csr->cache_head->filled_head = cr; - csr->cache_head->filled_tail = cr; - - return CSR1212_SUCCESS; -} - -#define CSR1212_KV_KEY(q) (be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT) -#define CSR1212_KV_KEY_TYPE(q) (CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT) -#define CSR1212_KV_KEY_ID(q) (CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK) -#define CSR1212_KV_VAL_MASK 0xffffff -#define CSR1212_KV_VAL(q) (be32_to_cpu(q) & CSR1212_KV_VAL_MASK) - -static int -csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos) -{ - int ret = CSR1212_SUCCESS; - struct csr1212_keyval *k = NULL; - u32 offset; - bool keep_keyval = true; - - switch (CSR1212_KV_KEY_TYPE(ki)) { - case CSR1212_KV_TYPE_IMMEDIATE: - k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki), - CSR1212_KV_VAL(ki)); - if (!k) { - ret = -ENOMEM; - goto out; - } - /* Don't keep local reference when parsing. */ - keep_keyval = false; - break; - - case CSR1212_KV_TYPE_CSR_OFFSET: - k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki), - CSR1212_KV_VAL(ki)); - if (!k) { - ret = -ENOMEM; - goto out; - } - /* Don't keep local reference when parsing. */ - keep_keyval = false; - break; - - default: - /* Compute the offset from 0xffff f000 0000. */ - offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos; - if (offset == kv_pos) { - /* Uh-oh. Can't have a relative offset of 0 for Leaves - * or Directories. The Config ROM image is most likely - * messed up, so we'll just abort here. */ - ret = -EIO; - goto out; - } - - k = csr1212_find_keyval_offset(dir, offset); - - if (k) - break; /* Found it. */ - - if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) - k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki)); - else - k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0); - - if (!k) { - ret = -ENOMEM; - goto out; - } - /* Don't keep local reference when parsing. */ - keep_keyval = false; - /* Contents not read yet so it's not valid. */ - k->valid = 0; - k->offset = offset; - - k->prev = dir; - k->next = dir->next; - dir->next->prev = k; - dir->next = k; - } - ret = __csr1212_attach_keyval_to_directory(dir, k, keep_keyval); -out: - if (ret != CSR1212_SUCCESS && k != NULL) - free_keyval(k); - return ret; -} - -int csr1212_parse_keyval(struct csr1212_keyval *kv, - struct csr1212_csr_rom_cache *cache) -{ - struct csr1212_keyval_img *kvi; - int i; - int ret = CSR1212_SUCCESS; - int kvi_len; - - kvi = (struct csr1212_keyval_img*) - &cache->data[bytes_to_quads(kv->offset - cache->offset)]; - kvi_len = be16_to_cpu(kvi->length); - - /* GUID is wrong in here in case of extended ROM. We don't care. */ - csr1212_check_crc(kvi->data, kvi_len, kvi->crc, &cache->data[3]); - - switch (kv->key.type) { - case CSR1212_KV_TYPE_DIRECTORY: - for (i = 0; i < kvi_len; i++) { - u32 ki = kvi->data[i]; - - /* Some devices put null entries in their unit - * directories. If we come across such an entry, - * then skip it. */ - if (ki == 0x0) - continue; - ret = csr1212_parse_dir_entry(kv, ki, - kv->offset + quads_to_bytes(i + 1)); - } - kv->value.directory.len = kvi_len; - break; - - case CSR1212_KV_TYPE_LEAF: - if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) { - size_t size = quads_to_bytes(kvi_len); - - kv->value.leaf.data = CSR1212_MALLOC(size); - if (!kv->value.leaf.data) { - ret = -ENOMEM; - goto out; - } - - kv->value.leaf.len = kvi_len; - memcpy(kv->value.leaf.data, kvi->data, size); - } - break; - } - - kv->valid = 1; -out: - return ret; -} - -static int -csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) -{ - struct csr1212_cache_region *cr, *ncr, *newcr = NULL; - struct csr1212_keyval_img *kvi = NULL; - struct csr1212_csr_rom_cache *cache; - int cache_index; - u64 addr; - u32 *cache_ptr; - u16 kv_len = 0; - - BUG_ON(!csr || !kv || csr->max_rom < 1); - - /* First find which cache the data should be in (or go in if not read - * yet). */ - for (cache = csr->cache_head; cache; cache = cache->next) - if (kv->offset >= cache->offset && - kv->offset < (cache->offset + cache->size)) - break; - - if (!cache) { - u32 q, cache_size; - - /* Only create a new cache for Extended ROM leaves. */ - if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) - return -EINVAL; - - if (csr->ops->bus_read(csr, - CSR1212_REGISTER_SPACE_BASE + kv->offset, - &q, csr->private)) - return -EIO; - - kv->value.leaf.len = be32_to_cpu(q) >> 16; - - cache_size = (quads_to_bytes(kv->value.leaf.len + 1) + - (csr->max_rom - 1)) & ~(csr->max_rom - 1); - - cache = csr1212_rom_cache_malloc(kv->offset, cache_size); - if (!cache) - return -ENOMEM; - - kv->value.leaf.data = &cache->data[1]; - csr->cache_tail->next = cache; - cache->prev = csr->cache_tail; - cache->next = NULL; - csr->cache_tail = cache; - cache->filled_head = - CSR1212_MALLOC(sizeof(*cache->filled_head)); - if (!cache->filled_head) - return -ENOMEM; - - cache->filled_head->offset_start = 0; - cache->filled_head->offset_end = sizeof(u32); - cache->filled_tail = cache->filled_head; - cache->filled_head->next = NULL; - cache->filled_head->prev = NULL; - cache->data[0] = q; - - /* Don't read the entire extended ROM now. Pieces of it will - * be read when entries inside it are read. */ - return csr1212_parse_keyval(kv, cache); - } - - cache_index = kv->offset - cache->offset; - - /* Now seach read portions of the cache to see if it is there. */ - for (cr = cache->filled_head; cr; cr = cr->next) { - if (cache_index < cr->offset_start) { - newcr = CSR1212_MALLOC(sizeof(*newcr)); - if (!newcr) - return -ENOMEM; - - newcr->offset_start = cache_index & ~(csr->max_rom - 1); - newcr->offset_end = newcr->offset_start; - newcr->next = cr; - newcr->prev = cr->prev; - cr->prev = newcr; - cr = newcr; - break; - } else if ((cache_index >= cr->offset_start) && - (cache_index < cr->offset_end)) { - kvi = (struct csr1212_keyval_img*) - (&cache->data[bytes_to_quads(cache_index)]); - kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1); - break; - } else if (cache_index == cr->offset_end) { - break; - } - } - - if (!cr) { - cr = cache->filled_tail; - newcr = CSR1212_MALLOC(sizeof(*newcr)); - if (!newcr) - return -ENOMEM; - - newcr->offset_start = cache_index & ~(csr->max_rom - 1); - newcr->offset_end = newcr->offset_start; - newcr->prev = cr; - newcr->next = cr->next; - cr->next = newcr; - cr = newcr; - cache->filled_tail = newcr; - } - - while(!kvi || cr->offset_end < cache_index + kv_len) { - cache_ptr = &cache->data[bytes_to_quads(cr->offset_end & - ~(csr->max_rom - 1))]; - - addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset + - cr->offset_end) & ~(csr->max_rom - 1); - - if (csr->ops->bus_read(csr, addr, cache_ptr, csr->private)) - return -EIO; - - cr->offset_end += csr->max_rom - (cr->offset_end & - (csr->max_rom - 1)); - - if (!kvi && (cr->offset_end > cache_index)) { - kvi = (struct csr1212_keyval_img*) - (&cache->data[bytes_to_quads(cache_index)]); - kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1); - } - - if ((kv_len + (kv->offset - cache->offset)) > cache->size) { - /* The Leaf or Directory claims its length extends - * beyond the ConfigROM image region and thus beyond the - * end of our cache region. Therefore, we abort now - * rather than seg faulting later. */ - return -EIO; - } - - ncr = cr->next; - - if (ncr && (cr->offset_end >= ncr->offset_start)) { - /* consolidate region entries */ - ncr->offset_start = cr->offset_start; - - if (cr->prev) - cr->prev->next = cr->next; - ncr->prev = cr->prev; - if (cache->filled_head == cr) - cache->filled_head = ncr; - CSR1212_FREE(cr); - cr = ncr; - } - } - - return csr1212_parse_keyval(kv, cache); -} - -struct csr1212_keyval * -csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) -{ - if (!kv) - return NULL; - if (!kv->valid) - if (csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS) - return NULL; - return kv; -} - -int csr1212_parse_csr(struct csr1212_csr *csr) -{ - struct csr1212_dentry *dentry; - int ret; - - BUG_ON(!csr || !csr->ops || !csr->ops->bus_read); - - ret = csr1212_parse_bus_info_block(csr); - if (ret != CSR1212_SUCCESS) - return ret; - - /* - * There has been a buggy firmware with bus_info_block.max_rom > 0 - * spotted which actually only supported quadlet read requests to the - * config ROM. Therefore read everything quadlet by quadlet regardless - * of what the bus info block says. - */ - csr->max_rom = 4; - - csr->cache_head->layout_head = csr->root_kv; - csr->cache_head->layout_tail = csr->root_kv; - - csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) + - csr->bus_info_len; - - csr->root_kv->valid = 0; - csr->root_kv->next = csr->root_kv; - csr->root_kv->prev = csr->root_kv; - ret = csr1212_read_keyval(csr, csr->root_kv); - if (ret != CSR1212_SUCCESS) - return ret; - - /* Scan through the Root directory finding all extended ROM regions - * and make cache regions for them */ - for (dentry = csr->root_kv->value.directory.dentries_head; - dentry; dentry = dentry->next) { - if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM && - !dentry->kv->valid) { - ret = csr1212_read_keyval(csr, dentry->kv); - if (ret != CSR1212_SUCCESS) - return ret; - } - } - - return CSR1212_SUCCESS; -} diff --git a/drivers/ieee1394/csr1212.h b/drivers/ieee1394/csr1212.h deleted file mode 100644 index a892d922dbc..00000000000 --- a/drivers/ieee1394/csr1212.h +++ /dev/null @@ -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__ */ diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c deleted file mode 100644 index d178699b194..00000000000 --- a/drivers/ieee1394/dma.c +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/dma.h b/drivers/ieee1394/dma.h deleted file mode 100644 index 467373cab8e..00000000000 --- a/drivers/ieee1394/dma.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/dv1394-private.h b/drivers/ieee1394/dv1394-private.h deleted file mode 100644 index 18b92cbf4a9..00000000000 --- a/drivers/ieee1394/dv1394-private.h +++ /dev/null @@ -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 */ - diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c deleted file mode 100644 index c5a031b79d0..00000000000 --- a/drivers/ieee1394/dv1394.c +++ /dev/null @@ -1,2584 +0,0 @@ -/* - * dv1394.c - 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.c - video driver for OHCI 1394 boards - * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au> - * - * 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. - */ - -/* - OVERVIEW - - I designed dv1394 as a "pipe" that you can use to shoot DV onto a - FireWire bus. In transmission mode, dv1394 does the following: - - 1. accepts contiguous frames of DV data from user-space, via write() - or mmap() (see dv1394.h for the complete API) - 2. wraps IEC 61883 packets around the DV data, inserting - empty synchronization packets as necessary - 3. assigns accurate SYT timestamps to the outgoing packets - 4. shoots them out using the OHCI card's IT DMA engine - - Thanks to Dan Dennedy, we now have a receive mode that does the following: - - 1. accepts raw IEC 61883 packets from the OHCI card - 2. re-assembles the DV data payloads into contiguous frames, - discarding empty packets - 3. sends the DV data to user-space via read() or mmap() -*/ - -/* - TODO: - - - tunable frame-drop behavior: either loop last frame, or halt transmission - - - use a scatter/gather buffer for DMA programs (f->descriptor_pool) - so that we don't rely on allocating 64KB of contiguous kernel memory - via pci_alloc_consistent() - - DONE: - - during reception, better handling of dropped frames and continuity errors - - during reception, prevent DMA from bypassing the irq tasklets - - reduce irq rate during reception (1/250 packets). - - add many more internal buffers during reception with scatter/gather dma. - - add dbc (continuity) checking on receive, increment status.dropped_frames - if not continuous. - - restart IT DMA after a bus reset - - safely obtain and release ISO Tx channels in cooperation with OHCI driver - - map received DIF blocks to their proper location in DV frame (ensure - recovery if dropped packet) - - handle bus resets gracefully (OHCI card seems to take care of this itself(!)) - - do not allow resizing the user_buf once allocated; eliminate nuke_buffer_mappings - - eliminated #ifdef DV1394_DEBUG_LEVEL by inventing macros debug_printk and irq_printk - - added wmb() and mb() to places where PCI read/write ordering needs to be enforced - - set video->id correctly - - store video_cards in an array indexed by OHCI card ID, rather than a list - - implement DMA context allocation to cooperate with other users of the OHCI - - fix all XXX showstoppers - - disable IR/IT DMA interrupts on shutdown - - flush pci writes to the card by issuing a read - - character device dispatching - - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!) - - keep all video_cards in a list (for open() via chardev), set file->private_data = video - - dv1394_poll should indicate POLLIN when receiving buffers are available - - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal - - expose xmit and recv as separate devices (not exclusive) - - expose NTSC and PAL as separate devices (can be overridden) - -*/ - -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/wait.h> -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/fs.h> -#include <linux/poll.h> -#include <linux/mutex.h> -#include <linux/bitops.h> -#include <asm/byteorder.h> -#include <asm/atomic.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <linux/delay.h> -#include <asm/pgtable.h> -#include <asm/page.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/vmalloc.h> -#include <linux/string.h> -#include <linux/compat.h> -#include <linux/cdev.h> - -#include "dv1394.h" -#include "dv1394-private.h" -#include "highlevel.h" -#include "hosts.h" -#include "ieee1394.h" -#include "ieee1394_core.h" -#include "ieee1394_hotplug.h" -#include "ieee1394_types.h" -#include "nodemgr.h" -#include "ohci1394.h" - -/* DEBUG LEVELS: - 0 - no debugging messages - 1 - some debugging messages, but none during DMA frame transmission - 2 - lots of messages, including during DMA frame transmission - (will cause underflows if your machine is too slow!) -*/ - -#define DV1394_DEBUG_LEVEL 0 - -/* for debugging use ONLY: allow more than one open() of the device */ -/* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */ - -#if DV1394_DEBUG_LEVEL >= 2 -#define irq_printk( args... ) printk( args ) -#else -#define irq_printk( args... ) do {} while (0) -#endif - -#if DV1394_DEBUG_LEVEL >= 1 -#define debug_printk( args... ) printk( args) -#else -#define debug_printk( args... ) do {} while (0) -#endif - -/* issue a dummy PCI read to force the preceding write - to be posted to the PCI bus immediately */ - -static inline void flush_pci_write(struct ti_ohci *ohci) -{ - mb(); - reg_read(ohci, OHCI1394_IsochronousCycleTimer); -} - -static void it_tasklet_func(unsigned long data); -static void ir_tasklet_func(unsigned long data); - -#ifdef CONFIG_COMPAT -static long dv1394_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg); -#endif - -/* GLOBAL DATA */ - -/* list of all video_cards */ -static LIST_HEAD(dv1394_cards); -static DEFINE_SPINLOCK(dv1394_cards_lock); - -/* translate from a struct file* to the corresponding struct video_card* */ - -static inline struct video_card* file_to_video_card(struct file *file) -{ - return file->private_data; -} - -/*** FRAME METHODS *********************************************************/ - -static void frame_reset(struct frame *f) -{ - f->state = FRAME_CLEAR; - f->done = 0; - f->n_packets = 0; - f->frame_begin_timestamp = NULL; - f->assigned_timestamp = 0; - f->cip_syt1 = NULL; - f->cip_syt2 = NULL; - f->mid_frame_timestamp = NULL; - f->frame_end_timestamp = NULL; - f->frame_end_branch = NULL; -} - -static struct frame* frame_new(unsigned int frame_num, struct video_card *video) -{ - struct frame *f = kmalloc(sizeof(*f), GFP_KERNEL); - if (!f) - return NULL; - - f->video = video; - f->frame_num = frame_num; - - f->header_pool = pci_alloc_consistent(f->video->ohci->dev, PAGE_SIZE, &f->header_pool_dma); - if (!f->header_pool) { - printk(KERN_ERR "dv1394: failed to allocate CIP header pool\n"); - kfree(f); - return NULL; - } - - debug_printk("dv1394: frame_new: allocated CIP header pool at virt 0x%08lx (contig) dma 0x%08lx size %ld\n", - (unsigned long) f->header_pool, (unsigned long) f->header_pool_dma, PAGE_SIZE); - - f->descriptor_pool_size = MAX_PACKETS * sizeof(struct DMA_descriptor_block); - /* make it an even # of pages */ - f->descriptor_pool_size += PAGE_SIZE - (f->descriptor_pool_size%PAGE_SIZE); - - f->descriptor_pool = pci_alloc_consistent(f->video->ohci->dev, - f->descriptor_pool_size, - &f->descriptor_pool_dma); - if (!f->descriptor_pool) { - pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma); - kfree(f); - return NULL; - } - - debug_printk("dv1394: frame_new: allocated DMA program memory at virt 0x%08lx (contig) dma 0x%08lx size %ld\n", - (unsigned long) f->descriptor_pool, (unsigned long) f->descriptor_pool_dma, f->descriptor_pool_size); - - f->data = 0; - frame_reset(f); - - return f; -} - -static void frame_delete(struct frame *f) -{ - pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma); - pci_free_consistent(f->video->ohci->dev, f->descriptor_pool_size, f->descriptor_pool, f->descriptor_pool_dma); - kfree(f); -} - - - - -/* - frame_prepare() - build the DMA program for transmitting - - Frame_prepare() must be called OUTSIDE the video->spinlock. - However, frame_prepare() must still be serialized, so - it should be called WITH the video->mtx taken. - */ - -static void frame_prepare(struct video_card *video, unsigned int this_frame) -{ - struct frame *f = video->frames[this_frame]; - int last_frame; - - struct DMA_descriptor_block *block; - dma_addr_t block_dma; - struct CIP_header *cip; - dma_addr_t cip_dma; - - unsigned int n_descriptors, full_packets, packets_per_frame, payload_size; - - /* these flags denote packets that need special attention */ - int empty_packet, first_packet, last_packet, mid_packet; - - __le32 *branch_address, *last_branch_address = NULL; - unsigned long data_p; - int first_packet_empty = 0; - u32 cycleTimer, ct_sec, ct_cyc, ct_off; - unsigned long irq_flags; - - irq_printk("frame_prepare( %d ) ---------------------\n", this_frame); - - full_packets = 0; - - - - if (video->pal_or_ntsc == DV1394_PAL) - packets_per_frame = DV1394_PAL_PACKETS_PER_FRAME; - else - packets_per_frame = DV1394_NTSC_PACKETS_PER_FRAME; - - while ( full_packets < packets_per_frame ) { - empty_packet = first_packet = last_packet = mid_packet = 0; - - data_p = f->data + full_packets * 480; - - /************************************************/ - /* allocate a descriptor block and a CIP header */ - /************************************************/ - - /* note: these should NOT cross a page boundary (DMA restriction) */ - - if (f->n_packets >= MAX_PACKETS) { - printk(KERN_ERR "dv1394: FATAL ERROR: max packet count exceeded\n"); - return; - } - - /* the block surely won't cross a page boundary, - since an even number of descriptor_blocks fit on a page */ - block = &(f->descriptor_pool[f->n_packets]); - - /* DMA address of the block = offset of block relative - to the kernel base address of the descriptor pool - + DMA base address of the descriptor pool */ - block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma; - - - /* the whole CIP pool fits on one page, so no worries about boundaries */ - if ( ((unsigned long) &(f->header_pool[f->n_packets]) - (unsigned long) f->header_pool) - > PAGE_SIZE) { - printk(KERN_ERR "dv1394: FATAL ERROR: no room to allocate CIP header\n"); - return; - } - - cip = &(f->header_pool[f->n_packets]); - - /* DMA address of the CIP header = offset of cip - relative to kernel base address of the header pool - + DMA base address of the header pool */ - cip_dma = (unsigned long) cip % PAGE_SIZE + f->header_pool_dma; - - /* is this an empty packet? */ - - if (video->cip_accum > (video->cip_d - video->cip_n)) { - empty_packet = 1; - payload_size = 8; - video->cip_accum -= (video->cip_d - video->cip_n); - } else { - payload_size = 488; - video->cip_accum += video->cip_n; - } - - /* there are three important packets each frame: - - the first packet in the frame - we ask the card to record the timestamp when - this packet is actually sent, so we can monitor - how accurate our timestamps are. Also, the first - packet serves as a semaphore to let us know that - it's OK to free the *previous* frame's DMA buffer - - the last packet in the frame - this packet is used to detect buffer underflows. - if this is the last ready frame, the last DMA block - will have a branch back to the beginning of the frame - (so that the card will re-send the frame on underflow). - if this branch gets taken, we know that at least one - frame has been dropped. When the next frame is ready, - the branch is pointed to its first packet, and the - semaphore is disabled. - - a "mid" packet slightly before the end of the frame - this packet should trigger - an interrupt so we can go and assign a timestamp to the first packet - in the next frame. We don't use the very last packet in the frame - for this purpose, because that would leave very little time to set - the timestamp before DMA starts on the next frame. - */ - - if (f->n_packets == 0) { - first_packet = 1; - } else if ( full_packets == (packets_per_frame-1) ) { - last_packet = 1; - } else if (f->n_packets == packets_per_frame) { - mid_packet = 1; - } - - - /********************/ - /* setup CIP header */ - /********************/ - - /* the timestamp will be written later from the - mid-frame interrupt handler. For now we just - store the address of the CIP header(s) that - need a timestamp. */ - - /* first packet in the frame needs a timestamp */ - if (first_packet) { - f->cip_syt1 = cip; - if (empty_packet) - first_packet_empty = 1; - - } else if (first_packet_empty && (f->n_packets == 1) ) { - /* if the first packet was empty, the second - packet's CIP header also needs a timestamp */ - f->cip_syt2 = cip; - } - - fill_cip_header(cip, - /* the node ID number of the OHCI card */ - reg_read(video->ohci, OHCI1394_NodeID) & 0x3F, - video->continuity_counter, - video->pal_or_ntsc, - 0xFFFF /* the timestamp is filled in later */); - - /* advance counter, only for full packets */ - if ( ! empty_packet ) - video->continuity_counter++; - - /******************************/ - /* setup DMA descriptor block */ - /******************************/ - - /* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */ - fill_output_more_immediate( &(block->u.out.omi), 1, video->channel, 0, payload_size); - - if (empty_packet) { - /* second descriptor - OUTPUT_LAST for CIP header */ - fill_output_last( &(block->u.out.u.empty.ol), - - /* want completion status on all interesting packets */ - (first_packet || mid_packet || last_packet) ? 1 : 0, - - /* want interrupts on all interesting packets */ - (first_packet || mid_packet || last_packet) ? 1 : 0, - - sizeof(struct CIP_header), /* data size */ - cip_dma); - - if (first_packet) - f->frame_begin_timestamp = &(block->u.out.u.empty.ol.q[3]); - else if (mid_packet) - f->mid_frame_timestamp = &(block->u.out.u.empty.ol.q[3]); - else if (last_packet) { - f->frame_end_timestamp = &(block->u.out.u.empty.ol.q[3]); - f->frame_end_branch = &(block->u.out.u.empty.ol.q[2]); - } - - branch_address = &(block->u.out.u.empty.ol.q[2]); - n_descriptors = 3; - if (first_packet) - f->first_n_descriptors = n_descriptors; - - } else { /* full packet */ - - /* second descriptor - OUTPUT_MORE for CIP header */ - fill_output_more( &(block->u.out.u.full.om), - sizeof(struct CIP_header), /* data size */ - cip_dma); - - - /* third (and possibly fourth) descriptor - for DV data */ - /* the 480-byte payload can cross a page boundary; if so, - we need to split it into two DMA descriptors */ - - /* does the 480-byte data payload cross a page boundary? */ - if ( (PAGE_SIZE- ((unsigned long)data_p % PAGE_SIZE) ) < 480 ) { - - /* page boundary crossed */ - - fill_output_more( &(block->u.out.u.full.u.cross.om), - /* data size - how much of data_p fits on the first page */ - PAGE_SIZE - (data_p % PAGE_SIZE), - - /* DMA address of data_p */ - dma_region_offset_to_bus(&video->dv_buf, - data_p - (unsigned long) video->dv_buf.kvirt)); - - fill_output_last( &(block->u.out.u.full.u.cross.ol), - - /* want completion status on all interesting packets */ - (first_packet || mid_packet || last_packet) ? 1 : 0, - - /* want interrupt on all interesting packets */ - (first_packet || mid_packet || last_packet) ? 1 : 0, - - /* data size - remaining portion of data_p */ - 480 - (PAGE_SIZE - (data_p % PAGE_SIZE)), - - /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */ - dma_region_offset_to_bus(&video->dv_buf, - data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) video->dv_buf.kvirt)); - - if (first_packet) - f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]); - else if (mid_packet) - f->mid_frame_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]); - else if (last_packet) { - f->frame_end_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]); - f->frame_end_branch = &(block->u.out.u.full.u.cross.ol.q[2]); - } - - branch_address = &(block->u.out.u.full.u.cross.ol.q[2]); - - n_descriptors = 5; - if (first_packet) - f->first_n_descriptors = n_descriptors; - - full_packets++; - - } else { - /* fits on one page */ - - fill_output_last( &(block->u.out.u.full.u.nocross.ol), - - /* want completion status on all interesting packets */ - (first_packet || mid_packet || last_packet) ? 1 : 0, - - /* want interrupt on all interesting packets */ - (first_packet || mid_packet || last_packet) ? 1 : 0, - - 480, /* data size (480 bytes of DV data) */ - - - /* DMA address of data_p */ - dma_region_offset_to_bus(&video->dv_buf, - data_p - (unsigned long) video->dv_buf.kvirt)); - - if (first_packet) - f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]); - else if (mid_packet) - f->mid_frame_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]); - else if (last_packet) { - f->frame_end_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]); - f->frame_end_branch = &(block->u.out.u.full.u.nocross.ol.q[2]); - } - - branch_address = &(block->u.out.u.full.u.nocross.ol.q[2]); - - n_descriptors = 4; - if (first_packet) - f->first_n_descriptors = n_descriptors; - - full_packets++; - } - } - - /* link this descriptor block into the DMA program by filling in - the branch address of the previous block */ - - /* note: we are not linked into the active DMA chain yet */ - - if (last_branch_address) { - *(last_branch_address) = cpu_to_le32(block_dma | n_descriptors); - } - - last_branch_address = branch_address; - - - f->n_packets++; - - } - - /* when we first assemble a new frame, set the final branch - to loop back up to the top */ - *(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors); - - /* make the latest version of this frame visible to the PCI card */ - dma_region_sync_for_device(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size); - - /* lock against DMA interrupt */ - spin_lock_irqsave(&video->spinlock, irq_flags); - - f->state = FRAME_READY; - - video->n_clear_frames--; - - last_frame = video->first_clear_frame - 1; - if (last_frame == -1) - last_frame = video->n_frames-1; - - video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames; - - irq_printk(" frame %d prepared, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n last=%d\n", - this_frame, video->active_frame, video->n_clear_frames, video->first_clear_frame, last_frame); - - irq_printk(" begin_ts %08lx mid_ts %08lx end_ts %08lx end_br %08lx\n", - (unsigned long) f->frame_begin_timestamp, - (unsigned long) f->mid_frame_timestamp, - (unsigned long) f->frame_end_timestamp, - (unsigned long) f->frame_end_branch); - - if (video->active_frame != -1) { - - /* if DMA is already active, we are almost done */ - /* just link us onto the active DMA chain */ - if (video->frames[last_frame]->frame_end_branch) { - u32 temp; - - /* point the previous frame's tail to this frame's head */ - *(video->frames[last_frame]->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors); - - /* this write MUST precede the next one, or we could silently drop frames */ - wmb(); - - /* disable the want_status semaphore on the last packet */ - temp = le32_to_cpu(*(video->frames[last_frame]->frame_end_branch - 2)); - temp &= 0xF7CFFFFF; - *(video->frames[last_frame]->frame_end_branch - 2) = cpu_to_le32(temp); - - /* flush these writes to memory ASAP */ - flush_pci_write(video->ohci); - - /* NOTE: - ideally the writes should be "atomic": if - the OHCI card reads the want_status flag in - between them, we'll falsely report a - dropped frame. Hopefully this window is too - small to really matter, and the consequence - is rather harmless. */ - - - irq_printk(" new frame %d linked onto DMA chain\n", this_frame); - - } else { - printk(KERN_ERR "dv1394: last frame not ready???\n"); - } - - } else { - - u32 transmit_sec, transmit_cyc; - u32 ts_cyc; - - /* DMA is stopped, so this is the very first frame */ - video->active_frame = this_frame; - - /* set CommandPtr to address and size of first descriptor block */ - reg_write(video->ohci, video->ohci_IsoXmitCommandPtr, - video->frames[video->active_frame]->descriptor_pool_dma | - f->first_n_descriptors); - - /* assign a timestamp based on the current cycle time... - We'll tell the card to begin DMA 100 cycles from now, - and assign a timestamp 103 cycles from now */ - - cycleTimer = reg_read(video->ohci, OHCI1394_IsochronousCycleTimer); - - ct_sec = cycleTimer >> 25; - ct_cyc = (cycleTimer >> 12) & 0x1FFF; - ct_off = cycleTimer & 0xFFF; - - transmit_sec = ct_sec; - transmit_cyc = ct_cyc + 100; - - transmit_sec += transmit_cyc/8000; - transmit_cyc %= 8000; - - ts_cyc = transmit_cyc + 3; - ts_cyc %= 8000; - - f->assigned_timestamp = (ts_cyc&0xF) << 12; - - /* now actually write the timestamp into the appropriate CIP headers */ - if (f->cip_syt1) { - f->cip_syt1->b[6] = f->assigned_timestamp >> 8; - f->cip_syt1->b[7] = f->assigned_timestamp & 0xFF; - } - if (f->cip_syt2) { - f->cip_syt2->b[6] = f->assigned_timestamp >> 8; - f->cip_syt2->b[7] = f->assigned_timestamp & 0xFF; - } - - /* --- start DMA --- */ - - /* clear all bits in ContextControl register */ - - reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, 0xFFFFFFFF); - wmb(); - - /* the OHCI card has the ability to start ISO transmission on a - particular cycle (start-on-cycle). This way we can ensure that - the first DV frame will have an accurate timestamp. - - However, start-on-cycle only appears to work if the OHCI card - is cycle master! Since the consequences of messing up the first - timestamp are minimal*, just disable start-on-cycle for now. - - * my DV deck drops the first few frames before it "locks in;" - so the first frame having an incorrect timestamp is inconsequential. - */ - -#if 0 - reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, - (1 << 31) /* enable start-on-cycle */ - | ( (transmit_sec & 0x3) << 29) - | (transmit_cyc << 16)); - wmb(); -#endif - - video->dma_running = 1; - - /* set the 'run' bit */ - reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000); - flush_pci_write(video->ohci); - - /* --- DMA should be running now --- */ - - debug_printk(" Cycle = %4u ContextControl = %08x CmdPtr = %08x\n", - (reg_read(video->ohci, OHCI1394_IsochronousCycleTimer) >> 12) & 0x1FFF, - reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), - reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)); - - debug_printk(" DMA start - current cycle %4u, transmit cycle %4u (%2u), assigning ts cycle %2u\n", - ct_cyc, transmit_cyc, transmit_cyc & 0xF, ts_cyc & 0xF); - -#if DV1394_DEBUG_LEVEL >= 2 - { - /* check if DMA is really running */ - int i = 0; - while (i < 20) { - mb(); - mdelay(1); - if (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) { - printk("DMA ACTIVE after %d msec\n", i); - break; - } - i++; - } - - printk("set = %08x, cmdPtr = %08x\n", - reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), - reg_read(video->ohci, video->ohci_IsoXmitCommandPtr) - ); - - if ( ! (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) { - printk("DMA did NOT go active after 20ms, event = %x\n", - reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & 0x1F); - } else - printk("DMA is RUNNING!\n"); - } -#endif - - } - - - spin_unlock_irqrestore(&video->spinlock, irq_flags); -} - - - -/*** RECEIVE FUNCTIONS *****************************************************/ - -/* - frame method put_packet - - map and copy the packet data to its location in the frame - based upon DIF section and sequence -*/ - -static void inline -frame_put_packet (struct frame *f, struct packet *p) -{ - int section_type = p->data[0] >> 5; /* section type is in bits 5 - 7 */ - int dif_sequence = p->data[1] >> 4; /* dif sequence number is in bits 4 - 7 */ - int dif_block = p->data[2]; - - /* sanity check */ - if (dif_sequence > 11 || dif_block > 149) return; - - switch (section_type) { - case 0: /* 1 Header block */ - memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480); - break; - - case 1: /* 2 Subcode blocks */ - memcpy( (void *) f->data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p->data, 480); - break; - - case 2: /* 3 VAUX blocks */ - memcpy( (void *) f->data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p->data, 480); - break; - - case 3: /* 9 Audio blocks interleaved with video */ - memcpy( (void *) f->data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p->data, 480); - break; - - case 4: /* 135 Video blocks interleaved with audio */ - memcpy( (void *) f->data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) + dif_block) * 80, p->data, 480); - break; - - default: /* we can not handle any other data */ - break; - } -} - - -static void start_dma_receive(struct video_card *video) -{ - if (video->first_run == 1) { - video->first_run = 0; - - /* start DMA once all of the frames are READY */ - video->n_clear_frames = 0; - video->first_clear_frame = -1; - video->current_packet = 0; - video->active_frame = 0; - - /* reset iso recv control register */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF); - wmb(); - - /* clear bufferFill, set isochHeader and speed (0=100) */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000); - - /* match on all tags, listen on channel */ - reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel); - - /* address and first descriptor block + Z=1 */ - reg_write(video->ohci, video->ohci_IsoRcvCommandPtr, - video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */ - wmb(); - - video->dma_running = 1; - - /* run */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000); - flush_pci_write(video->ohci); - - debug_printk("dv1394: DMA started\n"); - -#if DV1394_DEBUG_LEVEL >= 2 - { - int i; - - for (i = 0; i < 1000; ++i) { - mdelay(1); - if (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) { - printk("DMA ACTIVE after %d msec\n", i); - break; - } - } - if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) { - printk("DEAD, event = %x\n", - reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F); - } else - printk("RUNNING!\n"); - } -#endif - } else if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) { - debug_printk("DEAD, event = %x\n", - reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F); - - /* wake */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12)); - } -} - - -/* - receive_packets() - build the DMA program for receiving -*/ - -static void receive_packets(struct video_card *video) -{ - struct DMA_descriptor_block *block = NULL; - dma_addr_t block_dma = 0; - struct packet *data = NULL; - dma_addr_t data_dma = 0; - __le32 *last_branch_address = NULL; - unsigned long irq_flags; - int want_interrupt = 0; - struct frame *f = NULL; - int i, j; - - spin_lock_irqsave(&video->spinlock, irq_flags); - - for (j = 0; j < video->n_frames; j++) { - - /* connect frames */ - if (j > 0 && f != NULL && f->frame_end_branch != NULL) - *(f->frame_end_branch) = cpu_to_le32(video->frames[j]->descriptor_pool_dma | 1); /* set Z=1 */ - - f = video->frames[j]; - - for (i = 0; i < MAX_PACKETS; i++) { - /* locate a descriptor block and packet from the buffer */ - block = &(f->descriptor_pool[i]); - block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma; - - data = ((struct packet*)video->packet_buf.kvirt) + f->frame_num * MAX_PACKETS + i; - data_dma = dma_region_offset_to_bus( &video->packet_buf, - ((unsigned long) data - (unsigned long) video->packet_buf.kvirt) ); - - /* setup DMA descriptor block */ - want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1)); - fill_input_last( &(block->u.in.il), want_interrupt, 512, data_dma); - - /* link descriptors */ - last_branch_address = f->frame_end_branch; - - if (last_branch_address != NULL) - *(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */ - - f->frame_end_branch = &(block->u.in.il.q[2]); - } - - } /* next j */ - - spin_unlock_irqrestore(&video->spinlock, irq_flags); - -} - - - -/*** MANAGEMENT FUNCTIONS **************************************************/ - -static int do_dv1394_init(struct video_card *video, struct dv1394_init *init) -{ - unsigned long flags, new_buf_size; - int i; - u64 chan_mask; - int retval = -EINVAL; - - debug_printk("dv1394: initialising %d\n", video->id); - if (init->api_version != DV1394_API_VERSION) - return -EINVAL; - - /* first sanitize all the parameters */ - if ( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) ) - return -EINVAL; - - if ( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) ) - return -EINVAL; - - if ( (init->syt_offset == 0) || (init->syt_offset > 50) ) - /* default SYT offset is 3 cycles */ - init->syt_offset = 3; - - if (init->channel > 63) - init->channel = 63; - - chan_mask = (u64)1 << init->channel; - - /* calculate what size DMA buffer is needed */ - if (init->format == DV1394_NTSC) - new_buf_size = DV1394_NTSC_FRAME_SIZE * init->n_frames; - else - new_buf_size = DV1394_PAL_FRAME_SIZE * init->n_frames; - - /* round up to PAGE_SIZE */ - if (new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE); - - /* don't allow the user to allocate the DMA buffer more than once */ - if (video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) { - printk("dv1394: re-sizing the DMA buffer is not allowed\n"); - return -EINVAL; - } - - /* shutdown the card if it's currently active */ - /* (the card should not be reset if the parameters are screwy) */ - - do_dv1394_shutdown(video, 0); - - /* try to claim the ISO channel */ - spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); - if (video->ohci->ISO_channel_usage & chan_mask) { - spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); - retval = -EBUSY; - goto err; - } - video->ohci->ISO_channel_usage |= chan_mask; - spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); - - video->channel = init->channel; - - /* initialize misc. fields of video */ - video->n_frames = init->n_frames; - video->pal_or_ntsc = init->format; - - video->cip_accum = 0; - video->continuity_counter = 0; - - video->active_frame = -1; - video->first_clear_frame = 0; - video->n_clear_frames = video->n_frames; - video->dropped_frames = 0; - - video->write_off = 0; - - video->first_run = 1; - video->current_packet = -1; - video->first_frame = 0; - - if (video->pal_or_ntsc == DV1394_NTSC) { - video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC; - video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC; - video->frame_size = DV1394_NTSC_FRAME_SIZE; - } else { - video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL; - video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL; - video->frame_size = DV1394_PAL_FRAME_SIZE; - } - - video->syt_offset = init->syt_offset; - - /* find and claim DMA contexts on the OHCI card */ - - if (video->ohci_it_ctx == -1) { - ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT, - it_tasklet_func, (unsigned long) video); - - if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) { - printk(KERN_ERR "dv1394: could not find an available IT DMA context\n"); - retval = -EBUSY; - goto err; - } - - video->ohci_it_ctx = video->it_tasklet.context; - debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx); - } - - if (video->ohci_ir_ctx == -1) { - ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE, - ir_tasklet_func, (unsigned long) video); - - if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) { - printk(KERN_ERR "dv1394: could not find an available IR DMA context\n"); - retval = -EBUSY; - goto err; - } - video->ohci_ir_ctx = video->ir_tasklet.context; - debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx); - } - - /* allocate struct frames */ - for (i = 0; i < init->n_frames; i++) { - video->frames[i] = frame_new(i, video); - - if (!video->frames[i]) { - printk(KERN_ERR "dv1394: Cannot allocate frame structs\n"); - retval = -ENOMEM; - goto err; - } - } - - if (!video->dv_buf.kvirt) { - /* allocate the ringbuffer */ - retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE); - if (retval) - goto err; - - video->dv_buf_size = new_buf_size; - - debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", - video->n_frames, video->dv_buf.n_pages, - video->dv_buf.n_dma_pages, video->dv_buf_size); - } - - /* set up the frame->data pointers */ - for (i = 0; i < video->n_frames; i++) - video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size; - - if (!video->packet_buf.kvirt) { - /* allocate packet buffer */ - video->packet_buf_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS; - if (video->packet_buf_size % PAGE_SIZE) - video->packet_buf_size += PAGE_SIZE - (video->packet_buf_size % PAGE_SIZE); - - retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size, - video->ohci->dev, PCI_DMA_FROMDEVICE); - if (retval) - goto err; - - debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n", - video->n_frames*MAX_PACKETS, video->packet_buf.n_pages, - video->packet_buf.n_dma_pages, video->packet_buf_size); - } - - /* set up register offsets for IT context */ - /* IT DMA context registers are spaced 16 bytes apart */ - video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx; - video->ohci_IsoXmitContextControlClear = OHCI1394_IsoXmitContextControlClear+16*video->ohci_it_ctx; - video->ohci_IsoXmitCommandPtr = OHCI1394_IsoXmitCommandPtr+16*video->ohci_it_ctx; - - /* enable interrupts for IT context */ - reg_write(video->ohci, OHCI1394_IsoXmitIntMaskSet, (1 << video->ohci_it_ctx)); - debug_printk("dv1394: interrupts enabled for IT context %d\n", video->ohci_it_ctx); - - /* set up register offsets for IR context */ - /* IR DMA context registers are spaced 32 bytes apart */ - video->ohci_IsoRcvContextControlSet = OHCI1394_IsoRcvContextControlSet+32*video->ohci_ir_ctx; - video->ohci_IsoRcvContextControlClear = OHCI1394_IsoRcvContextControlClear+32*video->ohci_ir_ctx; - video->ohci_IsoRcvCommandPtr = OHCI1394_IsoRcvCommandPtr+32*video->ohci_ir_ctx; - video->ohci_IsoRcvContextMatch = OHCI1394_IsoRcvContextMatch+32*video->ohci_ir_ctx; - - /* enable interrupts for IR context */ - reg_write(video->ohci, OHCI1394_IsoRecvIntMaskSet, (1 << video->ohci_ir_ctx) ); - debug_printk("dv1394: interrupts enabled for IR context %d\n", video->ohci_ir_ctx); - - return 0; - -err: - do_dv1394_shutdown(video, 1); - return retval; -} - -/* if the user doesn't bother to call ioctl(INIT) before starting - mmap() or read()/write(), just give him some default values */ - -static int do_dv1394_init_default(struct video_card *video) -{ - struct dv1394_init init; - - init.api_version = DV1394_API_VERSION; - init.n_frames = DV1394_MAX_FRAMES / 4; - init.channel = video->channel; - init.format = video->pal_or_ntsc; - init.cip_n = video->cip_n; - init.cip_d = video->cip_d; - init.syt_offset = video->syt_offset; - - return do_dv1394_init(video, &init); -} - -/* do NOT call from interrupt context */ -static void stop_dma(struct video_card *video) -{ - unsigned long flags; - int i; - - /* no interrupts */ - spin_lock_irqsave(&video->spinlock, flags); - - video->dma_running = 0; - - if ( (video->ohci_it_ctx == -1) && (video->ohci_ir_ctx == -1) ) - goto out; - - /* stop DMA if in progress */ - if ( (video->active_frame != -1) || - (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) || - (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) { - - /* clear the .run bits */ - reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15)); - reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15)); - flush_pci_write(video->ohci); - - video->active_frame = -1; - video->first_run = 1; - - /* wait until DMA really stops */ - i = 0; - while (i < 1000) { - - /* wait 0.1 millisecond */ - udelay(100); - - if ( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) || - (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) { - /* still active */ - debug_printk("dv1394: stop_dma: DMA not stopped yet\n" ); - mb(); - } else { - debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10); - break; - } - - i++; - } - - if (i == 1000) { - printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10); - } - } - else - debug_printk("dv1394: stop_dma: already stopped.\n"); - -out: - spin_unlock_irqrestore(&video->spinlock, flags); -} - - - -static void do_dv1394_shutdown(struct video_card *video, int free_dv_buf) -{ - int i; - - debug_printk("dv1394: shutdown...\n"); - - /* stop DMA if in progress */ - stop_dma(video); - - /* release the DMA contexts */ - if (video->ohci_it_ctx != -1) { - video->ohci_IsoXmitContextControlSet = 0; - video->ohci_IsoXmitContextControlClear = 0; - video->ohci_IsoXmitCommandPtr = 0; - - /* disable interrupts for IT context */ - reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx)); - - /* remove tasklet */ - ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet); - debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx); - video->ohci_it_ctx = -1; - } - - if (video->ohci_ir_ctx != -1) { - video->ohci_IsoRcvContextControlSet = 0; - video->ohci_IsoRcvContextControlClear = 0; - video->ohci_IsoRcvCommandPtr = 0; - video->ohci_IsoRcvContextMatch = 0; - - /* disable interrupts for IR context */ - reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx)); - - /* remove tasklet */ - ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet); - debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx); - video->ohci_ir_ctx = -1; - } - - /* release the ISO channel */ - if (video->channel != -1) { - u64 chan_mask; - unsigned long flags; - - chan_mask = (u64)1 << video->channel; - - spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); - video->ohci->ISO_channel_usage &= ~(chan_mask); - spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); - - video->channel = -1; - } - - /* free the frame structs */ - for (i = 0; i < DV1394_MAX_FRAMES; i++) { - if (video->frames[i]) - frame_delete(video->frames[i]); - video->frames[i] = NULL; - } - - video->n_frames = 0; - - /* we can't free the DMA buffer unless it is guaranteed that - no more user-space mappings exist */ - - if (free_dv_buf) { - dma_region_free(&video->dv_buf); - video->dv_buf_size = 0; - } - - /* free packet buffer */ - dma_region_free(&video->packet_buf); - video->packet_buf_size = 0; - - debug_printk("dv1394: shutdown OK\n"); -} - -/* - ********************************** - *** MMAP() THEORY OF OPERATION *** - ********************************** - - The ringbuffer cannot be re-allocated or freed while - a user program maintains a mapping of it. (note that a mapping - can persist even after the device fd is closed!) - - So, only let the user process allocate the DMA buffer once. - To resize or deallocate it, you must close the device file - and open it again. - - Previously Dan M. hacked out a scheme that allowed the DMA - buffer to change by forcefully unmapping it from the user's - address space. It was prone to error because it's very hard to - track all the places the buffer could have been mapped (we - would have had to walk the vma list of every process in the - system to be sure we found all the mappings!). Instead, we - force the user to choose one buffer size and stick with - it. This small sacrifice is worth the huge reduction in - error-prone code in dv1394. -*/ - -static int dv1394_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_card *video = file_to_video_card(file); - int retval = -EINVAL; - - /* - * We cannot use the blocking variant mutex_lock here because .mmap - * is called with mmap_sem held, while .ioctl, .read, .write acquire - * video->mtx and subsequently call copy_to/from_user which will - * grab mmap_sem in case of a page fault. - */ - if (!mutex_trylock(&video->mtx)) - return -EAGAIN; - - if ( ! video_card_initialized(video) ) { - retval = do_dv1394_init_default(video); - if (retval) - goto out; - } - - retval = dma_region_mmap(&video->dv_buf, file, vma); -out: - mutex_unlock(&video->mtx); - return retval; -} - -/*** DEVICE FILE INTERFACE *************************************************/ - -/* no need to serialize, multiple threads OK */ -static unsigned int dv1394_poll(struct file *file, struct poll_table_struct *wait) -{ - struct video_card *video = file_to_video_card(file); - unsigned int mask = 0; - unsigned long flags; - - poll_wait(file, &video->waitq, wait); - - spin_lock_irqsave(&video->spinlock, flags); - if ( video->n_frames == 0 ) { - - } else if ( video->active_frame == -1 ) { - /* nothing going on */ - mask |= POLLOUT; - } else { - /* any clear/ready buffers? */ - if (video->n_clear_frames >0) - mask |= POLLOUT | POLLIN; - } - spin_unlock_irqrestore(&video->spinlock, flags); - - return mask; -} - -static int dv1394_fasync(int fd, struct file *file, int on) -{ - /* I just copied this code verbatim from Alan Cox's mouse driver example - (Documentation/DocBook/) */ - - struct video_card *video = file_to_video_card(file); - - return fasync_helper(fd, file, on, &video->fasync); -} - -static ssize_t dv1394_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct video_card *video = file_to_video_card(file); - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - size_t cnt; - unsigned long flags; - int target_frame; - - /* serialize this to prevent multi-threaded mayhem */ - if (file->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&video->mtx)) - return -EAGAIN; - } else { - if (mutex_lock_interruptible(&video->mtx)) - return -ERESTARTSYS; - } - - if ( !video_card_initialized(video) ) { - ret = do_dv1394_init_default(video); - if (ret) { - mutex_unlock(&video->mtx); - return ret; - } - } - - ret = 0; - add_wait_queue(&video->waitq, &wait); - - while (count > 0) { - - /* must set TASK_INTERRUPTIBLE *before* checking for free - buffers; otherwise we could miss a wakeup if the interrupt - fires between the check and the schedule() */ - - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irqsave(&video->spinlock, flags); - - target_frame = video->first_clear_frame; - - spin_unlock_irqrestore(&video->spinlock, flags); - - if (video->frames[target_frame]->state == FRAME_CLEAR) { - - /* how much room is left in the target frame buffer */ - cnt = video->frame_size - (video->write_off - target_frame * video->frame_size); - - } else { - /* buffer is already used */ - cnt = 0; - } - - if (cnt > count) - cnt = count; - - if (cnt <= 0) { - /* no room left, gotta wait */ - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - - schedule(); - - continue; /* start over from 'while(count > 0)...' */ - } - - if (copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - - video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size); - - count -= cnt; - buffer += cnt; - ret += cnt; - - if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) - frame_prepare(video, target_frame); - } - - remove_wait_queue(&video->waitq, &wait); - set_current_state(TASK_RUNNING); - mutex_unlock(&video->mtx); - return ret; -} - - -static ssize_t dv1394_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct video_card *video = file_to_video_card(file); - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - size_t cnt; - unsigned long flags; - int target_frame; - - /* serialize this to prevent multi-threaded mayhem */ - if (file->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&video->mtx)) - return -EAGAIN; - } else { - if (mutex_lock_interruptible(&video->mtx)) - return -ERESTARTSYS; - } - - if ( !video_card_initialized(video) ) { - ret = do_dv1394_init_default(video); - if (ret) { - mutex_unlock(&video->mtx); - return ret; - } - video->continuity_counter = -1; - - receive_packets(video); - - start_dma_receive(video); - } - - ret = 0; - add_wait_queue(&video->waitq, &wait); - - while (count > 0) { - - /* must set TASK_INTERRUPTIBLE *before* checking for free - buffers; otherwise we could miss a wakeup if the interrupt - fires between the check and the schedule() */ - - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irqsave(&video->spinlock, flags); - - target_frame = video->first_clear_frame; - - spin_unlock_irqrestore(&video->spinlock, flags); - - if (target_frame >= 0 && - video->n_clear_frames > 0 && - video->frames[target_frame]->state == FRAME_CLEAR) { - - /* how much room is left in the target frame buffer */ - cnt = video->frame_size - (video->write_off - target_frame * video->frame_size); - - } else { - /* buffer is already used */ - cnt = 0; - } - - if (cnt > count) - cnt = count; - - if (cnt <= 0) { - /* no room left, gotta wait */ - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - - schedule(); - - continue; /* start over from 'while(count > 0)...' */ - } - - if (copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - - video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size); - - count -= cnt; - buffer += cnt; - ret += cnt; - - if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) { - spin_lock_irqsave(&video->spinlock, flags); - video->n_clear_frames--; - video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames; - spin_unlock_irqrestore(&video->spinlock, flags); - } - } - - remove_wait_queue(&video->waitq, &wait); - set_current_state(TASK_RUNNING); - mutex_unlock(&video->mtx); - return ret; -} - - -/*** DEVICE IOCTL INTERFACE ************************************************/ - -static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct video_card *video = file_to_video_card(file); - unsigned long flags; - int ret = -EINVAL; - void __user *argp = (void __user *)arg; - - DECLARE_WAITQUEUE(wait, current); - - /* serialize this to prevent multi-threaded mayhem */ - if (file->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&video->mtx)) - return -EAGAIN; - } else { - if (mutex_lock_interruptible(&video->mtx)) - return -ERESTARTSYS; - } - - switch(cmd) - { - case DV1394_IOC_SUBMIT_FRAMES: { - unsigned int n_submit; - - if ( !video_card_initialized(video) ) { - ret = do_dv1394_init_default(video); - if (ret) - goto out; - } - - n_submit = (unsigned int) arg; - - if (n_submit > video->n_frames) { - ret = -EINVAL; - goto out; - } - - while (n_submit > 0) { - - add_wait_queue(&video->waitq, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irqsave(&video->spinlock, flags); - - /* wait until video->first_clear_frame is really CLEAR */ - while (video->frames[video->first_clear_frame]->state != FRAME_CLEAR) { - - spin_unlock_irqrestore(&video->spinlock, flags); - - if (signal_pending(current)) { - remove_wait_queue(&video->waitq, &wait); - set_current_state(TASK_RUNNING); - ret = -EINTR; - goto out; - } - - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irqsave(&video->spinlock, flags); - } - spin_unlock_irqrestore(&video->spinlock, flags); - - remove_wait_queue(&video->waitq, &wait); - set_current_state(TASK_RUNNING); - - frame_prepare(video, video->first_clear_frame); - - n_submit--; - } - - ret = 0; - break; - } - - case DV1394_IOC_WAIT_FRAMES: { - unsigned int n_wait; - - if ( !video_card_initialized(video) ) { - ret = -EINVAL; - goto out; - } - - n_wait = (unsigned int) arg; - - /* since we re-run the last frame on underflow, we will - never actually have n_frames clear frames; at most only - n_frames - 1 */ - - if (n_wait > (video->n_frames-1) ) { - ret = -EINVAL; - goto out; - } - - add_wait_queue(&video->waitq, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irqsave(&video->spinlock, flags); - - while (video->n_clear_frames < n_wait) { - - spin_unlock_irqrestore(&video->spinlock, flags); - - if (signal_pending(current)) { - remove_wait_queue(&video->waitq, &wait); - set_current_state(TASK_RUNNING); - ret = -EINTR; - goto out; - } - - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irqsave(&video->spinlock, flags); - } - - spin_unlock_irqrestore(&video->spinlock, flags); - - remove_wait_queue(&video->waitq, &wait); - set_current_state(TASK_RUNNING); - ret = 0; - break; - } - - case DV1394_IOC_RECEIVE_FRAMES: { - unsigned int n_recv; - - if ( !video_card_initialized(video) ) { - ret = -EINVAL; - goto out; - } - - n_recv = (unsigned int) arg; - - /* at least one frame must be active */ - if (n_recv > (video->n_frames-1) ) { - ret = -EINVAL; - goto out; - } - - spin_lock_irqsave(&video->spinlock, flags); - - /* release the clear frames */ - video->n_clear_frames -= n_recv; - - /* advance the clear frame cursor */ - video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames; - - /* reset dropped_frames */ - video->dropped_frames = 0; - - spin_unlock_irqrestore(&video->spinlock, flags); - - ret = 0; - break; - } - - case DV1394_IOC_START_RECEIVE: { - if ( !video_card_initialized(video) ) { - ret = do_dv1394_init_default(video); - if (ret) - goto out; - } - - video->continuity_counter = -1; - - receive_packets(video); - - start_dma_receive(video); - - ret = 0; - break; - } - - case DV1394_IOC_INIT: { - struct dv1394_init init; - if (!argp) { - ret = do_dv1394_init_default(video); - } else { - if (copy_from_user(&init, argp, sizeof(init))) { - ret = -EFAULT; - goto out; - } - ret = do_dv1394_init(video, &init); - } - break; - } - - case DV1394_IOC_SHUTDOWN: - do_dv1394_shutdown(video, 0); - ret = 0; - break; - - - case DV1394_IOC_GET_STATUS: { - struct dv1394_status status; - - if ( !video_card_initialized(video) ) { - ret = -EINVAL; - goto out; - } - - status.init.api_version = DV1394_API_VERSION; - status.init.channel = video->channel; - status.init.n_frames = video->n_frames; - status.init.format = video->pal_or_ntsc; - status.init.cip_n = video->cip_n; - status.init.cip_d = video->cip_d; - status.init.syt_offset = video->syt_offset; - - status.first_clear_frame = video->first_clear_frame; - - /* the rest of the fields need to be locked against the interrupt */ - spin_lock_irqsave(&video->spinlock, flags); - - status.active_frame = video->active_frame; - status.n_clear_frames = video->n_clear_frames; - - status.dropped_frames = video->dropped_frames; - - /* reset dropped_frames */ - video->dropped_frames = 0; - - spin_unlock_irqrestore(&video->spinlock, flags); - - if (copy_to_user(argp, &status, sizeof(status))) { - ret = -EFAULT; - goto out; - } - - ret = 0; - break; - } - - default: - break; - } - - out: - mutex_unlock(&video->mtx); - return ret; -} - -/*** DEVICE FILE INTERFACE CONTINUED ***************************************/ - -static int dv1394_open(struct inode *inode, struct file *file) -{ - struct video_card *video = NULL; - - if (file->private_data) { - video = file->private_data; - - } else { - /* look up the card by ID */ - unsigned long flags; - int idx = ieee1394_file_to_instance(file); - - spin_lock_irqsave(&dv1394_cards_lock, flags); - if (!list_empty(&dv1394_cards)) { - struct video_card *p; - list_for_each_entry(p, &dv1394_cards, list) { - if ((p->id) == idx) { - video = p; - break; - } - } - } - spin_unlock_irqrestore(&dv1394_cards_lock, flags); - - if (!video) { - debug_printk("dv1394: OHCI card %d not found", idx); - return -ENODEV; - } - - file->private_data = (void*) video; - } - -#ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN - - if ( test_and_set_bit(0, &video->open) ) { - /* video is already open by someone else */ - return -EBUSY; - } - -#endif - - printk(KERN_INFO "%s: NOTE, the dv1394 interface is unsupported " - "and will not be available in the new firewire driver stack. " - "Try libraw1394 based programs instead.\n", current->comm); - - return nonseekable_open(inode, file); -} - - -static int dv1394_release(struct inode *inode, struct file *file) -{ - struct video_card *video = file_to_video_card(file); - - /* OK to free the DMA buffer, no more mappings can exist */ - do_dv1394_shutdown(video, 1); - - /* give someone else a turn */ - clear_bit(0, &video->open); - - return 0; -} - - -/*** DEVICE DRIVER HANDLERS ************************************************/ - -static void it_tasklet_func(unsigned long data) -{ - int wake = 0; - struct video_card *video = (struct video_card*) data; - - spin_lock(&video->spinlock); - - if (!video->dma_running) - goto out; - - irq_printk("ContextControl = %08x, CommandPtr = %08x\n", - reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), - reg_read(video->ohci, video->ohci_IsoXmitCommandPtr) - ); - - - if ( (video->ohci_it_ctx != -1) && - (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) { - - struct frame *f; - unsigned int frame, i; - - - if (video->active_frame == -1) - frame = 0; - else - frame = video->active_frame; - - /* check all the DMA-able frames */ - for (i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) { - - irq_printk("IRQ checking frame %d...", frame); - f = video->frames[frame]; - if (f->state != FRAME_READY) { - irq_printk("clear, skipping\n"); - /* we don't own this frame */ - continue; - } - - irq_printk("DMA\n"); - - /* check the frame begin semaphore to see if we can free the previous frame */ - if ( *(f->frame_begin_timestamp) ) { - int prev_frame; - struct frame *prev_f; - - - - /* don't reset, need this later *(f->frame_begin_timestamp) = 0; */ - irq_printk(" BEGIN\n"); - - prev_frame = frame - 1; - if (prev_frame == -1) - prev_frame += video->n_frames; - prev_f = video->frames[prev_frame]; - - /* make sure we can actually garbage collect - this frame */ - if ( (prev_f->state == FRAME_READY) && - prev_f->done && (!f->done) ) - { - frame_reset(prev_f); - video->n_clear_frames++; - wake = 1; - video->active_frame = frame; - - irq_printk(" BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame); - } else { - irq_printk(" BEGIN - can't free yet\n"); - } - - f->done = 1; - } - - - /* see if we need to set the timestamp for the next frame */ - if ( *(f->mid_frame_timestamp) ) { - struct frame *next_frame; - u32 begin_ts, ts_cyc, ts_off; - - *(f->mid_frame_timestamp) = 0; - - begin_ts = le32_to_cpu(*(f->frame_begin_timestamp)); - - irq_printk(" MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n", - begin_ts & 0x1FFF, begin_ts & 0xF, - f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF); - - /* prepare next frame and assign timestamp */ - next_frame = video->frames[ (frame+1) % video->n_frames ]; - - if (next_frame->state == FRAME_READY) { - irq_printk(" MIDDLE - next frame is ready, good\n"); - } else { - debug_printk("dv1394: Underflow! At least one frame has been dropped.\n"); - next_frame = f; - } - - /* set the timestamp to the timestamp of the last frame sent, - plus the length of the last frame sent, plus the syt latency */ - ts_cyc = begin_ts & 0xF; - /* advance one frame, plus syt latency (typically 2-3) */ - ts_cyc += f->n_packets + video->syt_offset ; - - ts_off = 0; - - ts_cyc += ts_off/3072; - ts_off %= 3072; - - next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off; - if (next_frame->cip_syt1) { - next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8; - next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF; - } - if (next_frame->cip_syt2) { - next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8; - next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF; - } - - } - - /* see if the frame looped */ - if ( *(f->frame_end_timestamp) ) { - - *(f->frame_end_timestamp) = 0; - - debug_printk(" END - the frame looped at least once\n"); - - video->dropped_frames++; - } - - } /* for (each frame) */ - } - - if (wake) { - kill_fasync(&video->fasync, SIGIO, POLL_OUT); - - /* wake readers/writers/ioctl'ers */ - wake_up_interruptible(&video->waitq); - } - -out: - spin_unlock(&video->spinlock); -} - -static void ir_tasklet_func(unsigned long data) -{ - int wake = 0; - struct video_card *video = (struct video_card*) data; - - spin_lock(&video->spinlock); - - if (!video->dma_running) - goto out; - - if ( (video->ohci_ir_ctx != -1) && - (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { - - int sof=0; /* start-of-frame flag */ - struct frame *f; - u16 packet_length; - int i, dbc=0; - struct DMA_descriptor_block *block = NULL; - u16 xferstatus; - - int next_i, prev_i; - struct DMA_descriptor_block *next = NULL; - dma_addr_t next_dma = 0; - struct DMA_descriptor_block *prev = NULL; - - /* loop over all descriptors in all frames */ - for (i = 0; i < video->n_frames*MAX_PACKETS; i++) { - struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet); - - /* make sure we are seeing the latest changes to p */ - dma_region_sync_for_cpu(&video->packet_buf, - (unsigned long) p - (unsigned long) video->packet_buf.kvirt, - sizeof(struct packet)); - - packet_length = le16_to_cpu(p->data_length); - - /* get the descriptor based on packet_buffer cursor */ - f = video->frames[video->current_packet / MAX_PACKETS]; - block = &(f->descriptor_pool[video->current_packet % MAX_PACKETS]); - xferstatus = le32_to_cpu(block->u.in.il.q[3]) >> 16; - xferstatus &= 0x1F; - irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) ); - - /* get the current frame */ - f = video->frames[video->active_frame]; - - /* exclude empty packet */ - if (packet_length > 8 && xferstatus == 0x11) { - /* check for start of frame */ - /* DRD> Changed to check section type ([0]>>5==0) - and dif sequence ([1]>>4==0) */ - sof = ( (p->data[0] >> 5) == 0 && (p->data[1] >> 4) == 0); - - dbc = (int) (p->cip_h1 >> 24); - if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) ) - { - printk(KERN_WARNING "dv1394: discontinuity detected, dropping all frames\n" ); - video->dropped_frames += video->n_clear_frames + 1; - video->first_frame = 0; - video->n_clear_frames = 0; - video->first_clear_frame = -1; - } - video->continuity_counter = dbc; - - if (!video->first_frame) { - if (sof) { - video->first_frame = 1; - } - - } else if (sof) { - /* close current frame */ - frame_reset(f); /* f->state = STATE_CLEAR */ - video->n_clear_frames++; - if (video->n_clear_frames > video->n_frames) { - video->dropped_frames++; - printk(KERN_WARNING "dv1394: dropped a frame during reception\n" ); - video->n_clear_frames = video->n_frames-1; - video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames; - } - if (video->first_clear_frame == -1) - video->first_clear_frame = video->active_frame; - - /* get the next frame */ - video->active_frame = (video->active_frame + 1) % video->n_frames; - f = video->frames[video->active_frame]; - irq_printk(" frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n", - video->active_frame, video->n_clear_frames, video->first_clear_frame); - } - if (video->first_frame) { - if (sof) { - /* open next frame */ - f->state = FRAME_READY; - } - - /* copy to buffer */ - if (f->n_packets > (video->frame_size / 480)) { - printk(KERN_ERR "frame buffer overflow during receive\n"); - } - - frame_put_packet(f, p); - - } /* first_frame */ - } - - /* stop, end of ready packets */ - else if (xferstatus == 0) { - break; - } - - /* reset xferStatus & resCount */ - block->u.in.il.q[3] = cpu_to_le32(512); - - /* terminate dma chain at this (next) packet */ - next_i = video->current_packet; - f = video->frames[next_i / MAX_PACKETS]; - next = &(f->descriptor_pool[next_i % MAX_PACKETS]); - next_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma; - next->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */ - next->u.in.il.q[2] = cpu_to_le32(0); /* disable branch */ - - /* link previous to next */ - prev_i = (next_i == 0) ? (MAX_PACKETS * video->n_frames - 1) : (next_i - 1); - f = video->frames[prev_i / MAX_PACKETS]; - prev = &(f->descriptor_pool[prev_i % MAX_PACKETS]); - if (prev_i % (MAX_PACKETS/2)) { - prev->u.in.il.q[0] &= ~cpu_to_le32(3 << 20); /* no interrupt */ - } else { - prev->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */ - } - prev->u.in.il.q[2] = cpu_to_le32(next_dma | 1); /* set Z=1 */ - wmb(); - - /* wake up DMA in case it fell asleep */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12)); - - /* advance packet_buffer cursor */ - video->current_packet = (video->current_packet + 1) % (MAX_PACKETS * video->n_frames); - - } /* for all packets */ - - wake = 1; /* why the hell not? */ - - } /* receive interrupt */ - - if (wake) { - kill_fasync(&video->fasync, SIGIO, POLL_IN); - - /* wake readers/writers/ioctl'ers */ - wake_up_interruptible(&video->waitq); - } - -out: - spin_unlock(&video->spinlock); -} - -static struct cdev dv1394_cdev; -static const struct file_operations dv1394_fops= -{ - .owner = THIS_MODULE, - .poll = dv1394_poll, - .unlocked_ioctl = dv1394_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = dv1394_compat_ioctl, -#endif - .mmap = dv1394_mmap, - .open = dv1394_open, - .write = dv1394_write, - .read = dv1394_read, - .release = dv1394_release, - .fasync = dv1394_fasync, - .llseek = no_llseek, -}; - - -/*** HOTPLUG STUFF **********************************************************/ -/* - * Export information about protocols/devices supported by this driver. - */ -#ifdef MODULE -static const struct ieee1394_device_id dv1394_id_table[] = { - { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, - .version = AVC_SW_VERSION_ENTRY & 0xffffff - }, - { } -}; - -MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table); -#endif /* MODULE */ - -static struct hpsb_protocol_driver dv1394_driver = { - .name = "dv1394", -}; - - -/*** IEEE1394 HPSB CALLBACKS ***********************************************/ - -static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode) -{ - struct video_card *video; - unsigned long flags; - int i; - - video = kzalloc(sizeof(*video), GFP_KERNEL); - if (!video) { - printk(KERN_ERR "dv1394: cannot allocate video_card\n"); - return -1; - } - - video->ohci = ohci; - /* lower 2 bits of id indicate which of four "plugs" - per host */ - video->id = ohci->host->id << 2; - if (format == DV1394_NTSC) - video->id |= mode; - else - video->id |= 2 + mode; - - video->ohci_it_ctx = -1; - video->ohci_ir_ctx = -1; - - video->ohci_IsoXmitContextControlSet = 0; - video->ohci_IsoXmitContextControlClear = 0; - video->ohci_IsoXmitCommandPtr = 0; - - video->ohci_IsoRcvContextControlSet = 0; - video->ohci_IsoRcvContextControlClear = 0; - video->ohci_IsoRcvCommandPtr = 0; - video->ohci_IsoRcvContextMatch = 0; - - video->n_frames = 0; /* flag that video is not initialized */ - video->channel = 63; /* default to broadcast channel */ - video->active_frame = -1; - - /* initialize the following */ - video->pal_or_ntsc = format; - video->cip_n = 0; /* 0 = use builtin default */ - video->cip_d = 0; - video->syt_offset = 0; - video->mode = mode; - - for (i = 0; i < DV1394_MAX_FRAMES; i++) - video->frames[i] = NULL; - - dma_region_init(&video->dv_buf); - video->dv_buf_size = 0; - dma_region_init(&video->packet_buf); - video->packet_buf_size = 0; - - clear_bit(0, &video->open); - spin_lock_init(&video->spinlock); - video->dma_running = 0; - mutex_init(&video->mtx); - init_waitqueue_head(&video->waitq); - video->fasync = NULL; - - spin_lock_irqsave(&dv1394_cards_lock, flags); - INIT_LIST_HEAD(&video->list); - list_add_tail(&video->list, &dv1394_cards); - spin_unlock_irqrestore(&dv1394_cards_lock, flags); - - debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id); - return 0; -} - -static void dv1394_remove_host(struct hpsb_host *host) -{ - struct video_card *video, *tmp_video; - unsigned long flags; - int found_ohci_card = 0; - - do { - video = NULL; - spin_lock_irqsave(&dv1394_cards_lock, flags); - list_for_each_entry(tmp_video, &dv1394_cards, list) { - if ((tmp_video->id >> 2) == host->id) { - list_del(&tmp_video->list); - video = tmp_video; - found_ohci_card = 1; - break; - } - } - spin_unlock_irqrestore(&dv1394_cards_lock, flags); - - if (video) { - do_dv1394_shutdown(video, 1); - kfree(video); - } - } while (video); - - if (found_ohci_card) - device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR, - IEEE1394_MINOR_BLOCK_DV1394 * 16 + (host->id << 2))); -} - -static void dv1394_add_host(struct hpsb_host *host) -{ - struct ti_ohci *ohci; - int id = host->id; - - /* We only work with the OHCI-1394 driver */ - if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) - return; - - ohci = (struct ti_ohci *)host->hostdata; - - device_create(hpsb_protocol_class, NULL, - MKDEV(IEEE1394_MAJOR, - IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)), - NULL, "dv1394-%d", id); - - dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE); - dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT); - dv1394_init(ohci, DV1394_PAL, MODE_RECEIVE); - dv1394_init(ohci, DV1394_PAL, MODE_TRANSMIT); -} - - -/* Bus reset handler. In the event of a bus reset, we may need to - re-start the DMA contexts - otherwise the user program would - end up waiting forever. -*/ - -static void dv1394_host_reset(struct hpsb_host *host) -{ - struct video_card *video = NULL, *tmp_vid; - unsigned long flags; - - /* We only work with the OHCI-1394 driver */ - if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) - return; - - /* find the corresponding video_cards */ - spin_lock_irqsave(&dv1394_cards_lock, flags); - list_for_each_entry(tmp_vid, &dv1394_cards, list) { - if ((tmp_vid->id >> 2) == host->id) { - video = tmp_vid; - break; - } - } - spin_unlock_irqrestore(&dv1394_cards_lock, flags); - - if (!video) - return; - - - spin_lock_irqsave(&video->spinlock, flags); - - if (!video->dma_running) - goto out; - - /* check IT context */ - if (video->ohci_it_ctx != -1) { - u32 ctx; - - ctx = reg_read(video->ohci, video->ohci_IsoXmitContextControlSet); - - /* if (RUN but not ACTIVE) */ - if ( (ctx & (1<<15)) && - !(ctx & (1<<10)) ) { - - debug_printk("dv1394: IT context stopped due to bus reset; waking it up\n"); - - /* to be safe, assume a frame has been dropped. User-space programs - should handle this condition like an underflow. */ - video->dropped_frames++; - - /* for some reason you must clear, then re-set the RUN bit to restart DMA */ - - /* clear RUN */ - reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15)); - flush_pci_write(video->ohci); - - /* set RUN */ - reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 15)); - flush_pci_write(video->ohci); - - /* set the WAKE bit (just in case; this isn't strictly necessary) */ - reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 12)); - flush_pci_write(video->ohci); - - irq_printk("dv1394: AFTER IT restart ctx 0x%08x ptr 0x%08x\n", - reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), - reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)); - } - } - - /* check IR context */ - if (video->ohci_ir_ctx != -1) { - u32 ctx; - - ctx = reg_read(video->ohci, video->ohci_IsoRcvContextControlSet); - - /* if (RUN but not ACTIVE) */ - if ( (ctx & (1<<15)) && - !(ctx & (1<<10)) ) { - - debug_printk("dv1394: IR context stopped due to bus reset; waking it up\n"); - - /* to be safe, assume a frame has been dropped. User-space programs - should handle this condition like an overflow. */ - video->dropped_frames++; - - /* for some reason you must clear, then re-set the RUN bit to restart DMA */ - /* XXX this doesn't work for me, I can't get IR DMA to restart :[ */ - - /* clear RUN */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15)); - flush_pci_write(video->ohci); - - /* set RUN */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 15)); - flush_pci_write(video->ohci); - - /* set the WAKE bit (just in case; this isn't strictly necessary) */ - reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12)); - flush_pci_write(video->ohci); - - irq_printk("dv1394: AFTER IR restart ctx 0x%08x ptr 0x%08x\n", - reg_read(video->ohci, video->ohci_IsoRcvContextControlSet), - reg_read(video->ohci, video->ohci_IsoRcvCommandPtr)); - } - } - -out: - spin_unlock_irqrestore(&video->spinlock, flags); - - /* wake readers/writers/ioctl'ers */ - wake_up_interruptible(&video->waitq); -} - -static struct hpsb_highlevel dv1394_highlevel = { - .name = "dv1394", - .add_host = dv1394_add_host, - .remove_host = dv1394_remove_host, - .host_reset = dv1394_host_reset, -}; - -#ifdef CONFIG_COMPAT - -#define DV1394_IOC32_INIT _IOW('#', 0x06, struct dv1394_init32) -#define DV1394_IOC32_GET_STATUS _IOR('#', 0x0c, struct dv1394_status32) - -struct dv1394_init32 { - u32 api_version; - u32 channel; - u32 n_frames; - u32 format; - u32 cip_n; - u32 cip_d; - u32 syt_offset; -}; - -struct dv1394_status32 { - struct dv1394_init32 init; - s32 active_frame; - u32 first_clear_frame; - u32 n_clear_frames; - u32 dropped_frames; -}; - -/* RED-PEN: this should use compat_alloc_userspace instead */ - -static int handle_dv1394_init(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct dv1394_init32 dv32; - struct dv1394_init dv; - mm_segment_t old_fs; - int ret; - - if (file->f_op->unlocked_ioctl != dv1394_ioctl) - return -EFAULT; - - if (copy_from_user(&dv32, (void __user *)arg, sizeof(dv32))) - return -EFAULT; - - dv.api_version = dv32.api_version; - dv.channel = dv32.channel; - dv.n_frames = dv32.n_frames; - dv.format = dv32.format; - dv.cip_n = (unsigned long)dv32.cip_n; - dv.cip_d = (unsigned long)dv32.cip_d; - dv.syt_offset = dv32.syt_offset; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - ret = dv1394_ioctl(file, DV1394_IOC_INIT, (unsigned long)&dv); - set_fs(old_fs); - - return ret; -} - -static int handle_dv1394_get_status(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct dv1394_status32 dv32; - struct dv1394_status dv; - mm_segment_t old_fs; - int ret; - - if (file->f_op->unlocked_ioctl != dv1394_ioctl) - return -EFAULT; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - ret = dv1394_ioctl(file, DV1394_IOC_GET_STATUS, (unsigned long)&dv); - set_fs(old_fs); - - if (!ret) { - dv32.init.api_version = dv.init.api_version; - dv32.init.channel = dv.init.channel; - dv32.init.n_frames = dv.init.n_frames; - dv32.init.format = dv.init.format; - dv32.init.cip_n = (u32)dv.init.cip_n; - dv32.init.cip_d = (u32)dv.init.cip_d; - dv32.init.syt_offset = dv.init.syt_offset; - dv32.active_frame = dv.active_frame; - dv32.first_clear_frame = dv.first_clear_frame; - dv32.n_clear_frames = dv.n_clear_frames; - dv32.dropped_frames = dv.dropped_frames; - - if (copy_to_user((struct dv1394_status32 __user *)arg, &dv32, sizeof(dv32))) - ret = -EFAULT; - } - - return ret; -} - - - -static long dv1394_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - switch (cmd) { - case DV1394_IOC_SHUTDOWN: - case DV1394_IOC_SUBMIT_FRAMES: - case DV1394_IOC_WAIT_FRAMES: - case DV1394_IOC_RECEIVE_FRAMES: - case DV1394_IOC_START_RECEIVE: - return dv1394_ioctl(file, cmd, arg); - - case DV1394_IOC32_INIT: - return handle_dv1394_init(file, cmd, arg); - case DV1394_IOC32_GET_STATUS: - return handle_dv1394_get_status(file, cmd, arg); - default: - return -ENOIOCTLCMD; - } -} - -#endif /* CONFIG_COMPAT */ - - -/*** KERNEL MODULE HANDLERS ************************************************/ - -MODULE_AUTHOR("Dan Maas <dmaas@dcine.com>, Dan Dennedy <dan@dennedy.org>"); -MODULE_DESCRIPTION("driver for DV input/output on OHCI board"); -MODULE_SUPPORTED_DEVICE("dv1394"); -MODULE_LICENSE("GPL"); - -static void __exit dv1394_exit_module(void) -{ - hpsb_unregister_protocol(&dv1394_driver); - hpsb_unregister_highlevel(&dv1394_highlevel); - cdev_del(&dv1394_cdev); -} - -static int __init dv1394_init_module(void) -{ - int ret; - - cdev_init(&dv1394_cdev, &dv1394_fops); - dv1394_cdev.owner = THIS_MODULE; - ret = cdev_add(&dv1394_cdev, IEEE1394_DV1394_DEV, 16); - if (ret) { - printk(KERN_ERR "dv1394: unable to register character device\n"); - return ret; - } - - hpsb_register_highlevel(&dv1394_highlevel); - - ret = hpsb_register_protocol(&dv1394_driver); - if (ret) { - printk(KERN_ERR "dv1394: failed to register protocol\n"); - hpsb_unregister_highlevel(&dv1394_highlevel); - cdev_del(&dv1394_cdev); - return ret; - } - - return 0; -} - -module_init(dv1394_init_module); -module_exit(dv1394_exit_module); diff --git a/drivers/ieee1394/dv1394.h b/drivers/ieee1394/dv1394.h deleted file mode 100644 index 5807f528981..00000000000 --- a/drivers/ieee1394/dv1394.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c deleted file mode 100644 index bc289e367e3..00000000000 --- a/drivers/ieee1394/eth1394.c +++ /dev/null @@ -1,1736 +0,0 @@ -/* - * eth1394.c -- IPv4 driver for Linux IEEE-1394 Subsystem - * - * Copyright (C) 2001-2003 Ben Collins <bcollins@debian.org> - * 2000 Bonin Franck <boninf@free.fr> - * 2003 Steve Kinneberg <kinnebergsteve@acmsystems.com> - * - * 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. - */ - -/* - * This driver intends to support RFC 2734, which describes a method for - * transporting IPv4 datagrams over IEEE-1394 serial busses. - * - * TODO: - * RFC 2734 related: - * - Add MCAP. Limited Multicast exists only to 224.0.0.1 and 224.0.0.2. - * - * Non-RFC 2734 related: - * - Handle fragmented skb's coming from the networking layer. - * - Move generic GASP reception to core 1394 code - * - Convert kmalloc/kfree for link fragments to use kmem_cache_* instead - * - Stability improvements - * - Performance enhancements - * - Consider garbage collecting old partial datagrams after X amount of time - */ - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/workqueue.h> - -#include <linux/netdevice.h> -#include <linux/inetdevice.h> -#include <linux/if_arp.h> -#include <linux/if_ether.h> -#include <linux/ip.h> -#include <linux/in.h> -#include <linux/tcp.h> -#include <linux/skbuff.h> -#include <linux/bitops.h> -#include <linux/ethtool.h> -#include <asm/uaccess.h> -#include <asm/delay.h> -#include <asm/unaligned.h> -#include <net/arp.h> - -#include "config_roms.h" -#include "csr1212.h" -#include "eth1394.h" -#include "highlevel.h" -#include "ieee1394.h" -#include "ieee1394_core.h" -#include "ieee1394_hotplug.h" -#include "ieee1394_transactions.h" -#include "ieee1394_types.h" -#include "iso.h" -#include "nodemgr.h" - -#define ETH1394_PRINT_G(level, fmt, args...) \ - printk(level "%s: " fmt, driver_name, ## args) - -#define ETH1394_PRINT(level, dev_name, fmt, args...) \ - printk(level "%s: %s: " fmt, driver_name, dev_name, ## args) - -struct fragment_info { - struct list_head list; - int offset; - int len; -}; - -struct partial_datagram { - struct list_head list; - u16 dgl; - u16 dg_size; - __be16 ether_type; - struct sk_buff *skb; - char *pbuf; - struct list_head frag_info; -}; - -struct pdg_list { - struct list_head list; /* partial datagram list per node */ - unsigned int sz; /* partial datagram list size per node */ - spinlock_t lock; /* partial datagram lock */ -}; - -struct eth1394_host_info { - struct hpsb_host *host; - struct net_device *dev; -}; - -struct eth1394_node_ref { - struct unit_directory *ud; - struct list_head list; -}; - -struct eth1394_node_info { - u16 maxpayload; /* max payload */ - u8 sspd; /* max speed */ - u64 fifo; /* FIFO address */ - struct pdg_list pdg; /* partial RX datagram lists */ - int dgl; /* outgoing datagram label */ -}; - -static const char driver_name[] = "eth1394"; - -static struct kmem_cache *packet_task_cache; - -static struct hpsb_highlevel eth1394_highlevel; - -/* Use common.lf to determine header len */ -static const int hdr_type_len[] = { - sizeof(struct eth1394_uf_hdr), - sizeof(struct eth1394_ff_hdr), - sizeof(struct eth1394_sf_hdr), - sizeof(struct eth1394_sf_hdr) -}; - -static const u16 eth1394_speedto_maxpayload[] = { -/* S100, S200, S400, S800, S1600, S3200 */ - 512, 1024, 2048, 4096, 4096, 4096 -}; - -MODULE_AUTHOR("Ben Collins (bcollins@debian.org)"); -MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)"); -MODULE_LICENSE("GPL"); - -/* - * The max_partial_datagrams parameter is the maximum number of fragmented - * datagrams per node that eth1394 will keep in memory. Providing an upper - * bound allows us to limit the amount of memory that partial datagrams - * consume in the event that some partial datagrams are never completed. - */ -static int max_partial_datagrams = 25; -module_param(max_partial_datagrams, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(max_partial_datagrams, - "Maximum number of partially received fragmented datagrams " - "(default = 25)."); - - -static int ether1394_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *daddr, - const void *saddr, unsigned len); -static int ether1394_rebuild_header(struct sk_buff *skb); -static int ether1394_header_parse(const struct sk_buff *skb, - unsigned char *haddr); -static int ether1394_header_cache(const struct neighbour *neigh, - struct hh_cache *hh); -static void ether1394_header_cache_update(struct hh_cache *hh, - const struct net_device *dev, - const unsigned char *haddr); -static netdev_tx_t ether1394_tx(struct sk_buff *skb, - struct net_device *dev); -static void ether1394_iso(struct hpsb_iso *iso); - -static const struct ethtool_ops ethtool_ops; - -static int ether1394_write(struct hpsb_host *host, int srcid, int destid, - quadlet_t *data, u64 addr, size_t len, u16 flags); -static void ether1394_add_host(struct hpsb_host *host); -static void ether1394_remove_host(struct hpsb_host *host); -static void ether1394_host_reset(struct hpsb_host *host); - -/* Function for incoming 1394 packets */ -static const struct hpsb_address_ops addr_ops = { - .write = ether1394_write, -}; - -/* Ieee1394 highlevel driver functions */ -static struct hpsb_highlevel eth1394_highlevel = { - .name = driver_name, - .add_host = ether1394_add_host, - .remove_host = ether1394_remove_host, - .host_reset = ether1394_host_reset, -}; - -static int ether1394_recv_init(struct eth1394_priv *priv) -{ - unsigned int iso_buf_size; - - /* FIXME: rawiso limits us to PAGE_SIZE */ - iso_buf_size = min((unsigned int)PAGE_SIZE, - 2 * (1U << (priv->host->csr.max_rec + 1))); - - priv->iso = hpsb_iso_recv_init(priv->host, - ETHER1394_GASP_BUFFERS * iso_buf_size, - ETHER1394_GASP_BUFFERS, - priv->broadcast_channel, - HPSB_ISO_DMA_PACKET_PER_BUFFER, - 1, ether1394_iso); - if (priv->iso == NULL) { - ETH1394_PRINT_G(KERN_ERR, "Failed to allocate IR context\n"); - priv->bc_state = ETHER1394_BC_ERROR; - return -EAGAIN; - } - - if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) - priv->bc_state = ETHER1394_BC_STOPPED; - else - priv->bc_state = ETHER1394_BC_RUNNING; - return 0; -} - -/* This is called after an "ifup" */ -static int ether1394_open(struct net_device *dev) -{ - struct eth1394_priv *priv = netdev_priv(dev); - int ret; - - if (priv->bc_state == ETHER1394_BC_ERROR) { - ret = ether1394_recv_init(priv); - if (ret) - return ret; - } - netif_start_queue(dev); - return 0; -} - -/* This is called after an "ifdown" */ -static int ether1394_stop(struct net_device *dev) -{ - /* flush priv->wake */ - flush_scheduled_work(); - - netif_stop_queue(dev); - return 0; -} - -/* FIXME: What to do if we timeout? I think a host reset is probably in order, - * so that's what we do. Should we increment the stat counters too? */ -static void ether1394_tx_timeout(struct net_device *dev) -{ - struct hpsb_host *host = - ((struct eth1394_priv *)netdev_priv(dev))->host; - - ETH1394_PRINT(KERN_ERR, dev->name, "Timeout, resetting host\n"); - ether1394_host_reset(host); -} - -static inline int ether1394_max_mtu(struct hpsb_host* host) -{ - return (1 << (host->csr.max_rec + 1)) - - sizeof(union eth1394_hdr) - ETHER1394_GASP_OVERHEAD; -} - -static int ether1394_change_mtu(struct net_device *dev, int new_mtu) -{ - int max_mtu; - - if (new_mtu < 68) - return -EINVAL; - - max_mtu = ether1394_max_mtu( - ((struct eth1394_priv *)netdev_priv(dev))->host); - if (new_mtu > max_mtu) { - ETH1394_PRINT(KERN_INFO, dev->name, - "Local node constrains MTU to %d\n", max_mtu); - return -ERANGE; - } - - dev->mtu = new_mtu; - return 0; -} - -static void purge_partial_datagram(struct list_head *old) -{ - struct partial_datagram *pd; - struct list_head *lh, *n; - struct fragment_info *fi; - - pd = list_entry(old, struct partial_datagram, list); - - list_for_each_safe(lh, n, &pd->frag_info) { - fi = list_entry(lh, struct fragment_info, list); - list_del(lh); - kfree(fi); - } - list_del(old); - kfree_skb(pd->skb); - kfree(pd); -} - -/****************************************** - * 1394 bus activity functions - ******************************************/ - -static struct eth1394_node_ref *eth1394_find_node(struct list_head *inl, - struct unit_directory *ud) -{ - struct eth1394_node_ref *node; - - list_for_each_entry(node, inl, list) - if (node->ud == ud) - return node; - - return NULL; -} - -static struct eth1394_node_ref *eth1394_find_node_guid(struct list_head *inl, - u64 guid) -{ - struct eth1394_node_ref *node; - - list_for_each_entry(node, inl, list) - if (node->ud->ne->guid == guid) - return node; - - return NULL; -} - -static struct eth1394_node_ref *eth1394_find_node_nodeid(struct list_head *inl, - nodeid_t nodeid) -{ - struct eth1394_node_ref *node; - - list_for_each_entry(node, inl, list) - if (node->ud->ne->nodeid == nodeid) - return node; - - return NULL; -} - -static int eth1394_new_node(struct eth1394_host_info *hi, - struct unit_directory *ud) -{ - struct eth1394_priv *priv; - struct eth1394_node_ref *new_node; - struct eth1394_node_info *node_info; - - new_node = kmalloc(sizeof(*new_node), GFP_KERNEL); - if (!new_node) - return -ENOMEM; - - node_info = kmalloc(sizeof(*node_info), GFP_KERNEL); - if (!node_info) { - kfree(new_node); - return -ENOMEM; - } - - spin_lock_init(&node_info->pdg.lock); - INIT_LIST_HEAD(&node_info->pdg.list); - node_info->pdg.sz = 0; - node_info->fifo = CSR1212_INVALID_ADDR_SPACE; - - dev_set_drvdata(&ud->device, node_info); - new_node->ud = ud; - - priv = netdev_priv(hi->dev); - list_add_tail(&new_node->list, &priv->ip_node_list); - return 0; -} - -static int eth1394_probe(struct device *dev) -{ - struct unit_directory *ud; - struct eth1394_host_info *hi; - - ud = container_of(dev, struct unit_directory, device); - hi = hpsb_get_hostinfo(ð1394_highlevel, ud->ne->host); - if (!hi) - return -ENOENT; - - return eth1394_new_node(hi, ud); -} - -static int eth1394_remove(struct device *dev) -{ - struct unit_directory *ud; - struct eth1394_host_info *hi; - struct eth1394_priv *priv; - struct eth1394_node_ref *old_node; - struct eth1394_node_info *node_info; - struct list_head *lh, *n; - unsigned long flags; - - ud = container_of(dev, struct unit_directory, device); - hi = hpsb_get_hostinfo(ð1394_highlevel, ud->ne->host); - if (!hi) - return -ENOENT; - - priv = netdev_priv(hi->dev); - - old_node = eth1394_find_node(&priv->ip_node_list, ud); - if (!old_node) - return 0; - - list_del(&old_node->list); - kfree(old_node); - - node_info = dev_get_drvdata(&ud->device); - - spin_lock_irqsave(&node_info->pdg.lock, flags); - /* The partial datagram list should be empty, but we'll just - * make sure anyway... */ - list_for_each_safe(lh, n, &node_info->pdg.list) - purge_partial_datagram(lh); - spin_unlock_irqrestore(&node_info->pdg.lock, flags); - - kfree(node_info); - dev_set_drvdata(&ud->device, NULL); - return 0; -} - -static int eth1394_update(struct unit_directory *ud) -{ - struct eth1394_host_info *hi; - struct eth1394_priv *priv; - struct eth1394_node_ref *node; - - hi = hpsb_get_hostinfo(ð1394_highlevel, ud->ne->host); - if (!hi) - return -ENOENT; - - priv = netdev_priv(hi->dev); - node = eth1394_find_node(&priv->ip_node_list, ud); - if (node) - return 0; - - return eth1394_new_node(hi, ud); -} - -static const struct ieee1394_device_id eth1394_id_table[] = { - { - .match_flags = (IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION), - .specifier_id = ETHER1394_GASP_SPECIFIER_ID, - .version = ETHER1394_GASP_VERSION, - }, - {} -}; - -MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table); - -static struct hpsb_protocol_driver eth1394_proto_driver = { - .name = driver_name, - .id_table = eth1394_id_table, - .update = eth1394_update, - .driver = { - .probe = eth1394_probe, - .remove = eth1394_remove, - }, -}; - -static void ether1394_reset_priv(struct net_device *dev, int set_mtu) -{ - unsigned long flags; - int i; - struct eth1394_priv *priv = netdev_priv(dev); - struct hpsb_host *host = priv->host; - u64 guid = get_unaligned((u64 *)&(host->csr.rom->bus_info_data[3])); - int max_speed = IEEE1394_SPEED_MAX; - - spin_lock_irqsave(&priv->lock, flags); - - memset(priv->ud_list, 0, sizeof(priv->ud_list)); - priv->bc_maxpayload = 512; - - /* Determine speed limit */ - /* FIXME: This is broken for nodes with link speed < PHY speed, - * and it is suboptimal for S200B...S800B hardware. - * The result of nodemgr's speed probe should be used somehow. */ - for (i = 0; i < host->node_count; i++) { - /* take care of S100B...S400B PHY ports */ - if (host->speed[i] == SELFID_SPEED_UNKNOWN) { - max_speed = IEEE1394_SPEED_100; - break; - } - if (max_speed > host->speed[i]) - max_speed = host->speed[i]; - } - priv->bc_sspd = max_speed; - - if (set_mtu) { - /* Use the RFC 2734 default 1500 octets or the maximum payload - * as initial MTU */ - dev->mtu = min(1500, ether1394_max_mtu(host)); - - /* Set our hardware address while we're at it */ - memcpy(dev->dev_addr, &guid, sizeof(u64)); - memset(dev->broadcast, 0xff, sizeof(u64)); - } - - spin_unlock_irqrestore(&priv->lock, flags); -} - -static const struct header_ops ether1394_header_ops = { - .create = ether1394_header, - .rebuild = ether1394_rebuild_header, - .cache = ether1394_header_cache, - .cache_update = ether1394_header_cache_update, - .parse = ether1394_header_parse, -}; - -static const struct net_device_ops ether1394_netdev_ops = { - .ndo_open = ether1394_open, - .ndo_stop = ether1394_stop, - .ndo_start_xmit = ether1394_tx, - .ndo_tx_timeout = ether1394_tx_timeout, - .ndo_change_mtu = ether1394_change_mtu, -}; - -static void ether1394_init_dev(struct net_device *dev) -{ - - dev->header_ops = ðer1394_header_ops; - dev->netdev_ops = ðer1394_netdev_ops; - - SET_ETHTOOL_OPS(dev, ðtool_ops); - - dev->watchdog_timeo = ETHER1394_TIMEOUT; - dev->flags = IFF_BROADCAST | IFF_MULTICAST; - dev->features = NETIF_F_HIGHDMA; - dev->addr_len = ETH1394_ALEN; - dev->hard_header_len = ETH1394_HLEN; - dev->type = ARPHRD_IEEE1394; - - /* FIXME: This value was copied from ether_setup(). Is it too much? */ - dev->tx_queue_len = 1000; -} - -/* - * Wake the queue up after commonly encountered transmit failure conditions are - * hopefully over. Currently only tlabel exhaustion is accounted for. - */ -static void ether1394_wake_queue(struct work_struct *work) -{ - struct eth1394_priv *priv; - struct hpsb_packet *packet; - - priv = container_of(work, struct eth1394_priv, wake); - packet = hpsb_alloc_packet(0); - - /* This is really bad, but unjam the queue anyway. */ - if (!packet) - goto out; - - packet->host = priv->host; - packet->node_id = priv->wake_node; - /* - * A transaction label is all we really want. If we get one, it almost - * always means we can get a lot more because the ieee1394 core recycled - * a whole batch of tlabels, at last. - */ - if (hpsb_get_tlabel(packet) == 0) - hpsb_free_tlabel(packet); - - hpsb_free_packet(packet); -out: - netif_wake_queue(priv->wake_dev); -} - -/* - * This function is called every time a card is found. It is generally called - * when the module is installed. This is where we add all of our ethernet - * devices. One for each host. - */ -static void ether1394_add_host(struct hpsb_host *host) -{ - struct eth1394_host_info *hi = NULL; - struct net_device *dev = NULL; - struct eth1394_priv *priv; - u64 fifo_addr; - - if (hpsb_config_rom_ip1394_add(host) != 0) { - ETH1394_PRINT_G(KERN_ERR, "Can't add IP-over-1394 ROM entry\n"); - return; - } - - fifo_addr = hpsb_allocate_and_register_addrspace( - ð1394_highlevel, host, &addr_ops, - ETHER1394_REGION_ADDR_LEN, ETHER1394_REGION_ADDR_LEN, - CSR1212_INVALID_ADDR_SPACE, CSR1212_INVALID_ADDR_SPACE); - if (fifo_addr == CSR1212_INVALID_ADDR_SPACE) { - ETH1394_PRINT_G(KERN_ERR, "Cannot register CSR space\n"); - hpsb_config_rom_ip1394_remove(host); - return; - } - - dev = alloc_netdev(sizeof(*priv), "eth%d", ether1394_init_dev); - if (dev == NULL) { - ETH1394_PRINT_G(KERN_ERR, "Out of memory\n"); - goto out; - } - - SET_NETDEV_DEV(dev, &host->device); - - priv = netdev_priv(dev); - INIT_LIST_HEAD(&priv->ip_node_list); - spin_lock_init(&priv->lock); - priv->host = host; - priv->local_fifo = fifo_addr; - INIT_WORK(&priv->wake, ether1394_wake_queue); - priv->wake_dev = dev; - - hi = hpsb_create_hostinfo(ð1394_highlevel, host, sizeof(*hi)); - if (hi == NULL) { - ETH1394_PRINT_G(KERN_ERR, "Out of memory\n"); - goto out; - } - - ether1394_reset_priv(dev, 1); - - if (register_netdev(dev)) { - ETH1394_PRINT_G(KERN_ERR, "Cannot register the driver\n"); - goto out; - } - - ETH1394_PRINT(KERN_INFO, dev->name, "IPv4 over IEEE 1394 (fw-host%d)\n", - host->id); - - hi->host = host; - hi->dev = dev; - - /* Ignore validity in hopes that it will be set in the future. It'll - * be checked when the eth device is opened. */ - priv->broadcast_channel = host->csr.broadcast_channel & 0x3f; - - ether1394_recv_init(priv); - return; -out: - if (dev) - free_netdev(dev); - if (hi) - hpsb_destroy_hostinfo(ð1394_highlevel, host); - hpsb_unregister_addrspace(ð1394_highlevel, host, fifo_addr); - hpsb_config_rom_ip1394_remove(host); -} - -/* Remove a card from our list */ -static void ether1394_remove_host(struct hpsb_host *host) -{ - struct eth1394_host_info *hi; - struct eth1394_priv *priv; - - hi = hpsb_get_hostinfo(ð1394_highlevel, host); - if (!hi) - return; - priv = netdev_priv(hi->dev); - hpsb_unregister_addrspace(ð1394_highlevel, host, priv->local_fifo); - hpsb_config_rom_ip1394_remove(host); - if (priv->iso) - hpsb_iso_shutdown(priv->iso); - unregister_netdev(hi->dev); - free_netdev(hi->dev); -} - -/* A bus reset happened */ -static void ether1394_host_reset(struct hpsb_host *host) -{ - struct eth1394_host_info *hi; - struct eth1394_priv *priv; - struct net_device *dev; - struct list_head *lh, *n; - struct eth1394_node_ref *node; - struct eth1394_node_info *node_info; - unsigned long flags; - - hi = hpsb_get_hostinfo(ð1394_highlevel, host); - - /* This can happen for hosts that we don't use */ - if (!hi) - return; - - dev = hi->dev; - priv = netdev_priv(dev); - - /* Reset our private host data, but not our MTU */ - netif_stop_queue(dev); - ether1394_reset_priv(dev, 0); - - list_for_each_entry(node, &priv->ip_node_list, list) { - node_info = dev_get_drvdata(&node->ud->device); - - spin_lock_irqsave(&node_info->pdg.lock, flags); - - list_for_each_safe(lh, n, &node_info->pdg.list) - purge_partial_datagram(lh); - - INIT_LIST_HEAD(&(node_info->pdg.list)); - node_info->pdg.sz = 0; - - spin_unlock_irqrestore(&node_info->pdg.lock, flags); - } - - netif_wake_queue(dev); -} - -/****************************************** - * HW Header net device functions - ******************************************/ -/* These functions have been adapted from net/ethernet/eth.c */ - -/* Create a fake MAC header for an arbitrary protocol layer. - * saddr=NULL means use device source address - * daddr=NULL means leave destination address (eg unresolved arp). */ -static int ether1394_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *daddr, - const void *saddr, unsigned len) -{ - struct eth1394hdr *eth = - (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN); - - eth->h_proto = htons(type); - - if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { - memset(eth->h_dest, 0, dev->addr_len); - return dev->hard_header_len; - } - - if (daddr) { - memcpy(eth->h_dest, daddr, dev->addr_len); - return dev->hard_header_len; - } - - return -dev->hard_header_len; -} - -/* Rebuild the faked MAC header. This is called after an ARP - * (or in future other address resolution) has completed on this - * sk_buff. We now let ARP fill in the other fields. - * - * This routine CANNOT use cached dst->neigh! - * Really, it is used only when dst->neigh is wrong. - */ -static int ether1394_rebuild_header(struct sk_buff *skb) -{ - struct eth1394hdr *eth = (struct eth1394hdr *)skb->data; - - if (eth->h_proto == htons(ETH_P_IP)) - return arp_find((unsigned char *)ð->h_dest, skb); - - ETH1394_PRINT(KERN_DEBUG, skb->dev->name, - "unable to resolve type %04x addresses\n", - ntohs(eth->h_proto)); - return 0; -} - -static int ether1394_header_parse(const struct sk_buff *skb, - unsigned char *haddr) -{ - memcpy(haddr, skb->dev->dev_addr, ETH1394_ALEN); - return ETH1394_ALEN; -} - -static int ether1394_header_cache(const struct neighbour *neigh, - struct hh_cache *hh) -{ - __be16 type = hh->hh_type; - struct net_device *dev = neigh->dev; - struct eth1394hdr *eth = - (struct eth1394hdr *)((u8 *)hh->hh_data + 16 - ETH1394_HLEN); - - if (type == htons(ETH_P_802_3)) - return -1; - - eth->h_proto = type; - memcpy(eth->h_dest, neigh->ha, dev->addr_len); - - hh->hh_len = ETH1394_HLEN; - return 0; -} - -/* Called by Address Resolution module to notify changes in address. */ -static void ether1394_header_cache_update(struct hh_cache *hh, - const struct net_device *dev, - const unsigned char * haddr) -{ - memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len); -} - -/****************************************** - * Datagram reception code - ******************************************/ - -/* Copied from net/ethernet/eth.c */ -static __be16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - struct eth1394hdr *eth; - unsigned char *rawp; - - skb_reset_mac_header(skb); - skb_pull(skb, ETH1394_HLEN); - eth = eth1394_hdr(skb); - - if (*eth->h_dest & 1) { - if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len) == 0) - skb->pkt_type = PACKET_BROADCAST; -#if 0 - else - skb->pkt_type = PACKET_MULTICAST; -#endif - } else { - if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len)) - skb->pkt_type = PACKET_OTHERHOST; - } - - if (ntohs(eth->h_proto) >= 1536) - return eth->h_proto; - - rawp = skb->data; - - if (*(unsigned short *)rawp == 0xFFFF) - return htons(ETH_P_802_3); - - return htons(ETH_P_802_2); -} - -/* Parse an encapsulated IP1394 header into an ethernet frame packet. - * We also perform ARP translation here, if need be. */ -static __be16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev, - nodeid_t srcid, nodeid_t destid, - __be16 ether_type) -{ - struct eth1394_priv *priv = netdev_priv(dev); - __be64 dest_hw; - __be16 ret = 0; - - /* Setup our hw addresses. We use these to build the ethernet header. */ - if (destid == (LOCAL_BUS | ALL_NODES)) - dest_hw = ~cpu_to_be64(0); /* broadcast */ - else - dest_hw = cpu_to_be64((u64)priv->host->csr.guid_hi << 32 | - priv->host->csr.guid_lo); - - /* If this is an ARP packet, convert it. First, we want to make - * use of some of the fields, since they tell us a little bit - * about the sending machine. */ - if (ether_type == htons(ETH_P_ARP)) { - struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data; - struct arphdr *arp = (struct arphdr *)skb->data; - unsigned char *arp_ptr = (unsigned char *)(arp + 1); - u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 | - ntohl(arp1394->fifo_lo); - u8 max_rec = min(priv->host->csr.max_rec, - (u8)(arp1394->max_rec)); - int sspd = arp1394->sspd; - u16 maxpayload; - struct eth1394_node_ref *node; - struct eth1394_node_info *node_info; - __be64 guid; - - /* Sanity check. MacOSX seems to be sending us 131 in this - * field (atleast on my Panther G5). Not sure why. */ - if (sspd > 5 || sspd < 0) - sspd = 0; - - maxpayload = min(eth1394_speedto_maxpayload[sspd], - (u16)(1 << (max_rec + 1))); - - guid = get_unaligned(&arp1394->s_uniq_id); - node = eth1394_find_node_guid(&priv->ip_node_list, - be64_to_cpu(guid)); - if (!node) - return cpu_to_be16(0); - - node_info = dev_get_drvdata(&node->ud->device); - - /* Update our speed/payload/fifo_offset table */ - node_info->maxpayload = maxpayload; - node_info->sspd = sspd; - node_info->fifo = fifo_addr; - - /* Now that we're done with the 1394 specific stuff, we'll - * need to alter some of the data. Believe it or not, all - * that needs to be done is sender_IP_address needs to be - * moved, the destination hardware address get stuffed - * in and the hardware address length set to 8. - * - * IMPORTANT: The code below overwrites 1394 specific data - * needed above so keep the munging of the data for the - * higher level IP stack last. */ - - arp->ar_hln = 8; - arp_ptr += arp->ar_hln; /* skip over sender unique id */ - *(u32 *)arp_ptr = arp1394->sip; /* move sender IP addr */ - arp_ptr += arp->ar_pln; /* skip over sender IP addr */ - - if (arp->ar_op == htons(ARPOP_REQUEST)) - memset(arp_ptr, 0, sizeof(u64)); - else - memcpy(arp_ptr, dev->dev_addr, sizeof(u64)); - } - - /* Now add the ethernet header. */ - if (dev_hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL, - skb->len) >= 0) - ret = ether1394_type_trans(skb, dev); - - return ret; -} - -static int fragment_overlap(struct list_head *frag_list, int offset, int len) -{ - struct fragment_info *fi; - int end = offset + len; - - list_for_each_entry(fi, frag_list, list) - if (offset < fi->offset + fi->len && end > fi->offset) - return 1; - - return 0; -} - -static struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl) -{ - struct partial_datagram *pd; - - list_for_each_entry(pd, pdgl, list) - if (pd->dgl == dgl) - return &pd->list; - - return NULL; -} - -/* Assumes that new fragment does not overlap any existing fragments */ -static int new_fragment(struct list_head *frag_info, int offset, int len) -{ - struct list_head *lh; - struct fragment_info *fi, *fi2, *new; - - list_for_each(lh, frag_info) { - fi = list_entry(lh, struct fragment_info, list); - if (fi->offset + fi->len == offset) { - /* The new fragment can be tacked on to the end */ - fi->len += len; - /* Did the new fragment plug a hole? */ - fi2 = list_entry(lh->next, struct fragment_info, list); - if (fi->offset + fi->len == fi2->offset) { - /* glue fragments together */ - fi->len += fi2->len; - list_del(lh->next); - kfree(fi2); - } - return 0; - } else if (offset + len == fi->offset) { - /* The new fragment can be tacked on to the beginning */ - fi->offset = offset; - fi->len += len; - /* Did the new fragment plug a hole? */ - fi2 = list_entry(lh->prev, struct fragment_info, list); - if (fi2->offset + fi2->len == fi->offset) { - /* glue fragments together */ - fi2->len += fi->len; - list_del(lh); - kfree(fi); - } - return 0; - } else if (offset > fi->offset + fi->len) { - break; - } else if (offset + len < fi->offset) { - lh = lh->prev; - break; - } - } - - new = kmalloc(sizeof(*new), GFP_ATOMIC); - if (!new) - return -ENOMEM; - - new->offset = offset; - new->len = len; - - list_add(&new->list, lh); - return 0; -} - -static int new_partial_datagram(struct net_device *dev, struct list_head *pdgl, - int dgl, int dg_size, char *frag_buf, - int frag_off, int frag_len) -{ - struct partial_datagram *new; - - new = kmalloc(sizeof(*new), GFP_ATOMIC); - if (!new) - return -ENOMEM; - - INIT_LIST_HEAD(&new->frag_info); - - if (new_fragment(&new->frag_info, frag_off, frag_len) < 0) { - kfree(new); - return -ENOMEM; - } - - new->dgl = dgl; - new->dg_size = dg_size; - - new->skb = dev_alloc_skb(dg_size + dev->hard_header_len + 15); - if (!new->skb) { - struct fragment_info *fi = list_entry(new->frag_info.next, - struct fragment_info, - list); - kfree(fi); - kfree(new); - return -ENOMEM; - } - - skb_reserve(new->skb, (dev->hard_header_len + 15) & ~15); - new->pbuf = skb_put(new->skb, dg_size); - memcpy(new->pbuf + frag_off, frag_buf, frag_len); - - list_add(&new->list, pdgl); - return 0; -} - -static int update_partial_datagram(struct list_head *pdgl, struct list_head *lh, - char *frag_buf, int frag_off, int frag_len) -{ - struct partial_datagram *pd = - list_entry(lh, struct partial_datagram, list); - - if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0) - return -ENOMEM; - - memcpy(pd->pbuf + frag_off, frag_buf, frag_len); - - /* Move list entry to beginnig of list so that oldest partial - * datagrams percolate to the end of the list */ - list_move(lh, pdgl); - return 0; -} - -static int is_datagram_complete(struct list_head *lh, int dg_size) -{ - struct partial_datagram *pd; - struct fragment_info *fi; - - pd = list_entry(lh, struct partial_datagram, list); - fi = list_entry(pd->frag_info.next, struct fragment_info, list); - - return (fi->len == dg_size); -} - -/* Packet reception. We convert the IP1394 encapsulation header to an - * ethernet header, and fill it with some of our other fields. This is - * an incoming packet from the 1394 bus. */ -static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, - char *buf, int len) -{ - struct sk_buff *skb; - unsigned long flags; - struct eth1394_priv *priv = netdev_priv(dev); - union eth1394_hdr *hdr = (union eth1394_hdr *)buf; - __be16 ether_type = cpu_to_be16(0); /* initialized to clear warning */ - int hdr_len; - struct unit_directory *ud = priv->ud_list[NODEID_TO_NODE(srcid)]; - struct eth1394_node_info *node_info; - - if (!ud) { - struct eth1394_node_ref *node; - node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid); - if (unlikely(!node)) { - HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid " - "lookup failure: " NODE_BUS_FMT, - NODE_BUS_ARGS(priv->host, srcid)); - dev->stats.rx_dropped++; - return -1; - } - ud = node->ud; - - priv->ud_list[NODEID_TO_NODE(srcid)] = ud; - } - - node_info = dev_get_drvdata(&ud->device); - - /* First, did we receive a fragmented or unfragmented datagram? */ - hdr->words.word1 = ntohs(hdr->words.word1); - - hdr_len = hdr_type_len[hdr->common.lf]; - - if (hdr->common.lf == ETH1394_HDR_LF_UF) { - /* An unfragmented datagram has been received by the ieee1394 - * bus. Build an skbuff around it so we can pass it to the - * high level network layer. */ - - skb = dev_alloc_skb(len + dev->hard_header_len + 15); - if (unlikely(!skb)) { - ETH1394_PRINT_G(KERN_ERR, "Out of memory\n"); - dev->stats.rx_dropped++; - return -1; - } - skb_reserve(skb, (dev->hard_header_len + 15) & ~15); - memcpy(skb_put(skb, len - hdr_len), buf + hdr_len, - len - hdr_len); - ether_type = hdr->uf.ether_type; - } else { - /* A datagram fragment has been received, now the fun begins. */ - - struct list_head *pdgl, *lh; - struct partial_datagram *pd; - int fg_off; - int fg_len = len - hdr_len; - int dg_size; - int dgl; - int retval; - struct pdg_list *pdg = &(node_info->pdg); - - hdr->words.word3 = ntohs(hdr->words.word3); - /* The 4th header word is reserved so no need to do ntohs() */ - - if (hdr->common.lf == ETH1394_HDR_LF_FF) { - ether_type = hdr->ff.ether_type; - dgl = hdr->ff.dgl; - dg_size = hdr->ff.dg_size + 1; - fg_off = 0; - } else { - hdr->words.word2 = ntohs(hdr->words.word2); - dgl = hdr->sf.dgl; - dg_size = hdr->sf.dg_size + 1; - fg_off = hdr->sf.fg_off; - } - spin_lock_irqsave(&pdg->lock, flags); - - pdgl = &(pdg->list); - lh = find_partial_datagram(pdgl, dgl); - - if (lh == NULL) { - while (pdg->sz >= max_partial_datagrams) { - /* remove the oldest */ - purge_partial_datagram(pdgl->prev); - pdg->sz--; - } - - retval = new_partial_datagram(dev, pdgl, dgl, dg_size, - buf + hdr_len, fg_off, - fg_len); - if (retval < 0) { - spin_unlock_irqrestore(&pdg->lock, flags); - goto bad_proto; - } - pdg->sz++; - lh = find_partial_datagram(pdgl, dgl); - } else { - pd = list_entry(lh, struct partial_datagram, list); - - if (fragment_overlap(&pd->frag_info, fg_off, fg_len)) { - /* Overlapping fragments, obliterate old - * datagram and start new one. */ - purge_partial_datagram(lh); - retval = new_partial_datagram(dev, pdgl, dgl, - dg_size, - buf + hdr_len, - fg_off, fg_len); - if (retval < 0) { - pdg->sz--; - spin_unlock_irqrestore(&pdg->lock, flags); - goto bad_proto; - } - } else { - retval = update_partial_datagram(pdgl, lh, - buf + hdr_len, - fg_off, fg_len); - if (retval < 0) { - /* Couldn't save off fragment anyway - * so might as well obliterate the - * datagram now. */ - purge_partial_datagram(lh); - pdg->sz--; - spin_unlock_irqrestore(&pdg->lock, flags); - goto bad_proto; - } - } /* fragment overlap */ - } /* new datagram or add to existing one */ - - pd = list_entry(lh, struct partial_datagram, list); - - if (hdr->common.lf == ETH1394_HDR_LF_FF) - pd->ether_type = ether_type; - - if (is_datagram_complete(lh, dg_size)) { - ether_type = pd->ether_type; - pdg->sz--; - skb = skb_get(pd->skb); - purge_partial_datagram(lh); - spin_unlock_irqrestore(&pdg->lock, flags); - } else { - /* Datagram is not complete, we're done for the - * moment. */ - spin_unlock_irqrestore(&pdg->lock, flags); - return 0; - } - } /* unframgented datagram or fragmented one */ - - /* Write metadata, and then pass to the receive level */ - skb->dev = dev; - skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ - - /* Parse the encapsulation header. This actually does the job of - * converting to an ethernet frame header, aswell as arp - * conversion if needed. ARP conversion is easier in this - * direction, since we are using ethernet as our backend. */ - skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid, - ether_type); - - spin_lock_irqsave(&priv->lock, flags); - - if (!skb->protocol) { - dev->stats.rx_errors++; - dev->stats.rx_dropped++; - dev_kfree_skb_any(skb); - } else if (netif_rx(skb) == NET_RX_DROP) { - dev->stats.rx_errors++; - dev->stats.rx_dropped++; - } else { - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - } - - spin_unlock_irqrestore(&priv->lock, flags); - -bad_proto: - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); - - return 0; -} - -static int ether1394_write(struct hpsb_host *host, int srcid, int destid, - quadlet_t *data, u64 addr, size_t len, u16 flags) -{ - struct eth1394_host_info *hi; - - hi = hpsb_get_hostinfo(ð1394_highlevel, host); - if (unlikely(!hi)) { - ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n", - host->id); - return RCODE_ADDRESS_ERROR; - } - - if (ether1394_data_handler(hi->dev, srcid, destid, (char*)data, len)) - return RCODE_ADDRESS_ERROR; - else - return RCODE_COMPLETE; -} - -static void ether1394_iso(struct hpsb_iso *iso) -{ - __be32 *data; - char *buf; - struct eth1394_host_info *hi; - struct net_device *dev; - unsigned int len; - u32 specifier_id; - u16 source_id; - int i; - int nready; - - hi = hpsb_get_hostinfo(ð1394_highlevel, iso->host); - if (unlikely(!hi)) { - ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n", - iso->host->id); - return; - } - - dev = hi->dev; - - nready = hpsb_iso_n_ready(iso); - for (i = 0; i < nready; i++) { - struct hpsb_iso_packet_info *info = - &iso->infos[(iso->first_packet + i) % iso->buf_packets]; - data = (__be32 *)(iso->data_buf.kvirt + info->offset); - - /* skip over GASP header */ - buf = (char *)data + 8; - len = info->len - 8; - - specifier_id = (be32_to_cpu(data[0]) & 0xffff) << 8 | - (be32_to_cpu(data[1]) & 0xff000000) >> 24; - source_id = be32_to_cpu(data[0]) >> 16; - - if (info->channel != (iso->host->csr.broadcast_channel & 0x3f) - || specifier_id != ETHER1394_GASP_SPECIFIER_ID) { - /* This packet is not for us */ - continue; - } - ether1394_data_handler(dev, source_id, LOCAL_BUS | ALL_NODES, - buf, len); - } - - hpsb_iso_recv_release_packets(iso, i); - -} - -/****************************************** - * Datagram transmission code - ******************************************/ - -/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the entire - * arphdr) is the same format as the ip1394 header, so they overlap. The rest - * needs to be munged a bit. The remainder of the arphdr is formatted based - * on hwaddr len and ipaddr len. We know what they'll be, so it's easy to - * judge. - * - * Now that the EUI is used for the hardware address all we need to do to make - * this work for 1394 is to insert 2 quadlets that contain max_rec size, - * speed, and unicast FIFO address information between the sender_unique_id - * and the IP addresses. - */ -static void ether1394_arp_to_1394arp(struct sk_buff *skb, - struct net_device *dev) -{ - struct eth1394_priv *priv = netdev_priv(dev); - struct arphdr *arp = (struct arphdr *)skb->data; - unsigned char *arp_ptr = (unsigned char *)(arp + 1); - struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data; - - arp1394->hw_addr_len = 16; - arp1394->sip = *(u32*)(arp_ptr + ETH1394_ALEN); - arp1394->max_rec = priv->host->csr.max_rec; - arp1394->sspd = priv->host->csr.lnk_spd; - arp1394->fifo_hi = htons(priv->local_fifo >> 32); - arp1394->fifo_lo = htonl(priv->local_fifo & ~0x0); -} - -/* We need to encapsulate the standard header with our own. We use the - * ethernet header's proto for our own. */ -static unsigned int ether1394_encapsulate_prep(unsigned int max_payload, - __be16 proto, - union eth1394_hdr *hdr, - u16 dg_size, u16 dgl) -{ - unsigned int adj_max_payload = - max_payload - hdr_type_len[ETH1394_HDR_LF_UF]; - - /* Does it all fit in one packet? */ - if (dg_size <= adj_max_payload) { - hdr->uf.lf = ETH1394_HDR_LF_UF; - hdr->uf.ether_type = proto; - } else { - hdr->ff.lf = ETH1394_HDR_LF_FF; - hdr->ff.ether_type = proto; - hdr->ff.dg_size = dg_size - 1; - hdr->ff.dgl = dgl; - adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF]; - } - return DIV_ROUND_UP(dg_size, adj_max_payload); -} - -static unsigned int ether1394_encapsulate(struct sk_buff *skb, - unsigned int max_payload, - union eth1394_hdr *hdr) -{ - union eth1394_hdr *bufhdr; - int ftype = hdr->common.lf; - int hdrsz = hdr_type_len[ftype]; - unsigned int adj_max_payload = max_payload - hdrsz; - - switch (ftype) { - case ETH1394_HDR_LF_UF: - bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz); - bufhdr->words.word1 = htons(hdr->words.word1); - bufhdr->words.word2 = hdr->words.word2; - break; - - case ETH1394_HDR_LF_FF: - bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz); - bufhdr->words.word1 = htons(hdr->words.word1); - bufhdr->words.word2 = hdr->words.word2; - bufhdr->words.word3 = htons(hdr->words.word3); - bufhdr->words.word4 = 0; - - /* Set frag type here for future interior fragments */ - hdr->common.lf = ETH1394_HDR_LF_IF; - hdr->sf.fg_off = 0; - break; - - default: - hdr->sf.fg_off += adj_max_payload; - bufhdr = (union eth1394_hdr *)skb_pull(skb, adj_max_payload); - if (max_payload >= skb->len) - hdr->common.lf = ETH1394_HDR_LF_LF; - bufhdr->words.word1 = htons(hdr->words.word1); - bufhdr->words.word2 = htons(hdr->words.word2); - bufhdr->words.word3 = htons(hdr->words.word3); - bufhdr->words.word4 = 0; - } - return min(max_payload, skb->len); -} - -static struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host) -{ - struct hpsb_packet *p; - - p = hpsb_alloc_packet(0); - if (p) { - p->host = host; - p->generation = get_hpsb_generation(host); - p->type = hpsb_async; - } - return p; -} - -static int ether1394_prep_write_packet(struct hpsb_packet *p, - struct hpsb_host *host, nodeid_t node, - u64 addr, void *data, int tx_len) -{ - p->node_id = node; - - if (hpsb_get_tlabel(p)) - return -EAGAIN; - - p->tcode = TCODE_WRITEB; - p->header_size = 16; - p->expect_response = 1; - p->header[0] = - p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4; - p->header[1] = host->node_id << 16 | addr >> 32; - p->header[2] = addr & 0xffffffff; - p->header[3] = tx_len << 16; - p->data_size = (tx_len + 3) & ~3; - p->data = data; - - return 0; -} - -static void ether1394_prep_gasp_packet(struct hpsb_packet *p, - struct eth1394_priv *priv, - struct sk_buff *skb, int length) -{ - p->header_size = 4; - p->tcode = TCODE_STREAM_DATA; - - p->header[0] = length << 16 | 3 << 14 | priv->broadcast_channel << 8 | - TCODE_STREAM_DATA << 4; - p->data_size = length; - p->data = (quadlet_t *)skb->data - 2; - p->data[0] = cpu_to_be32(priv->host->node_id << 16 | - ETHER1394_GASP_SPECIFIER_ID_HI); - p->data[1] = cpu_to_be32(ETHER1394_GASP_SPECIFIER_ID_LO << 24 | - ETHER1394_GASP_VERSION); - - p->speed_code = priv->bc_sspd; - - /* prevent hpsb_send_packet() from overriding our speed code */ - p->node_id = LOCAL_BUS | ALL_NODES; -} - -static void ether1394_free_packet(struct hpsb_packet *packet) -{ - if (packet->tcode != TCODE_STREAM_DATA) - hpsb_free_tlabel(packet); - hpsb_free_packet(packet); -} - -static void ether1394_complete_cb(void *__ptask); - -static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len) -{ - struct eth1394_priv *priv = ptask->priv; - struct hpsb_packet *packet = NULL; - - packet = ether1394_alloc_common_packet(priv->host); - if (!packet) - return -ENOMEM; - - if (ptask->tx_type == ETH1394_GASP) { - int length = tx_len + 2 * sizeof(quadlet_t); - - ether1394_prep_gasp_packet(packet, priv, ptask->skb, length); - } else if (ether1394_prep_write_packet(packet, priv->host, - ptask->dest_node, - ptask->addr, ptask->skb->data, - tx_len)) { - hpsb_free_packet(packet); - return -EAGAIN; - } - - ptask->packet = packet; - hpsb_set_packet_complete_task(ptask->packet, ether1394_complete_cb, - ptask); - - if (hpsb_send_packet(packet) < 0) { - ether1394_free_packet(packet); - return -EIO; - } - - return 0; -} - -/* Task function to be run when a datagram transmission is completed */ -static void ether1394_dg_complete(struct packet_task *ptask, int fail) -{ - struct sk_buff *skb = ptask->skb; - struct net_device *dev = skb->dev; - struct eth1394_priv *priv = netdev_priv(dev); - unsigned long flags; - - /* Statistics */ - spin_lock_irqsave(&priv->lock, flags); - if (fail) { - dev->stats.tx_dropped++; - dev->stats.tx_errors++; - } else { - dev->stats.tx_bytes += skb->len; - dev->stats.tx_packets++; - } - spin_unlock_irqrestore(&priv->lock, flags); - - dev_kfree_skb_any(skb); - kmem_cache_free(packet_task_cache, ptask); -} - -/* Callback for when a packet has been sent and the status of that packet is - * known */ -static void ether1394_complete_cb(void *__ptask) -{ - struct packet_task *ptask = (struct packet_task *)__ptask; - struct hpsb_packet *packet = ptask->packet; - int fail = 0; - - if (packet->tcode != TCODE_STREAM_DATA) - fail = hpsb_packet_success(packet); - - ether1394_free_packet(packet); - - ptask->outstanding_pkts--; - if (ptask->outstanding_pkts > 0 && !fail) { - int tx_len, err; - - /* Add the encapsulation header to the fragment */ - tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload, - &ptask->hdr); - err = ether1394_send_packet(ptask, tx_len); - if (err) { - if (err == -EAGAIN) - ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n"); - - ether1394_dg_complete(ptask, 1); - } - } else { - ether1394_dg_complete(ptask, fail); - } -} - -/* Transmit a packet (called by kernel) */ -static netdev_tx_t ether1394_tx(struct sk_buff *skb, - struct net_device *dev) -{ - struct eth1394hdr hdr_buf; - struct eth1394_priv *priv = netdev_priv(dev); - __be16 proto; - unsigned long flags; - nodeid_t dest_node; - eth1394_tx_type tx_type; - unsigned int tx_len; - unsigned int max_payload; - u16 dg_size; - u16 dgl; - struct packet_task *ptask; - struct eth1394_node_ref *node; - struct eth1394_node_info *node_info = NULL; - - ptask = kmem_cache_alloc(packet_task_cache, GFP_ATOMIC); - if (ptask == NULL) - goto fail; - - /* XXX Ignore this for now. Noticed that when MacOSX is the IRM, - * it does not set our validity bit. We need to compensate for - * that somewhere else, but not in eth1394. */ -#if 0 - if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000) - goto fail; -#endif - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - goto fail; - - /* Get rid of the fake eth1394 header, but first make a copy. - * We might need to rebuild the header on tx failure. */ - memcpy(&hdr_buf, skb->data, sizeof(hdr_buf)); - skb_pull(skb, ETH1394_HLEN); - - proto = hdr_buf.h_proto; - dg_size = skb->len; - - /* Set the transmission type for the packet. ARP packets and IP - * broadcast packets are sent via GASP. */ - if (memcmp(hdr_buf.h_dest, dev->broadcast, ETH1394_ALEN) == 0 || - proto == htons(ETH_P_ARP) || - (proto == htons(ETH_P_IP) && - IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) { - tx_type = ETH1394_GASP; - dest_node = LOCAL_BUS | ALL_NODES; - max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD; - BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD); - dgl = priv->bc_dgl; - if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) - priv->bc_dgl++; - } else { - __be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest); - - node = eth1394_find_node_guid(&priv->ip_node_list, - be64_to_cpu(guid)); - if (!node) - goto fail; - - node_info = dev_get_drvdata(&node->ud->device); - if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE) - goto fail; - - dest_node = node->ud->ne->nodeid; - max_payload = node_info->maxpayload; - BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD); - - dgl = node_info->dgl; - if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) - node_info->dgl++; - tx_type = ETH1394_WRREQ; - } - - /* If this is an ARP packet, convert it */ - if (proto == htons(ETH_P_ARP)) - ether1394_arp_to_1394arp(skb, dev); - - ptask->hdr.words.word1 = 0; - ptask->hdr.words.word2 = 0; - ptask->hdr.words.word3 = 0; - ptask->hdr.words.word4 = 0; - ptask->skb = skb; - ptask->priv = priv; - ptask->tx_type = tx_type; - - if (tx_type != ETH1394_GASP) { - u64 addr; - - spin_lock_irqsave(&priv->lock, flags); - addr = node_info->fifo; - spin_unlock_irqrestore(&priv->lock, flags); - - ptask->addr = addr; - ptask->dest_node = dest_node; - } - - ptask->tx_type = tx_type; - ptask->max_payload = max_payload; - ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload, - proto, &ptask->hdr, dg_size, dgl); - - /* Add the encapsulation header to the fragment */ - tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr); - dev->trans_start = jiffies; - if (ether1394_send_packet(ptask, tx_len)) { - if (dest_node == (LOCAL_BUS | ALL_NODES)) - goto fail; - - /* At this point we want to restore the packet. When we return - * here with NETDEV_TX_BUSY we will get another entrance in this - * routine with the same skb and we need it to look the same. - * So we pull 4 more bytes, then build the header again. */ - skb_pull(skb, 4); - ether1394_header(skb, dev, ntohs(hdr_buf.h_proto), - hdr_buf.h_dest, NULL, 0); - - /* Most failures of ether1394_send_packet are recoverable. */ - netif_stop_queue(dev); - priv->wake_node = dest_node; - schedule_work(&priv->wake); - kmem_cache_free(packet_task_cache, ptask); - return NETDEV_TX_BUSY; - } - - return NETDEV_TX_OK; -fail: - if (ptask) - kmem_cache_free(packet_task_cache, ptask); - - if (skb != NULL) - dev_kfree_skb(skb); - - spin_lock_irqsave(&priv->lock, flags); - dev->stats.tx_dropped++; - dev->stats.tx_errors++; - spin_unlock_irqrestore(&priv->lock, flags); - - return NETDEV_TX_OK; -} - -static void ether1394_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strcpy(info->driver, driver_name); - strcpy(info->bus_info, "ieee1394"); /* FIXME provide more detail? */ -} - -static const struct ethtool_ops ethtool_ops = { - .get_drvinfo = ether1394_get_drvinfo -}; - -static int __init ether1394_init_module(void) -{ - int err; - - packet_task_cache = kmem_cache_create("packet_task", - sizeof(struct packet_task), - 0, 0, NULL); - if (!packet_task_cache) - return -ENOMEM; - - hpsb_register_highlevel(ð1394_highlevel); - err = hpsb_register_protocol(ð1394_proto_driver); - if (err) { - hpsb_unregister_highlevel(ð1394_highlevel); - kmem_cache_destroy(packet_task_cache); - } - return err; -} - -static void __exit ether1394_exit_module(void) -{ - hpsb_unregister_protocol(ð1394_proto_driver); - hpsb_unregister_highlevel(ð1394_highlevel); - kmem_cache_destroy(packet_task_cache); -} - -module_init(ether1394_init_module); -module_exit(ether1394_exit_module); diff --git a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h deleted file mode 100644 index d53bac47b86..00000000000 --- a/drivers/ieee1394/eth1394.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c deleted file mode 100644 index 4bc443546e0..00000000000 --- a/drivers/ieee1394/highlevel.c +++ /dev/null @@ -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; -} diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h deleted file mode 100644 index 9dba89fc60a..00000000000 --- a/drivers/ieee1394/highlevel.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c deleted file mode 100644 index e947d8ffac8..00000000000 --- a/drivers/ieee1394/hosts.c +++ /dev/null @@ -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; -} diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h deleted file mode 100644 index 49c359022c5..00000000000 --- a/drivers/ieee1394/hosts.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/ieee1394-ioctl.h b/drivers/ieee1394/ieee1394-ioctl.h deleted file mode 100644 index 46878fef136..00000000000 --- a/drivers/ieee1394/ieee1394-ioctl.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h deleted file mode 100644 index af320e2c507..00000000000 --- a/drivers/ieee1394/ieee1394.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c deleted file mode 100644 index 87233800372..00000000000 --- a/drivers/ieee1394/ieee1394_core.c +++ /dev/null @@ -1,1380 +0,0 @@ -/* - * IEEE 1394 for Linux - * - * Core support: hpsb_packet management, packet handling and forwarding to - * highlevel or lowlevel code - * - * Copyright (C) 1999, 2000 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> - * loopback functionality in hpsb_send_packet - * allow highlevel drivers to disable automatic response generation - * and to generate responses themselves (deferred) - * - */ - -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/bitops.h> -#include <linux/kdev_t.h> -#include <linux/freezer.h> -#include <linux/suspend.h> -#include <linux/kthread.h> -#include <linux/preempt.h> -#include <linux/time.h> - -#include <asm/system.h> -#include <asm/byteorder.h> - -#include "ieee1394_types.h" -#include "ieee1394.h" -#include "hosts.h" -#include "ieee1394_core.h" -#include "highlevel.h" -#include "ieee1394_transactions.h" -#include "csr.h" -#include "nodemgr.h" -#include "dma.h" -#include "iso.h" -#include "config_roms.h" - -/* - * Disable the nodemgr detection and config rom reading functionality. - */ -static int disable_nodemgr; -module_param(disable_nodemgr, int, 0444); -MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality."); - -/* Disable Isochronous Resource Manager functionality */ -int hpsb_disable_irm = 0; -module_param_named(disable_irm, hpsb_disable_irm, bool, 0444); -MODULE_PARM_DESC(disable_irm, - "Disable Isochronous Resource Manager functionality."); - -/* We are GPL, so treat us special */ -MODULE_LICENSE("GPL"); - -/* Some globals used */ -const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" }; -struct class *hpsb_protocol_class; - -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG -static void dump_packet(const char *text, quadlet_t *data, int size, int speed) -{ - int i; - - size /= 4; - size = (size > 4 ? 4 : size); - - printk(KERN_DEBUG "ieee1394: %s", text); - if (speed > -1 && speed < 6) - printk(" at %s", hpsb_speedto_str[speed]); - printk(":"); - for (i = 0; i < size; i++) - printk(" %08x", data[i]); - printk("\n"); -} -#else -#define dump_packet(a,b,c,d) do {} while (0) -#endif - -static void abort_requests(struct hpsb_host *host); -static void queue_packet_complete(struct hpsb_packet *packet); - - -/** - * hpsb_set_packet_complete_task - set task that runs when a packet completes - * @packet: the packet whose completion we want the task added to - * @routine: function to call - * @data: data (if any) to pass to the above function - * - * Set the task that runs when a packet completes. You cannot call this more - * than once on a single packet before it is sent. - * - * Typically, the complete @routine is responsible to call hpsb_free_packet(). - */ -void hpsb_set_packet_complete_task(struct hpsb_packet *packet, - void (*routine)(void *), void *data) -{ - WARN_ON(packet->complete_routine != NULL); - packet->complete_routine = routine; - packet->complete_data = data; - return; -} - -/** - * hpsb_alloc_packet - allocate new packet structure - * @data_size: size of the data block to be allocated, in bytes - * - * This function allocates, initializes and returns a new &struct hpsb_packet. - * It can be used in interrupt context. A header block is always included and - * initialized with zeros. Its size is big enough to contain all possible 1394 - * headers. The data block is only allocated if @data_size is not zero. - * - * For packets for which responses will be received the @data_size has to be big - * enough to contain the response's data block since no further allocation - * occurs at response matching time. - * - * The packet's generation value will be set to the current generation number - * for ease of use. Remember to overwrite it with your own recorded generation - * number if you can not be sure that your code will not race with a bus reset. - * - * Return value: A pointer to a &struct hpsb_packet or NULL on allocation - * failure. - */ -struct hpsb_packet *hpsb_alloc_packet(size_t data_size) -{ - struct hpsb_packet *packet; - - data_size = ((data_size + 3) & ~3); - - packet = kzalloc(sizeof(*packet) + data_size, GFP_ATOMIC); - if (!packet) - return NULL; - - packet->state = hpsb_unused; - packet->generation = -1; - INIT_LIST_HEAD(&packet->driver_list); - INIT_LIST_HEAD(&packet->queue); - atomic_set(&packet->refcnt, 1); - - if (data_size) { - packet->data = packet->embedded_data; - packet->allocated_data_size = data_size; - } - return packet; -} - -/** - * hpsb_free_packet - free packet and data associated with it - * @packet: packet to free (is NULL safe) - * - * Frees @packet->data only if it was allocated through hpsb_alloc_packet(). - */ -void hpsb_free_packet(struct hpsb_packet *packet) -{ - if (packet && atomic_dec_and_test(&packet->refcnt)) { - BUG_ON(!list_empty(&packet->driver_list) || - !list_empty(&packet->queue)); - kfree(packet); - } -} - -/** - * hpsb_reset_bus - initiate bus reset on the given host - * @host: host controller whose bus to reset - * @type: one of enum reset_types - * - * Returns 1 if bus reset already in progress, 0 otherwise. - */ -int hpsb_reset_bus(struct hpsb_host *host, int type) -{ - if (!host->in_bus_reset) { - host->driver->devctl(host, RESET_BUS, type); - return 0; - } else { - return 1; - } -} - -/** - * hpsb_read_cycle_timer - read cycle timer register and system time - * @host: host whose isochronous cycle timer register is read - * @cycle_timer: address of bitfield to return the register contents - * @local_time: address to return the system time - * - * The format of * @cycle_timer, is described in OHCI 1.1 clause 5.13. This - * format is also read from non-OHCI controllers. * @local_time contains the - * system time in microseconds since the Epoch, read at the moment when the - * cycle timer was read. - * - * Return value: 0 for success or error number otherwise. - */ -int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer, - u64 *local_time) -{ - int ctr; - struct timeval tv; - unsigned long flags; - - if (!host || !cycle_timer || !local_time) - return -EINVAL; - - preempt_disable(); - local_irq_save(flags); - - ctr = host->driver->devctl(host, GET_CYCLE_COUNTER, 0); - if (ctr) - do_gettimeofday(&tv); - - local_irq_restore(flags); - preempt_enable(); - - if (!ctr) - return -EIO; - *cycle_timer = ctr; - *local_time = tv.tv_sec * 1000000ULL + tv.tv_usec; - return 0; -} - -/** - * hpsb_bus_reset - notify a bus reset to the core - * - * For host driver module usage. Safe to use in interrupt context, although - * quite complex; so you may want to run it in the bottom rather than top half. - * - * Returns 1 if bus reset already in progress, 0 otherwise. - */ -int hpsb_bus_reset(struct hpsb_host *host) -{ - if (host->in_bus_reset) { - HPSB_NOTICE("%s called while bus reset already in progress", - __func__); - return 1; - } - - abort_requests(host); - host->in_bus_reset = 1; - host->irm_id = -1; - host->is_irm = 0; - host->busmgr_id = -1; - host->is_busmgr = 0; - host->is_cycmst = 0; - host->node_count = 0; - host->selfid_count = 0; - - return 0; -} - - -/* - * Verify num_of_selfids SelfIDs and return number of nodes. Return zero in - * case verification failed. - */ -static int check_selfids(struct hpsb_host *host) -{ - int nodeid = -1; - int rest_of_selfids = host->selfid_count; - struct selfid *sid = (struct selfid *)host->topology_map; - struct ext_selfid *esid; - int esid_seq = 23; - - host->nodes_active = 0; - - while (rest_of_selfids--) { - if (!sid->extended) { - nodeid++; - esid_seq = 0; - - if (sid->phy_id != nodeid) { - HPSB_INFO("SelfIDs failed monotony check with " - "%d", sid->phy_id); - return 0; - } - - if (sid->link_active) { - host->nodes_active++; - if (sid->contender) - host->irm_id = LOCAL_BUS | sid->phy_id; - } - } else { - esid = (struct ext_selfid *)sid; - - if ((esid->phy_id != nodeid) - || (esid->seq_nr != esid_seq)) { - HPSB_INFO("SelfIDs failed monotony check with " - "%d/%d", esid->phy_id, esid->seq_nr); - return 0; - } - esid_seq++; - } - sid++; - } - - esid = (struct ext_selfid *)(sid - 1); - while (esid->extended) { - if ((esid->porta == SELFID_PORT_PARENT) || - (esid->portb == SELFID_PORT_PARENT) || - (esid->portc == SELFID_PORT_PARENT) || - (esid->portd == SELFID_PORT_PARENT) || - (esid->porte == SELFID_PORT_PARENT) || - (esid->portf == SELFID_PORT_PARENT) || - (esid->portg == SELFID_PORT_PARENT) || - (esid->porth == SELFID_PORT_PARENT)) { - HPSB_INFO("SelfIDs failed root check on " - "extended SelfID"); - return 0; - } - esid--; - } - - sid = (struct selfid *)esid; - if ((sid->port0 == SELFID_PORT_PARENT) || - (sid->port1 == SELFID_PORT_PARENT) || - (sid->port2 == SELFID_PORT_PARENT)) { - HPSB_INFO("SelfIDs failed root check"); - return 0; - } - - host->node_count = nodeid + 1; - return 1; -} - -static void build_speed_map(struct hpsb_host *host, int nodecount) -{ - u8 cldcnt[nodecount]; - u8 *map = host->speed_map; - u8 *speedcap = host->speed; - u8 local_link_speed = host->csr.lnk_spd; - struct selfid *sid; - struct ext_selfid *esid; - int i, j, n; - - for (i = 0; i < (nodecount * 64); i += 64) { - for (j = 0; j < nodecount; j++) { - map[i+j] = IEEE1394_SPEED_MAX; - } - } - - for (i = 0; i < nodecount; i++) { - cldcnt[i] = 0; - } - - /* find direct children count and speed */ - for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1], - n = nodecount - 1; - (void *)sid >= (void *)host->topology_map; sid--) { - if (sid->extended) { - esid = (struct ext_selfid *)sid; - - if (esid->porta == SELFID_PORT_CHILD) cldcnt[n]++; - if (esid->portb == SELFID_PORT_CHILD) cldcnt[n]++; - if (esid->portc == SELFID_PORT_CHILD) cldcnt[n]++; - if (esid->portd == SELFID_PORT_CHILD) cldcnt[n]++; - if (esid->porte == SELFID_PORT_CHILD) cldcnt[n]++; - if (esid->portf == SELFID_PORT_CHILD) cldcnt[n]++; - if (esid->portg == SELFID_PORT_CHILD) cldcnt[n]++; - if (esid->porth == SELFID_PORT_CHILD) cldcnt[n]++; - } else { - if (sid->port0 == SELFID_PORT_CHILD) cldcnt[n]++; - if (sid->port1 == SELFID_PORT_CHILD) cldcnt[n]++; - if (sid->port2 == SELFID_PORT_CHILD) cldcnt[n]++; - - speedcap[n] = sid->speed; - if (speedcap[n] > local_link_speed) - speedcap[n] = local_link_speed; - n--; - } - } - - /* set self mapping */ - for (i = 0; i < nodecount; i++) { - map[64*i + i] = speedcap[i]; - } - - /* fix up direct children count to total children count; - * also fix up speedcaps for sibling and parent communication */ - for (i = 1; i < nodecount; i++) { - for (j = cldcnt[i], n = i - 1; j > 0; j--) { - cldcnt[i] += cldcnt[n]; - speedcap[n] = min(speedcap[n], speedcap[i]); - n -= cldcnt[n] + 1; - } - } - - for (n = 0; n < nodecount; n++) { - for (i = n - cldcnt[n]; i <= n; i++) { - for (j = 0; j < (n - cldcnt[n]); j++) { - map[j*64 + i] = map[i*64 + j] = - min(map[i*64 + j], speedcap[n]); - } - for (j = n + 1; j < nodecount; j++) { - map[j*64 + i] = map[i*64 + j] = - min(map[i*64 + j], speedcap[n]); - } - } - } - - /* assume a maximum speed for 1394b PHYs, nodemgr will correct it */ - if (local_link_speed > SELFID_SPEED_UNKNOWN) - for (i = 0; i < nodecount; i++) - if (speedcap[i] == SELFID_SPEED_UNKNOWN) - speedcap[i] = local_link_speed; -} - - -/** - * hpsb_selfid_received - hand over received selfid packet to the core - * - * For host driver module usage. Safe to use in interrupt context. - * - * The host driver should have done a successful complement check (second - * quadlet is complement of first) beforehand. - */ -void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) -{ - if (host->in_bus_reset) { - HPSB_VERBOSE("Including SelfID 0x%x", sid); - host->topology_map[host->selfid_count++] = sid; - } else { - HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d", - sid, NODEID_TO_BUS(host->node_id)); - } -} - -/** - * hpsb_selfid_complete - notify completion of SelfID stage to the core - * - * For host driver module usage. Safe to use in interrupt context, although - * quite complex; so you may want to run it in the bottom rather than top half. - * - * Notify completion of SelfID stage to the core and report new physical ID - * and whether host is root now. - */ -void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) -{ - if (!host->in_bus_reset) - HPSB_NOTICE("SelfID completion called outside of bus reset!"); - - host->node_id = LOCAL_BUS | phyid; - host->is_root = isroot; - - if (!check_selfids(host)) { - if (host->reset_retries++ < 20) { - /* selfid stage did not complete without error */ - HPSB_NOTICE("Error in SelfID stage, resetting"); - host->in_bus_reset = 0; - /* this should work from ohci1394 now... */ - hpsb_reset_bus(host, LONG_RESET); - return; - } else { - HPSB_NOTICE("Stopping out-of-control reset loop"); - HPSB_NOTICE("Warning - topology map and speed map will not be valid"); - host->reset_retries = 0; - } - } else { - host->reset_retries = 0; - build_speed_map(host, host->node_count); - } - - HPSB_VERBOSE("selfid_complete called with successful SelfID stage " - "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id); - - /* irm_id is kept up to date by check_selfids() */ - if (host->irm_id == host->node_id) { - host->is_irm = 1; - } else { - host->is_busmgr = 0; - host->is_irm = 0; - } - - if (isroot) { - host->driver->devctl(host, ACT_CYCLE_MASTER, 1); - host->is_cycmst = 1; - } - atomic_inc(&host->generation); - host->in_bus_reset = 0; - highlevel_host_reset(host); -} - -static DEFINE_SPINLOCK(pending_packets_lock); - -/** - * hpsb_packet_sent - notify core of sending a packet - * - * For host driver module usage. Safe to call from within a transmit packet - * routine. - * - * Notify core of sending a packet. Ackcode is the ack code returned for async - * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE - * for other cases (internal errors that don't justify a panic). - */ -void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, - int ackcode) -{ - unsigned long flags; - - spin_lock_irqsave(&pending_packets_lock, flags); - - packet->ack_code = ackcode; - - if (packet->no_waiter || packet->state == hpsb_complete) { - /* if packet->no_waiter, must not have a tlabel allocated */ - spin_unlock_irqrestore(&pending_packets_lock, flags); - hpsb_free_packet(packet); - return; - } - - atomic_dec(&packet->refcnt); /* drop HC's reference */ - /* here the packet must be on the host->pending_packets queue */ - - if (ackcode != ACK_PENDING || !packet->expect_response) { - packet->state = hpsb_complete; - list_del_init(&packet->queue); - spin_unlock_irqrestore(&pending_packets_lock, flags); - queue_packet_complete(packet); - return; - } - - packet->state = hpsb_pending; - packet->sendtime = jiffies; - - spin_unlock_irqrestore(&pending_packets_lock, flags); - - mod_timer(&host->timeout, jiffies + host->timeout_interval); -} - -/** - * hpsb_send_phy_config - transmit a PHY configuration packet on the bus - * @host: host that PHY config packet gets sent through - * @rootid: root whose force_root bit should get set (-1 = don't set force_root) - * @gapcnt: gap count value to set (-1 = don't set gap count) - * - * This function sends a PHY config packet on the bus through the specified - * host. - * - * Return value: 0 for success or negative error number otherwise. - */ -int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt) -{ - struct hpsb_packet *packet; - quadlet_t d = 0; - int retval = 0; - - if (rootid >= ALL_NODES || rootid < -1 || gapcnt > 0x3f || gapcnt < -1 || - (rootid == -1 && gapcnt == -1)) { - HPSB_DEBUG("Invalid Parameter: rootid = %d gapcnt = %d", - rootid, gapcnt); - return -EINVAL; - } - - if (rootid != -1) - d |= PHYPACKET_PHYCONFIG_R | rootid << PHYPACKET_PORT_SHIFT; - if (gapcnt != -1) - d |= PHYPACKET_PHYCONFIG_T | gapcnt << PHYPACKET_GAPCOUNT_SHIFT; - - packet = hpsb_make_phypacket(host, d); - if (!packet) - return -ENOMEM; - - packet->generation = get_hpsb_generation(host); - retval = hpsb_send_packet_and_wait(packet); - hpsb_free_packet(packet); - - return retval; -} - -/** - * hpsb_send_packet - transmit a packet on the bus - * @packet: packet to send - * - * The packet is sent through the host specified in the packet->host field. - * Before sending, the packet's transmit speed is automatically determined - * using the local speed map when it is an async, non-broadcast packet. - * - * Possibilities for failure are that host is either not initialized, in bus - * reset, the packet's generation number doesn't match the current generation - * number or the host reports a transmit error. - * - * Return value: 0 on success, negative errno on failure. - */ -int hpsb_send_packet(struct hpsb_packet *packet) -{ - struct hpsb_host *host = packet->host; - - if (host->is_shutdown) - return -EINVAL; - if (host->in_bus_reset || - (packet->generation != get_hpsb_generation(host))) - return -EAGAIN; - - packet->state = hpsb_queued; - - /* This just seems silly to me */ - WARN_ON(packet->no_waiter && packet->expect_response); - - if (!packet->no_waiter || packet->expect_response) { - unsigned long flags; - - atomic_inc(&packet->refcnt); - /* Set the initial "sendtime" to 10 seconds from now, to - prevent premature expiry. If a packet takes more than - 10 seconds to hit the wire, we have bigger problems :) */ - packet->sendtime = jiffies + 10 * HZ; - spin_lock_irqsave(&pending_packets_lock, flags); - list_add_tail(&packet->queue, &host->pending_packets); - spin_unlock_irqrestore(&pending_packets_lock, flags); - } - - if (packet->node_id == host->node_id) { - /* it is a local request, so handle it locally */ - - quadlet_t *data; - size_t size = packet->data_size + packet->header_size; - - data = kmalloc(size, GFP_ATOMIC); - if (!data) { - HPSB_ERR("unable to allocate memory for concatenating header and data"); - return -ENOMEM; - } - - memcpy(data, packet->header, packet->header_size); - - if (packet->data_size) - memcpy(((u8*)data) + packet->header_size, packet->data, packet->data_size); - - dump_packet("send packet local", packet->header, packet->header_size, -1); - - hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE); - hpsb_packet_received(host, data, size, 0); - - kfree(data); - - return 0; - } - - if (packet->type == hpsb_async && - NODEID_TO_NODE(packet->node_id) != ALL_NODES) - packet->speed_code = - host->speed[NODEID_TO_NODE(packet->node_id)]; - - dump_packet("send packet", packet->header, packet->header_size, packet->speed_code); - - return host->driver->transmit_packet(host, packet); -} - -/* We could just use complete() directly as the packet complete - * callback, but this is more typesafe, in the sense that we get a - * compiler error if the prototype for complete() changes. */ - -static void complete_packet(void *data) -{ - complete((struct completion *) data); -} - -/** - * hpsb_send_packet_and_wait - enqueue packet, block until transaction completes - * @packet: packet to send - * - * Return value: 0 on success, negative errno on failure. - */ -int hpsb_send_packet_and_wait(struct hpsb_packet *packet) -{ - struct completion done; - int retval; - - init_completion(&done); - hpsb_set_packet_complete_task(packet, complete_packet, &done); - retval = hpsb_send_packet(packet); - if (retval == 0) - wait_for_completion(&done); - - return retval; -} - -static void send_packet_nocare(struct hpsb_packet *packet) -{ - if (hpsb_send_packet(packet) < 0) { - hpsb_free_packet(packet); - } -} - -static size_t packet_size_to_data_size(size_t packet_size, size_t header_size, - size_t buffer_size, int tcode) -{ - size_t ret = packet_size <= header_size ? 0 : packet_size - header_size; - - if (unlikely(ret > buffer_size)) - ret = buffer_size; - - if (unlikely(ret + header_size != packet_size)) - HPSB_ERR("unexpected packet size %zd (tcode %d), bug?", - packet_size, tcode); - return ret; -} - -static void handle_packet_response(struct hpsb_host *host, int tcode, - quadlet_t *data, size_t size) -{ - struct hpsb_packet *packet; - int tlabel = (data[0] >> 10) & 0x3f; - size_t header_size; - unsigned long flags; - - spin_lock_irqsave(&pending_packets_lock, flags); - - list_for_each_entry(packet, &host->pending_packets, queue) - if (packet->tlabel == tlabel && - packet->node_id == (data[1] >> 16)) - goto found; - - spin_unlock_irqrestore(&pending_packets_lock, flags); - HPSB_DEBUG("unsolicited response packet received - %s", - "no tlabel match"); - dump_packet("contents", data, 16, -1); - return; - -found: - switch (packet->tcode) { - case TCODE_WRITEQ: - case TCODE_WRITEB: - if (unlikely(tcode != TCODE_WRITE_RESPONSE)) - break; - header_size = 12; - size = 0; - goto dequeue; - - case TCODE_READQ: - if (unlikely(tcode != TCODE_READQ_RESPONSE)) - break; - header_size = 16; - size = 0; - goto dequeue; - - case TCODE_READB: - if (unlikely(tcode != TCODE_READB_RESPONSE)) - break; - header_size = 16; - size = packet_size_to_data_size(size, header_size, - packet->allocated_data_size, - tcode); - goto dequeue; - - case TCODE_LOCK_REQUEST: - if (unlikely(tcode != TCODE_LOCK_RESPONSE)) - break; - header_size = 16; - size = packet_size_to_data_size(min(size, (size_t)(16 + 8)), - header_size, - packet->allocated_data_size, - tcode); - goto dequeue; - } - - spin_unlock_irqrestore(&pending_packets_lock, flags); - HPSB_DEBUG("unsolicited response packet received - %s", - "tcode mismatch"); - dump_packet("contents", data, 16, -1); - return; - -dequeue: - list_del_init(&packet->queue); - spin_unlock_irqrestore(&pending_packets_lock, flags); - - if (packet->state == hpsb_queued) { - packet->sendtime = jiffies; - packet->ack_code = ACK_PENDING; - } - packet->state = hpsb_complete; - - memcpy(packet->header, data, header_size); - if (size) - memcpy(packet->data, data + 4, size); - - queue_packet_complete(packet); -} - - -static struct hpsb_packet *create_reply_packet(struct hpsb_host *host, - quadlet_t *data, size_t dsize) -{ - struct hpsb_packet *p; - - p = hpsb_alloc_packet(dsize); - if (unlikely(p == NULL)) { - /* FIXME - send data_error response */ - HPSB_ERR("out of memory, cannot send response packet"); - return NULL; - } - - p->type = hpsb_async; - p->state = hpsb_unused; - p->host = host; - p->node_id = data[1] >> 16; - p->tlabel = (data[0] >> 10) & 0x3f; - p->no_waiter = 1; - - p->generation = get_hpsb_generation(host); - - if (dsize % 4) - p->data[dsize / 4] = 0; - - return p; -} - -#define PREP_ASYNC_HEAD_RCODE(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) | (rcode << 12); \ - packet->header[2] = 0 - -static void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode, - quadlet_t data) -{ - PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE); - packet->header[3] = data; - packet->header_size = 16; - packet->data_size = 0; -} - -static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode, - int length) -{ - if (rcode != RCODE_COMPLETE) - length = 0; - - PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE); - packet->header[3] = length << 16; - packet->header_size = 16; - packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0); -} - -static void fill_async_write_resp(struct hpsb_packet *packet, int rcode) -{ - PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE); - packet->header_size = 12; - packet->data_size = 0; -} - -static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode, - int length) -{ - if (rcode != RCODE_COMPLETE) - length = 0; - - PREP_ASYNC_HEAD_RCODE(TCODE_LOCK_RESPONSE); - packet->header[3] = (length << 16) | extcode; - packet->header_size = 16; - packet->data_size = length; -} - -static void handle_incoming_packet(struct hpsb_host *host, int tcode, - quadlet_t *data, size_t size, - int write_acked) -{ - struct hpsb_packet *packet; - int length, rcode, extcode; - quadlet_t buffer; - nodeid_t source = data[1] >> 16; - nodeid_t dest = data[0] >> 16; - u16 flags = (u16) data[0]; - u64 addr; - - /* FIXME? - * Out-of-bounds lengths are left for highlevel_read|write to cap. */ - - switch (tcode) { - case TCODE_WRITEQ: - addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_write(host, source, dest, data + 3, - addr, 4, flags); - goto handle_write_request; - - case TCODE_WRITEB: - addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_write(host, source, dest, data + 4, - addr, data[3] >> 16, flags); -handle_write_request: - if (rcode < 0 || write_acked || - NODEID_TO_NODE(data[0] >> 16) == NODE_MASK) - return; - /* not a broadcast write, reply */ - packet = create_reply_packet(host, data, 0); - if (packet) { - fill_async_write_resp(packet, rcode); - send_packet_nocare(packet); - } - return; - - case TCODE_READQ: - addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_read(host, source, &buffer, addr, 4, flags); - if (rcode < 0) - return; - - packet = create_reply_packet(host, data, 0); - if (packet) { - fill_async_readquad_resp(packet, rcode, buffer); - send_packet_nocare(packet); - } - return; - - case TCODE_READB: - length = data[3] >> 16; - packet = create_reply_packet(host, data, length); - if (!packet) - return; - - addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_read(host, source, packet->data, addr, - length, flags); - if (rcode < 0) { - hpsb_free_packet(packet); - return; - } - fill_async_readblock_resp(packet, rcode, length); - send_packet_nocare(packet); - return; - - case TCODE_LOCK_REQUEST: - length = data[3] >> 16; - extcode = data[3] & 0xffff; - addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - - packet = create_reply_packet(host, data, 8); - if (!packet) - return; - - if (extcode == 0 || extcode >= 7) { - /* let switch default handle error */ - length = 0; - } - - switch (length) { - case 4: - rcode = highlevel_lock(host, source, packet->data, addr, - data[4], 0, extcode, flags); - fill_async_lock_resp(packet, rcode, extcode, 4); - break; - case 8: - if (extcode != EXTCODE_FETCH_ADD && - extcode != EXTCODE_LITTLE_ADD) { - rcode = highlevel_lock(host, source, - packet->data, addr, - data[5], data[4], - extcode, flags); - fill_async_lock_resp(packet, rcode, extcode, 4); - } else { - rcode = highlevel_lock64(host, source, - (octlet_t *)packet->data, addr, - *(octlet_t *)(data + 4), 0ULL, - extcode, flags); - fill_async_lock_resp(packet, rcode, extcode, 8); - } - break; - case 16: - rcode = highlevel_lock64(host, source, - (octlet_t *)packet->data, addr, - *(octlet_t *)(data + 6), - *(octlet_t *)(data + 4), - extcode, flags); - fill_async_lock_resp(packet, rcode, extcode, 8); - break; - default: - rcode = RCODE_TYPE_ERROR; - fill_async_lock_resp(packet, rcode, extcode, 0); - } - - if (rcode < 0) - hpsb_free_packet(packet); - else - send_packet_nocare(packet); - return; - } -} - -/** - * hpsb_packet_received - hand over received packet to the core - * - * For host driver module usage. - * - * The contents of data are expected to be the full packet but with the CRCs - * left out (data block follows header immediately), with the header (i.e. the - * first four quadlets) in machine byte order and the data block in big endian. - * *@data can be safely overwritten after this call. - * - * If the packet is a write request, @write_acked is to be set to true if it was - * ack_complete'd already, false otherwise. This argument is ignored for any - * other packet type. - */ -void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, - int write_acked) -{ - int tcode; - - if (unlikely(host->in_bus_reset)) { - HPSB_DEBUG("received packet during reset; ignoring"); - return; - } - - dump_packet("received packet", data, size, -1); - - tcode = (data[0] >> 4) & 0xf; - - switch (tcode) { - case TCODE_WRITE_RESPONSE: - case TCODE_READQ_RESPONSE: - case TCODE_READB_RESPONSE: - case TCODE_LOCK_RESPONSE: - handle_packet_response(host, tcode, data, size); - break; - - case TCODE_WRITEQ: - case TCODE_WRITEB: - case TCODE_READQ: - case TCODE_READB: - case TCODE_LOCK_REQUEST: - handle_incoming_packet(host, tcode, data, size, write_acked); - break; - - case TCODE_CYCLE_START: - /* simply ignore this packet if it is passed on */ - break; - - default: - HPSB_DEBUG("received packet with bogus transaction code %d", - tcode); - break; - } -} - -static void abort_requests(struct hpsb_host *host) -{ - struct hpsb_packet *packet, *p; - struct list_head tmp; - unsigned long flags; - - host->driver->devctl(host, CANCEL_REQUESTS, 0); - - INIT_LIST_HEAD(&tmp); - spin_lock_irqsave(&pending_packets_lock, flags); - list_splice_init(&host->pending_packets, &tmp); - spin_unlock_irqrestore(&pending_packets_lock, flags); - - list_for_each_entry_safe(packet, p, &tmp, queue) { - list_del_init(&packet->queue); - packet->state = hpsb_complete; - packet->ack_code = ACKX_ABORTED; - queue_packet_complete(packet); - } -} - -void abort_timedouts(unsigned long __opaque) -{ - struct hpsb_host *host = (struct hpsb_host *)__opaque; - struct hpsb_packet *packet, *p; - struct list_head tmp; - unsigned long flags, expire, j; - - spin_lock_irqsave(&host->csr.lock, flags); - expire = host->csr.expire; - spin_unlock_irqrestore(&host->csr.lock, flags); - - j = jiffies; - INIT_LIST_HEAD(&tmp); - spin_lock_irqsave(&pending_packets_lock, flags); - - list_for_each_entry_safe(packet, p, &host->pending_packets, queue) { - if (time_before(packet->sendtime + expire, j)) - list_move_tail(&packet->queue, &tmp); - else - /* Since packets are added to the tail, the oldest - * ones are first, always. When we get to one that - * isn't timed out, the rest aren't either. */ - break; - } - if (!list_empty(&host->pending_packets)) - mod_timer(&host->timeout, j + host->timeout_interval); - - spin_unlock_irqrestore(&pending_packets_lock, flags); - - list_for_each_entry_safe(packet, p, &tmp, queue) { - list_del_init(&packet->queue); - packet->state = hpsb_complete; - packet->ack_code = ACKX_TIMEOUT; - queue_packet_complete(packet); - } -} - -static struct task_struct *khpsbpkt_thread; -static LIST_HEAD(hpsbpkt_queue); - -static void queue_packet_complete(struct hpsb_packet *packet) -{ - unsigned long flags; - - if (packet->no_waiter) { - hpsb_free_packet(packet); - return; - } - if (packet->complete_routine != NULL) { - spin_lock_irqsave(&pending_packets_lock, flags); - list_add_tail(&packet->queue, &hpsbpkt_queue); - spin_unlock_irqrestore(&pending_packets_lock, flags); - wake_up_process(khpsbpkt_thread); - } - return; -} - -/* - * Kernel thread which handles packets that are completed. This way the - * packet's "complete" function is asynchronously run in process context. - * Only packets which have a "complete" function may be sent here. - */ -static int hpsbpkt_thread(void *__hi) -{ - struct hpsb_packet *packet, *p; - struct list_head tmp; - int may_schedule; - - while (!kthread_should_stop()) { - - INIT_LIST_HEAD(&tmp); - spin_lock_irq(&pending_packets_lock); - list_splice_init(&hpsbpkt_queue, &tmp); - spin_unlock_irq(&pending_packets_lock); - - list_for_each_entry_safe(packet, p, &tmp, queue) { - list_del_init(&packet->queue); - packet->complete_routine(packet->complete_data); - } - - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irq(&pending_packets_lock); - may_schedule = list_empty(&hpsbpkt_queue); - spin_unlock_irq(&pending_packets_lock); - if (may_schedule) - schedule(); - __set_current_state(TASK_RUNNING); - } - return 0; -} - -static int __init ieee1394_init(void) -{ - int i, ret; - - /* non-fatal error */ - if (hpsb_init_config_roms()) { - HPSB_ERR("Failed to initialize some config rom entries.\n"); - HPSB_ERR("Some features may not be available\n"); - } - - khpsbpkt_thread = kthread_run(hpsbpkt_thread, NULL, "khpsbpkt"); - if (IS_ERR(khpsbpkt_thread)) { - HPSB_ERR("Failed to start hpsbpkt thread!\n"); - ret = PTR_ERR(khpsbpkt_thread); - goto exit_cleanup_config_roms; - } - - if (register_chrdev_region(IEEE1394_CORE_DEV, 256, "ieee1394")) { - HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR); - ret = -ENODEV; - goto exit_release_kernel_thread; - } - - ret = bus_register(&ieee1394_bus_type); - if (ret < 0) { - HPSB_INFO("bus register failed"); - goto release_chrdev; - } - - for (i = 0; fw_bus_attrs[i]; i++) { - ret = bus_create_file(&ieee1394_bus_type, fw_bus_attrs[i]); - if (ret < 0) { - while (i >= 0) { - bus_remove_file(&ieee1394_bus_type, - fw_bus_attrs[i--]); - } - bus_unregister(&ieee1394_bus_type); - goto release_chrdev; - } - } - - ret = class_register(&hpsb_host_class); - if (ret < 0) - goto release_all_bus; - - hpsb_protocol_class = class_create(THIS_MODULE, "ieee1394_protocol"); - if (IS_ERR(hpsb_protocol_class)) { - ret = PTR_ERR(hpsb_protocol_class); - goto release_class_host; - } - - ret = init_csr(); - if (ret) { - HPSB_INFO("init csr failed"); - ret = -ENOMEM; - goto release_class_protocol; - } - - if (disable_nodemgr) { - HPSB_INFO("nodemgr and IRM functionality disabled"); - /* We shouldn't contend for IRM with nodemgr disabled, since - nodemgr implements functionality required of ieee1394a-2000 - IRMs */ - hpsb_disable_irm = 1; - - return 0; - } - - if (hpsb_disable_irm) { - HPSB_INFO("IRM functionality disabled"); - } - - ret = init_ieee1394_nodemgr(); - if (ret < 0) { - HPSB_INFO("init nodemgr failed"); - goto cleanup_csr; - } - - return 0; - -cleanup_csr: - cleanup_csr(); -release_class_protocol: - class_destroy(hpsb_protocol_class); -release_class_host: - class_unregister(&hpsb_host_class); -release_all_bus: - for (i = 0; fw_bus_attrs[i]; i++) - bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]); - bus_unregister(&ieee1394_bus_type); -release_chrdev: - unregister_chrdev_region(IEEE1394_CORE_DEV, 256); -exit_release_kernel_thread: - kthread_stop(khpsbpkt_thread); -exit_cleanup_config_roms: - hpsb_cleanup_config_roms(); - return ret; -} - -static void __exit ieee1394_cleanup(void) -{ - int i; - - if (!disable_nodemgr) - cleanup_ieee1394_nodemgr(); - - cleanup_csr(); - - class_destroy(hpsb_protocol_class); - class_unregister(&hpsb_host_class); - for (i = 0; fw_bus_attrs[i]; i++) - bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]); - bus_unregister(&ieee1394_bus_type); - - kthread_stop(khpsbpkt_thread); - - hpsb_cleanup_config_roms(); - - unregister_chrdev_region(IEEE1394_CORE_DEV, 256); -} - -fs_initcall(ieee1394_init); -module_exit(ieee1394_cleanup); - -/* Exported symbols */ - -/** hosts.c **/ -EXPORT_SYMBOL(hpsb_alloc_host); -EXPORT_SYMBOL(hpsb_add_host); -EXPORT_SYMBOL(hpsb_resume_host); -EXPORT_SYMBOL(hpsb_remove_host); -EXPORT_SYMBOL(hpsb_update_config_rom_image); - -/** ieee1394_core.c **/ -EXPORT_SYMBOL(hpsb_speedto_str); -EXPORT_SYMBOL(hpsb_protocol_class); -EXPORT_SYMBOL(hpsb_set_packet_complete_task); -EXPORT_SYMBOL(hpsb_alloc_packet); -EXPORT_SYMBOL(hpsb_free_packet); -EXPORT_SYMBOL(hpsb_send_packet); -EXPORT_SYMBOL(hpsb_reset_bus); -EXPORT_SYMBOL(hpsb_read_cycle_timer); -EXPORT_SYMBOL(hpsb_bus_reset); -EXPORT_SYMBOL(hpsb_selfid_received); -EXPORT_SYMBOL(hpsb_selfid_complete); -EXPORT_SYMBOL(hpsb_packet_sent); -EXPORT_SYMBOL(hpsb_packet_received); -EXPORT_SYMBOL_GPL(hpsb_disable_irm); - -/** ieee1394_transactions.c **/ -EXPORT_SYMBOL(hpsb_get_tlabel); -EXPORT_SYMBOL(hpsb_free_tlabel); -EXPORT_SYMBOL(hpsb_make_readpacket); -EXPORT_SYMBOL(hpsb_make_writepacket); -EXPORT_SYMBOL(hpsb_make_streampacket); -EXPORT_SYMBOL(hpsb_make_lockpacket); -EXPORT_SYMBOL(hpsb_make_lock64packet); -EXPORT_SYMBOL(hpsb_make_phypacket); -EXPORT_SYMBOL(hpsb_read); -EXPORT_SYMBOL(hpsb_write); -EXPORT_SYMBOL(hpsb_lock); -EXPORT_SYMBOL(hpsb_packet_success); - -/** highlevel.c **/ -EXPORT_SYMBOL(hpsb_register_highlevel); -EXPORT_SYMBOL(hpsb_unregister_highlevel); -EXPORT_SYMBOL(hpsb_register_addrspace); -EXPORT_SYMBOL(hpsb_unregister_addrspace); -EXPORT_SYMBOL(hpsb_allocate_and_register_addrspace); -EXPORT_SYMBOL(hpsb_get_hostinfo); -EXPORT_SYMBOL(hpsb_create_hostinfo); -EXPORT_SYMBOL(hpsb_destroy_hostinfo); -EXPORT_SYMBOL(hpsb_set_hostinfo_key); -EXPORT_SYMBOL(hpsb_get_hostinfo_bykey); -EXPORT_SYMBOL(hpsb_set_hostinfo); - -/** nodemgr.c **/ -EXPORT_SYMBOL(hpsb_node_fill_packet); -EXPORT_SYMBOL(hpsb_node_write); -EXPORT_SYMBOL(__hpsb_register_protocol); -EXPORT_SYMBOL(hpsb_unregister_protocol); - -/** csr.c **/ -EXPORT_SYMBOL(hpsb_update_config_rom); - -/** dma.c **/ -EXPORT_SYMBOL(dma_prog_region_init); -EXPORT_SYMBOL(dma_prog_region_alloc); -EXPORT_SYMBOL(dma_prog_region_free); -EXPORT_SYMBOL(dma_region_init); -EXPORT_SYMBOL(dma_region_alloc); -EXPORT_SYMBOL(dma_region_free); -EXPORT_SYMBOL(dma_region_sync_for_cpu); -EXPORT_SYMBOL(dma_region_sync_for_device); -EXPORT_SYMBOL(dma_region_mmap); -EXPORT_SYMBOL(dma_region_offset_to_bus); - -/** iso.c **/ -EXPORT_SYMBOL(hpsb_iso_xmit_init); -EXPORT_SYMBOL(hpsb_iso_recv_init); -EXPORT_SYMBOL(hpsb_iso_xmit_start); -EXPORT_SYMBOL(hpsb_iso_recv_start); -EXPORT_SYMBOL(hpsb_iso_recv_listen_channel); -EXPORT_SYMBOL(hpsb_iso_recv_unlisten_channel); -EXPORT_SYMBOL(hpsb_iso_recv_set_channel_mask); -EXPORT_SYMBOL(hpsb_iso_stop); -EXPORT_SYMBOL(hpsb_iso_shutdown); -EXPORT_SYMBOL(hpsb_iso_xmit_queue_packet); -EXPORT_SYMBOL(hpsb_iso_xmit_sync); -EXPORT_SYMBOL(hpsb_iso_recv_release_packets); -EXPORT_SYMBOL(hpsb_iso_n_ready); -EXPORT_SYMBOL(hpsb_iso_packet_sent); -EXPORT_SYMBOL(hpsb_iso_packet_received); -EXPORT_SYMBOL(hpsb_iso_wake); -EXPORT_SYMBOL(hpsb_iso_recv_flush); - -/** csr1212.c **/ -EXPORT_SYMBOL(csr1212_attach_keyval_to_directory); -EXPORT_SYMBOL(csr1212_detach_keyval_from_directory); -EXPORT_SYMBOL(csr1212_get_keyval); -EXPORT_SYMBOL(csr1212_new_directory); -EXPORT_SYMBOL(csr1212_parse_keyval); -EXPORT_SYMBOL(csr1212_read); -EXPORT_SYMBOL(csr1212_release_keyval); diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h deleted file mode 100644 index 28b9f58bafd..00000000000 --- a/drivers/ieee1394/ieee1394_core.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/ieee1394_hotplug.h b/drivers/ieee1394/ieee1394_hotplug.h deleted file mode 100644 index dd5500ed832..00000000000 --- a/drivers/ieee1394/ieee1394_hotplug.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c deleted file mode 100644 index 675b3135d5f..00000000000 --- a/drivers/ieee1394/ieee1394_transactions.c +++ /dev/null @@ -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; -} diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h deleted file mode 100644 index 20b693be14b..00000000000 --- a/drivers/ieee1394/ieee1394_transactions.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h deleted file mode 100644 index 9803aaa15be..00000000000 --- a/drivers/ieee1394/ieee1394_types.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c deleted file mode 100644 index 1cf6487b65b..00000000000 --- a/drivers/ieee1394/iso.c +++ /dev/null @@ -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); -} diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h deleted file mode 100644 index c2089c093aa..00000000000 --- a/drivers/ieee1394/iso.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c deleted file mode 100644 index 18350213479..00000000000 --- a/drivers/ieee1394/nodemgr.c +++ /dev/null @@ -1,1901 +0,0 @@ -/* - * Node information (ConfigROM) collection and management. - * - * Copyright (C) 2000 Andreas E. Bombe - * 2001-2003 Ben Collins <bcollins@debian.net> - * - * This code is licensed under the GPL. See the file COPYING in the root - * directory of the kernel sources for details. - */ - -#include <linux/bitmap.h> -#include <linux/kernel.h> -#include <linux/kmemcheck.h> -#include <linux/list.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/kthread.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/mutex.h> -#include <linux/freezer.h> -#include <asm/atomic.h> - -#include "csr.h" -#include "highlevel.h" -#include "hosts.h" -#include "ieee1394.h" -#include "ieee1394_core.h" -#include "ieee1394_hotplug.h" -#include "ieee1394_types.h" -#include "ieee1394_transactions.h" -#include "nodemgr.h" - -static int ignore_drivers; -module_param(ignore_drivers, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers."); - -struct nodemgr_csr_info { - struct hpsb_host *host; - nodeid_t nodeid; - unsigned int generation; - - kmemcheck_bitfield_begin(flags); - unsigned int speed_unverified:1; - kmemcheck_bitfield_end(flags); -}; - - -/* - * Correct the speed map entry. This is necessary - * - for nodes with link speed < phy speed, - * - for 1394b nodes with negotiated phy port speed < IEEE1394_SPEED_MAX. - * A possible speed is determined by trial and error, using quadlet reads. - */ -static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr, - quadlet_t *buffer) -{ - quadlet_t q; - u8 i, *speed, old_speed, good_speed; - int error; - - speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]); - old_speed = *speed; - good_speed = IEEE1394_SPEED_MAX + 1; - - /* Try every speed from S100 to old_speed. - * If we did it the other way around, a too low speed could be caught - * if the retry succeeded for some other reason, e.g. because the link - * just finished its initialization. */ - for (i = IEEE1394_SPEED_100; i <= old_speed; i++) { - *speed = i; - error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr, - &q, 4); - if (error) - break; - *buffer = q; - good_speed = i; - } - if (good_speed <= IEEE1394_SPEED_MAX) { - HPSB_DEBUG("Speed probe of node " NODE_BUS_FMT " yields %s", - NODE_BUS_ARGS(ci->host, ci->nodeid), - hpsb_speedto_str[good_speed]); - *speed = good_speed; - ci->speed_unverified = 0; - return 0; - } - *speed = old_speed; - return error; -} - -static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, - void *buffer, void *__ci) -{ - struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci; - int i, error; - - for (i = 1; ; i++) { - error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr, - buffer, 4); - if (!error) { - ci->speed_unverified = 0; - break; - } - /* Give up after 3rd failure. */ - if (i == 3) - break; - - /* The ieee1394_core guessed the node's speed capability from - * the self ID. Check whether a lower speed works. */ - if (ci->speed_unverified) { - error = nodemgr_check_speed(ci, addr, buffer); - if (!error) - break; - } - if (msleep_interruptible(334)) - return -EINTR; - } - return error; -} - -static struct csr1212_bus_ops nodemgr_csr_ops = { - .bus_read = nodemgr_bus_read, -}; - - -/* - * Basically what we do here is start off retrieving the bus_info block. - * From there will fill in some info about the node, verify it is of IEEE - * 1394 type, and that the crc checks out ok. After that we start off with - * the root directory, and subdirectories. To do this, we retrieve the - * quadlet header for a directory, find out the length, and retrieve the - * complete directory entry (be it a leaf or a directory). We then process - * it and add the info to our structure for that particular node. - * - * We verify CRC's along the way for each directory/block/leaf. The entire - * node structure is generic, and simply stores the information in a way - * that's easy to parse by the protocol interface. - */ - -/* - * The nodemgr relies heavily on the Driver Model for device callbacks and - * driver/device mappings. The old nodemgr used to handle all this itself, - * but now we are much simpler because of the LDM. - */ - -struct host_info { - struct hpsb_host *host; - struct list_head list; - struct task_struct *thread; -}; - -static int nodemgr_bus_match(struct device * dev, struct device_driver * drv); -static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env); - -struct bus_type ieee1394_bus_type = { - .name = "ieee1394", - .match = nodemgr_bus_match, -}; - -static void host_cls_release(struct device *dev) -{ - put_device(&container_of((dev), struct hpsb_host, host_dev)->device); -} - -struct class hpsb_host_class = { - .name = "ieee1394_host", - .dev_release = host_cls_release, -}; - -static void ne_cls_release(struct device *dev) -{ - put_device(&container_of((dev), struct node_entry, node_dev)->device); -} - -static struct class nodemgr_ne_class = { - .name = "ieee1394_node", - .dev_release = ne_cls_release, -}; - -static void ud_cls_release(struct device *dev) -{ - put_device(&container_of((dev), struct unit_directory, unit_dev)->device); -} - -/* The name here is only so that unit directory hotplug works with old - * style hotplug, which only ever did unit directories anyway. - */ -static struct class nodemgr_ud_class = { - .name = "ieee1394", - .dev_release = ud_cls_release, - .dev_uevent = nodemgr_uevent, -}; - -static struct hpsb_highlevel nodemgr_highlevel; - - -static void nodemgr_release_ud(struct device *dev) -{ - struct unit_directory *ud = container_of(dev, struct unit_directory, device); - - if (ud->vendor_name_kv) - csr1212_release_keyval(ud->vendor_name_kv); - if (ud->model_name_kv) - csr1212_release_keyval(ud->model_name_kv); - - kfree(ud); -} - -static void nodemgr_release_ne(struct device *dev) -{ - struct node_entry *ne = container_of(dev, struct node_entry, device); - - if (ne->vendor_name_kv) - csr1212_release_keyval(ne->vendor_name_kv); - - kfree(ne); -} - - -static void nodemgr_release_host(struct device *dev) -{ - struct hpsb_host *host = container_of(dev, struct hpsb_host, device); - - csr1212_destroy_csr(host->csr.rom); - - kfree(host); -} - -static int nodemgr_ud_platform_data; - -static struct device nodemgr_dev_template_ud = { - .bus = &ieee1394_bus_type, - .release = nodemgr_release_ud, - .platform_data = &nodemgr_ud_platform_data, -}; - -static struct device nodemgr_dev_template_ne = { - .bus = &ieee1394_bus_type, - .release = nodemgr_release_ne, -}; - -/* This dummy driver prevents the host devices from being scanned. We have no - * useful drivers for them yet, and there would be a deadlock possible if the - * driver core scans the host device while the host's low-level driver (i.e. - * the host's parent device) is being removed. */ -static struct device_driver nodemgr_mid_layer_driver = { - .bus = &ieee1394_bus_type, - .name = "nodemgr", - .owner = THIS_MODULE, -}; - -struct device nodemgr_dev_template_host = { - .bus = &ieee1394_bus_type, - .release = nodemgr_release_host, -}; - - -#define fw_attr(class, class_type, field, type, format_string) \ -static ssize_t fw_show_##class##_##field (struct device *dev, struct device_attribute *attr, char *buf)\ -{ \ - class_type *class; \ - class = container_of(dev, class_type, device); \ - return sprintf(buf, format_string, (type)class->field); \ -} \ -static struct device_attribute dev_attr_##class##_##field = { \ - .attr = {.name = __stringify(field), .mode = S_IRUGO }, \ - .show = fw_show_##class##_##field, \ -}; - -#define fw_attr_td(class, class_type, td_kv) \ -static ssize_t fw_show_##class##_##td_kv (struct device *dev, struct device_attribute *attr, char *buf)\ -{ \ - int len; \ - class_type *class = container_of(dev, class_type, device); \ - len = (class->td_kv->value.leaf.len - 2) * sizeof(quadlet_t); \ - memcpy(buf, \ - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(class->td_kv), \ - len); \ - while (buf[len - 1] == '\0') \ - len--; \ - buf[len++] = '\n'; \ - buf[len] = '\0'; \ - return len; \ -} \ -static struct device_attribute dev_attr_##class##_##td_kv = { \ - .attr = {.name = __stringify(td_kv), .mode = S_IRUGO }, \ - .show = fw_show_##class##_##td_kv, \ -}; - - -#define fw_drv_attr(field, type, format_string) \ -static ssize_t fw_drv_show_##field (struct device_driver *drv, char *buf) \ -{ \ - struct hpsb_protocol_driver *driver; \ - driver = container_of(drv, struct hpsb_protocol_driver, driver); \ - return sprintf(buf, format_string, (type)driver->field);\ -} \ -static struct driver_attribute driver_attr_drv_##field = { \ - .attr = {.name = __stringify(field), .mode = S_IRUGO }, \ - .show = fw_drv_show_##field, \ -}; - - -static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct node_entry *ne = container_of(dev, struct node_entry, device); - - return sprintf(buf, "IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d) " - "LSPD(%d) MAX_REC(%d) MAX_ROM(%d) CYC_CLK_ACC(%d)\n", - ne->busopt.irmc, - ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc, - ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd, - ne->busopt.max_rec, - ne->busopt.max_rom, - ne->busopt.cyc_clk_acc); -} -static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL); - - -#ifdef HPSB_DEBUG_TLABELS -static ssize_t fw_show_ne_tlabels_free(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct node_entry *ne = container_of(dev, struct node_entry, device); - unsigned long flags; - unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map; - int tf; - - spin_lock_irqsave(&hpsb_tlabel_lock, flags); - tf = 64 - bitmap_weight(tp, 64); - spin_unlock_irqrestore(&hpsb_tlabel_lock, flags); - - return sprintf(buf, "%d\n", tf); -} -static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL); - - -static ssize_t fw_show_ne_tlabels_mask(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct node_entry *ne = container_of(dev, struct node_entry, device); - unsigned long flags; - unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map; - u64 tm; - - spin_lock_irqsave(&hpsb_tlabel_lock, flags); -#if (BITS_PER_LONG <= 32) - tm = ((u64)tp[0] << 32) + tp[1]; -#else - tm = tp[0]; -#endif - spin_unlock_irqrestore(&hpsb_tlabel_lock, flags); - - return sprintf(buf, "0x%016llx\n", (unsigned long long)tm); -} -static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL); -#endif /* HPSB_DEBUG_TLABELS */ - - -static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct unit_directory *ud = container_of(dev, struct unit_directory, device); - int state = simple_strtoul(buf, NULL, 10); - - if (state == 1) { - ud->ignore_driver = 1; - device_release_driver(dev); - } else if (state == 0) - ud->ignore_driver = 0; - - return count; -} -static ssize_t fw_get_ignore_driver(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct unit_directory *ud = container_of(dev, struct unit_directory, device); - - return sprintf(buf, "%d\n", ud->ignore_driver); -} -static DEVICE_ATTR(ignore_driver, S_IWUSR | S_IRUGO, fw_get_ignore_driver, fw_set_ignore_driver); - - -static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf, - size_t count) -{ - int error = 0; - - if (simple_strtoul(buf, NULL, 10) == 1) - error = bus_rescan_devices(&ieee1394_bus_type); - return error ? error : count; -} -static ssize_t fw_get_rescan(struct bus_type *bus, char *buf) -{ - return sprintf(buf, "You can force a rescan of the bus for " - "drivers by writing a 1 to this file\n"); -} -static BUS_ATTR(rescan, S_IWUSR | S_IRUGO, fw_get_rescan, fw_set_rescan); - - -static ssize_t fw_set_ignore_drivers(struct bus_type *bus, const char *buf, size_t count) -{ - int state = simple_strtoul(buf, NULL, 10); - - if (state == 1) - ignore_drivers = 1; - else if (state == 0) - ignore_drivers = 0; - - return count; -} -static ssize_t fw_get_ignore_drivers(struct bus_type *bus, char *buf) -{ - return sprintf(buf, "%d\n", ignore_drivers); -} -static BUS_ATTR(ignore_drivers, S_IWUSR | S_IRUGO, fw_get_ignore_drivers, fw_set_ignore_drivers); - - -struct bus_attribute *const fw_bus_attrs[] = { - &bus_attr_rescan, - &bus_attr_ignore_drivers, - NULL -}; - - -fw_attr(ne, struct node_entry, capabilities, unsigned int, "0x%06x\n") -fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n") - -fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n") -fw_attr_td(ne, struct node_entry, vendor_name_kv) - -fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n") -fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n") -fw_attr(ne, struct node_entry, in_limbo, int, "%d\n"); - -static struct device_attribute *const fw_ne_attrs[] = { - &dev_attr_ne_guid, - &dev_attr_ne_guid_vendor_id, - &dev_attr_ne_capabilities, - &dev_attr_ne_vendor_id, - &dev_attr_ne_nodeid, - &dev_attr_bus_options, -#ifdef HPSB_DEBUG_TLABELS - &dev_attr_tlabels_free, - &dev_attr_tlabels_mask, -#endif -}; - - - -fw_attr(ud, struct unit_directory, address, unsigned long long, "0x%016Lx\n") -fw_attr(ud, struct unit_directory, length, int, "%d\n") -/* These are all dependent on the value being provided */ -fw_attr(ud, struct unit_directory, vendor_id, unsigned int, "0x%06x\n") -fw_attr(ud, struct unit_directory, model_id, unsigned int, "0x%06x\n") -fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n") -fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n") -fw_attr_td(ud, struct unit_directory, vendor_name_kv) -fw_attr_td(ud, struct unit_directory, model_name_kv) - -static struct device_attribute *const fw_ud_attrs[] = { - &dev_attr_ud_address, - &dev_attr_ud_length, - &dev_attr_ignore_driver, -}; - - -fw_attr(host, struct hpsb_host, node_count, int, "%d\n") -fw_attr(host, struct hpsb_host, selfid_count, int, "%d\n") -fw_attr(host, struct hpsb_host, nodes_active, int, "%d\n") -fw_attr(host, struct hpsb_host, in_bus_reset, int, "%d\n") -fw_attr(host, struct hpsb_host, is_root, int, "%d\n") -fw_attr(host, struct hpsb_host, is_cycmst, int, "%d\n") -fw_attr(host, struct hpsb_host, is_irm, int, "%d\n") -fw_attr(host, struct hpsb_host, is_busmgr, int, "%d\n") - -static struct device_attribute *const fw_host_attrs[] = { - &dev_attr_host_node_count, - &dev_attr_host_selfid_count, - &dev_attr_host_nodes_active, - &dev_attr_host_in_bus_reset, - &dev_attr_host_is_root, - &dev_attr_host_is_cycmst, - &dev_attr_host_is_irm, - &dev_attr_host_is_busmgr, -}; - - -static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf) -{ - struct hpsb_protocol_driver *driver; - const struct ieee1394_device_id *id; - int length = 0; - char *scratch = buf; - - driver = container_of(drv, struct hpsb_protocol_driver, driver); - id = driver->id_table; - if (!id) - return 0; - - for (; id->match_flags != 0; id++) { - int need_coma = 0; - - if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) { - length += sprintf(scratch, "vendor_id=0x%06x", id->vendor_id); - scratch = buf + length; - need_coma++; - } - - if (id->match_flags & IEEE1394_MATCH_MODEL_ID) { - length += sprintf(scratch, "%smodel_id=0x%06x", - need_coma++ ? "," : "", - id->model_id); - scratch = buf + length; - } - - if (id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) { - length += sprintf(scratch, "%sspecifier_id=0x%06x", - need_coma++ ? "," : "", - id->specifier_id); - scratch = buf + length; - } - - if (id->match_flags & IEEE1394_MATCH_VERSION) { - length += sprintf(scratch, "%sversion=0x%06x", - need_coma++ ? "," : "", - id->version); - scratch = buf + length; - } - - if (need_coma) { - *scratch++ = '\n'; - length++; - } - } - - return length; -} -static DRIVER_ATTR(device_ids,S_IRUGO,fw_show_drv_device_ids,NULL); - - -fw_drv_attr(name, const char *, "%s\n") - -static struct driver_attribute *const fw_drv_attrs[] = { - &driver_attr_drv_name, - &driver_attr_device_ids, -}; - - -static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver) -{ - struct device_driver *drv = &driver->driver; - int i; - - for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++) - if (driver_create_file(drv, fw_drv_attrs[i])) - goto fail; - return; -fail: - HPSB_ERR("Failed to add sysfs attribute"); -} - - -static void nodemgr_remove_drv_files(struct hpsb_protocol_driver *driver) -{ - struct device_driver *drv = &driver->driver; - int i; - - for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++) - driver_remove_file(drv, fw_drv_attrs[i]); -} - - -static void nodemgr_create_ne_dev_files(struct node_entry *ne) -{ - struct device *dev = &ne->device; - int i; - - for (i = 0; i < ARRAY_SIZE(fw_ne_attrs); i++) - if (device_create_file(dev, fw_ne_attrs[i])) - goto fail; - return; -fail: - HPSB_ERR("Failed to add sysfs attribute"); -} - - -static void nodemgr_create_host_dev_files(struct hpsb_host *host) -{ - struct device *dev = &host->device; - int i; - - for (i = 0; i < ARRAY_SIZE(fw_host_attrs); i++) - if (device_create_file(dev, fw_host_attrs[i])) - goto fail; - return; -fail: - HPSB_ERR("Failed to add sysfs attribute"); -} - - -static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, - nodeid_t nodeid); - -static void nodemgr_update_host_dev_links(struct hpsb_host *host) -{ - struct device *dev = &host->device; - struct node_entry *ne; - - sysfs_remove_link(&dev->kobj, "irm_id"); - sysfs_remove_link(&dev->kobj, "busmgr_id"); - sysfs_remove_link(&dev->kobj, "host_id"); - - if ((ne = find_entry_by_nodeid(host, host->irm_id)) && - sysfs_create_link(&dev->kobj, &ne->device.kobj, "irm_id")) - goto fail; - if ((ne = find_entry_by_nodeid(host, host->busmgr_id)) && - sysfs_create_link(&dev->kobj, &ne->device.kobj, "busmgr_id")) - goto fail; - if ((ne = find_entry_by_nodeid(host, host->node_id)) && - sysfs_create_link(&dev->kobj, &ne->device.kobj, "host_id")) - goto fail; - return; -fail: - HPSB_ERR("Failed to update sysfs attributes for host %d", host->id); -} - -static void nodemgr_create_ud_dev_files(struct unit_directory *ud) -{ - struct device *dev = &ud->device; - int i; - - for (i = 0; i < ARRAY_SIZE(fw_ud_attrs); i++) - if (device_create_file(dev, fw_ud_attrs[i])) - goto fail; - if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) - if (device_create_file(dev, &dev_attr_ud_specifier_id)) - goto fail; - if (ud->flags & UNIT_DIRECTORY_VERSION) - if (device_create_file(dev, &dev_attr_ud_version)) - goto fail; - if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) { - if (device_create_file(dev, &dev_attr_ud_vendor_id)) - goto fail; - if (ud->vendor_name_kv && - device_create_file(dev, &dev_attr_ud_vendor_name_kv)) - goto fail; - } - if (ud->flags & UNIT_DIRECTORY_MODEL_ID) { - if (device_create_file(dev, &dev_attr_ud_model_id)) - goto fail; - if (ud->model_name_kv && - device_create_file(dev, &dev_attr_ud_model_name_kv)) - goto fail; - } - return; -fail: - HPSB_ERR("Failed to add sysfs attribute"); -} - - -static int nodemgr_bus_match(struct device * dev, struct device_driver * drv) -{ - struct hpsb_protocol_driver *driver; - struct unit_directory *ud; - const struct ieee1394_device_id *id; - - /* We only match unit directories */ - if (dev->platform_data != &nodemgr_ud_platform_data) - return 0; - - ud = container_of(dev, struct unit_directory, device); - if (ud->ne->in_limbo || ud->ignore_driver) - return 0; - - /* We only match drivers of type hpsb_protocol_driver */ - if (drv == &nodemgr_mid_layer_driver) - return 0; - - driver = container_of(drv, struct hpsb_protocol_driver, driver); - id = driver->id_table; - if (!id) - return 0; - - for (; id->match_flags != 0; id++) { - if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) && - id->vendor_id != ud->vendor_id) - continue; - - if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) && - id->model_id != ud->model_id) - continue; - - if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) && - id->specifier_id != ud->specifier_id) - continue; - - if ((id->match_flags & IEEE1394_MATCH_VERSION) && - id->version != ud->version) - continue; - - return 1; - } - - return 0; -} - - -static DEFINE_MUTEX(nodemgr_serialize_remove_uds); - -static int match_ne(struct device *dev, void *data) -{ - struct unit_directory *ud; - struct node_entry *ne = data; - - ud = container_of(dev, struct unit_directory, unit_dev); - return ud->ne == ne; -} - -static void nodemgr_remove_uds(struct node_entry *ne) -{ - struct device *dev; - struct unit_directory *ud; - - /* Use class_find device to iterate the devices. Since this code - * may be called from other contexts besides the knodemgrds, - * protect it by nodemgr_serialize_remove_uds. - */ - mutex_lock(&nodemgr_serialize_remove_uds); - for (;;) { - dev = class_find_device(&nodemgr_ud_class, NULL, ne, match_ne); - if (!dev) - break; - ud = container_of(dev, struct unit_directory, unit_dev); - put_device(dev); - device_unregister(&ud->unit_dev); - device_unregister(&ud->device); - } - mutex_unlock(&nodemgr_serialize_remove_uds); -} - - -static void nodemgr_remove_ne(struct node_entry *ne) -{ - struct device *dev; - - dev = get_device(&ne->device); - if (!dev) - return; - - HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", - NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); - nodemgr_remove_uds(ne); - - device_unregister(&ne->node_dev); - device_unregister(dev); - - put_device(dev); -} - -static int remove_host_dev(struct device *dev, void *data) -{ - if (dev->bus == &ieee1394_bus_type) - nodemgr_remove_ne(container_of(dev, struct node_entry, - device)); - return 0; -} - -static void nodemgr_remove_host_dev(struct device *dev) -{ - device_for_each_child(dev, NULL, remove_host_dev); - sysfs_remove_link(&dev->kobj, "irm_id"); - sysfs_remove_link(&dev->kobj, "busmgr_id"); - sysfs_remove_link(&dev->kobj, "host_id"); -} - - -static void nodemgr_update_bus_options(struct node_entry *ne) -{ -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - static const u16 mr[] = { 4, 64, 1024, 0}; -#endif - quadlet_t busoptions = be32_to_cpu(ne->csr->bus_info_data[2]); - - ne->busopt.irmc = (busoptions >> 31) & 1; - ne->busopt.cmc = (busoptions >> 30) & 1; - ne->busopt.isc = (busoptions >> 29) & 1; - ne->busopt.bmc = (busoptions >> 28) & 1; - ne->busopt.pmc = (busoptions >> 27) & 1; - ne->busopt.cyc_clk_acc = (busoptions >> 16) & 0xff; - ne->busopt.max_rec = 1 << (((busoptions >> 12) & 0xf) + 1); - ne->busopt.max_rom = (busoptions >> 8) & 0x3; - ne->busopt.generation = (busoptions >> 4) & 0xf; - ne->busopt.lnkspd = busoptions & 0x7; - - HPSB_VERBOSE("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d " - "cyc_clk_acc=%d max_rec=%d max_rom=%d gen=%d lspd=%d", - busoptions, ne->busopt.irmc, ne->busopt.cmc, - ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc, - ne->busopt.cyc_clk_acc, ne->busopt.max_rec, - mr[ne->busopt.max_rom], - ne->busopt.generation, ne->busopt.lnkspd); -} - - -static struct node_entry *nodemgr_create_node(octlet_t guid, - struct csr1212_csr *csr, struct hpsb_host *host, - nodeid_t nodeid, unsigned int generation) -{ - struct node_entry *ne; - - ne = kzalloc(sizeof(*ne), GFP_KERNEL); - if (!ne) - goto fail_alloc; - - ne->host = host; - ne->nodeid = nodeid; - ne->generation = generation; - ne->needs_probe = true; - - ne->guid = guid; - ne->guid_vendor_id = (guid >> 40) & 0xffffff; - ne->csr = csr; - - memcpy(&ne->device, &nodemgr_dev_template_ne, - sizeof(ne->device)); - ne->device.parent = &host->device; - dev_set_name(&ne->device, "%016Lx", (unsigned long long)(ne->guid)); - - ne->node_dev.parent = &ne->device; - ne->node_dev.class = &nodemgr_ne_class; - dev_set_name(&ne->node_dev, "%016Lx", (unsigned long long)(ne->guid)); - - if (device_register(&ne->device)) - goto fail_devreg; - if (device_register(&ne->node_dev)) - goto fail_classdevreg; - get_device(&ne->device); - - nodemgr_create_ne_dev_files(ne); - - nodemgr_update_bus_options(ne); - - HPSB_DEBUG("%s added: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", - (host->node_id == nodeid) ? "Host" : "Node", - NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid); - - return ne; - -fail_classdevreg: - device_unregister(&ne->device); -fail_devreg: - kfree(ne); -fail_alloc: - HPSB_ERR("Failed to create node ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", - NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid); - - return NULL; -} - -static int match_ne_guid(struct device *dev, void *data) -{ - struct node_entry *ne; - u64 *guid = data; - - ne = container_of(dev, struct node_entry, node_dev); - return ne->guid == *guid; -} - -static struct node_entry *find_entry_by_guid(u64 guid) -{ - struct device *dev; - struct node_entry *ne; - - dev = class_find_device(&nodemgr_ne_class, NULL, &guid, match_ne_guid); - if (!dev) - return NULL; - ne = container_of(dev, struct node_entry, node_dev); - put_device(dev); - - return ne; -} - -struct match_nodeid_parameter { - struct hpsb_host *host; - nodeid_t nodeid; -}; - -static int match_ne_nodeid(struct device *dev, void *data) -{ - int found = 0; - struct node_entry *ne; - struct match_nodeid_parameter *p = data; - - if (!dev) - goto ret; - ne = container_of(dev, struct node_entry, node_dev); - if (ne->host == p->host && ne->nodeid == p->nodeid) - found = 1; -ret: - return found; -} - -static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, - nodeid_t nodeid) -{ - struct device *dev; - struct node_entry *ne; - struct match_nodeid_parameter p; - - p.host = host; - p.nodeid = nodeid; - - dev = class_find_device(&nodemgr_ne_class, NULL, &p, match_ne_nodeid); - if (!dev) - return NULL; - ne = container_of(dev, struct node_entry, node_dev); - put_device(dev); - - return ne; -} - - -static void nodemgr_register_device(struct node_entry *ne, - struct unit_directory *ud, struct device *parent) -{ - memcpy(&ud->device, &nodemgr_dev_template_ud, - sizeof(ud->device)); - - ud->device.parent = parent; - - dev_set_name(&ud->device, "%s-%u", dev_name(&ne->device), ud->id); - - ud->unit_dev.parent = &ud->device; - ud->unit_dev.class = &nodemgr_ud_class; - dev_set_name(&ud->unit_dev, "%s-%u", dev_name(&ne->device), ud->id); - - if (device_register(&ud->device)) - goto fail_devreg; - if (device_register(&ud->unit_dev)) - goto fail_classdevreg; - get_device(&ud->device); - - nodemgr_create_ud_dev_files(ud); - - return; - -fail_classdevreg: - device_unregister(&ud->device); -fail_devreg: - HPSB_ERR("Failed to create unit %s", dev_name(&ud->device)); -} - - -/* This implementation currently only scans the config rom and its - * immediate unit directories looking for software_id and - * software_version entries, in order to get driver autoloading working. */ -static struct unit_directory *nodemgr_process_unit_directory - (struct node_entry *ne, struct csr1212_keyval *ud_kv, - unsigned int *id, struct unit_directory *parent) -{ - struct unit_directory *ud; - struct unit_directory *ud_child = NULL; - struct csr1212_dentry *dentry; - struct csr1212_keyval *kv; - u8 last_key_id = 0; - - ud = kzalloc(sizeof(*ud), GFP_KERNEL); - if (!ud) - goto unit_directory_error; - - ud->ne = ne; - ud->ignore_driver = ignore_drivers; - ud->address = ud_kv->offset + CSR1212_REGISTER_SPACE_BASE; - ud->directory_id = ud->address & 0xffffff; - ud->ud_kv = ud_kv; - ud->id = (*id)++; - - /* inherit vendor_id from root directory if none exists in unit dir */ - ud->vendor_id = ne->vendor_id; - - csr1212_for_each_dir_entry(ne->csr, kv, ud_kv, dentry) { - switch (kv->key.id) { - case CSR1212_KV_ID_VENDOR: - if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) { - ud->vendor_id = kv->value.immediate; - ud->flags |= UNIT_DIRECTORY_VENDOR_ID; - } - break; - - case CSR1212_KV_ID_MODEL: - ud->model_id = kv->value.immediate; - ud->flags |= UNIT_DIRECTORY_MODEL_ID; - break; - - case CSR1212_KV_ID_SPECIFIER_ID: - ud->specifier_id = kv->value.immediate; - ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID; - break; - - case CSR1212_KV_ID_VERSION: - ud->version = kv->value.immediate; - ud->flags |= UNIT_DIRECTORY_VERSION; - break; - - case CSR1212_KV_ID_DESCRIPTOR: - if (kv->key.type == CSR1212_KV_TYPE_LEAF && - CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 && - CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 && - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 && - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 && - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) { - switch (last_key_id) { - case CSR1212_KV_ID_VENDOR: - csr1212_keep_keyval(kv); - ud->vendor_name_kv = kv; - break; - - case CSR1212_KV_ID_MODEL: - csr1212_keep_keyval(kv); - ud->model_name_kv = kv; - break; - - } - } /* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */ - break; - - case CSR1212_KV_ID_DEPENDENT_INFO: - /* Logical Unit Number */ - if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) { - if (ud->flags & UNIT_DIRECTORY_HAS_LUN) { - ud_child = kmemdup(ud, sizeof(*ud_child), GFP_KERNEL); - if (!ud_child) - goto unit_directory_error; - nodemgr_register_device(ne, ud_child, &ne->device); - ud_child = NULL; - - ud->id = (*id)++; - } - ud->lun = kv->value.immediate; - ud->flags |= UNIT_DIRECTORY_HAS_LUN; - - /* Logical Unit Directory */ - } else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) { - /* This should really be done in SBP2 as this is - * doing SBP2 specific parsing. - */ - - /* first register the parent unit */ - ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY; - if (ud->device.bus != &ieee1394_bus_type) - nodemgr_register_device(ne, ud, &ne->device); - - /* process the child unit */ - ud_child = nodemgr_process_unit_directory(ne, kv, id, ud); - - if (ud_child == NULL) - break; - - /* inherit unspecified values, the driver core picks it up */ - if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) && - !(ud_child->flags & UNIT_DIRECTORY_MODEL_ID)) - { - ud_child->flags |= UNIT_DIRECTORY_MODEL_ID; - ud_child->model_id = ud->model_id; - } - if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) && - !(ud_child->flags & UNIT_DIRECTORY_SPECIFIER_ID)) - { - ud_child->flags |= UNIT_DIRECTORY_SPECIFIER_ID; - ud_child->specifier_id = ud->specifier_id; - } - if ((ud->flags & UNIT_DIRECTORY_VERSION) && - !(ud_child->flags & UNIT_DIRECTORY_VERSION)) - { - ud_child->flags |= UNIT_DIRECTORY_VERSION; - ud_child->version = ud->version; - } - - /* register the child unit */ - ud_child->flags |= UNIT_DIRECTORY_LUN_DIRECTORY; - nodemgr_register_device(ne, ud_child, &ud->device); - } - - break; - - case CSR1212_KV_ID_DIRECTORY_ID: - ud->directory_id = kv->value.immediate; - break; - - default: - break; - } - last_key_id = kv->key.id; - } - - /* do not process child units here and only if not already registered */ - if (!parent && ud->device.bus != &ieee1394_bus_type) - nodemgr_register_device(ne, ud, &ne->device); - - return ud; - -unit_directory_error: - kfree(ud); - return NULL; -} - - -static void nodemgr_process_root_directory(struct node_entry *ne) -{ - unsigned int ud_id = 0; - struct csr1212_dentry *dentry; - struct csr1212_keyval *kv, *vendor_name_kv = NULL; - u8 last_key_id = 0; - - ne->needs_probe = false; - - csr1212_for_each_dir_entry(ne->csr, kv, ne->csr->root_kv, dentry) { - switch (kv->key.id) { - case CSR1212_KV_ID_VENDOR: - ne->vendor_id = kv->value.immediate; - break; - - case CSR1212_KV_ID_NODE_CAPABILITIES: - ne->capabilities = kv->value.immediate; - break; - - case CSR1212_KV_ID_UNIT: - nodemgr_process_unit_directory(ne, kv, &ud_id, NULL); - break; - - case CSR1212_KV_ID_DESCRIPTOR: - if (last_key_id == CSR1212_KV_ID_VENDOR) { - if (kv->key.type == CSR1212_KV_TYPE_LEAF && - CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 && - CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 && - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 && - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 && - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) { - csr1212_keep_keyval(kv); - vendor_name_kv = kv; - } - } - break; - } - last_key_id = kv->key.id; - } - - if (ne->vendor_name_kv) { - kv = ne->vendor_name_kv; - ne->vendor_name_kv = vendor_name_kv; - csr1212_release_keyval(kv); - } else if (vendor_name_kv) { - ne->vendor_name_kv = vendor_name_kv; - if (device_create_file(&ne->device, - &dev_attr_ne_vendor_name_kv) != 0) - HPSB_ERR("Failed to add sysfs attribute"); - } -} - -#ifdef CONFIG_HOTPLUG - -static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct unit_directory *ud; - int retval = 0; - /* ieee1394:venNmoNspNverN */ - char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1]; - - if (!dev) - return -ENODEV; - - ud = container_of(dev, struct unit_directory, unit_dev); - - if (ud->ne->in_limbo || ud->ignore_driver) - return -ENODEV; - -#define PUT_ENVP(fmt,val) \ -do { \ - retval = add_uevent_var(env, fmt, val); \ - if (retval) \ - return retval; \ -} while (0) - - PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id); - PUT_ENVP("MODEL_ID=%06x", ud->model_id); - PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid); - PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id); - PUT_ENVP("VERSION=%06x", ud->version); - snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X", - ud->vendor_id, - ud->model_id, - ud->specifier_id, - ud->version); - PUT_ENVP("MODALIAS=%s", buf); - -#undef PUT_ENVP - - return 0; -} - -#else - -static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return -ENODEV; -} - -#endif /* CONFIG_HOTPLUG */ - - -int __hpsb_register_protocol(struct hpsb_protocol_driver *drv, - struct module *owner) -{ - int error; - - drv->driver.bus = &ieee1394_bus_type; - drv->driver.owner = owner; - drv->driver.name = drv->name; - - /* This will cause a probe for devices */ - error = driver_register(&drv->driver); - if (!error) - nodemgr_create_drv_files(drv); - return error; -} - -void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver) -{ - nodemgr_remove_drv_files(driver); - /* This will subsequently disconnect all devices that our driver - * is attached to. */ - driver_unregister(&driver->driver); -} - - -/* - * This function updates nodes that were present on the bus before the - * reset and still are after the reset. The nodeid and the config rom - * may have changed, and the drivers managing this device must be - * informed that this device just went through a bus reset, to allow - * the to take whatever actions required. - */ -static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr, - nodeid_t nodeid, unsigned int generation) -{ - if (ne->nodeid != nodeid) { - HPSB_DEBUG("Node changed: " NODE_BUS_FMT " -> " NODE_BUS_FMT, - NODE_BUS_ARGS(ne->host, ne->nodeid), - NODE_BUS_ARGS(ne->host, nodeid)); - ne->nodeid = nodeid; - } - - if (ne->busopt.generation != ((be32_to_cpu(csr->bus_info_data[2]) >> 4) & 0xf)) { - kfree(ne->csr->private); - csr1212_destroy_csr(ne->csr); - ne->csr = csr; - - /* If the node's configrom generation has changed, we - * unregister all the unit directories. */ - nodemgr_remove_uds(ne); - - nodemgr_update_bus_options(ne); - - /* Mark the node as new, so it gets re-probed */ - ne->needs_probe = true; - } else { - /* old cache is valid, so update its generation */ - struct nodemgr_csr_info *ci = ne->csr->private; - ci->generation = generation; - /* free the partially filled now unneeded new cache */ - kfree(csr->private); - csr1212_destroy_csr(csr); - } - - /* Finally, mark the node current */ - smp_wmb(); - ne->generation = generation; - - if (ne->in_limbo) { - device_remove_file(&ne->device, &dev_attr_ne_in_limbo); - ne->in_limbo = false; - - HPSB_DEBUG("Node reactivated: " - "ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", - NODE_BUS_ARGS(ne->host, ne->nodeid), - (unsigned long long)ne->guid); - } -} - -static void nodemgr_node_scan_one(struct hpsb_host *host, - nodeid_t nodeid, int generation) -{ - struct node_entry *ne; - octlet_t guid; - struct csr1212_csr *csr; - struct nodemgr_csr_info *ci; - u8 *speed; - - ci = kmalloc(sizeof(*ci), GFP_KERNEL); - kmemcheck_annotate_bitfield(ci, flags); - if (!ci) - return; - - ci->host = host; - ci->nodeid = nodeid; - ci->generation = generation; - - /* Prepare for speed probe which occurs when reading the ROM */ - speed = &(host->speed[NODEID_TO_NODE(nodeid)]); - if (*speed > host->csr.lnk_spd) - *speed = host->csr.lnk_spd; - ci->speed_unverified = *speed > IEEE1394_SPEED_100; - - /* We need to detect when the ConfigROM's generation has changed, - * so we only update the node's info when it needs to be. */ - - csr = csr1212_create_csr(&nodemgr_csr_ops, 5 * sizeof(quadlet_t), ci); - if (!csr || csr1212_parse_csr(csr) != CSR1212_SUCCESS) { - HPSB_ERR("Error parsing configrom for node " NODE_BUS_FMT, - NODE_BUS_ARGS(host, nodeid)); - if (csr) - csr1212_destroy_csr(csr); - kfree(ci); - return; - } - - if (csr->bus_info_data[1] != IEEE1394_BUSID_MAGIC) { - /* This isn't a 1394 device, but we let it slide. There - * was a report of a device with broken firmware which - * reported '2394' instead of '1394', which is obviously a - * mistake. One would hope that a non-1394 device never - * gets connected to Firewire bus. If someone does, we - * shouldn't be held responsible, so we'll allow it with a - * warning. */ - HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]", - NODE_BUS_ARGS(host, nodeid), csr->bus_info_data[1]); - } - - guid = ((u64)be32_to_cpu(csr->bus_info_data[3]) << 32) | be32_to_cpu(csr->bus_info_data[4]); - ne = find_entry_by_guid(guid); - - if (ne && ne->host != host && ne->in_limbo) { - /* Must have moved this device from one host to another */ - nodemgr_remove_ne(ne); - ne = NULL; - } - - if (!ne) - nodemgr_create_node(guid, csr, host, nodeid, generation); - else - nodemgr_update_node(ne, csr, nodeid, generation); -} - - -static void nodemgr_node_scan(struct hpsb_host *host, int generation) -{ - int count; - struct selfid *sid = (struct selfid *)host->topology_map; - nodeid_t nodeid = LOCAL_BUS; - - /* Scan each node on the bus */ - for (count = host->selfid_count; count; count--, sid++) { - if (sid->extended) - continue; - - if (!sid->link_active) { - nodeid++; - continue; - } - nodemgr_node_scan_one(host, nodeid++, generation); - } -} - -static void nodemgr_pause_ne(struct node_entry *ne) -{ - HPSB_DEBUG("Node paused: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", - NODE_BUS_ARGS(ne->host, ne->nodeid), - (unsigned long long)ne->guid); - - ne->in_limbo = true; - WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo)); -} - -static int update_pdrv(struct device *dev, void *data) -{ - struct unit_directory *ud; - struct device_driver *drv; - struct hpsb_protocol_driver *pdrv; - struct node_entry *ne = data; - int error; - - ud = container_of(dev, struct unit_directory, unit_dev); - if (ud->ne == ne) { - drv = get_driver(ud->device.driver); - if (drv) { - error = 0; - pdrv = container_of(drv, struct hpsb_protocol_driver, - driver); - if (pdrv->update) { - device_lock(&ud->device); - error = pdrv->update(ud); - device_unlock(&ud->device); - } - if (error) - device_release_driver(&ud->device); - put_driver(drv); - } - } - - return 0; -} - -static void nodemgr_update_pdrv(struct node_entry *ne) -{ - class_for_each_device(&nodemgr_ud_class, NULL, ne, update_pdrv); -} - -/* Write the BROADCAST_CHANNEL as per IEEE1394a 8.3.2.3.11 and 8.4.2.3. This - * seems like an optional service but in the end it is practically mandatory - * as a consequence of these clauses. - * - * Note that we cannot do a broadcast write to all nodes at once because some - * pre-1394a devices would hang. */ -static void nodemgr_irm_write_bc(struct node_entry *ne, int generation) -{ - const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL); - quadlet_t bc_remote, bc_local; - int error; - - if (!ne->host->is_irm || ne->generation != generation || - ne->nodeid == ne->host->node_id) - return; - - bc_local = cpu_to_be32(ne->host->csr.broadcast_channel); - - /* Check if the register is implemented and 1394a compliant. */ - error = hpsb_read(ne->host, ne->nodeid, generation, bc_addr, &bc_remote, - sizeof(bc_remote)); - if (!error && bc_remote & cpu_to_be32(0x80000000) && - bc_remote != bc_local) - hpsb_node_write(ne, bc_addr, &bc_local, sizeof(bc_local)); -} - - -static void nodemgr_probe_ne(struct hpsb_host *host, struct node_entry *ne, - int generation) -{ - struct device *dev; - - if (ne->host != host || ne->in_limbo) - return; - - dev = get_device(&ne->device); - if (!dev) - return; - - nodemgr_irm_write_bc(ne, generation); - - /* If "needs_probe", then this is either a new or changed node we - * rescan totally. If the generation matches for an existing node - * (one that existed prior to the bus reset) we send update calls - * down to the drivers. Otherwise, this is a dead node and we - * suspend it. */ - if (ne->needs_probe) - nodemgr_process_root_directory(ne); - else if (ne->generation == generation) - nodemgr_update_pdrv(ne); - else - nodemgr_pause_ne(ne); - - put_device(dev); -} - -struct node_probe_parameter { - struct hpsb_host *host; - int generation; - bool probe_now; -}; - -static int node_probe(struct device *dev, void *data) -{ - struct node_probe_parameter *p = data; - struct node_entry *ne; - - if (p->generation != get_hpsb_generation(p->host)) - return -EAGAIN; - - ne = container_of(dev, struct node_entry, node_dev); - if (ne->needs_probe == p->probe_now) - nodemgr_probe_ne(p->host, ne, p->generation); - return 0; -} - -static int nodemgr_node_probe(struct hpsb_host *host, int generation) -{ - struct node_probe_parameter p; - - p.host = host; - p.generation = generation; - /* - * Do some processing of the nodes we've probed. This pulls them - * into the sysfs layer if needed, and can result in processing of - * unit-directories, or just updating the node and it's - * unit-directories. - * - * Run updates before probes. Usually, updates are time-critical - * while probes are time-consuming. - * - * Meanwhile, another bus reset may have happened. In this case we - * skip everything here and let the next bus scan handle it. - * Otherwise we may prematurely remove nodes which are still there. - */ - p.probe_now = false; - if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0) - return 0; - - p.probe_now = true; - if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0) - return 0; - /* - * Now let's tell the bus to rescan our devices. This may seem - * like overhead, but the driver-model core will only scan a - * device for a driver when either the device is added, or when a - * new driver is added. A bus reset is a good reason to rescan - * devices that were there before. For example, an sbp2 device - * may become available for login, if the host that held it was - * just removed. - */ - if (bus_rescan_devices(&ieee1394_bus_type) != 0) - HPSB_DEBUG("bus_rescan_devices had an error"); - - return 1; -} - -static int remove_nodes_in_limbo(struct device *dev, void *data) -{ - struct node_entry *ne; - - if (dev->bus != &ieee1394_bus_type) - return 0; - - ne = container_of(dev, struct node_entry, device); - if (ne->in_limbo) - nodemgr_remove_ne(ne); - - return 0; -} - -static void nodemgr_remove_nodes_in_limbo(struct hpsb_host *host) -{ - device_for_each_child(&host->device, NULL, remove_nodes_in_limbo); -} - -static int nodemgr_send_resume_packet(struct hpsb_host *host) -{ - struct hpsb_packet *packet; - int error = -ENOMEM; - - packet = hpsb_make_phypacket(host, - EXTPHYPACKET_TYPE_RESUME | - NODEID_TO_NODE(host->node_id) << PHYPACKET_PORT_SHIFT); - if (packet) { - packet->no_waiter = 1; - packet->generation = get_hpsb_generation(host); - error = hpsb_send_packet(packet); - } - if (error) - HPSB_WARN("fw-host%d: Failed to broadcast resume packet", - host->id); - return error; -} - -/* Perform a few high-level IRM responsibilities. */ -static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles) -{ - quadlet_t bc; - - /* if irm_id == -1 then there is no IRM on this bus */ - if (!host->is_irm || host->irm_id == (nodeid_t)-1) - return 1; - - /* We are a 1394a-2000 compliant IRM. Set the validity bit. */ - host->csr.broadcast_channel |= 0x40000000; - - /* If there is no bus manager then we should set the root node's - * force_root bit to promote bus stability per the 1394 - * spec. (8.4.2.6) */ - if (host->busmgr_id == 0xffff && host->node_count > 1) - { - u16 root_node = host->node_count - 1; - - /* get cycle master capability flag from root node */ - if (host->is_cycmst || - (!hpsb_read(host, LOCAL_BUS | root_node, get_hpsb_generation(host), - (CSR_REGISTER_BASE + CSR_CONFIG_ROM + 2 * sizeof(quadlet_t)), - &bc, sizeof(quadlet_t)) && - be32_to_cpu(bc) & 1 << CSR_CMC_SHIFT)) - hpsb_send_phy_config(host, root_node, -1); - else { - HPSB_DEBUG("The root node is not cycle master capable; " - "selecting a new root node and resetting..."); - - if (cycles >= 5) { - /* Oh screw it! Just leave the bus as it is */ - HPSB_DEBUG("Stopping reset loop for IRM sanity"); - return 1; - } - - hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1); - hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT); - - return 0; - } - } - - /* Some devices suspend their ports while being connected to an inactive - * host adapter, i.e. if connected before the low-level driver is - * loaded. They become visible either when physically unplugged and - * replugged, or when receiving a resume packet. Send one once. */ - if (!host->resume_packet_sent && !nodemgr_send_resume_packet(host)) - host->resume_packet_sent = 1; - - return 1; -} - -/* We need to ensure that if we are not the IRM, that the IRM node is capable of - * everything we can do, otherwise issue a bus reset and try to become the IRM - * ourselves. */ -static int nodemgr_check_irm_capability(struct hpsb_host *host, int cycles) -{ - quadlet_t bc; - int status; - - if (hpsb_disable_irm || host->is_irm) - return 1; - - status = hpsb_read(host, LOCAL_BUS | (host->irm_id), - get_hpsb_generation(host), - (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL), - &bc, sizeof(quadlet_t)); - - if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) { - /* The current irm node does not have a valid BROADCAST_CHANNEL - * register and we do, so reset the bus with force_root set */ - HPSB_DEBUG("Current remote IRM is not 1394a-2000 compliant, resetting..."); - - if (cycles >= 5) { - /* Oh screw it! Just leave the bus as it is */ - HPSB_DEBUG("Stopping reset loop for IRM sanity"); - return 1; - } - - hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1); - hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT); - - return 0; - } - - return 1; -} - -static int nodemgr_host_thread(void *data) -{ - struct hpsb_host *host = data; - unsigned int g, generation = 0; - int i, reset_cycles = 0; - - set_freezable(); - /* Setup our device-model entries */ - nodemgr_create_host_dev_files(host); - - for (;;) { - /* Sleep until next bus reset */ - set_current_state(TASK_INTERRUPTIBLE); - if (get_hpsb_generation(host) == generation && - !kthread_should_stop()) - schedule(); - __set_current_state(TASK_RUNNING); - - /* Thread may have been woken up to freeze or to exit */ - if (try_to_freeze()) - continue; - if (kthread_should_stop()) - goto exit; - - /* Pause for 1/4 second in 1/16 second intervals, - * to make sure things settle down. */ - g = get_hpsb_generation(host); - for (i = 0; i < 4 ; i++) { - msleep_interruptible(63); - try_to_freeze(); - if (kthread_should_stop()) - goto exit; - - /* Now get the generation in which the node ID's we collect - * are valid. During the bus scan we will use this generation - * for the read transactions, so that if another reset occurs - * during the scan the transactions will fail instead of - * returning bogus data. */ - generation = get_hpsb_generation(host); - - /* If we get a reset before we are done waiting, then - * start the waiting over again */ - if (generation != g) - g = generation, i = 0; - } - - if (!nodemgr_check_irm_capability(host, reset_cycles) || - !nodemgr_do_irm_duties(host, reset_cycles)) { - reset_cycles++; - continue; - } - reset_cycles = 0; - - /* Scan our nodes to get the bus options and create node - * entries. This does not do the sysfs stuff, since that - * would trigger uevents and such, which is a bad idea at - * this point. */ - nodemgr_node_scan(host, generation); - - /* This actually does the full probe, with sysfs - * registration. */ - if (!nodemgr_node_probe(host, generation)) - continue; - - /* Update some of our sysfs symlinks */ - nodemgr_update_host_dev_links(host); - - /* Sleep 3 seconds */ - for (i = 3000/200; i; i--) { - msleep_interruptible(200); - try_to_freeze(); - if (kthread_should_stop()) - goto exit; - - if (generation != get_hpsb_generation(host)) - break; - } - /* Remove nodes which are gone, unless a bus reset happened */ - if (!i) - nodemgr_remove_nodes_in_limbo(host); - } -exit: - HPSB_VERBOSE("NodeMgr: Exiting thread"); - return 0; -} - -struct per_host_parameter { - void *data; - int (*cb)(struct hpsb_host *, void *); -}; - -static int per_host(struct device *dev, void *data) -{ - struct hpsb_host *host; - struct per_host_parameter *p = data; - - host = container_of(dev, struct hpsb_host, host_dev); - return p->cb(host, p->data); -} - -/** - * nodemgr_for_each_host - call a function for each IEEE 1394 host - * @data: an address to supply to the callback - * @cb: function to call for each host - * - * Iterate the hosts, calling a given function with supplied data for each host. - * If the callback fails on a host, i.e. if it returns a non-zero value, the - * iteration is stopped. - * - * Return value: 0 on success, non-zero on failure (same as returned by last run - * of the callback). - */ -int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)) -{ - struct per_host_parameter p; - - p.cb = cb; - p.data = data; - return class_for_each_device(&hpsb_host_class, NULL, &p, per_host); -} - -/* The following two convenience functions use a struct node_entry - * for addressing a node on the bus. They are intended for use by any - * process context, not just the nodemgr thread, so we need to be a - * little careful when reading out the node ID and generation. The - * thing that can go wrong is that we get the node ID, then a bus - * reset occurs, and then we read the generation. The node ID is - * possibly invalid, but the generation is current, and we end up - * sending a packet to a the wrong node. - * - * The solution is to make sure we read the generation first, so that - * if a reset occurs in the process, we end up with a stale generation - * and the transactions will fail instead of silently using wrong node - * ID's. - */ - -/** - * hpsb_node_fill_packet - fill some destination information into a packet - * @ne: destination node - * @packet: packet to fill in - * - * This will fill in the given, pre-initialised hpsb_packet with the current - * information from the node entry (host, node ID, bus generation number). - */ -void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet) -{ - packet->host = ne->host; - packet->generation = ne->generation; - smp_rmb(); - packet->node_id = ne->nodeid; -} - -int hpsb_node_write(struct node_entry *ne, u64 addr, - quadlet_t *buffer, size_t length) -{ - unsigned int generation = ne->generation; - - smp_rmb(); - return hpsb_write(ne->host, ne->nodeid, generation, - addr, buffer, length); -} - -static void nodemgr_add_host(struct hpsb_host *host) -{ - struct host_info *hi; - - hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi)); - if (!hi) { - HPSB_ERR("NodeMgr: out of memory in add host"); - return; - } - hi->host = host; - hi->thread = kthread_run(nodemgr_host_thread, host, "knodemgrd_%d", - host->id); - if (IS_ERR(hi->thread)) { - HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id); - hpsb_destroy_hostinfo(&nodemgr_highlevel, host); - } -} - -static void nodemgr_host_reset(struct hpsb_host *host) -{ - struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); - - if (hi) { - HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id); - wake_up_process(hi->thread); - } -} - -static void nodemgr_remove_host(struct hpsb_host *host) -{ - struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); - - if (hi) { - kthread_stop(hi->thread); - nodemgr_remove_host_dev(&host->device); - } -} - -static struct hpsb_highlevel nodemgr_highlevel = { - .name = "Node manager", - .add_host = nodemgr_add_host, - .host_reset = nodemgr_host_reset, - .remove_host = nodemgr_remove_host, -}; - -int init_ieee1394_nodemgr(void) -{ - int error; - - error = class_register(&nodemgr_ne_class); - if (error) - goto fail_ne; - error = class_register(&nodemgr_ud_class); - if (error) - goto fail_ud; - error = driver_register(&nodemgr_mid_layer_driver); - if (error) - goto fail_ml; - /* This driver is not used if nodemgr is off (disable_nodemgr=1). */ - nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver; - - hpsb_register_highlevel(&nodemgr_highlevel); - return 0; - -fail_ml: - class_unregister(&nodemgr_ud_class); -fail_ud: - class_unregister(&nodemgr_ne_class); -fail_ne: - return error; -} - -void cleanup_ieee1394_nodemgr(void) -{ - hpsb_unregister_highlevel(&nodemgr_highlevel); - driver_unregister(&nodemgr_mid_layer_driver); - class_unregister(&nodemgr_ud_class); - class_unregister(&nodemgr_ne_class); -} diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h deleted file mode 100644 index 749b271d310..00000000000 --- a/drivers/ieee1394/nodemgr.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c deleted file mode 100644 index 50815022cff..00000000000 --- a/drivers/ieee1394/ohci1394.c +++ /dev/null @@ -1,3590 +0,0 @@ -/* - * ohci1394.c - driver for OHCI 1394 boards - * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au> - * Gord Peters <GordPeters@smarttech.com> - * 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. - */ - -/* - * Things known to be working: - * . Async Request Transmit - * . Async Response Receive - * . Async Request Receive - * . Async Response Transmit - * . Iso Receive - * . DMA mmap for iso receive - * . Config ROM generation - * - * Things implemented, but still in test phase: - * . Iso Transmit - * . Async Stream Packets Transmit (Receive done via Iso interface) - * - * Things not implemented: - * . DMA error recovery - * - * Known bugs: - * . devctl BUS_RESET arg confusion (reset type or root holdoff?) - * added LONG_RESET_ROOT and SHORT_RESET_ROOT for root holdoff --kk - */ - -/* - * Acknowledgments: - * - * Adam J Richter <adam@yggdrasil.com> - * . Use of pci_class to find device - * - * Emilie Chung <emilie.chung@axis.com> - * . Tip on Async Request Filter - * - * Pascal Drolet <pascal.drolet@informission.ca> - * . Various tips for optimization and functionnalities - * - * Robert Ficklin <rficklin@westengineering.com> - * . Loop in irq_handler - * - * James Goodwin <jamesg@Filanet.com> - * . Various tips on initialization, self-id reception, etc. - * - * Albrecht Dress <ad@mpifr-bonn.mpg.de> - * . Apple PowerBook detection - * - * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de> - * . Reset the board properly before leaving + misc cleanups - * - * Leon van Stuivenberg <leonvs@iae.nl> - * . Bug fixes - * - * Ben Collins <bcollins@debian.org> - * . Working big-endian support - * . Updated to 2.4.x module scheme (PCI aswell) - * . Config ROM generation - * - * Manfred Weihs <weihs@ict.tuwien.ac.at> - * . Reworked code for initiating bus resets - * (long, short, with or without hold-off) - * - * Nandu Santhi <contactnandu@users.sourceforge.net> - * . Added support for nVidia nForce2 onboard Firewire chipset - * - */ - -#include <linux/bitops.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/wait.h> -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/pci.h> -#include <linux/fs.h> -#include <linux/poll.h> -#include <asm/byteorder.h> -#include <asm/atomic.h> -#include <asm/uaccess.h> -#include <linux/delay.h> -#include <linux/spinlock.h> - -#include <asm/pgtable.h> -#include <asm/page.h> -#include <asm/irq.h> -#include <linux/types.h> -#include <linux/vmalloc.h> -#include <linux/init.h> - -#ifdef CONFIG_PPC_PMAC -#include <asm/machdep.h> -#include <asm/pmac_feature.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#endif - -#include "csr1212.h" -#include "ieee1394.h" -#include "ieee1394_types.h" -#include "hosts.h" -#include "dma.h" -#include "iso.h" -#include "ieee1394_core.h" -#include "highlevel.h" -#include "ohci1394.h" - -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG -#define OHCI1394_DEBUG -#endif - -#ifdef DBGMSG -#undef DBGMSG -#endif - -#ifdef OHCI1394_DEBUG -#define DBGMSG(fmt, args...) \ -printk(KERN_INFO "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args) -#else -#define DBGMSG(fmt, args...) do {} while (0) -#endif - -/* print general (card independent) information */ -#define PRINT_G(level, fmt, args...) \ -printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args) - -/* print card specific information */ -#define PRINT(level, fmt, args...) \ -printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args) - -/* Module Parameters */ -static int phys_dma = 1; -module_param(phys_dma, int, 0444); -MODULE_PARM_DESC(phys_dma, "Enable physical DMA (default = 1)."); - -static void dma_trm_tasklet(unsigned long data); -static void dma_trm_reset(struct dma_trm_ctx *d); - -static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, - enum context_type type, int ctx, int num_desc, - int buf_size, int split_buf_size, int context_base); -static void free_dma_rcv_ctx(struct dma_rcv_ctx *d); - -static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, - enum context_type type, int ctx, int num_desc, - int context_base); - -static void ohci1394_pci_remove(struct pci_dev *pdev); - -#ifndef __LITTLE_ENDIAN -static const size_t hdr_sizes[] = { - 3, /* TCODE_WRITEQ */ - 4, /* TCODE_WRITEB */ - 3, /* TCODE_WRITE_RESPONSE */ - 0, /* reserved */ - 3, /* TCODE_READQ */ - 4, /* TCODE_READB */ - 3, /* TCODE_READQ_RESPONSE */ - 4, /* TCODE_READB_RESPONSE */ - 1, /* TCODE_CYCLE_START */ - 4, /* TCODE_LOCK_REQUEST */ - 2, /* TCODE_ISO_DATA */ - 4, /* TCODE_LOCK_RESPONSE */ - /* rest is reserved or link-internal */ -}; - -static inline void header_le32_to_cpu(quadlet_t *data, unsigned char tcode) -{ - size_t size; - - if (unlikely(tcode >= ARRAY_SIZE(hdr_sizes))) - return; - - size = hdr_sizes[tcode]; - while (size--) - data[size] = le32_to_cpu(data[size]); -} -#else -#define header_le32_to_cpu(w,x) do {} while (0) -#endif /* !LITTLE_ENDIAN */ - -/*********************************** - * IEEE-1394 functionality section * - ***********************************/ - -static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr) -{ - int i; - unsigned long flags; - quadlet_t r; - - spin_lock_irqsave (&ohci->phy_reg_lock, flags); - - reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000); - - for (i = 0; i < OHCI_LOOP_COUNT; i++) { - if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000) - break; - - mdelay(1); - } - - r = reg_read(ohci, OHCI1394_PhyControl); - - if (i >= OHCI_LOOP_COUNT) - PRINT (KERN_ERR, "Get PHY Reg timeout [0x%08x/0x%08x/%d]", - r, r & 0x80000000, i); - - spin_unlock_irqrestore (&ohci->phy_reg_lock, flags); - - return (r & 0x00ff0000) >> 16; -} - -static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data) -{ - int i; - unsigned long flags; - u32 r = 0; - - spin_lock_irqsave (&ohci->phy_reg_lock, flags); - - reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000); - - for (i = 0; i < OHCI_LOOP_COUNT; i++) { - r = reg_read(ohci, OHCI1394_PhyControl); - if (!(r & 0x00004000)) - break; - - mdelay(1); - } - - if (i == OHCI_LOOP_COUNT) - PRINT (KERN_ERR, "Set PHY Reg timeout [0x%08x/0x%08x/%d]", - r, r & 0x00004000, i); - - spin_unlock_irqrestore (&ohci->phy_reg_lock, flags); - - return; -} - -/* Or's our value into the current value */ -static void set_phy_reg_mask(struct ti_ohci *ohci, u8 addr, u8 data) -{ - u8 old; - - old = get_phy_reg (ohci, addr); - old |= data; - set_phy_reg (ohci, addr, old); - - return; -} - -static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host, - int phyid, int isroot) -{ - quadlet_t *q = ohci->selfid_buf_cpu; - quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount); - size_t size; - quadlet_t q0, q1; - - /* Check status of self-id reception */ - - if (ohci->selfid_swap) - q0 = le32_to_cpu(q[0]); - else - q0 = q[0]; - - if ((self_id_count & 0x80000000) || - ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) { - PRINT(KERN_ERR, - "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)", - self_id_count, q0, ohci->self_id_errors); - - /* Tip by James Goodwin <jamesg@Filanet.com>: - * We had an error, generate another bus reset in response. */ - if (ohci->self_id_errors<OHCI1394_MAX_SELF_ID_ERRORS) { - set_phy_reg_mask (ohci, 1, 0x40); - ohci->self_id_errors++; - } else { - PRINT(KERN_ERR, - "Too many errors on SelfID error reception, giving up!"); - } - return; - } - - /* SelfID Ok, reset error counter. */ - ohci->self_id_errors = 0; - - size = ((self_id_count & 0x00001FFC) >> 2) - 1; - q++; - - while (size > 0) { - if (ohci->selfid_swap) { - q0 = le32_to_cpu(q[0]); - q1 = le32_to_cpu(q[1]); - } else { - q0 = q[0]; - q1 = q[1]; - } - - if (q0 == ~q1) { - DBGMSG ("SelfID packet 0x%x received", q0); - hpsb_selfid_received(host, cpu_to_be32(q0)); - if (((q0 & 0x3f000000) >> 24) == phyid) - DBGMSG ("SelfID for this node is 0x%08x", q0); - } else { - PRINT(KERN_ERR, - "SelfID is inconsistent [0x%08x/0x%08x]", q0, q1); - } - q += 2; - size -= 2; - } - - DBGMSG("SelfID complete"); - - return; -} - -static void ohci_soft_reset(struct ti_ohci *ohci) { - int i; - - reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset); - - for (i = 0; i < OHCI_LOOP_COUNT; i++) { - if (!(reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset)) - break; - mdelay(1); - } - DBGMSG ("Soft reset finished"); -} - - -/* Generate the dma receive prgs and start the context */ -static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d, int generate_irq) -{ - struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); - int i; - - ohci1394_stop_context(ohci, d->ctrlClear, NULL); - - for (i=0; i<d->num_desc; i++) { - u32 c; - - c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH; - if (generate_irq) - c |= DMA_CTL_IRQ; - - d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size); - - /* End of descriptor list? */ - if (i + 1 < d->num_desc) { - d->prg_cpu[i]->branchAddress = - cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1); - } else { - d->prg_cpu[i]->branchAddress = - cpu_to_le32((d->prg_bus[0] & 0xfffffff0)); - } - - d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]); - d->prg_cpu[i]->status = cpu_to_le32(d->buf_size); - } - - d->buf_ind = 0; - d->buf_offset = 0; - - if (d->type == DMA_CTX_ISO) { - /* Clear contextControl */ - reg_write(ohci, d->ctrlClear, 0xffffffff); - - /* Set bufferFill, isochHeader, multichannel for IR context */ - reg_write(ohci, d->ctrlSet, 0xd0000000); - - /* Set the context match register to match on all tags */ - reg_write(ohci, d->ctxtMatch, 0xf0000000); - - /* Clear the multi channel mask high and low registers */ - reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff); - reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff); - - /* Set up isoRecvIntMask to generate interrupts */ - reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << d->ctx); - } - - /* Tell the controller where the first AR program is */ - reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1); - - /* Run context */ - reg_write(ohci, d->ctrlSet, 0x00008000); - - DBGMSG("Receive DMA ctx=%d initialized", d->ctx); -} - -/* Initialize the dma transmit context */ -static void initialize_dma_trm_ctx(struct dma_trm_ctx *d) -{ - struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); - - /* Stop the context */ - ohci1394_stop_context(ohci, d->ctrlClear, NULL); - - d->prg_ind = 0; - d->sent_ind = 0; - d->free_prgs = d->num_desc; - d->branchAddrPtr = NULL; - INIT_LIST_HEAD(&d->fifo_list); - INIT_LIST_HEAD(&d->pending_list); - - if (d->type == DMA_CTX_ISO) { - /* enable interrupts */ - reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << d->ctx); - } - - DBGMSG("Transmit DMA ctx=%d initialized", d->ctx); -} - -/* Count the number of available iso contexts */ -static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg) -{ - u32 tmp; - - reg_write(ohci, reg, 0xffffffff); - tmp = reg_read(ohci, reg); - - DBGMSG("Iso contexts reg: %08x implemented: %08x", reg, tmp); - - /* Count the number of contexts */ - return hweight32(tmp); -} - -/* Global initialization */ -static void ohci_initialize(struct ti_ohci *ohci) -{ - quadlet_t buf; - int num_ports, i; - - spin_lock_init(&ohci->phy_reg_lock); - - /* Put some defaults to these undefined bus options */ - buf = reg_read(ohci, OHCI1394_BusOptions); - buf |= 0x60000000; /* Enable CMC and ISC */ - if (hpsb_disable_irm) - buf &= ~0x80000000; - else - buf |= 0x80000000; /* Enable IRMC */ - buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */ - buf &= ~0x18000000; /* Disable PMC and BMC */ - reg_write(ohci, OHCI1394_BusOptions, buf); - - /* Set the bus number */ - reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); - - /* Enable posted writes */ - reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_postedWriteEnable); - - /* Clear link control register */ - reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); - - /* Enable cycle timer and cycle master and set the IRM - * contender bit in our self ID packets if appropriate. */ - reg_write(ohci, OHCI1394_LinkControlSet, - OHCI1394_LinkControl_CycleTimerEnable | - OHCI1394_LinkControl_CycleMaster); - i = get_phy_reg(ohci, 4) | PHY_04_LCTRL; - if (hpsb_disable_irm) - i &= ~PHY_04_CONTENDER; - else - i |= PHY_04_CONTENDER; - set_phy_reg(ohci, 4, i); - - /* Set up self-id dma buffer */ - reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus); - - /* enable self-id */ - reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID); - - /* Set the Config ROM mapping register */ - reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus); - - /* Now get our max packet size */ - ohci->max_packet_size = - 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1); - - /* Clear the interrupt mask */ - reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); - reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); - - /* Clear the interrupt mask */ - reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); - reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); - - /* Initialize AR dma */ - initialize_dma_rcv_ctx(&ohci->ar_req_context, 0); - initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0); - - /* Initialize AT dma */ - initialize_dma_trm_ctx(&ohci->at_req_context); - initialize_dma_trm_ctx(&ohci->at_resp_context); - - /* Accept AR requests from all nodes */ - reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000); - - /* Set the address range of the physical response unit. - * Most controllers do not implement it as a writable register though. - * They will keep a hardwired offset of 0x00010000 and show 0x0 as - * register content. - * To actually enable physical responses is the job of our interrupt - * handler which programs the physical request filter. */ - reg_write(ohci, OHCI1394_PhyUpperBound, - OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED >> 16); - - DBGMSG("physUpperBoundOffset=%08x", - reg_read(ohci, OHCI1394_PhyUpperBound)); - - /* Specify AT retries */ - reg_write(ohci, OHCI1394_ATRetries, - OHCI1394_MAX_AT_REQ_RETRIES | - (OHCI1394_MAX_AT_RESP_RETRIES<<4) | - (OHCI1394_MAX_PHYS_RESP_RETRIES<<8)); - - /* We don't want hardware swapping */ - reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap); - - /* Enable interrupts */ - reg_write(ohci, OHCI1394_IntMaskSet, - OHCI1394_unrecoverableError | - OHCI1394_masterIntEnable | - OHCI1394_busReset | - OHCI1394_selfIDComplete | - OHCI1394_RSPkt | - OHCI1394_RQPkt | - OHCI1394_respTxComplete | - OHCI1394_reqTxComplete | - OHCI1394_isochRx | - OHCI1394_isochTx | - OHCI1394_postedWriteErr | - OHCI1394_cycleTooLong | - OHCI1394_cycleInconsistent); - - /* Enable link */ - reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable); - - buf = reg_read(ohci, OHCI1394_Version); - PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%d] " - "MMIO=[%llx-%llx] Max Packet=[%d] IR/IT contexts=[%d/%d]", - ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), - ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq, - (unsigned long long)pci_resource_start(ohci->dev, 0), - (unsigned long long)pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1, - ohci->max_packet_size, - ohci->nb_iso_rcv_ctx, ohci->nb_iso_xmit_ctx); - - /* Check all of our ports to make sure that if anything is - * connected, we enable that port. */ - num_ports = get_phy_reg(ohci, 2) & 0xf; - for (i = 0; i < num_ports; i++) { - unsigned int status; - - set_phy_reg(ohci, 7, i); - status = get_phy_reg(ohci, 8); - - if (status & 0x20) - set_phy_reg(ohci, 8, status & ~1); - } - - /* Serial EEPROM Sanity check. */ - if ((ohci->max_packet_size < 512) || - (ohci->max_packet_size > 4096)) { - /* Serial EEPROM contents are suspect, set a sane max packet - * size and print the raw contents for bug reports if verbose - * debug is enabled. */ -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - int i; -#endif - - PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, " - "attempting to set max_packet_size to 512 bytes"); - reg_write(ohci, OHCI1394_BusOptions, - (reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002); - ohci->max_packet_size = 512; -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - PRINT(KERN_DEBUG, " EEPROM Present: %d", - (reg_read(ohci, OHCI1394_Version) >> 24) & 0x1); - reg_write(ohci, OHCI1394_GUID_ROM, 0x80000000); - - for (i = 0; - ((i < 1000) && - (reg_read(ohci, OHCI1394_GUID_ROM) & 0x80000000)); i++) - udelay(10); - - for (i = 0; i < 0x20; i++) { - reg_write(ohci, OHCI1394_GUID_ROM, 0x02000000); - PRINT(KERN_DEBUG, " EEPROM %02x: %02x", i, - (reg_read(ohci, OHCI1394_GUID_ROM) >> 16) & 0xff); - } -#endif - } -} - -/* - * Insert a packet in the DMA fifo and generate the DMA prg - * FIXME: rewrite the program in order to accept packets crossing - * page boundaries. - * check also that a single dma descriptor doesn't cross a - * page boundary. - */ -static void insert_packet(struct ti_ohci *ohci, - struct dma_trm_ctx *d, struct hpsb_packet *packet) -{ - u32 cycleTimer; - int idx = d->prg_ind; - - DBGMSG("Inserting packet for node " NODE_BUS_FMT - ", tlabel=%d, tcode=0x%x, speed=%d", - NODE_BUS_ARGS(ohci->host, packet->node_id), packet->tlabel, - packet->tcode, packet->speed_code); - - d->prg_cpu[idx]->begin.address = 0; - d->prg_cpu[idx]->begin.branchAddress = 0; - - if (d->type == DMA_CTX_ASYNC_RESP) { - /* - * For response packets, we need to put a timeout value in - * the 16 lower bits of the status... let's try 1 sec timeout - */ - cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer); - d->prg_cpu[idx]->begin.status = cpu_to_le32( - (((((cycleTimer>>25)&0x7)+1)&0x7)<<13) | - ((cycleTimer&0x01fff000)>>12)); - - DBGMSG("cycleTimer: %08x timeStamp: %08x", - cycleTimer, d->prg_cpu[idx]->begin.status); - } else - d->prg_cpu[idx]->begin.status = 0; - - if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) { - - if (packet->type == hpsb_raw) { - d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4); - d->prg_cpu[idx]->data[1] = cpu_to_le32(packet->header[0]); - d->prg_cpu[idx]->data[2] = cpu_to_le32(packet->header[1]); - } else { - d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | - (packet->header[0] & 0xFFFF); - - if (packet->tcode == TCODE_ISO_DATA) { - /* Sending an async stream packet */ - d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; - } else { - /* Sending a normal async request or response */ - d->prg_cpu[idx]->data[1] = - (packet->header[1] & 0xFFFF) | - (packet->header[0] & 0xFFFF0000); - d->prg_cpu[idx]->data[2] = packet->header[2]; - d->prg_cpu[idx]->data[3] = packet->header[3]; - } - header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode); - } - - if (packet->data_size) { /* block transmit */ - if (packet->tcode == TCODE_STREAM_DATA){ - d->prg_cpu[idx]->begin.control = - cpu_to_le32(DMA_CTL_OUTPUT_MORE | - DMA_CTL_IMMEDIATE | 0x8); - } else { - d->prg_cpu[idx]->begin.control = - cpu_to_le32(DMA_CTL_OUTPUT_MORE | - DMA_CTL_IMMEDIATE | 0x10); - } - d->prg_cpu[idx]->end.control = - cpu_to_le32(DMA_CTL_OUTPUT_LAST | - DMA_CTL_IRQ | - DMA_CTL_BRANCH | - packet->data_size); - /* - * Check that the packet data buffer - * does not cross a page boundary. - * - * XXX Fix this some day. eth1394 seems to trigger - * it, but ignoring it doesn't seem to cause a - * problem. - */ -#if 0 - if (cross_bound((unsigned long)packet->data, - packet->data_size)>0) { - /* FIXME: do something about it */ - PRINT(KERN_ERR, - "%s: packet data addr: %p size %Zd bytes " - "cross page boundary", __func__, - packet->data, packet->data_size); - } -#endif - d->prg_cpu[idx]->end.address = cpu_to_le32( - pci_map_single(ohci->dev, packet->data, - packet->data_size, - PCI_DMA_TODEVICE)); - - d->prg_cpu[idx]->end.branchAddress = 0; - d->prg_cpu[idx]->end.status = 0; - if (d->branchAddrPtr) - *(d->branchAddrPtr) = - cpu_to_le32(d->prg_bus[idx] | 0x3); - d->branchAddrPtr = - &(d->prg_cpu[idx]->end.branchAddress); - } else { /* quadlet transmit */ - if (packet->type == hpsb_raw) - d->prg_cpu[idx]->begin.control = - cpu_to_le32(DMA_CTL_OUTPUT_LAST | - DMA_CTL_IMMEDIATE | - DMA_CTL_IRQ | - DMA_CTL_BRANCH | - (packet->header_size + 4)); - else - d->prg_cpu[idx]->begin.control = - cpu_to_le32(DMA_CTL_OUTPUT_LAST | - DMA_CTL_IMMEDIATE | - DMA_CTL_IRQ | - DMA_CTL_BRANCH | - packet->header_size); - - if (d->branchAddrPtr) - *(d->branchAddrPtr) = - cpu_to_le32(d->prg_bus[idx] | 0x2); - d->branchAddrPtr = - &(d->prg_cpu[idx]->begin.branchAddress); - } - - } else { /* iso packet */ - d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | - (packet->header[0] & 0xFFFF); - d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; - header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode); - - d->prg_cpu[idx]->begin.control = - cpu_to_le32(DMA_CTL_OUTPUT_MORE | - DMA_CTL_IMMEDIATE | 0x8); - d->prg_cpu[idx]->end.control = - cpu_to_le32(DMA_CTL_OUTPUT_LAST | - DMA_CTL_UPDATE | - DMA_CTL_IRQ | - DMA_CTL_BRANCH | - packet->data_size); - d->prg_cpu[idx]->end.address = cpu_to_le32( - pci_map_single(ohci->dev, packet->data, - packet->data_size, PCI_DMA_TODEVICE)); - - d->prg_cpu[idx]->end.branchAddress = 0; - d->prg_cpu[idx]->end.status = 0; - DBGMSG("Iso xmit context info: header[%08x %08x]\n" - " begin=%08x %08x %08x %08x\n" - " %08x %08x %08x %08x\n" - " end =%08x %08x %08x %08x", - d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1], - d->prg_cpu[idx]->begin.control, - d->prg_cpu[idx]->begin.address, - d->prg_cpu[idx]->begin.branchAddress, - d->prg_cpu[idx]->begin.status, - d->prg_cpu[idx]->data[0], - d->prg_cpu[idx]->data[1], - d->prg_cpu[idx]->data[2], - d->prg_cpu[idx]->data[3], - d->prg_cpu[idx]->end.control, - d->prg_cpu[idx]->end.address, - d->prg_cpu[idx]->end.branchAddress, - d->prg_cpu[idx]->end.status); - if (d->branchAddrPtr) - *(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3); - d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress); - } - d->free_prgs--; - - /* queue the packet in the appropriate context queue */ - list_add_tail(&packet->driver_list, &d->fifo_list); - d->prg_ind = (d->prg_ind + 1) % d->num_desc; -} - -/* - * This function fills the FIFO with the (eventual) pending packets - * and runs or wakes up the DMA prg if necessary. - * - * The function MUST be called with the d->lock held. - */ -static void dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d) -{ - struct hpsb_packet *packet, *ptmp; - int idx = d->prg_ind; - int z = 0; - - /* insert the packets into the dma fifo */ - list_for_each_entry_safe(packet, ptmp, &d->pending_list, driver_list) { - if (!d->free_prgs) - break; - - /* For the first packet only */ - if (!z) - z = (packet->data_size) ? 3 : 2; - - /* Insert the packet */ - list_del_init(&packet->driver_list); - insert_packet(ohci, d, packet); - } - - /* Nothing must have been done, either no free_prgs or no packets */ - if (z == 0) - return; - - /* Is the context running ? (should be unless it is - the first packet to be sent in this context) */ - if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) { - u32 nodeId = reg_read(ohci, OHCI1394_NodeID); - - DBGMSG("Starting transmit DMA ctx=%d",d->ctx); - reg_write(ohci, d->cmdPtr, d->prg_bus[idx] | z); - - /* Check that the node id is valid, and not 63 */ - if (!(nodeId & 0x80000000) || (nodeId & 0x3f) == 63) - PRINT(KERN_ERR, "Running dma failed because Node ID is not valid"); - else - reg_write(ohci, d->ctrlSet, 0x8000); - } else { - /* Wake up the dma context if necessary */ - if (!(reg_read(ohci, d->ctrlSet) & 0x400)) - DBGMSG("Waking transmit DMA ctx=%d",d->ctx); - - /* do this always, to avoid race condition */ - reg_write(ohci, d->ctrlSet, 0x1000); - } - - return; -} - -/* Transmission of an async or iso packet */ -static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet) -{ - struct ti_ohci *ohci = host->hostdata; - struct dma_trm_ctx *d; - unsigned long flags; - - if (packet->data_size > ohci->max_packet_size) { - PRINT(KERN_ERR, - "Transmit packet size %Zd is too big", - packet->data_size); - return -EOVERFLOW; - } - - if (packet->type == hpsb_raw) - d = &ohci->at_req_context; - else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA)) - d = &ohci->at_resp_context; - else - d = &ohci->at_req_context; - - spin_lock_irqsave(&d->lock,flags); - - list_add_tail(&packet->driver_list, &d->pending_list); - - dma_trm_flush(ohci, d); - - spin_unlock_irqrestore(&d->lock,flags); - - return 0; -} - -static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) -{ - struct ti_ohci *ohci = host->hostdata; - int retval = 0, phy_reg; - - switch (cmd) { - case RESET_BUS: - switch (arg) { - case SHORT_RESET: - phy_reg = get_phy_reg(ohci, 5); - phy_reg |= 0x40; - set_phy_reg(ohci, 5, phy_reg); /* set ISBR */ - break; - case LONG_RESET: - phy_reg = get_phy_reg(ohci, 1); - phy_reg |= 0x40; - set_phy_reg(ohci, 1, phy_reg); /* set IBR */ - break; - case SHORT_RESET_NO_FORCE_ROOT: - phy_reg = get_phy_reg(ohci, 1); - if (phy_reg & 0x80) { - phy_reg &= ~0x80; - set_phy_reg(ohci, 1, phy_reg); /* clear RHB */ - } - - phy_reg = get_phy_reg(ohci, 5); - phy_reg |= 0x40; - set_phy_reg(ohci, 5, phy_reg); /* set ISBR */ - break; - case LONG_RESET_NO_FORCE_ROOT: - phy_reg = get_phy_reg(ohci, 1); - phy_reg &= ~0x80; - phy_reg |= 0x40; - set_phy_reg(ohci, 1, phy_reg); /* clear RHB, set IBR */ - break; - case SHORT_RESET_FORCE_ROOT: - phy_reg = get_phy_reg(ohci, 1); - if (!(phy_reg & 0x80)) { - phy_reg |= 0x80; - set_phy_reg(ohci, 1, phy_reg); /* set RHB */ - } - - phy_reg = get_phy_reg(ohci, 5); - phy_reg |= 0x40; - set_phy_reg(ohci, 5, phy_reg); /* set ISBR */ - break; - case LONG_RESET_FORCE_ROOT: - phy_reg = get_phy_reg(ohci, 1); - phy_reg |= 0xc0; - set_phy_reg(ohci, 1, phy_reg); /* set RHB and IBR */ - break; - default: - retval = -1; - } - break; - - case GET_CYCLE_COUNTER: - retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer); - break; - - case SET_CYCLE_COUNTER: - reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg); - break; - - case SET_BUS_ID: - PRINT(KERN_ERR, "devctl command SET_BUS_ID err"); - break; - - case ACT_CYCLE_MASTER: - if (arg) { - /* check if we are root and other nodes are present */ - u32 nodeId = reg_read(ohci, OHCI1394_NodeID); - if ((nodeId & (1<<30)) && (nodeId & 0x3f)) { - /* - * enable cycleTimer, cycleMaster - */ - DBGMSG("Cycle master enabled"); - reg_write(ohci, OHCI1394_LinkControlSet, - OHCI1394_LinkControl_CycleTimerEnable | - OHCI1394_LinkControl_CycleMaster); - } - } else { - /* disable cycleTimer, cycleMaster, cycleSource */ - reg_write(ohci, OHCI1394_LinkControlClear, - OHCI1394_LinkControl_CycleTimerEnable | - OHCI1394_LinkControl_CycleMaster | - OHCI1394_LinkControl_CycleSource); - } - break; - - case CANCEL_REQUESTS: - DBGMSG("Cancel request received"); - dma_trm_reset(&ohci->at_req_context); - dma_trm_reset(&ohci->at_resp_context); - break; - - default: - PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet", - cmd); - break; - } - return retval; -} - -/*********************************** - * rawiso ISO reception * - ***********************************/ - -/* - We use either buffer-fill or packet-per-buffer DMA mode. The DMA - buffer is split into "blocks" (regions described by one DMA - descriptor). Each block must be one page or less in size, and - must not cross a page boundary. - - There is one little wrinkle with buffer-fill mode: a packet that - starts in the final block may wrap around into the first block. But - the user API expects all packets to be contiguous. Our solution is - to keep the very last page of the DMA buffer in reserve - if a - packet spans the gap, we copy its tail into this page. -*/ - -struct ohci_iso_recv { - struct ti_ohci *ohci; - - struct ohci1394_iso_tasklet task; - int task_active; - - enum { BUFFER_FILL_MODE = 0, - PACKET_PER_BUFFER_MODE = 1 } dma_mode; - - /* memory and PCI mapping for the DMA descriptors */ - struct dma_prog_region prog; - struct dma_cmd *block; /* = (struct dma_cmd*) prog.virt */ - - /* how many DMA blocks fit in the buffer */ - unsigned int nblocks; - - /* stride of DMA blocks */ - unsigned int buf_stride; - - /* number of blocks to batch between interrupts */ - int block_irq_interval; - - /* block that DMA will finish next */ - int block_dma; - - /* (buffer-fill only) block that the reader will release next */ - int block_reader; - - /* (buffer-fill only) bytes of buffer the reader has released, - less than one block */ - int released_bytes; - - /* (buffer-fill only) buffer offset at which the next packet will appear */ - int dma_offset; - - /* OHCI DMA context control registers */ - u32 ContextControlSet; - u32 ContextControlClear; - u32 CommandPtr; - u32 ContextMatch; -}; - -static void ohci_iso_recv_task(unsigned long data); -static void ohci_iso_recv_stop(struct hpsb_iso *iso); -static void ohci_iso_recv_shutdown(struct hpsb_iso *iso); -static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync); -static void ohci_iso_recv_program(struct hpsb_iso *iso); - -static int ohci_iso_recv_init(struct hpsb_iso *iso) -{ - struct ti_ohci *ohci = iso->host->hostdata; - struct ohci_iso_recv *recv; - int ctx; - int ret = -ENOMEM; - - recv = kmalloc(sizeof(*recv), GFP_KERNEL); - if (!recv) - return -ENOMEM; - - iso->hostdata = recv; - recv->ohci = ohci; - recv->task_active = 0; - dma_prog_region_init(&recv->prog); - recv->block = NULL; - - /* use buffer-fill mode, unless irq_interval is 1 - (note: multichannel requires buffer-fill) */ - - if (((iso->irq_interval == 1 && iso->dma_mode == HPSB_ISO_DMA_OLD_ABI) || - iso->dma_mode == HPSB_ISO_DMA_PACKET_PER_BUFFER) && iso->channel != -1) { - recv->dma_mode = PACKET_PER_BUFFER_MODE; - } else { - recv->dma_mode = BUFFER_FILL_MODE; - } - - /* set nblocks, buf_stride, block_irq_interval */ - - if (recv->dma_mode == BUFFER_FILL_MODE) { - recv->buf_stride = PAGE_SIZE; - - /* one block per page of data in the DMA buffer, minus the final guard page */ - recv->nblocks = iso->buf_size/PAGE_SIZE - 1; - if (recv->nblocks < 3) { - DBGMSG("ohci_iso_recv_init: DMA buffer too small"); - goto err; - } - - /* iso->irq_interval is in packets - translate that to blocks */ - if (iso->irq_interval == 1) - recv->block_irq_interval = 1; - else - recv->block_irq_interval = iso->irq_interval * - ((recv->nblocks+1)/iso->buf_packets); - if (recv->block_irq_interval*4 > recv->nblocks) - recv->block_irq_interval = recv->nblocks/4; - if (recv->block_irq_interval < 1) - recv->block_irq_interval = 1; - - } else { - int max_packet_size; - - recv->nblocks = iso->buf_packets; - recv->block_irq_interval = iso->irq_interval; - if (recv->block_irq_interval * 4 > iso->buf_packets) - recv->block_irq_interval = iso->buf_packets / 4; - if (recv->block_irq_interval < 1) - recv->block_irq_interval = 1; - - /* choose a buffer stride */ - /* must be a power of 2, and <= PAGE_SIZE */ - - max_packet_size = iso->buf_size / iso->buf_packets; - - for (recv->buf_stride = 8; recv->buf_stride < max_packet_size; - recv->buf_stride *= 2); - - if (recv->buf_stride*iso->buf_packets > iso->buf_size || - recv->buf_stride > PAGE_SIZE) { - /* this shouldn't happen, but anyway... */ - DBGMSG("ohci_iso_recv_init: problem choosing a buffer stride"); - goto err; - } - } - - recv->block_reader = 0; - recv->released_bytes = 0; - recv->block_dma = 0; - recv->dma_offset = 0; - - /* size of DMA program = one descriptor per block */ - if (dma_prog_region_alloc(&recv->prog, - sizeof(struct dma_cmd) * recv->nblocks, - recv->ohci->dev)) - goto err; - - recv->block = (struct dma_cmd*) recv->prog.kvirt; - - ohci1394_init_iso_tasklet(&recv->task, - iso->channel == -1 ? OHCI_ISO_MULTICHANNEL_RECEIVE : - OHCI_ISO_RECEIVE, - ohci_iso_recv_task, (unsigned long) iso); - - if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) { - ret = -EBUSY; - goto err; - } - - recv->task_active = 1; - - /* recv context registers are spaced 32 bytes apart */ - ctx = recv->task.context; - recv->ContextControlSet = OHCI1394_IsoRcvContextControlSet + 32 * ctx; - recv->ContextControlClear = OHCI1394_IsoRcvContextControlClear + 32 * ctx; - recv->CommandPtr = OHCI1394_IsoRcvCommandPtr + 32 * ctx; - recv->ContextMatch = OHCI1394_IsoRcvContextMatch + 32 * ctx; - - if (iso->channel == -1) { - /* clear multi-channel selection mask */ - reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, 0xFFFFFFFF); - reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, 0xFFFFFFFF); - } - - /* write the DMA program */ - ohci_iso_recv_program(iso); - - DBGMSG("ohci_iso_recv_init: %s mode, DMA buffer is %lu pages" - " (%u bytes), using %u blocks, buf_stride %u, block_irq_interval %d", - recv->dma_mode == BUFFER_FILL_MODE ? - "buffer-fill" : "packet-per-buffer", - iso->buf_size/PAGE_SIZE, iso->buf_size, - recv->nblocks, recv->buf_stride, recv->block_irq_interval); - - return 0; - -err: - ohci_iso_recv_shutdown(iso); - return ret; -} - -static void ohci_iso_recv_stop(struct hpsb_iso *iso) -{ - struct ohci_iso_recv *recv = iso->hostdata; - - /* disable interrupts */ - reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context); - - /* halt DMA */ - ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL); -} - -static void ohci_iso_recv_shutdown(struct hpsb_iso *iso) -{ - struct ohci_iso_recv *recv = iso->hostdata; - - if (recv->task_active) { - ohci_iso_recv_stop(iso); - ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task); - recv->task_active = 0; - } - - dma_prog_region_free(&recv->prog); - kfree(recv); - iso->hostdata = NULL; -} - -/* set up a "gapped" ring buffer DMA program */ -static void ohci_iso_recv_program(struct hpsb_iso *iso) -{ - struct ohci_iso_recv *recv = iso->hostdata; - int blk; - - /* address of 'branch' field in previous DMA descriptor */ - u32 *prev_branch = NULL; - - for (blk = 0; blk < recv->nblocks; blk++) { - u32 control; - - /* the DMA descriptor */ - struct dma_cmd *cmd = &recv->block[blk]; - - /* offset of the DMA descriptor relative to the DMA prog buffer */ - unsigned long prog_offset = blk * sizeof(struct dma_cmd); - - /* offset of this packet's data within the DMA buffer */ - unsigned long buf_offset = blk * recv->buf_stride; - - if (recv->dma_mode == BUFFER_FILL_MODE) { - control = 2 << 28; /* INPUT_MORE */ - } else { - control = 3 << 28; /* INPUT_LAST */ - } - - control |= 8 << 24; /* s = 1, update xferStatus and resCount */ - - /* interrupt on last block, and at intervals */ - if (blk == recv->nblocks-1 || (blk % recv->block_irq_interval) == 0) { - control |= 3 << 20; /* want interrupt */ - } - - control |= 3 << 18; /* enable branch to address */ - control |= recv->buf_stride; - - cmd->control = cpu_to_le32(control); - cmd->address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, buf_offset)); - cmd->branchAddress = 0; /* filled in on next loop */ - cmd->status = cpu_to_le32(recv->buf_stride); - - /* link the previous descriptor to this one */ - if (prev_branch) { - *prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1); - } - - prev_branch = &cmd->branchAddress; - } - - /* the final descriptor's branch address and Z should be left at 0 */ -} - -/* listen or unlisten to a specific channel (multi-channel mode only) */ -static void ohci_iso_recv_change_channel(struct hpsb_iso *iso, unsigned char channel, int listen) -{ - struct ohci_iso_recv *recv = iso->hostdata; - int reg, i; - - if (channel < 32) { - reg = listen ? OHCI1394_IRMultiChanMaskLoSet : OHCI1394_IRMultiChanMaskLoClear; - i = channel; - } else { - reg = listen ? OHCI1394_IRMultiChanMaskHiSet : OHCI1394_IRMultiChanMaskHiClear; - i = channel - 32; - } - - reg_write(recv->ohci, reg, (1 << i)); - - /* issue a dummy read to force all PCI writes to be posted immediately */ - mb(); - reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); -} - -static void ohci_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask) -{ - struct ohci_iso_recv *recv = iso->hostdata; - int i; - - for (i = 0; i < 64; i++) { - if (mask & (1ULL << i)) { - if (i < 32) - reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoSet, (1 << i)); - else - reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiSet, (1 << (i-32))); - } else { - if (i < 32) - reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, (1 << i)); - else - reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, (1 << (i-32))); - } - } - - /* issue a dummy read to force all PCI writes to be posted immediately */ - mb(); - reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); -} - -static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync) -{ - struct ohci_iso_recv *recv = iso->hostdata; - struct ti_ohci *ohci = recv->ohci; - u32 command, contextMatch; - - reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF); - wmb(); - - /* always keep ISO headers */ - command = (1 << 30); - - if (recv->dma_mode == BUFFER_FILL_MODE) - command |= (1 << 31); - - reg_write(recv->ohci, recv->ContextControlSet, command); - - /* match on specified tags */ - contextMatch = tag_mask << 28; - - if (iso->channel == -1) { - /* enable multichannel reception */ - reg_write(recv->ohci, recv->ContextControlSet, (1 << 28)); - } else { - /* listen on channel */ - contextMatch |= iso->channel; - } - - if (cycle != -1) { - u32 seconds; - - /* enable cycleMatch */ - reg_write(recv->ohci, recv->ContextControlSet, (1 << 29)); - - /* set starting cycle */ - cycle &= 0x1FFF; - - /* 'cycle' is only mod 8000, but we also need two 'seconds' bits - - just snarf them from the current time */ - seconds = reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer) >> 25; - - /* advance one second to give some extra time for DMA to start */ - seconds += 1; - - cycle |= (seconds & 3) << 13; - - contextMatch |= cycle << 12; - } - - if (sync != -1) { - /* set sync flag on first DMA descriptor */ - struct dma_cmd *cmd = &recv->block[recv->block_dma]; - cmd->control |= cpu_to_le32(DMA_CTL_WAIT); - - /* match sync field */ - contextMatch |= (sync&0xf)<<8; - } - - reg_write(recv->ohci, recv->ContextMatch, contextMatch); - - /* address of first descriptor block */ - command = dma_prog_region_offset_to_bus(&recv->prog, - recv->block_dma * sizeof(struct dma_cmd)); - command |= 1; /* Z=1 */ - - reg_write(recv->ohci, recv->CommandPtr, command); - - /* enable interrupts */ - reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << recv->task.context); - - wmb(); - - /* run */ - reg_write(recv->ohci, recv->ContextControlSet, 0x8000); - - /* issue a dummy read of the cycle timer register to force - all PCI writes to be posted immediately */ - mb(); - reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); - - /* check RUN */ - if (!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) { - PRINT(KERN_ERR, - "Error starting IR DMA (ContextControl 0x%08x)\n", - reg_read(recv->ohci, recv->ContextControlSet)); - return -1; - } - - return 0; -} - -static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block) -{ - /* re-use the DMA descriptor for the block */ - /* by linking the previous descriptor to it */ - - int next_i = block; - int prev_i = (next_i == 0) ? (recv->nblocks - 1) : (next_i - 1); - - struct dma_cmd *next = &recv->block[next_i]; - struct dma_cmd *prev = &recv->block[prev_i]; - - /* ignore out-of-range requests */ - if ((block < 0) || (block > recv->nblocks)) - return; - - /* 'next' becomes the new end of the DMA chain, - so disable branch and enable interrupt */ - next->branchAddress = 0; - next->control |= cpu_to_le32(3 << 20); - next->status = cpu_to_le32(recv->buf_stride); - - /* link prev to next */ - prev->branchAddress = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, - sizeof(struct dma_cmd) * next_i) - | 1); /* Z=1 */ - - /* disable interrupt on previous DMA descriptor, except at intervals */ - if ((prev_i % recv->block_irq_interval) == 0) { - prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */ - } else { - prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */ - } - wmb(); - - /* wake up DMA in case it fell asleep */ - reg_write(recv->ohci, recv->ContextControlSet, (1 << 12)); -} - -static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv, - struct hpsb_iso_packet_info *info) -{ - /* release the memory where the packet was */ - recv->released_bytes += info->total_len; - - /* have we released enough memory for one block? */ - while (recv->released_bytes > recv->buf_stride) { - ohci_iso_recv_release_block(recv, recv->block_reader); - recv->block_reader = (recv->block_reader + 1) % recv->nblocks; - recv->released_bytes -= recv->buf_stride; - } -} - -static inline void ohci_iso_recv_release(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info) -{ - struct ohci_iso_recv *recv = iso->hostdata; - if (recv->dma_mode == BUFFER_FILL_MODE) { - ohci_iso_recv_bufferfill_release(recv, info); - } else { - ohci_iso_recv_release_block(recv, info - iso->infos); - } -} - -/* parse all packets from blocks that have been fully received */ -static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso_recv *recv) -{ - int wake = 0; - int runaway = 0; - struct ti_ohci *ohci = recv->ohci; - - while (1) { - /* we expect the next parsable packet to begin at recv->dma_offset */ - /* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */ - - unsigned int offset; - unsigned short len, cycle, total_len; - unsigned char channel, tag, sy; - - unsigned char *p = iso->data_buf.kvirt; - - unsigned int this_block = recv->dma_offset/recv->buf_stride; - - /* don't loop indefinitely */ - if (runaway++ > 100000) { - atomic_inc(&iso->overflows); - PRINT(KERN_ERR, - "IR DMA error - Runaway during buffer parsing!\n"); - break; - } - - /* stop parsing once we arrive at block_dma (i.e. don't get ahead of DMA) */ - if (this_block == recv->block_dma) - break; - - wake = 1; - - /* parse data length, tag, channel, and sy */ - - /* note: we keep our own local copies of 'len' and 'offset' - so the user can't mess with them by poking in the mmap area */ - - len = p[recv->dma_offset+2] | (p[recv->dma_offset+3] << 8); - - if (len > 4096) { - PRINT(KERN_ERR, - "IR DMA error - bogus 'len' value %u\n", len); - } - - channel = p[recv->dma_offset+1] & 0x3F; - tag = p[recv->dma_offset+1] >> 6; - sy = p[recv->dma_offset+0] & 0xF; - - /* advance to data payload */ - recv->dma_offset += 4; - - /* check for wrap-around */ - if (recv->dma_offset >= recv->buf_stride*recv->nblocks) { - recv->dma_offset -= recv->buf_stride*recv->nblocks; - } - - /* dma_offset now points to the first byte of the data payload */ - offset = recv->dma_offset; - - /* advance to xferStatus/timeStamp */ - recv->dma_offset += len; - - total_len = len + 8; /* 8 bytes header+trailer in OHCI packet */ - /* payload is padded to 4 bytes */ - if (len % 4) { - recv->dma_offset += 4 - (len%4); - total_len += 4 - (len%4); - } - - /* check for wrap-around */ - if (recv->dma_offset >= recv->buf_stride*recv->nblocks) { - /* uh oh, the packet data wraps from the last - to the first DMA block - make the packet - contiguous by copying its "tail" into the - guard page */ - - int guard_off = recv->buf_stride*recv->nblocks; - int tail_len = len - (guard_off - offset); - - if (tail_len > 0 && tail_len < recv->buf_stride) { - memcpy(iso->data_buf.kvirt + guard_off, - iso->data_buf.kvirt, - tail_len); - } - - recv->dma_offset -= recv->buf_stride*recv->nblocks; - } - - /* parse timestamp */ - cycle = p[recv->dma_offset+0] | (p[recv->dma_offset+1]<<8); - cycle &= 0x1FFF; - - /* advance to next packet */ - recv->dma_offset += 4; - - /* check for wrap-around */ - if (recv->dma_offset >= recv->buf_stride*recv->nblocks) { - recv->dma_offset -= recv->buf_stride*recv->nblocks; - } - - hpsb_iso_packet_received(iso, offset, len, total_len, cycle, channel, tag, sy); - } - - if (wake) - hpsb_iso_wake(iso); -} - -static void ohci_iso_recv_bufferfill_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv) -{ - int loop; - struct ti_ohci *ohci = recv->ohci; - - /* loop over all blocks */ - for (loop = 0; loop < recv->nblocks; loop++) { - - /* check block_dma to see if it's done */ - struct dma_cmd *im = &recv->block[recv->block_dma]; - - /* check the DMA descriptor for new writes to xferStatus */ - u16 xferstatus = le32_to_cpu(im->status) >> 16; - - /* rescount is the number of bytes *remaining to be written* in the block */ - u16 rescount = le32_to_cpu(im->status) & 0xFFFF; - - unsigned char event = xferstatus & 0x1F; - - if (!event) { - /* nothing has happened to this block yet */ - break; - } - - if (event != 0x11) { - atomic_inc(&iso->overflows); - PRINT(KERN_ERR, - "IR DMA error - OHCI error code 0x%02x\n", event); - } - - if (rescount != 0) { - /* the card is still writing to this block; - we can't touch it until it's done */ - break; - } - - /* OK, the block is finished... */ - - /* sync our view of the block */ - dma_region_sync_for_cpu(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride); - - /* reset the DMA descriptor */ - im->status = recv->buf_stride; - - /* advance block_dma */ - recv->block_dma = (recv->block_dma + 1) % recv->nblocks; - - if ((recv->block_dma+1) % recv->nblocks == recv->block_reader) { - atomic_inc(&iso->overflows); - DBGMSG("ISO reception overflow - " - "ran out of DMA blocks"); - } - } - - /* parse any packets that have arrived */ - ohci_iso_recv_bufferfill_parse(iso, recv); -} - -static void ohci_iso_recv_packetperbuf_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv) -{ - int count; - int wake = 0; - struct ti_ohci *ohci = recv->ohci; - - /* loop over the entire buffer */ - for (count = 0; count < recv->nblocks; count++) { - u32 packet_len = 0; - - /* pointer to the DMA descriptor */ - struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma; - - /* check the DMA descriptor for new writes to xferStatus */ - u16 xferstatus = le32_to_cpu(il->status) >> 16; - u16 rescount = le32_to_cpu(il->status) & 0xFFFF; - - unsigned char event = xferstatus & 0x1F; - - if (!event) { - /* this packet hasn't come in yet; we are done for now */ - goto out; - } - - if (event == 0x11) { - /* packet received successfully! */ - - /* rescount is the number of bytes *remaining* in the packet buffer, - after the packet was written */ - packet_len = recv->buf_stride - rescount; - - } else if (event == 0x02) { - PRINT(KERN_ERR, "IR DMA error - packet too long for buffer\n"); - } else if (event) { - PRINT(KERN_ERR, "IR DMA error - OHCI error code 0x%02x\n", event); - } - - /* sync our view of the buffer */ - dma_region_sync_for_cpu(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride); - - /* record the per-packet info */ - { - /* iso header is 8 bytes ahead of the data payload */ - unsigned char *hdr; - - unsigned int offset; - unsigned short cycle; - unsigned char channel, tag, sy; - - offset = iso->pkt_dma * recv->buf_stride; - hdr = iso->data_buf.kvirt + offset; - - /* skip iso header */ - offset += 8; - packet_len -= 8; - - cycle = (hdr[0] | (hdr[1] << 8)) & 0x1FFF; - channel = hdr[5] & 0x3F; - tag = hdr[5] >> 6; - sy = hdr[4] & 0xF; - - hpsb_iso_packet_received(iso, offset, packet_len, - recv->buf_stride, cycle, channel, tag, sy); - } - - /* reset the DMA descriptor */ - il->status = recv->buf_stride; - - wake = 1; - recv->block_dma = iso->pkt_dma; - } - -out: - if (wake) - hpsb_iso_wake(iso); -} - -static void ohci_iso_recv_task(unsigned long data) -{ - struct hpsb_iso *iso = (struct hpsb_iso*) data; - struct ohci_iso_recv *recv = iso->hostdata; - - if (recv->dma_mode == BUFFER_FILL_MODE) - ohci_iso_recv_bufferfill_task(iso, recv); - else - ohci_iso_recv_packetperbuf_task(iso, recv); -} - -/*********************************** - * rawiso ISO transmission * - ***********************************/ - -struct ohci_iso_xmit { - struct ti_ohci *ohci; - struct dma_prog_region prog; - struct ohci1394_iso_tasklet task; - int task_active; - int last_cycle; - atomic_t skips; - - u32 ContextControlSet; - u32 ContextControlClear; - u32 CommandPtr; -}; - -/* transmission DMA program: - one OUTPUT_MORE_IMMEDIATE for the IT header - one OUTPUT_LAST for the buffer data */ - -struct iso_xmit_cmd { - struct dma_cmd output_more_immediate; - u8 iso_hdr[8]; - u32 unused[2]; - struct dma_cmd output_last; -}; - -static int ohci_iso_xmit_init(struct hpsb_iso *iso); -static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle); -static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso); -static void ohci_iso_xmit_task(unsigned long data); - -static int ohci_iso_xmit_init(struct hpsb_iso *iso) -{ - struct ohci_iso_xmit *xmit; - unsigned int prog_size; - int ctx; - int ret = -ENOMEM; - - xmit = kmalloc(sizeof(*xmit), GFP_KERNEL); - if (!xmit) - return -ENOMEM; - - iso->hostdata = xmit; - xmit->ohci = iso->host->hostdata; - xmit->task_active = 0; - xmit->last_cycle = -1; - atomic_set(&iso->skips, 0); - - dma_prog_region_init(&xmit->prog); - - prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets; - - if (dma_prog_region_alloc(&xmit->prog, prog_size, xmit->ohci->dev)) - goto err; - - ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT, - ohci_iso_xmit_task, (unsigned long) iso); - - if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) { - ret = -EBUSY; - goto err; - } - - xmit->task_active = 1; - - /* xmit context registers are spaced 16 bytes apart */ - ctx = xmit->task.context; - xmit->ContextControlSet = OHCI1394_IsoXmitContextControlSet + 16 * ctx; - xmit->ContextControlClear = OHCI1394_IsoXmitContextControlClear + 16 * ctx; - xmit->CommandPtr = OHCI1394_IsoXmitCommandPtr + 16 * ctx; - - return 0; - -err: - ohci_iso_xmit_shutdown(iso); - return ret; -} - -static void ohci_iso_xmit_stop(struct hpsb_iso *iso) -{ - struct ohci_iso_xmit *xmit = iso->hostdata; - struct ti_ohci *ohci = xmit->ohci; - - /* disable interrupts */ - reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context); - - /* halt DMA */ - if (ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL)) { - /* XXX the DMA context will lock up if you try to send too much data! */ - PRINT(KERN_ERR, - "you probably exceeded the OHCI card's bandwidth limit - " - "reload the module and reduce xmit bandwidth"); - } -} - -static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso) -{ - struct ohci_iso_xmit *xmit = iso->hostdata; - - if (xmit->task_active) { - ohci_iso_xmit_stop(iso); - ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task); - xmit->task_active = 0; - } - - dma_prog_region_free(&xmit->prog); - kfree(xmit); - iso->hostdata = NULL; -} - -static void ohci_iso_xmit_task(unsigned long data) -{ - struct hpsb_iso *iso = (struct hpsb_iso*) data; - struct ohci_iso_xmit *xmit = iso->hostdata; - struct ti_ohci *ohci = xmit->ohci; - int wake = 0; - int count; - - /* check the whole buffer if necessary, starting at pkt_dma */ - for (count = 0; count < iso->buf_packets; count++) { - int cycle; - - /* DMA descriptor */ - struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma); - - /* check for new writes to xferStatus */ - u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16; - u8 event = xferstatus & 0x1F; - - if (!event) { - /* packet hasn't been sent yet; we are done for now */ - break; - } - - if (event != 0x11) - PRINT(KERN_ERR, - "IT DMA error - OHCI error code 0x%02x\n", event); - - /* at least one packet went out, so wake up the writer */ - wake = 1; - - /* parse cycle */ - cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF; - - if (xmit->last_cycle > -1) { - int cycle_diff = cycle - xmit->last_cycle; - int skip; - - /* unwrap */ - if (cycle_diff < 0) { - cycle_diff += 8000; - if (cycle_diff < 0) - PRINT(KERN_ERR, "bogus cycle diff %d\n", - cycle_diff); - } - - skip = cycle_diff - 1; - if (skip > 0) { - DBGMSG("skipped %d cycles without packet loss", skip); - atomic_add(skip, &iso->skips); - } - } - xmit->last_cycle = cycle; - - /* tell the subsystem the packet has gone out */ - hpsb_iso_packet_sent(iso, cycle, event != 0x11); - - /* reset the DMA descriptor for next time */ - cmd->output_last.status = 0; - } - - if (wake) - hpsb_iso_wake(iso); -} - -static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info) -{ - struct ohci_iso_xmit *xmit = iso->hostdata; - struct ti_ohci *ohci = xmit->ohci; - - int next_i, prev_i; - struct iso_xmit_cmd *next, *prev; - - unsigned int offset; - unsigned short len; - unsigned char tag, sy; - - /* check that the packet doesn't cross a page boundary - (we could allow this if we added OUTPUT_MORE descriptor support) */ - if (cross_bound(info->offset, info->len)) { - PRINT(KERN_ERR, - "rawiso xmit: packet %u crosses a page boundary", - iso->first_packet); - return -EINVAL; - } - - offset = info->offset; - len = info->len; - tag = info->tag; - sy = info->sy; - - /* sync up the card's view of the buffer */ - dma_region_sync_for_device(&iso->data_buf, offset, len); - - /* append first_packet to the DMA chain */ - /* by linking the previous descriptor to it */ - /* (next will become the new end of the DMA chain) */ - - next_i = iso->first_packet; - prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1); - - next = dma_region_i(&xmit->prog, struct iso_xmit_cmd, next_i); - prev = dma_region_i(&xmit->prog, struct iso_xmit_cmd, prev_i); - - /* set up the OUTPUT_MORE_IMMEDIATE descriptor */ - memset(next, 0, sizeof(struct iso_xmit_cmd)); - next->output_more_immediate.control = cpu_to_le32(0x02000008); - - /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */ - - /* tcode = 0xA, and sy */ - next->iso_hdr[0] = 0xA0 | (sy & 0xF); - - /* tag and channel number */ - next->iso_hdr[1] = (tag << 6) | (iso->channel & 0x3F); - - /* transmission speed */ - next->iso_hdr[2] = iso->speed & 0x7; - - /* payload size */ - next->iso_hdr[6] = len & 0xFF; - next->iso_hdr[7] = len >> 8; - - /* set up the OUTPUT_LAST */ - next->output_last.control = cpu_to_le32(1 << 28); - next->output_last.control |= cpu_to_le32(1 << 27); /* update timeStamp */ - next->output_last.control |= cpu_to_le32(3 << 20); /* want interrupt */ - next->output_last.control |= cpu_to_le32(3 << 18); /* enable branch */ - next->output_last.control |= cpu_to_le32(len); - - /* payload bus address */ - next->output_last.address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, offset)); - - /* leave branchAddress at zero for now */ - - /* re-write the previous DMA descriptor to chain to this one */ - - /* set prev branch address to point to next (Z=3) */ - prev->output_last.branchAddress = cpu_to_le32( - dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3); - - /* - * Link the skip address to this descriptor itself. This causes a - * context to skip a cycle whenever lost cycles or FIFO overruns occur, - * without dropping the data at that point the application should then - * decide whether this is an error condition or not. Some protocols - * can deal with this by dropping some rate-matching padding packets. - */ - next->output_more_immediate.branchAddress = - prev->output_last.branchAddress; - - /* disable interrupt, unless required by the IRQ interval */ - if (prev_i % iso->irq_interval) { - prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */ - } else { - prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */ - } - - wmb(); - - /* wake DMA in case it is sleeping */ - reg_write(xmit->ohci, xmit->ContextControlSet, 1 << 12); - - /* issue a dummy read of the cycle timer to force all PCI - writes to be posted immediately */ - mb(); - reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer); - - return 0; -} - -static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle) -{ - struct ohci_iso_xmit *xmit = iso->hostdata; - struct ti_ohci *ohci = xmit->ohci; - - /* clear out the control register */ - reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF); - wmb(); - - /* address and length of first descriptor block (Z=3) */ - reg_write(xmit->ohci, xmit->CommandPtr, - dma_prog_region_offset_to_bus(&xmit->prog, iso->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3); - - /* cycle match */ - if (cycle != -1) { - u32 start = cycle & 0x1FFF; - - /* 'cycle' is only mod 8000, but we also need two 'seconds' bits - - just snarf them from the current time */ - u32 seconds = reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer) >> 25; - - /* advance one second to give some extra time for DMA to start */ - seconds += 1; - - start |= (seconds & 3) << 13; - - reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16)); - } - - /* enable interrupts */ - reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << xmit->task.context); - - /* run */ - reg_write(xmit->ohci, xmit->ContextControlSet, 0x8000); - mb(); - - /* wait 100 usec to give the card time to go active */ - udelay(100); - - /* check the RUN bit */ - if (!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) { - PRINT(KERN_ERR, "Error starting IT DMA (ContextControl 0x%08x)\n", - reg_read(xmit->ohci, xmit->ContextControlSet)); - return -1; - } - - return 0; -} - -static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, unsigned long arg) -{ - - switch(cmd) { - case XMIT_INIT: - return ohci_iso_xmit_init(iso); - case XMIT_START: - return ohci_iso_xmit_start(iso, arg); - case XMIT_STOP: - ohci_iso_xmit_stop(iso); - return 0; - case XMIT_QUEUE: - return ohci_iso_xmit_queue(iso, (struct hpsb_iso_packet_info*) arg); - case XMIT_SHUTDOWN: - ohci_iso_xmit_shutdown(iso); - return 0; - - case RECV_INIT: - return ohci_iso_recv_init(iso); - case RECV_START: { - int *args = (int*) arg; - return ohci_iso_recv_start(iso, args[0], args[1], args[2]); - } - case RECV_STOP: - ohci_iso_recv_stop(iso); - return 0; - case RECV_RELEASE: - ohci_iso_recv_release(iso, (struct hpsb_iso_packet_info*) arg); - return 0; - case RECV_FLUSH: - ohci_iso_recv_task((unsigned long) iso); - return 0; - case RECV_SHUTDOWN: - ohci_iso_recv_shutdown(iso); - return 0; - case RECV_LISTEN_CHANNEL: - ohci_iso_recv_change_channel(iso, arg, 1); - return 0; - case RECV_UNLISTEN_CHANNEL: - ohci_iso_recv_change_channel(iso, arg, 0); - return 0; - case RECV_SET_CHANNEL_MASK: - ohci_iso_recv_set_channel_mask(iso, *((u64*) arg)); - return 0; - - default: - PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet", - cmd); - break; - } - return -EINVAL; -} - -/*************************************** - * IEEE-1394 functionality section END * - ***************************************/ - - -/******************************************************** - * Global stuff (interrupt handler, init/shutdown code) * - ********************************************************/ - -static void dma_trm_reset(struct dma_trm_ctx *d) -{ - unsigned long flags; - LIST_HEAD(packet_list); - struct ti_ohci *ohci = d->ohci; - struct hpsb_packet *packet, *ptmp; - - ohci1394_stop_context(ohci, d->ctrlClear, NULL); - - /* Lock the context, reset it and release it. Move the packets - * that were pending in the context to packet_list and free - * them after releasing the lock. */ - - spin_lock_irqsave(&d->lock, flags); - - list_splice_init(&d->fifo_list, &packet_list); - list_splice_init(&d->pending_list, &packet_list); - - d->branchAddrPtr = NULL; - d->sent_ind = d->prg_ind; - d->free_prgs = d->num_desc; - - spin_unlock_irqrestore(&d->lock, flags); - - if (list_empty(&packet_list)) - return; - - PRINT(KERN_INFO, "AT dma reset ctx=%d, aborting transmission", d->ctx); - - /* Now process subsystem callbacks for the packets from this - * context. */ - list_for_each_entry_safe(packet, ptmp, &packet_list, driver_list) { - list_del_init(&packet->driver_list); - hpsb_packet_sent(ohci->host, packet, ACKX_ABORTED); - } -} - -static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci, - quadlet_t rx_event, - quadlet_t tx_event) -{ - struct ohci1394_iso_tasklet *t; - unsigned long mask; - unsigned long flags; - - spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); - - list_for_each_entry(t, &ohci->iso_tasklet_list, link) { - mask = 1 << t->context; - - if (t->type == OHCI_ISO_TRANSMIT) { - if (tx_event & mask) - tasklet_schedule(&t->tasklet); - } else { - /* OHCI_ISO_RECEIVE or OHCI_ISO_MULTICHANNEL_RECEIVE */ - if (rx_event & mask) - tasklet_schedule(&t->tasklet); - } - } - - spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); -} - -static irqreturn_t ohci_irq_handler(int irq, void *dev_id) -{ - quadlet_t event, node_id; - struct ti_ohci *ohci = (struct ti_ohci *)dev_id; - struct hpsb_host *host = ohci->host; - int phyid = -1, isroot = 0; - unsigned long flags; - - /* Read and clear the interrupt event register. Don't clear - * the busReset event, though. This is done when we get the - * selfIDComplete interrupt. */ - spin_lock_irqsave(&ohci->event_lock, flags); - event = reg_read(ohci, OHCI1394_IntEventClear); - reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset); - spin_unlock_irqrestore(&ohci->event_lock, flags); - - if (!event) - return IRQ_NONE; - - /* If event is ~(u32)0 cardbus card was ejected. In this case - * we just return, and clean up in the ohci1394_pci_remove - * function. */ - if (event == ~(u32) 0) { - DBGMSG("Device removed."); - return IRQ_NONE; - } - - DBGMSG("IntEvent: %08x", event); - - if (event & OHCI1394_unrecoverableError) { - int ctx; - PRINT(KERN_ERR, "Unrecoverable error!"); - - if (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800) - PRINT(KERN_ERR, "Async Req Tx Context died: " - "ctrl[%08x] cmdptr[%08x]", - reg_read(ohci, OHCI1394_AsReqTrContextControlSet), - reg_read(ohci, OHCI1394_AsReqTrCommandPtr)); - - if (reg_read(ohci, OHCI1394_AsRspTrContextControlSet) & 0x800) - PRINT(KERN_ERR, "Async Rsp Tx Context died: " - "ctrl[%08x] cmdptr[%08x]", - reg_read(ohci, OHCI1394_AsRspTrContextControlSet), - reg_read(ohci, OHCI1394_AsRspTrCommandPtr)); - - if (reg_read(ohci, OHCI1394_AsReqRcvContextControlSet) & 0x800) - PRINT(KERN_ERR, "Async Req Rcv Context died: " - "ctrl[%08x] cmdptr[%08x]", - reg_read(ohci, OHCI1394_AsReqRcvContextControlSet), - reg_read(ohci, OHCI1394_AsReqRcvCommandPtr)); - - if (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x800) - PRINT(KERN_ERR, "Async Rsp Rcv Context died: " - "ctrl[%08x] cmdptr[%08x]", - reg_read(ohci, OHCI1394_AsRspRcvContextControlSet), - reg_read(ohci, OHCI1394_AsRspRcvCommandPtr)); - - for (ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) { - if (reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800) - PRINT(KERN_ERR, "Iso Xmit %d Context died: " - "ctrl[%08x] cmdptr[%08x]", ctx, - reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)), - reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx))); - } - - for (ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) { - if (reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800) - PRINT(KERN_ERR, "Iso Recv %d Context died: " - "ctrl[%08x] cmdptr[%08x] match[%08x]", ctx, - reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)), - reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)), - reg_read(ohci, OHCI1394_IsoRcvContextMatch + (32 * ctx))); - } - - event &= ~OHCI1394_unrecoverableError; - } - if (event & OHCI1394_postedWriteErr) { - PRINT(KERN_ERR, "physical posted write error"); - /* no recovery strategy yet, had to involve protocol drivers */ - event &= ~OHCI1394_postedWriteErr; - } - if (event & OHCI1394_cycleTooLong) { - if(printk_ratelimit()) - PRINT(KERN_WARNING, "isochronous cycle too long"); - else - DBGMSG("OHCI1394_cycleTooLong"); - reg_write(ohci, OHCI1394_LinkControlSet, - OHCI1394_LinkControl_CycleMaster); - event &= ~OHCI1394_cycleTooLong; - } - if (event & OHCI1394_cycleInconsistent) { - /* We subscribe to the cycleInconsistent event only to - * clear the corresponding event bit... otherwise, - * isochronous cycleMatch DMA won't work. */ - DBGMSG("OHCI1394_cycleInconsistent"); - event &= ~OHCI1394_cycleInconsistent; - } - if (event & OHCI1394_busReset) { - /* The busReset event bit can't be cleared during the - * selfID phase, so we disable busReset interrupts, to - * avoid burying the cpu in interrupt requests. */ - spin_lock_irqsave(&ohci->event_lock, flags); - reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset); - - if (ohci->check_busreset) { - int loop_count = 0; - - udelay(10); - - while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) { - reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); - - spin_unlock_irqrestore(&ohci->event_lock, flags); - udelay(10); - spin_lock_irqsave(&ohci->event_lock, flags); - - /* The loop counter check is to prevent the driver - * from remaining in this state forever. For the - * initial bus reset, the loop continues for ever - * and the system hangs, until some device is plugged-in - * or out manually into a port! The forced reset seems - * to solve this problem. This mainly effects nForce2. */ - if (loop_count > 10000) { - ohci_devctl(host, RESET_BUS, LONG_RESET); - DBGMSG("Detected bus-reset loop. Forced a bus reset!"); - loop_count = 0; - } - - loop_count++; - } - } - spin_unlock_irqrestore(&ohci->event_lock, flags); - if (!host->in_bus_reset) { - DBGMSG("irq_handler: Bus reset requested"); - - /* Subsystem call */ - hpsb_bus_reset(ohci->host); - } - event &= ~OHCI1394_busReset; - } - if (event & OHCI1394_reqTxComplete) { - struct dma_trm_ctx *d = &ohci->at_req_context; - DBGMSG("Got reqTxComplete interrupt " - "status=0x%08X", reg_read(ohci, d->ctrlSet)); - if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, - "reqTxComplete"); - else - dma_trm_tasklet((unsigned long)d); - //tasklet_schedule(&d->task); - event &= ~OHCI1394_reqTxComplete; - } - if (event & OHCI1394_respTxComplete) { - struct dma_trm_ctx *d = &ohci->at_resp_context; - DBGMSG("Got respTxComplete interrupt " - "status=0x%08X", reg_read(ohci, d->ctrlSet)); - if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, - "respTxComplete"); - else - tasklet_schedule(&d->task); - event &= ~OHCI1394_respTxComplete; - } - if (event & OHCI1394_RQPkt) { - struct dma_rcv_ctx *d = &ohci->ar_req_context; - DBGMSG("Got RQPkt interrupt status=0x%08X", - reg_read(ohci, d->ctrlSet)); - if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt"); - else - tasklet_schedule(&d->task); - event &= ~OHCI1394_RQPkt; - } - if (event & OHCI1394_RSPkt) { - struct dma_rcv_ctx *d = &ohci->ar_resp_context; - DBGMSG("Got RSPkt interrupt status=0x%08X", - reg_read(ohci, d->ctrlSet)); - if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt"); - else - tasklet_schedule(&d->task); - event &= ~OHCI1394_RSPkt; - } - if (event & OHCI1394_isochRx) { - quadlet_t rx_event; - - rx_event = reg_read(ohci, OHCI1394_IsoRecvIntEventSet); - reg_write(ohci, OHCI1394_IsoRecvIntEventClear, rx_event); - ohci_schedule_iso_tasklets(ohci, rx_event, 0); - event &= ~OHCI1394_isochRx; - } - if (event & OHCI1394_isochTx) { - quadlet_t tx_event; - - tx_event = reg_read(ohci, OHCI1394_IsoXmitIntEventSet); - reg_write(ohci, OHCI1394_IsoXmitIntEventClear, tx_event); - ohci_schedule_iso_tasklets(ohci, 0, tx_event); - event &= ~OHCI1394_isochTx; - } - if (event & OHCI1394_selfIDComplete) { - if (host->in_bus_reset) { - node_id = reg_read(ohci, OHCI1394_NodeID); - - if (!(node_id & 0x80000000)) { - PRINT(KERN_ERR, - "SelfID received, but NodeID invalid " - "(probably new bus reset occurred): %08X", - node_id); - goto selfid_not_valid; - } - - phyid = node_id & 0x0000003f; - isroot = (node_id & 0x40000000) != 0; - - DBGMSG("SelfID interrupt received " - "(phyid %d, %s)", phyid, - (isroot ? "root" : "not root")); - - handle_selfid(ohci, host, phyid, isroot); - - /* Clear the bus reset event and re-enable the - * busReset interrupt. */ - spin_lock_irqsave(&ohci->event_lock, flags); - reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); - reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); - spin_unlock_irqrestore(&ohci->event_lock, flags); - - /* Turn on phys dma reception. - * - * TODO: Enable some sort of filtering management. - */ - if (phys_dma) { - reg_write(ohci, OHCI1394_PhyReqFilterHiSet, - 0xffffffff); - reg_write(ohci, OHCI1394_PhyReqFilterLoSet, - 0xffffffff); - } - - DBGMSG("PhyReqFilter=%08x%08x", - reg_read(ohci, OHCI1394_PhyReqFilterHiSet), - reg_read(ohci, OHCI1394_PhyReqFilterLoSet)); - - hpsb_selfid_complete(host, phyid, isroot); - } else - PRINT(KERN_ERR, - "SelfID received outside of bus reset sequence"); - -selfid_not_valid: - event &= ~OHCI1394_selfIDComplete; - } - - /* Make sure we handle everything, just in case we accidentally - * enabled an interrupt that we didn't write a handler for. */ - if (event) - PRINT(KERN_ERR, "Unhandled interrupt(s) 0x%08x", - event); - - return IRQ_HANDLED; -} - -/* Put the buffer back into the dma context */ -static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx) -{ - struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); - DBGMSG("Inserting dma buf ctx=%d idx=%d", d->ctx, idx); - - d->prg_cpu[idx]->status = cpu_to_le32(d->buf_size); - d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0); - idx = (idx + d->num_desc - 1 ) % d->num_desc; - d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001); - - /* To avoid a race, ensure 1394 interface hardware sees the inserted - * context program descriptors before it sees the wakeup bit set. */ - wmb(); - - /* wake up the dma context if necessary */ - if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { - PRINT(KERN_INFO, - "Waking dma ctx=%d ... processing is probably too slow", - d->ctx); - } - - /* do this always, to avoid race condition */ - reg_write(ohci, d->ctrlSet, 0x1000); -} - -#define cond_le32_to_cpu(data, noswap) \ - (noswap ? data : le32_to_cpu(data)) - -static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0, - -1, 0, -1, 0, -1, -1, 16, -1}; - -/* - * Determine the length of a packet in the buffer - * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca> - */ -static inline int packet_length(struct dma_rcv_ctx *d, int idx, - quadlet_t *buf_ptr, int offset, - unsigned char tcode, int noswap) -{ - int length = -1; - - if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) { - length = TCODE_SIZE[tcode]; - if (length == 0) { - if (offset + 12 >= d->buf_size) { - length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc] - [3 - ((d->buf_size - offset) >> 2)], noswap) >> 16); - } else { - length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16); - } - length += 20; - } - } else if (d->type == DMA_CTX_ISO) { - /* Assumption: buffer fill mode with header/trailer */ - length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8; - } - - if (length > 0 && length % 4) - length += 4 - (length % 4); - - return length; -} - -/* Tasklet that processes dma receive buffers */ -static void dma_rcv_tasklet (unsigned long data) -{ - struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data; - struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); - unsigned int split_left, idx, offset, rescount; - unsigned char tcode; - int length, bytes_left, ack; - unsigned long flags; - quadlet_t *buf_ptr; - char *split_ptr; - char msg[256]; - - spin_lock_irqsave(&d->lock, flags); - - idx = d->buf_ind; - offset = d->buf_offset; - buf_ptr = d->buf_cpu[idx] + offset/4; - - rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; - bytes_left = d->buf_size - rescount - offset; - - while (bytes_left > 0) { - tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf; - - /* packet_length() will return < 4 for an error */ - length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming); - - if (length < 4) { /* something is wrong */ - sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d", - tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming), - d->ctx, length); - ohci1394_stop_context(ohci, d->ctrlClear, msg); - spin_unlock_irqrestore(&d->lock, flags); - return; - } - - /* The first case is where we have a packet that crosses - * over more than one descriptor. The next case is where - * it's all in the first descriptor. */ - if ((offset + length) > d->buf_size) { - DBGMSG("Split packet rcv'd"); - if (length > d->split_buf_size) { - ohci1394_stop_context(ohci, d->ctrlClear, - "Split packet size exceeded"); - d->buf_ind = idx; - d->buf_offset = offset; - spin_unlock_irqrestore(&d->lock, flags); - return; - } - - if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status) - == d->buf_size) { - /* Other part of packet not written yet. - * this should never happen I think - * anyway we'll get it on the next call. */ - PRINT(KERN_INFO, - "Got only half a packet!"); - d->buf_ind = idx; - d->buf_offset = offset; - spin_unlock_irqrestore(&d->lock, flags); - return; - } - - split_left = length; - split_ptr = (char *)d->spb; - memcpy(split_ptr,buf_ptr,d->buf_size-offset); - split_left -= d->buf_size-offset; - split_ptr += d->buf_size-offset; - insert_dma_buffer(d, idx); - idx = (idx+1) % d->num_desc; - buf_ptr = d->buf_cpu[idx]; - offset=0; - - while (split_left >= d->buf_size) { - memcpy(split_ptr,buf_ptr,d->buf_size); - split_ptr += d->buf_size; - split_left -= d->buf_size; - insert_dma_buffer(d, idx); - idx = (idx+1) % d->num_desc; - buf_ptr = d->buf_cpu[idx]; - } - - if (split_left > 0) { - memcpy(split_ptr, buf_ptr, split_left); - offset = split_left; - buf_ptr += offset/4; - } - } else { - DBGMSG("Single packet rcv'd"); - memcpy(d->spb, buf_ptr, length); - offset += length; - buf_ptr += length/4; - if (offset==d->buf_size) { - insert_dma_buffer(d, idx); - idx = (idx+1) % d->num_desc; - buf_ptr = d->buf_cpu[idx]; - offset=0; - } - } - - /* We get one phy packet to the async descriptor for each - * bus reset. We always ignore it. */ - if (tcode != OHCI1394_TCODE_PHY) { - if (!ohci->no_swap_incoming) - header_le32_to_cpu(d->spb, tcode); - DBGMSG("Packet received from node" - " %d ack=0x%02X spd=%d tcode=0x%X" - " length=%d ctx=%d tlabel=%d", - (d->spb[1]>>16)&0x3f, - (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f, - (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3, - tcode, length, d->ctx, - (d->spb[0]>>10)&0x3f); - - ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f) - == 0x11) ? 1 : 0; - - hpsb_packet_received(ohci->host, d->spb, - length-4, ack); - } -#ifdef OHCI1394_DEBUG - else - PRINT (KERN_DEBUG, "Got phy packet ctx=%d ... discarded", - d->ctx); -#endif - - rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; - - bytes_left = d->buf_size - rescount - offset; - - } - - d->buf_ind = idx; - d->buf_offset = offset; - - spin_unlock_irqrestore(&d->lock, flags); -} - -/* Bottom half that processes sent packets */ -static void dma_trm_tasklet (unsigned long data) -{ - struct dma_trm_ctx *d = (struct dma_trm_ctx*)data; - struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); - struct hpsb_packet *packet, *ptmp; - unsigned long flags; - u32 status, ack; - size_t datasize; - - spin_lock_irqsave(&d->lock, flags); - - list_for_each_entry_safe(packet, ptmp, &d->fifo_list, driver_list) { - datasize = packet->data_size; - if (datasize && packet->type != hpsb_raw) - status = le32_to_cpu( - d->prg_cpu[d->sent_ind]->end.status) >> 16; - else - status = le32_to_cpu( - d->prg_cpu[d->sent_ind]->begin.status) >> 16; - - if (status == 0) - /* this packet hasn't been sent yet*/ - break; - -#ifdef OHCI1394_DEBUG - if (datasize) - if (((le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf) == 0xa) - DBGMSG("Stream packet sent to channel %d tcode=0x%X " - "ack=0x%X spd=%d dataLength=%d ctx=%d", - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>8)&0x3f, - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf, - status&0x1f, (status>>5)&0x3, - le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16, - d->ctx); - else - DBGMSG("Packet sent to node %d tcode=0x%X tLabel=" - "%d ack=0x%X spd=%d dataLength=%d ctx=%d", - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16)&0x3f, - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf, - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>10)&0x3f, - status&0x1f, (status>>5)&0x3, - le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3])>>16, - d->ctx); - else - DBGMSG("Packet sent to node %d tcode=0x%X tLabel=" - "%d ack=0x%X spd=%d data=0x%08X ctx=%d", - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) - >>16)&0x3f, - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) - >>4)&0xf, - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) - >>10)&0x3f, - status&0x1f, (status>>5)&0x3, - le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]), - d->ctx); -#endif - - if (status & 0x10) { - ack = status & 0xf; - } else { - switch (status & 0x1f) { - case EVT_NO_STATUS: /* that should never happen */ - case EVT_RESERVED_A: /* that should never happen */ - case EVT_LONG_PACKET: /* that should never happen */ - PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f); - ack = ACKX_SEND_ERROR; - break; - case EVT_MISSING_ACK: - ack = ACKX_TIMEOUT; - break; - case EVT_UNDERRUN: - ack = ACKX_SEND_ERROR; - break; - case EVT_OVERRUN: /* that should never happen */ - PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f); - ack = ACKX_SEND_ERROR; - break; - case EVT_DESCRIPTOR_READ: - case EVT_DATA_READ: - case EVT_DATA_WRITE: - ack = ACKX_SEND_ERROR; - break; - case EVT_BUS_RESET: /* that should never happen */ - PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f); - ack = ACKX_SEND_ERROR; - break; - case EVT_TIMEOUT: - ack = ACKX_TIMEOUT; - break; - case EVT_TCODE_ERR: - ack = ACKX_SEND_ERROR; - break; - case EVT_RESERVED_B: /* that should never happen */ - case EVT_RESERVED_C: /* that should never happen */ - PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f); - ack = ACKX_SEND_ERROR; - break; - case EVT_UNKNOWN: - case EVT_FLUSHED: - ack = ACKX_SEND_ERROR; - break; - default: - PRINT(KERN_ERR, "Unhandled OHCI evt_* error 0x%x", status & 0x1f); - ack = ACKX_SEND_ERROR; - BUG(); - } - } - - list_del_init(&packet->driver_list); - hpsb_packet_sent(ohci->host, packet, ack); - - if (datasize) - pci_unmap_single(ohci->dev, - cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address), - datasize, PCI_DMA_TODEVICE); - - d->sent_ind = (d->sent_ind+1)%d->num_desc; - d->free_prgs++; - } - - dma_trm_flush(ohci, d); - - spin_unlock_irqrestore(&d->lock, flags); -} - -static void free_dma_rcv_ctx(struct dma_rcv_ctx *d) -{ - int i; - struct ti_ohci *ohci = d->ohci; - - if (ohci == NULL) - return; - - DBGMSG("Freeing dma_rcv_ctx %d", d->ctx); - - if (d->buf_cpu) { - for (i=0; i<d->num_desc; i++) - if (d->buf_cpu[i] && d->buf_bus[i]) - pci_free_consistent( - ohci->dev, d->buf_size, - d->buf_cpu[i], d->buf_bus[i]); - kfree(d->buf_cpu); - kfree(d->buf_bus); - } - if (d->prg_cpu) { - for (i=0; i<d->num_desc; i++) - if (d->prg_cpu[i] && d->prg_bus[i]) - pci_pool_free(d->prg_pool, d->prg_cpu[i], - d->prg_bus[i]); - pci_pool_destroy(d->prg_pool); - kfree(d->prg_cpu); - kfree(d->prg_bus); - } - kfree(d->spb); - - /* Mark this context as freed. */ - d->ohci = NULL; -} - -static int -alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, - enum context_type type, int ctx, int num_desc, - int buf_size, int split_buf_size, int context_base) -{ - int i, len; - static int num_allocs; - static char pool_name[20]; - - d->ohci = ohci; - d->type = type; - d->ctx = ctx; - - d->num_desc = num_desc; - d->buf_size = buf_size; - d->split_buf_size = split_buf_size; - - d->ctrlSet = 0; - d->ctrlClear = 0; - d->cmdPtr = 0; - - d->buf_cpu = kzalloc(d->num_desc * sizeof(*d->buf_cpu), GFP_ATOMIC); - d->buf_bus = kzalloc(d->num_desc * sizeof(*d->buf_bus), GFP_ATOMIC); - - if (d->buf_cpu == NULL || d->buf_bus == NULL) { - PRINT(KERN_ERR, "Failed to allocate %s", "DMA buffer"); - free_dma_rcv_ctx(d); - return -ENOMEM; - } - - d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_ATOMIC); - d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_ATOMIC); - - if (d->prg_cpu == NULL || d->prg_bus == NULL) { - PRINT(KERN_ERR, "Failed to allocate %s", "DMA prg"); - free_dma_rcv_ctx(d); - return -ENOMEM; - } - - d->spb = kmalloc(d->split_buf_size, GFP_ATOMIC); - - if (d->spb == NULL) { - PRINT(KERN_ERR, "Failed to allocate %s", "split buffer"); - free_dma_rcv_ctx(d); - return -ENOMEM; - } - - len = sprintf(pool_name, "ohci1394_rcv_prg"); - sprintf(pool_name+len, "%d", num_allocs); - d->prg_pool = pci_pool_create(pool_name, ohci->dev, - sizeof(struct dma_cmd), 4, 0); - if(d->prg_pool == NULL) - { - PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name); - free_dma_rcv_ctx(d); - return -ENOMEM; - } - num_allocs++; - - for (i=0; i<d->num_desc; i++) { - d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, - d->buf_size, - d->buf_bus+i); - - if (d->buf_cpu[i] != NULL) { - memset(d->buf_cpu[i], 0, d->buf_size); - } else { - PRINT(KERN_ERR, - "Failed to allocate %s", "DMA buffer"); - free_dma_rcv_ctx(d); - return -ENOMEM; - } - - d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i); - - if (d->prg_cpu[i] != NULL) { - memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd)); - } else { - PRINT(KERN_ERR, - "Failed to allocate %s", "DMA prg"); - free_dma_rcv_ctx(d); - return -ENOMEM; - } - } - - spin_lock_init(&d->lock); - - d->ctrlSet = context_base + OHCI1394_ContextControlSet; - d->ctrlClear = context_base + OHCI1394_ContextControlClear; - d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; - - tasklet_init(&d->task, dma_rcv_tasklet, (unsigned long) d); - return 0; -} - -static void free_dma_trm_ctx(struct dma_trm_ctx *d) -{ - int i; - struct ti_ohci *ohci = d->ohci; - - if (ohci == NULL) - return; - - DBGMSG("Freeing dma_trm_ctx %d", d->ctx); - - if (d->prg_cpu) { - for (i=0; i<d->num_desc; i++) - if (d->prg_cpu[i] && d->prg_bus[i]) - pci_pool_free(d->prg_pool, d->prg_cpu[i], - d->prg_bus[i]); - pci_pool_destroy(d->prg_pool); - kfree(d->prg_cpu); - kfree(d->prg_bus); - } - - /* Mark this context as freed. */ - d->ohci = NULL; -} - -static int -alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, - enum context_type type, int ctx, int num_desc, - int context_base) -{ - int i, len; - static char pool_name[20]; - static int num_allocs=0; - - d->ohci = ohci; - d->type = type; - d->ctx = ctx; - d->num_desc = num_desc; - d->ctrlSet = 0; - d->ctrlClear = 0; - d->cmdPtr = 0; - - d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_KERNEL); - d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_KERNEL); - - if (d->prg_cpu == NULL || d->prg_bus == NULL) { - PRINT(KERN_ERR, "Failed to allocate %s", "AT DMA prg"); - free_dma_trm_ctx(d); - return -ENOMEM; - } - - len = sprintf(pool_name, "ohci1394_trm_prg"); - sprintf(pool_name+len, "%d", num_allocs); - d->prg_pool = pci_pool_create(pool_name, ohci->dev, - sizeof(struct at_dma_prg), 4, 0); - if (d->prg_pool == NULL) { - PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name); - free_dma_trm_ctx(d); - return -ENOMEM; - } - num_allocs++; - - for (i = 0; i < d->num_desc; i++) { - d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i); - - if (d->prg_cpu[i] != NULL) { - memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg)); - } else { - PRINT(KERN_ERR, - "Failed to allocate %s", "AT DMA prg"); - free_dma_trm_ctx(d); - return -ENOMEM; - } - } - - spin_lock_init(&d->lock); - - /* initialize tasklet */ - d->ctrlSet = context_base + OHCI1394_ContextControlSet; - d->ctrlClear = context_base + OHCI1394_ContextControlClear; - d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; - tasklet_init(&d->task, dma_trm_tasklet, (unsigned long)d); - return 0; -} - -static void ohci_set_hw_config_rom(struct hpsb_host *host, __be32 *config_rom) -{ - struct ti_ohci *ohci = host->hostdata; - - reg_write(ohci, OHCI1394_ConfigROMhdr, be32_to_cpu(config_rom[0])); - reg_write(ohci, OHCI1394_BusOptions, be32_to_cpu(config_rom[2])); - - memcpy(ohci->csr_config_rom_cpu, config_rom, OHCI_CONFIG_ROM_LEN); -} - - -static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg, - quadlet_t data, quadlet_t compare) -{ - struct ti_ohci *ohci = host->hostdata; - int i; - - reg_write(ohci, OHCI1394_CSRData, data); - reg_write(ohci, OHCI1394_CSRCompareData, compare); - reg_write(ohci, OHCI1394_CSRControl, reg & 0x3); - - for (i = 0; i < OHCI_LOOP_COUNT; i++) { - if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) - break; - - mdelay(1); - } - - return reg_read(ohci, OHCI1394_CSRData); -} - -static struct hpsb_host_driver ohci1394_driver = { - .owner = THIS_MODULE, - .name = OHCI1394_DRIVER_NAME, - .set_hw_config_rom = ohci_set_hw_config_rom, - .transmit_packet = ohci_transmit, - .devctl = ohci_devctl, - .isoctl = ohci_isoctl, - .hw_csr_reg = ohci_hw_csr_reg, -}; - -/*********************************** - * PCI Driver Interface functions * - ***********************************/ - -#ifdef CONFIG_PPC_PMAC -static void ohci1394_pmac_on(struct pci_dev *dev) -{ - if (machine_is(powermac)) { - struct device_node *ofn = pci_device_to_OF_node(dev); - - if (ofn) { - pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1); - pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); - } - } -} - -static void ohci1394_pmac_off(struct pci_dev *dev) -{ - if (machine_is(powermac)) { - struct device_node *ofn = pci_device_to_OF_node(dev); - - if (ofn) { - pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); - pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); - } - } -} -#else -#define ohci1394_pmac_on(dev) -#define ohci1394_pmac_off(dev) -#endif /* CONFIG_PPC_PMAC */ - -static int __devinit ohci1394_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - struct hpsb_host *host; - struct ti_ohci *ohci; /* shortcut to currently handled device */ - resource_size_t ohci_base; - int err = -ENOMEM; - - ohci1394_pmac_on(dev); - if (pci_enable_device(dev)) { - PRINT_G(KERN_ERR, "Failed to enable OHCI hardware"); - err = -ENXIO; - goto err; - } - pci_set_master(dev); - - host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci), &dev->dev); - if (!host) { - PRINT_G(KERN_ERR, "Failed to allocate %s", "host structure"); - goto err; - } - ohci = host->hostdata; - ohci->dev = dev; - ohci->host = host; - ohci->init_state = OHCI_INIT_ALLOC_HOST; - host->pdev = dev; - pci_set_drvdata(dev, ohci); - - /* We don't want hardware swapping */ - pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0); - - /* Some oddball Apple controllers do not order the selfid - * properly, so we make up for it here. */ -#ifndef __LITTLE_ENDIAN - /* XXX: Need a better way to check this. I'm wondering if we can - * read the values of the OHCI1394_PCI_HCI_Control and the - * noByteSwapData registers to see if they were not cleared to - * zero. Should this work? Obviously it's not defined what these - * registers will read when they aren't supported. Bleh! */ - if (dev->vendor == PCI_VENDOR_ID_APPLE && - dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { - ohci->no_swap_incoming = 1; - ohci->selfid_swap = 0; - } else - ohci->selfid_swap = 1; -#endif - - -#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_FW -#define PCI_DEVICE_ID_NVIDIA_NFORCE2_FW 0x006e -#endif - - /* These chipsets require a bit of extra care when checking after - * a busreset. */ - if ((dev->vendor == PCI_VENDOR_ID_APPLE && - dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) || - (dev->vendor == PCI_VENDOR_ID_NVIDIA && - dev->device == PCI_DEVICE_ID_NVIDIA_NFORCE2_FW)) - ohci->check_busreset = 1; - - /* We hardwire the MMIO length, since some CardBus adaptors - * fail to report the right length. Anyway, the ohci spec - * clearly says it's 2kb, so this shouldn't be a problem. */ - ohci_base = pci_resource_start(dev, 0); - if (pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE) - PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!", - (unsigned long long)pci_resource_len(dev, 0)); - - if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE, - OHCI1394_DRIVER_NAME)) { - PRINT_G(KERN_ERR, "MMIO resource (0x%llx - 0x%llx) unavailable", - (unsigned long long)ohci_base, - (unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE); - goto err; - } - ohci->init_state = OHCI_INIT_HAVE_MEM_REGION; - - ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE); - if (ohci->registers == NULL) { - PRINT_G(KERN_ERR, "Failed to remap registers"); - err = -ENXIO; - goto err; - } - ohci->init_state = OHCI_INIT_HAVE_IOMAPPING; - DBGMSG("Remapped memory spaces reg 0x%p", ohci->registers); - - /* csr_config rom allocation */ - ohci->csr_config_rom_cpu = - pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, - &ohci->csr_config_rom_bus); - if (ohci->csr_config_rom_cpu == NULL) { - PRINT_G(KERN_ERR, "Failed to allocate %s", "buffer config rom"); - goto err; - } - ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER; - - /* self-id dma buffer allocation */ - ohci->selfid_buf_cpu = - pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, - &ohci->selfid_buf_bus); - if (ohci->selfid_buf_cpu == NULL) { - PRINT_G(KERN_ERR, "Failed to allocate %s", "self-ID buffer"); - goto err; - } - ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER; - - if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff) - PRINT(KERN_INFO, "SelfID buffer %p is not aligned on " - "8Kb boundary... may cause problems on some CXD3222 chip", - ohci->selfid_buf_cpu); - - /* No self-id errors at startup */ - ohci->self_id_errors = 0; - - ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE; - /* AR DMA request context allocation */ - if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context, - DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC, - AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE, - OHCI1394_AsReqRcvContextBase) < 0) { - PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Req context"); - goto err; - } - /* AR DMA response context allocation */ - if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context, - DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC, - AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE, - OHCI1394_AsRspRcvContextBase) < 0) { - PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Resp context"); - goto err; - } - /* AT DMA request context */ - if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context, - DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC, - OHCI1394_AsReqTrContextBase) < 0) { - PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Req context"); - goto err; - } - /* AT DMA response context */ - if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context, - DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC, - OHCI1394_AsRspTrContextBase) < 0) { - PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Resp context"); - goto err; - } - /* Start off with a soft reset, to clear everything to a sane - * state. */ - ohci_soft_reset(ohci); - - /* Now enable LPS, which we need in order to start accessing - * most of the registers. In fact, on some cards (ALI M5251), - * accessing registers in the SClk domain without LPS enabled - * will lock up the machine. */ - reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS); - - /* Disable and clear interrupts */ - reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); - reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); - - /* Flush MMIO writes and wait to make sure we have full link enabled. */ - reg_read(ohci, OHCI1394_Version); - msleep(50); - - /* Determine the number of available IR and IT contexts. */ - ohci->nb_iso_rcv_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); - ohci->nb_iso_xmit_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); - - /* Set the usage bits for non-existent contexts so they can't - * be allocated */ - ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx; - ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx; - - INIT_LIST_HEAD(&ohci->iso_tasklet_list); - spin_lock_init(&ohci->iso_tasklet_list_lock); - ohci->ISO_channel_usage = 0; - spin_lock_init(&ohci->IR_channel_lock); - - spin_lock_init(&ohci->event_lock); - - /* - * interrupts are disabled, all right, but... due to IRQF_SHARED we - * might get called anyway. We'll see no event, of course, but - * we need to get to that "no event", so enough should be initialized - * by that point. - */ - err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED, - OHCI1394_DRIVER_NAME, ohci); - if (err) { - PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq); - goto err; - } - ohci->init_state = OHCI_INIT_HAVE_IRQ; - ohci_initialize(ohci); - - /* Set certain csr values */ - host->csr.guid_hi = reg_read(ohci, OHCI1394_GUIDHi); - host->csr.guid_lo = reg_read(ohci, OHCI1394_GUIDLo); - host->csr.cyc_clk_acc = 100; /* how do we determine clk accuracy? */ - host->csr.max_rec = (reg_read(ohci, OHCI1394_BusOptions) >> 12) & 0xf; - host->csr.lnk_spd = reg_read(ohci, OHCI1394_BusOptions) & 0x7; - - if (phys_dma) { - host->low_addr_space = - (u64) reg_read(ohci, OHCI1394_PhyUpperBound) << 16; - if (!host->low_addr_space) - host->low_addr_space = OHCI1394_PHYS_UPPER_BOUND_FIXED; - } - host->middle_addr_space = OHCI1394_MIDDLE_ADDRESS_SPACE; - - /* Tell the highlevel this host is ready */ - if (hpsb_add_host(host)) { - PRINT_G(KERN_ERR, "Failed to register host with highlevel"); - goto err; - } - ohci->init_state = OHCI_INIT_DONE; - - return 0; -err: - ohci1394_pci_remove(dev); - return err; -} - -static void ohci1394_pci_remove(struct pci_dev *dev) -{ - struct ti_ohci *ohci; - struct device *device; - - ohci = pci_get_drvdata(dev); - if (!ohci) - goto out; - - device = get_device(&ohci->host->device); - - switch (ohci->init_state) { - case OHCI_INIT_DONE: - hpsb_remove_host(ohci->host); - - /* Clear out BUS Options */ - reg_write(ohci, OHCI1394_ConfigROMhdr, 0); - reg_write(ohci, OHCI1394_BusOptions, - (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) | - 0x00ff0000); - memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN); - - case OHCI_INIT_HAVE_IRQ: - /* Clear interrupt registers */ - reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); - reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); - reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); - reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); - reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); - reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); - - /* Disable IRM Contender */ - set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4)); - - /* Clear link control register */ - reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); - - /* Let all other nodes know to ignore us */ - ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT); - - /* Soft reset before we start - this disables - * interrupts and clears linkEnable and LPS. */ - ohci_soft_reset(ohci); - free_irq(dev->irq, ohci); - - case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE: - /* The ohci_soft_reset() stops all DMA contexts, so we - * dont need to do this. */ - free_dma_rcv_ctx(&ohci->ar_req_context); - free_dma_rcv_ctx(&ohci->ar_resp_context); - free_dma_trm_ctx(&ohci->at_req_context); - free_dma_trm_ctx(&ohci->at_resp_context); - - case OHCI_INIT_HAVE_SELFID_BUFFER: - pci_free_consistent(dev, OHCI1394_SI_DMA_BUF_SIZE, - ohci->selfid_buf_cpu, - ohci->selfid_buf_bus); - - case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER: - pci_free_consistent(dev, OHCI_CONFIG_ROM_LEN, - ohci->csr_config_rom_cpu, - ohci->csr_config_rom_bus); - - case OHCI_INIT_HAVE_IOMAPPING: - iounmap(ohci->registers); - - case OHCI_INIT_HAVE_MEM_REGION: - release_mem_region(pci_resource_start(dev, 0), - OHCI1394_REGISTER_SIZE); - - case OHCI_INIT_ALLOC_HOST: - pci_set_drvdata(dev, NULL); - } - - if (device) - put_device(device); -out: - ohci1394_pmac_off(dev); -} - -#ifdef CONFIG_PM -static int ohci1394_pci_suspend(struct pci_dev *dev, pm_message_t state) -{ - int err; - struct ti_ohci *ohci = pci_get_drvdata(dev); - - if (!ohci) { - printk(KERN_ERR "%s: tried to suspend nonexisting host\n", - OHCI1394_DRIVER_NAME); - return -ENXIO; - } - DBGMSG("suspend called"); - - /* Clear the async DMA contexts and stop using the controller */ - hpsb_bus_reset(ohci->host); - - /* See ohci1394_pci_remove() for comments on this sequence */ - reg_write(ohci, OHCI1394_ConfigROMhdr, 0); - reg_write(ohci, OHCI1394_BusOptions, - (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) | - 0x00ff0000); - reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); - reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); - reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); - reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); - reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); - reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); - set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4)); - reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); - ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT); - ohci_soft_reset(ohci); - - free_irq(dev->irq, ohci); - err = pci_save_state(dev); - if (err) { - PRINT(KERN_ERR, "pci_save_state failed with %d", err); - return err; - } - err = pci_set_power_state(dev, pci_choose_state(dev, state)); - if (err) - DBGMSG("pci_set_power_state failed with %d", err); - ohci1394_pmac_off(dev); - - return 0; -} - -static int ohci1394_pci_resume(struct pci_dev *dev) -{ - int err; - struct ti_ohci *ohci = pci_get_drvdata(dev); - - if (!ohci) { - printk(KERN_ERR "%s: tried to resume nonexisting host\n", - OHCI1394_DRIVER_NAME); - return -ENXIO; - } - DBGMSG("resume called"); - - ohci1394_pmac_on(dev); - pci_set_power_state(dev, PCI_D0); - pci_restore_state(dev); - err = pci_enable_device(dev); - if (err) { - PRINT(KERN_ERR, "pci_enable_device failed with %d", err); - return err; - } - - /* See ohci1394_pci_probe() for comments on this sequence */ - ohci_soft_reset(ohci); - reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS); - reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); - reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); - reg_read(ohci, OHCI1394_Version); - msleep(50); - - err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED, - OHCI1394_DRIVER_NAME, ohci); - if (err) { - PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq); - return err; - } - - ohci_initialize(ohci); - - hpsb_resume_host(ohci->host); - return 0; -} -#endif /* CONFIG_PM */ - -static struct pci_device_id ohci1394_pci_tbl[] = { - { - .class = PCI_CLASS_SERIAL_FIREWIRE_OHCI, - .class_mask = PCI_ANY_ID, - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, }, -}; - -MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl); - -static struct pci_driver ohci1394_pci_driver = { - .name = OHCI1394_DRIVER_NAME, - .id_table = ohci1394_pci_tbl, - .probe = ohci1394_pci_probe, - .remove = ohci1394_pci_remove, -#ifdef CONFIG_PM - .resume = ohci1394_pci_resume, - .suspend = ohci1394_pci_suspend, -#endif -}; - -/*********************************** - * OHCI1394 Video Interface * - ***********************************/ - -/* essentially the only purpose of this code is to allow another - module to hook into ohci's interrupt handler */ - -/* returns zero if successful, one if DMA context is locked up */ -int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg) -{ - int i=0; - - /* stop the channel program if it's still running */ - reg_write(ohci, reg, 0x8000); - - /* Wait until it effectively stops */ - while (reg_read(ohci, reg) & 0x400) { - i++; - if (i>5000) { - PRINT(KERN_ERR, - "Runaway loop while stopping context: %s...", msg ? msg : ""); - return 1; - } - - mb(); - udelay(10); - } - if (msg) PRINT(KERN_ERR, "%s: dma prg stopped", msg); - return 0; -} - -void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type, - void (*func)(unsigned long), unsigned long data) -{ - tasklet_init(&tasklet->tasklet, func, data); - tasklet->type = type; - /* We init the tasklet->link field, so we can list_del() it - * without worrying whether it was added to the list or not. */ - INIT_LIST_HEAD(&tasklet->link); -} - -int ohci1394_register_iso_tasklet(struct ti_ohci *ohci, - struct ohci1394_iso_tasklet *tasklet) -{ - unsigned long flags, *usage; - int n, i, r = -EBUSY; - - if (tasklet->type == OHCI_ISO_TRANSMIT) { - n = ohci->nb_iso_xmit_ctx; - usage = &ohci->it_ctx_usage; - } - else { - n = ohci->nb_iso_rcv_ctx; - usage = &ohci->ir_ctx_usage; - - /* only one receive context can be multichannel (OHCI sec 10.4.1) */ - if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) { - if (test_and_set_bit(0, &ohci->ir_multichannel_used)) { - return r; - } - } - } - - spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); - - for (i = 0; i < n; i++) - if (!test_and_set_bit(i, usage)) { - tasklet->context = i; - list_add_tail(&tasklet->link, &ohci->iso_tasklet_list); - r = 0; - break; - } - - spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); - - return r; -} - -void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci, - struct ohci1394_iso_tasklet *tasklet) -{ - unsigned long flags; - - tasklet_kill(&tasklet->tasklet); - - spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); - - if (tasklet->type == OHCI_ISO_TRANSMIT) - clear_bit(tasklet->context, &ohci->it_ctx_usage); - else { - clear_bit(tasklet->context, &ohci->ir_ctx_usage); - - if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) { - clear_bit(0, &ohci->ir_multichannel_used); - } - } - - list_del(&tasklet->link); - - spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); -} - -EXPORT_SYMBOL(ohci1394_stop_context); -EXPORT_SYMBOL(ohci1394_init_iso_tasklet); -EXPORT_SYMBOL(ohci1394_register_iso_tasklet); -EXPORT_SYMBOL(ohci1394_unregister_iso_tasklet); - -/*********************************** - * General module initialization * - ***********************************/ - -MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>"); -MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers"); -MODULE_LICENSE("GPL"); - -static void __exit ohci1394_cleanup (void) -{ - pci_unregister_driver(&ohci1394_pci_driver); -} - -static int __init ohci1394_init(void) -{ - return pci_register_driver(&ohci1394_pci_driver); -} - -module_init(ohci1394_init); -module_exit(ohci1394_cleanup); diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h deleted file mode 100644 index 7fb8ab9780a..00000000000 --- a/drivers/ieee1394/ohci1394.h +++ /dev/null @@ -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 diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c deleted file mode 100644 index bf47fee7980..00000000000 --- a/drivers/ieee1394/pcilynx.c +++ /dev/null @@ -1,1554 +0,0 @@ -/* - * pcilynx.c - Texas Instruments PCILynx driver - * Copyright (C) 1999,2000 Andreas Bombe <andreas.bombe@munich.netsurf.de>, - * Stephan Linz <linz@mazet.de> - * Manfred Weihs <weihs@ict.tuwien.ac.at> - * - * 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. - */ - -/* - * Contributions: - * - * Manfred Weihs <weihs@ict.tuwien.ac.at> - * reading bus info block (containing GUID) from serial - * eeprom via i2c and storing it in config ROM - * Reworked code for initiating bus resets - * (long, short, with or without hold-off) - * Enhancements in async and iso send code - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/wait.h> -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/fs.h> -#include <linux/poll.h> -#include <linux/kdev_t.h> -#include <linux/dma-mapping.h> -#include <asm/byteorder.h> -#include <asm/atomic.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/irq.h> - -#include "csr1212.h" -#include "ieee1394.h" -#include "ieee1394_types.h" -#include "hosts.h" -#include "ieee1394_core.h" -#include "highlevel.h" -#include "pcilynx.h" - -#include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> - -/* print general (card independent) information */ -#define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args) -/* print card specific information */ -#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args) - -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG -#define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args) -#define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args) -#else -#define PRINT_GD(level, fmt, args...) do {} while (0) -#define PRINTD(level, card, fmt, args...) do {} while (0) -#endif - - -/* Module Parameters */ -static int skip_eeprom; -module_param(skip_eeprom, int, 0444); -MODULE_PARM_DESC(skip_eeprom, "Use generic bus info block instead of serial eeprom (default = 0)."); - - -static struct hpsb_host_driver lynx_driver; -static unsigned int card_id; - - - -/* - * I2C stuff - */ - -/* the i2c stuff was inspired by i2c-philips-par.c */ - -static void bit_setscl(void *data, int state) -{ - if (state) { - ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000040; - } else { - ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000040; - } - reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state); -} - -static void bit_setsda(void *data, int state) -{ - if (state) { - ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000010; - } else { - ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000010; - } - reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state); -} - -static int bit_getscl(void *data) -{ - return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000040; -} - -static int bit_getsda(void *data) -{ - return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000010; -} - -static struct i2c_algo_bit_data bit_data = { - .setsda = bit_setsda, - .setscl = bit_setscl, - .getsda = bit_getsda, - .getscl = bit_getscl, - .udelay = 5, - .timeout = 100, -}; - - -/* - * PCL handling functions. - */ - -static pcl_t alloc_pcl(struct ti_lynx *lynx) -{ - u8 m; - int i, j; - - spin_lock(&lynx->lock); - /* FIXME - use ffz() to make this readable */ - for (i = 0; i < (LOCALRAM_SIZE / 1024); i++) { - m = lynx->pcl_bmap[i]; - for (j = 0; j < 8; j++) { - if (m & 1<<j) { - continue; - } - m |= 1<<j; - lynx->pcl_bmap[i] = m; - spin_unlock(&lynx->lock); - return 8 * i + j; - } - } - spin_unlock(&lynx->lock); - - return -1; -} - - -#if 0 -static void free_pcl(struct ti_lynx *lynx, pcl_t pclid) -{ - int off, bit; - - off = pclid / 8; - bit = pclid % 8; - - if (pclid < 0) { - return; - } - - spin_lock(&lynx->lock); - if (lynx->pcl_bmap[off] & 1<<bit) { - lynx->pcl_bmap[off] &= ~(1<<bit); - } else { - PRINT(KERN_ERR, lynx->id, - "attempted to free unallocated PCL %d", pclid); - } - spin_unlock(&lynx->lock); -} - -/* functions useful for debugging */ -static void pretty_print_pcl(const struct ti_pcl *pcl) -{ - int i; - - printk("PCL next %08x, userdata %08x, status %08x, remtrans %08x, nextbuf %08x\n", - pcl->next, pcl->user_data, pcl->pcl_status, - pcl->remaining_transfer_count, pcl->next_data_buffer); - - printk("PCL"); - for (i=0; i<13; i++) { - printk(" c%x:%08x d%x:%08x", - i, pcl->buffer[i].control, i, pcl->buffer[i].pointer); - if (!(i & 0x3) && (i != 12)) printk("\nPCL"); - } - printk("\n"); -} - -static void print_pcl(const struct ti_lynx *lynx, pcl_t pclid) -{ - struct ti_pcl pcl; - - get_pcl(lynx, pclid, &pcl); - pretty_print_pcl(&pcl); -} -#endif - - - -/*********************************** - * IEEE-1394 functionality section * - ***********************************/ - - -static int get_phy_reg(struct ti_lynx *lynx, int addr) -{ - int retval; - int i = 0; - - unsigned long flags; - - if (addr > 15) { - PRINT(KERN_ERR, lynx->id, - "%s: PHY register address %d out of range", - __func__, addr); - return -1; - } - - spin_lock_irqsave(&lynx->phy_reg_lock, flags); - - reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr)); - do { - retval = reg_read(lynx, LINK_PHY); - - if (i > 10000) { - PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting", - __func__); - retval = -1; - break; - } - i++; - } while ((retval & 0xf00) != LINK_PHY_RADDR(addr)); - - reg_write(lynx, LINK_INT_STATUS, LINK_INT_PHY_REG_RCVD); - spin_unlock_irqrestore(&lynx->phy_reg_lock, flags); - - if (retval != -1) { - return retval & 0xff; - } else { - return -1; - } -} - -static int set_phy_reg(struct ti_lynx *lynx, int addr, int val) -{ - unsigned long flags; - - if (addr > 15) { - PRINT(KERN_ERR, lynx->id, - "%s: PHY register address %d out of range", __func__, addr); - return -1; - } - - if (val > 0xff) { - PRINT(KERN_ERR, lynx->id, - "%s: PHY register value %d out of range", __func__, val); - return -1; - } - - spin_lock_irqsave(&lynx->phy_reg_lock, flags); - - reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | LINK_PHY_ADDR(addr) - | LINK_PHY_WDATA(val)); - - spin_unlock_irqrestore(&lynx->phy_reg_lock, flags); - - return 0; -} - -static int sel_phy_reg_page(struct ti_lynx *lynx, int page) -{ - int reg; - - if (page > 7) { - PRINT(KERN_ERR, lynx->id, - "%s: PHY page %d out of range", __func__, page); - return -1; - } - - reg = get_phy_reg(lynx, 7); - if (reg != -1) { - reg &= 0x1f; - reg |= (page << 5); - set_phy_reg(lynx, 7, reg); - return 0; - } else { - return -1; - } -} - -#if 0 /* not needed at this time */ -static int sel_phy_reg_port(struct ti_lynx *lynx, int port) -{ - int reg; - - if (port > 15) { - PRINT(KERN_ERR, lynx->id, - "%s: PHY port %d out of range", __func__, port); - return -1; - } - - reg = get_phy_reg(lynx, 7); - if (reg != -1) { - reg &= 0xf0; - reg |= port; - set_phy_reg(lynx, 7, reg); - return 0; - } else { - return -1; - } -} -#endif - -static u32 get_phy_vendorid(struct ti_lynx *lynx) -{ - u32 pvid = 0; - sel_phy_reg_page(lynx, 1); - pvid |= (get_phy_reg(lynx, 10) << 16); - pvid |= (get_phy_reg(lynx, 11) << 8); - pvid |= get_phy_reg(lynx, 12); - PRINT(KERN_INFO, lynx->id, "PHY vendor id 0x%06x", pvid); - return pvid; -} - -static u32 get_phy_productid(struct ti_lynx *lynx) -{ - u32 id = 0; - sel_phy_reg_page(lynx, 1); - id |= (get_phy_reg(lynx, 13) << 16); - id |= (get_phy_reg(lynx, 14) << 8); - id |= get_phy_reg(lynx, 15); - PRINT(KERN_INFO, lynx->id, "PHY product id 0x%06x", id); - return id; -} - -static quadlet_t generate_own_selfid(struct ti_lynx *lynx, - struct hpsb_host *host) -{ - quadlet_t lsid; - char phyreg[7]; - int i; - - phyreg[0] = lynx->phy_reg0; - for (i = 1; i < 7; i++) { - phyreg[i] = get_phy_reg(lynx, i); - } - - /* FIXME? We assume a TSB21LV03A phy here. This code doesn't support - more than 3 ports on the PHY anyway. */ - - lsid = 0x80400000 | ((phyreg[0] & 0xfc) << 22); - lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */ - lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */ - if (!hpsb_disable_irm) - lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dependent) */ - /* lsid |= 1 << 11; *//* set contender (hack) */ - lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */ - - for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */ - if (phyreg[3 + i] & 0x4) { - lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3) - << (6 - i*2); - } else { - lsid |= 1 << (6 - i*2); - } - } - - cpu_to_be32s(&lsid); - PRINT(KERN_DEBUG, lynx->id, "generated own selfid 0x%x", lsid); - return lsid; -} - -static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host) -{ - quadlet_t *q = lynx->rcv_page; - int phyid, isroot, size; - quadlet_t lsid = 0; - int i; - - if (lynx->phy_reg0 == -1 || lynx->selfid_size == -1) return; - - size = lynx->selfid_size; - phyid = lynx->phy_reg0; - - i = (size > 16 ? 16 : size) / 4 - 1; - while (i >= 0) { - cpu_to_be32s(&q[i]); - i--; - } - - if (!lynx->phyic.reg_1394a) { - lsid = generate_own_selfid(lynx, host); - } - - isroot = (phyid & 2) != 0; - phyid >>= 2; - PRINT(KERN_INFO, lynx->id, "SelfID process finished (phyid %d, %s)", - phyid, (isroot ? "root" : "not root")); - reg_write(lynx, LINK_ID, (0xffc0 | phyid) << 16); - - if (!lynx->phyic.reg_1394a && !size) { - hpsb_selfid_received(host, lsid); - } - - while (size > 0) { - struct selfid *sid = (struct selfid *)q; - - if (!lynx->phyic.reg_1394a && !sid->extended - && (sid->phy_id == (phyid + 1))) { - hpsb_selfid_received(host, lsid); - } - - if (q[0] == ~q[1]) { - PRINT(KERN_DEBUG, lynx->id, "SelfID packet 0x%x rcvd", - q[0]); - hpsb_selfid_received(host, q[0]); - } else { - PRINT(KERN_INFO, lynx->id, - "inconsistent selfid 0x%x/0x%x", q[0], q[1]); - } - q += 2; - size -= 8; - } - - if (!lynx->phyic.reg_1394a && isroot && phyid != 0) { - hpsb_selfid_received(host, lsid); - } - - hpsb_selfid_complete(host, phyid, isroot); - - if (host->in_bus_reset) return; /* in bus reset again */ - - if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); //FIXME: I do not think, we need this here - reg_set_bits(lynx, LINK_CONTROL, - LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN - | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_CYCTIMEREN); -} - - - -/* This must be called with the respective queue_lock held. */ -static void send_next(struct ti_lynx *lynx, int what) -{ - struct ti_pcl pcl; - struct lynx_send_data *d; - struct hpsb_packet *packet; - -#if 0 /* has been removed from ieee1394 core */ - d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async); -#else - d = &lynx->async; -#endif - if (!list_empty(&d->pcl_queue)) { - PRINT(KERN_ERR, lynx->id, "trying to queue a new packet in nonempty fifo"); - BUG(); - } - - packet = driver_packet(d->queue.next); - list_move_tail(&packet->driver_list, &d->pcl_queue); - - d->header_dma = pci_map_single(lynx->dev, packet->header, - packet->header_size, PCI_DMA_TODEVICE); - if (packet->data_size) { - d->data_dma = pci_map_single(lynx->dev, packet->data, - packet->data_size, - PCI_DMA_TODEVICE); - } else { - d->data_dma = 0; - } - - pcl.next = PCL_NEXT_INVALID; - pcl.async_error_next = PCL_NEXT_INVALID; - pcl.pcl_status = 0; - pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size; -#ifndef __BIG_ENDIAN - pcl.buffer[0].control |= PCL_BIGENDIAN; -#endif - pcl.buffer[0].pointer = d->header_dma; - pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size; - pcl.buffer[1].pointer = d->data_dma; - - switch (packet->type) { - case hpsb_async: - pcl.buffer[0].control |= PCL_CMD_XMT; - break; -#if 0 /* has been removed from ieee1394 core */ - case hpsb_iso: - pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE; - break; -#endif - case hpsb_raw: - pcl.buffer[0].control |= PCL_CMD_UNFXMT; - break; - } - - put_pcl(lynx, d->pcl, &pcl); - run_pcl(lynx, d->pcl_start, d->channel); -} - - -/* called from subsystem core */ -static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet) -{ - struct ti_lynx *lynx = host->hostdata; - struct lynx_send_data *d; - unsigned long flags; - - if (packet->data_size >= 4096) { - PRINT(KERN_ERR, lynx->id, "transmit packet data too big (%Zd)", - packet->data_size); - return -EOVERFLOW; - } - - switch (packet->type) { - case hpsb_async: - case hpsb_raw: - d = &lynx->async; - break; -#if 0 /* has been removed from ieee1394 core */ - case hpsb_iso: - d = &lynx->iso_send; - break; -#endif - default: - PRINT(KERN_ERR, lynx->id, "invalid packet type %d", - packet->type); - return -EINVAL; - } - - if (packet->tcode == TCODE_WRITEQ - || packet->tcode == TCODE_READQ_RESPONSE) { - cpu_to_be32s(&packet->header[3]); - } - - spin_lock_irqsave(&d->queue_lock, flags); - - list_add_tail(&packet->driver_list, &d->queue); - if (list_empty(&d->pcl_queue)) - send_next(lynx, packet->type); - - spin_unlock_irqrestore(&d->queue_lock, flags); - - return 0; -} - - -/* called from subsystem core */ -static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) -{ - struct ti_lynx *lynx = host->hostdata; - int retval = 0; - struct hpsb_packet *packet; - LIST_HEAD(packet_list); - unsigned long flags; - int phy_reg; - - switch (cmd) { - case RESET_BUS: - if (reg_read(lynx, LINK_INT_STATUS) & LINK_INT_PHY_BUSRESET) { - retval = 0; - break; - } - - switch (arg) { - case SHORT_RESET: - if (lynx->phyic.reg_1394a) { - phy_reg = get_phy_reg(lynx, 5); - if (phy_reg == -1) { - PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); - retval = -1; - break; - } - phy_reg |= 0x40; - - PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset) on request"); - - lynx->selfid_size = -1; - lynx->phy_reg0 = -1; - set_phy_reg(lynx, 5, phy_reg); /* set ISBR */ - break; - } else { - PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy"); - /* fall through to long bus reset */ - } - case LONG_RESET: - phy_reg = get_phy_reg(lynx, 1); - if (phy_reg == -1) { - PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); - retval = -1; - break; - } - phy_reg |= 0x40; - - PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset) on request"); - - lynx->selfid_size = -1; - lynx->phy_reg0 = -1; - set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */ - break; - case SHORT_RESET_NO_FORCE_ROOT: - if (lynx->phyic.reg_1394a) { - phy_reg = get_phy_reg(lynx, 1); - if (phy_reg == -1) { - PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); - retval = -1; - break; - } - if (phy_reg & 0x80) { - phy_reg &= ~0x80; - set_phy_reg(lynx, 1, phy_reg); /* clear RHB */ - } - - phy_reg = get_phy_reg(lynx, 5); - if (phy_reg == -1) { - PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); - retval = -1; - break; - } - phy_reg |= 0x40; - - PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, no force_root) on request"); - - lynx->selfid_size = -1; - lynx->phy_reg0 = -1; - set_phy_reg(lynx, 5, phy_reg); /* set ISBR */ - break; - } else { - PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy"); - /* fall through to long bus reset */ - } - case LONG_RESET_NO_FORCE_ROOT: - phy_reg = get_phy_reg(lynx, 1); - if (phy_reg == -1) { - PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); - retval = -1; - break; - } - phy_reg &= ~0x80; - phy_reg |= 0x40; - - PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, no force_root) on request"); - - lynx->selfid_size = -1; - lynx->phy_reg0 = -1; - set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */ - break; - case SHORT_RESET_FORCE_ROOT: - if (lynx->phyic.reg_1394a) { - phy_reg = get_phy_reg(lynx, 1); - if (phy_reg == -1) { - PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); - retval = -1; - break; - } - if (!(phy_reg & 0x80)) { - phy_reg |= 0x80; - set_phy_reg(lynx, 1, phy_reg); /* set RHB */ - } - - phy_reg = get_phy_reg(lynx, 5); - if (phy_reg == -1) { - PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); - retval = -1; - break; - } - phy_reg |= 0x40; - - PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, force_root set) on request"); - - lynx->selfid_size = -1; - lynx->phy_reg0 = -1; - set_phy_reg(lynx, 5, phy_reg); /* set ISBR */ - break; - } else { - PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy"); - /* fall through to long bus reset */ - } - case LONG_RESET_FORCE_ROOT: - phy_reg = get_phy_reg(lynx, 1); - if (phy_reg == -1) { - PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); - retval = -1; - break; - } - phy_reg |= 0xc0; - - PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, force_root set) on request"); - - lynx->selfid_size = -1; - lynx->phy_reg0 = -1; - set_phy_reg(lynx, 1, phy_reg); /* set IBR and RHB */ - break; - default: - PRINT(KERN_ERR, lynx->id, "unknown argument for reset_bus command %d", arg); - retval = -1; - } - - break; - - case GET_CYCLE_COUNTER: - retval = reg_read(lynx, CYCLE_TIMER); - break; - - case SET_CYCLE_COUNTER: - reg_write(lynx, CYCLE_TIMER, arg); - break; - - case SET_BUS_ID: - reg_write(lynx, LINK_ID, - (arg << 22) | (reg_read(lynx, LINK_ID) & 0x003f0000)); - break; - - case ACT_CYCLE_MASTER: - if (arg) { - reg_set_bits(lynx, LINK_CONTROL, - LINK_CONTROL_CYCMASTER); - } else { - reg_clear_bits(lynx, LINK_CONTROL, - LINK_CONTROL_CYCMASTER); - } - break; - - case CANCEL_REQUESTS: - spin_lock_irqsave(&lynx->async.queue_lock, flags); - - reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0); - list_splice_init(&lynx->async.queue, &packet_list); - - if (list_empty(&lynx->async.pcl_queue)) { - spin_unlock_irqrestore(&lynx->async.queue_lock, flags); - PRINTD(KERN_DEBUG, lynx->id, "no async packet in PCL to cancel"); - } else { - struct ti_pcl pcl; - u32 ack; - - PRINT(KERN_INFO, lynx->id, "cancelling async packet, that was already in PCL"); - - get_pcl(lynx, lynx->async.pcl, &pcl); - - packet = driver_packet(lynx->async.pcl_queue.next); - list_del_init(&packet->driver_list); - - pci_unmap_single(lynx->dev, lynx->async.header_dma, - packet->header_size, PCI_DMA_TODEVICE); - if (packet->data_size) { - pci_unmap_single(lynx->dev, lynx->async.data_dma, - packet->data_size, PCI_DMA_TODEVICE); - } - - spin_unlock_irqrestore(&lynx->async.queue_lock, flags); - - if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { - if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { - ack = (pcl.pcl_status >> 15) & 0xf; - PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); - ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); - } else { - ack = (pcl.pcl_status >> 15) & 0xf; - } - } else { - PRINT(KERN_INFO, lynx->id, "async packet was not completed"); - ack = ACKX_ABORTED; - } - hpsb_packet_sent(host, packet, ack); - } - - while (!list_empty(&packet_list)) { - packet = driver_packet(packet_list.next); - list_del_init(&packet->driver_list); - hpsb_packet_sent(host, packet, ACKX_ABORTED); - } - - break; -#if 0 /* has been removed from ieee1394 core */ - case ISO_LISTEN_CHANNEL: - spin_lock_irqsave(&lynx->iso_rcv.lock, flags); - - if (lynx->iso_rcv.chan_count++ == 0) { - reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), - DMA_WORD1_CMP_ENABLE_MASTER); - } - - spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags); - break; - - case ISO_UNLISTEN_CHANNEL: - spin_lock_irqsave(&lynx->iso_rcv.lock, flags); - - if (--lynx->iso_rcv.chan_count == 0) { - reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), - 0); - } - - spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags); - break; -#endif - default: - PRINT(KERN_ERR, lynx->id, "unknown devctl command %d", cmd); - retval = -1; - } - - return retval; -} - - -/*************************************** - * IEEE-1394 functionality section END * - ***************************************/ - - -/******************************************************** - * Global stuff (interrupt handler, init/shutdown code) * - ********************************************************/ - - -static irqreturn_t lynx_irq_handler(int irq, void *dev_id) -{ - struct ti_lynx *lynx = (struct ti_lynx *)dev_id; - struct hpsb_host *host = lynx->host; - u32 intmask; - u32 linkint; - - linkint = reg_read(lynx, LINK_INT_STATUS); - intmask = reg_read(lynx, PCI_INT_STATUS); - - if (!(intmask & PCI_INT_INT_PEND)) - return IRQ_NONE; - - PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask, - linkint); - - reg_write(lynx, LINK_INT_STATUS, linkint); - reg_write(lynx, PCI_INT_STATUS, intmask); - - if (intmask & PCI_INT_1394) { - if (linkint & LINK_INT_PHY_TIMEOUT) { - PRINT(KERN_INFO, lynx->id, "PHY timeout occurred"); - } - if (linkint & LINK_INT_PHY_BUSRESET) { - PRINT(KERN_INFO, lynx->id, "bus reset interrupt"); - lynx->selfid_size = -1; - lynx->phy_reg0 = -1; - if (!host->in_bus_reset) - hpsb_bus_reset(host); - } - if (linkint & LINK_INT_PHY_REG_RCVD) { - u32 reg; - - spin_lock(&lynx->phy_reg_lock); - reg = reg_read(lynx, LINK_PHY); - spin_unlock(&lynx->phy_reg_lock); - - if (!host->in_bus_reset) { - PRINT(KERN_INFO, lynx->id, - "phy reg received without reset"); - } else if (reg & 0xf00) { - PRINT(KERN_INFO, lynx->id, - "unsolicited phy reg %d received", - (reg >> 8) & 0xf); - } else { - lynx->phy_reg0 = reg & 0xff; - handle_selfid(lynx, host); - } - } - if (linkint & LINK_INT_ISO_STUCK) { - PRINT(KERN_INFO, lynx->id, "isochronous transmitter stuck"); - } - if (linkint & LINK_INT_ASYNC_STUCK) { - PRINT(KERN_INFO, lynx->id, "asynchronous transmitter stuck"); - } - if (linkint & LINK_INT_SENT_REJECT) { - PRINT(KERN_INFO, lynx->id, "sent reject"); - } - if (linkint & LINK_INT_TX_INVALID_TC) { - PRINT(KERN_INFO, lynx->id, "invalid transaction code"); - } - if (linkint & LINK_INT_GRF_OVERFLOW) { - /* flush FIFO if overflow happens during reset */ - if (host->in_bus_reset) - reg_write(lynx, FIFO_CONTROL, - FIFO_CONTROL_GRF_FLUSH); - PRINT(KERN_INFO, lynx->id, "GRF overflow"); - } - if (linkint & LINK_INT_ITF_UNDERFLOW) { - PRINT(KERN_INFO, lynx->id, "ITF underflow"); - } - if (linkint & LINK_INT_ATF_UNDERFLOW) { - PRINT(KERN_INFO, lynx->id, "ATF underflow"); - } - } - - if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) { - PRINTD(KERN_DEBUG, lynx->id, "iso receive"); - - spin_lock(&lynx->iso_rcv.lock); - - lynx->iso_rcv.stat[lynx->iso_rcv.next] = - reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ISO_RCV)); - - lynx->iso_rcv.used++; - lynx->iso_rcv.next = (lynx->iso_rcv.next + 1) % NUM_ISORCV_PCL; - - if ((lynx->iso_rcv.next == lynx->iso_rcv.last) - || !lynx->iso_rcv.chan_count) { - PRINTD(KERN_DEBUG, lynx->id, "stopped"); - reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0); - } - - run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, lynx->iso_rcv.next, - CHANNEL_ISO_RCV); - - spin_unlock(&lynx->iso_rcv.lock); - - tasklet_schedule(&lynx->iso_rcv.tq); - } - - if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) { - PRINTD(KERN_DEBUG, lynx->id, "async sent"); - spin_lock(&lynx->async.queue_lock); - - if (list_empty(&lynx->async.pcl_queue)) { - spin_unlock(&lynx->async.queue_lock); - PRINT(KERN_WARNING, lynx->id, "async dma halted, but no queued packet (maybe it was cancelled)"); - } else { - struct ti_pcl pcl; - u32 ack; - struct hpsb_packet *packet; - - get_pcl(lynx, lynx->async.pcl, &pcl); - - packet = driver_packet(lynx->async.pcl_queue.next); - list_del_init(&packet->driver_list); - - pci_unmap_single(lynx->dev, lynx->async.header_dma, - packet->header_size, PCI_DMA_TODEVICE); - if (packet->data_size) { - pci_unmap_single(lynx->dev, lynx->async.data_dma, - packet->data_size, PCI_DMA_TODEVICE); - } - - if (!list_empty(&lynx->async.queue)) { - send_next(lynx, hpsb_async); - } - - spin_unlock(&lynx->async.queue_lock); - - if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { - if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { - ack = (pcl.pcl_status >> 15) & 0xf; - PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); - ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); - } else { - ack = (pcl.pcl_status >> 15) & 0xf; - } - } else { - PRINT(KERN_INFO, lynx->id, "async packet was not completed"); - ack = ACKX_SEND_ERROR; - } - hpsb_packet_sent(host, packet, ack); - } - } - - if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) { - PRINTD(KERN_DEBUG, lynx->id, "iso sent"); - spin_lock(&lynx->iso_send.queue_lock); - - if (list_empty(&lynx->iso_send.pcl_queue)) { - spin_unlock(&lynx->iso_send.queue_lock); - PRINT(KERN_ERR, lynx->id, "iso send dma halted, but no queued packet"); - } else { - struct ti_pcl pcl; - u32 ack; - struct hpsb_packet *packet; - - get_pcl(lynx, lynx->iso_send.pcl, &pcl); - - packet = driver_packet(lynx->iso_send.pcl_queue.next); - list_del_init(&packet->driver_list); - - pci_unmap_single(lynx->dev, lynx->iso_send.header_dma, - packet->header_size, PCI_DMA_TODEVICE); - if (packet->data_size) { - pci_unmap_single(lynx->dev, lynx->iso_send.data_dma, - packet->data_size, PCI_DMA_TODEVICE); - } -#if 0 /* has been removed from ieee1394 core */ - if (!list_empty(&lynx->iso_send.queue)) { - send_next(lynx, hpsb_iso); - } -#endif - spin_unlock(&lynx->iso_send.queue_lock); - - if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { - if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { - ack = (pcl.pcl_status >> 15) & 0xf; - PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); - ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); - } else { - ack = (pcl.pcl_status >> 15) & 0xf; - } - } else { - PRINT(KERN_INFO, lynx->id, "iso send packet was not completed"); - ack = ACKX_SEND_ERROR; - } - - hpsb_packet_sent(host, packet, ack); //FIXME: maybe we should just use ACK_COMPLETE and ACKX_SEND_ERROR - } - } - - if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) { - /* general receive DMA completed */ - int stat = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_RCV)); - - PRINTD(KERN_DEBUG, lynx->id, "received packet size %d", - stat & 0x1fff); - - if (stat & DMA_CHAN_STAT_SELFID) { - lynx->selfid_size = stat & 0x1fff; - handle_selfid(lynx, host); - } else { - quadlet_t *q_data = lynx->rcv_page; - if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE - || (*q_data >> 4 & 0xf) == TCODE_WRITEQ) { - cpu_to_be32s(q_data + 3); - } - hpsb_packet_received(host, q_data, stat & 0x1fff, 0); - } - - run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV); - } - - return IRQ_HANDLED; -} - - -static void iso_rcv_bh(struct ti_lynx *lynx) -{ - unsigned int idx; - quadlet_t *data; - unsigned long flags; - - spin_lock_irqsave(&lynx->iso_rcv.lock, flags); - - while (lynx->iso_rcv.used) { - idx = lynx->iso_rcv.last; - spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags); - - data = lynx->iso_rcv.page[idx / ISORCV_PER_PAGE] - + (idx % ISORCV_PER_PAGE) * MAX_ISORCV_SIZE; - - if ((*data >> 16) + 4 != (lynx->iso_rcv.stat[idx] & 0x1fff)) { - PRINT(KERN_ERR, lynx->id, - "iso length mismatch 0x%08x/0x%08x", *data, - lynx->iso_rcv.stat[idx]); - } - - if (lynx->iso_rcv.stat[idx] - & (DMA_CHAN_STAT_PCIERR | DMA_CHAN_STAT_PKTERR)) { - PRINT(KERN_INFO, lynx->id, - "iso receive error on %d to 0x%p", idx, data); - } else { - hpsb_packet_received(lynx->host, data, - lynx->iso_rcv.stat[idx] & 0x1fff, - 0); - } - - spin_lock_irqsave(&lynx->iso_rcv.lock, flags); - lynx->iso_rcv.last = (idx + 1) % NUM_ISORCV_PCL; - lynx->iso_rcv.used--; - } - - if (lynx->iso_rcv.chan_count) { - reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), - DMA_WORD1_CMP_ENABLE_MASTER); - } - spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags); -} - - -static void remove_card(struct pci_dev *dev) -{ - struct ti_lynx *lynx; - struct device *lynx_dev; - int i; - - lynx = pci_get_drvdata(dev); - if (!lynx) return; - pci_set_drvdata(dev, NULL); - - lynx_dev = get_device(&lynx->host->device); - - switch (lynx->state) { - case is_host: - reg_write(lynx, PCI_INT_ENABLE, 0); - hpsb_remove_host(lynx->host); - case have_intr: - reg_write(lynx, PCI_INT_ENABLE, 0); - free_irq(lynx->dev->irq, lynx); - - /* Disable IRM Contender and LCtrl */ - if (lynx->phyic.reg_1394a) - set_phy_reg(lynx, 4, ~0xc0 & get_phy_reg(lynx, 4)); - - /* Let all other nodes know to ignore us */ - lynx_devctl(lynx->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT); - - case have_iomappings: - reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); - /* Fix buggy cards with autoboot pin not tied low: */ - reg_write(lynx, DMA0_CHAN_CTRL, 0); - iounmap(lynx->registers); - iounmap(lynx->local_rom); - iounmap(lynx->local_ram); - iounmap(lynx->aux_port); - case have_1394_buffers: - for (i = 0; i < ISORCV_PAGES; i++) { - if (lynx->iso_rcv.page[i]) { - pci_free_consistent(lynx->dev, PAGE_SIZE, - lynx->iso_rcv.page[i], - lynx->iso_rcv.page_dma[i]); - } - } - pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page, - lynx->rcv_page_dma); - case have_aux_buf: - case have_pcl_mem: - pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem, - lynx->pcl_mem_dma); - case clear: - /* do nothing - already freed */ - ; - } - - tasklet_kill(&lynx->iso_rcv.tq); - - if (lynx_dev) - put_device(lynx_dev); -} - - -static int __devinit add_card(struct pci_dev *dev, - const struct pci_device_id *devid_is_unused) -{ -#define FAIL(fmt, args...) do { \ - PRINT_G(KERN_ERR, fmt , ## args); \ - remove_card(dev); \ - return error; \ - } while (0) - - char irq_buf[16]; - struct hpsb_host *host; - struct ti_lynx *lynx; /* shortcut to currently handled device */ - struct ti_pcl pcl; - u32 *pcli; - int i; - int error; - - error = -ENXIO; - - if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) - FAIL("DMA address limits not supported for PCILynx hardware"); - if (pci_enable_device(dev)) - FAIL("failed to enable PCILynx hardware"); - pci_set_master(dev); - - error = -ENOMEM; - - host = hpsb_alloc_host(&lynx_driver, sizeof(struct ti_lynx), &dev->dev); - if (!host) FAIL("failed to allocate control structure memory"); - - lynx = host->hostdata; - lynx->id = card_id++; - lynx->dev = dev; - lynx->state = clear; - lynx->host = host; - host->pdev = dev; - pci_set_drvdata(dev, lynx); - - spin_lock_init(&lynx->lock); - spin_lock_init(&lynx->phy_reg_lock); - - lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE, - &lynx->pcl_mem_dma); - - if (lynx->pcl_mem != NULL) { - lynx->state = have_pcl_mem; - PRINT(KERN_INFO, lynx->id, - "allocated PCL memory %d Bytes @ 0x%p", LOCALRAM_SIZE, - lynx->pcl_mem); - } else { - FAIL("failed to allocate PCL memory area"); - } - - lynx->rcv_page = pci_alloc_consistent(dev, PAGE_SIZE, - &lynx->rcv_page_dma); - if (lynx->rcv_page == NULL) { - FAIL("failed to allocate receive buffer"); - } - lynx->state = have_1394_buffers; - - for (i = 0; i < ISORCV_PAGES; i++) { - lynx->iso_rcv.page[i] = - pci_alloc_consistent(dev, PAGE_SIZE, - &lynx->iso_rcv.page_dma[i]); - if (lynx->iso_rcv.page[i] == NULL) { - FAIL("failed to allocate iso receive buffers"); - } - } - - lynx->registers = ioremap_nocache(pci_resource_start(dev,0), - PCILYNX_MAX_REGISTER); - lynx->local_ram = ioremap(pci_resource_start(dev,1), PCILYNX_MAX_MEMORY); - lynx->aux_port = ioremap(pci_resource_start(dev,2), PCILYNX_MAX_MEMORY); - lynx->local_rom = ioremap(pci_resource_start(dev,PCI_ROM_RESOURCE), - PCILYNX_MAX_MEMORY); - lynx->state = have_iomappings; - - if (lynx->registers == NULL) { - FAIL("failed to remap registers - card not accessible"); - } - - reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); - /* Fix buggy cards with autoboot pin not tied low: */ - reg_write(lynx, DMA0_CHAN_CTRL, 0); - - sprintf (irq_buf, "%d", dev->irq); - - if (!request_irq(dev->irq, lynx_irq_handler, IRQF_SHARED, - PCILYNX_DRIVER_NAME, lynx)) { - PRINT(KERN_INFO, lynx->id, "allocated interrupt %s", irq_buf); - lynx->state = have_intr; - } else { - FAIL("failed to allocate shared interrupt %s", irq_buf); - } - - /* alloc_pcl return values are not checked, it is expected that the - * provided PCL space is sufficient for the initial allocations */ - lynx->rcv_pcl = alloc_pcl(lynx); - lynx->rcv_pcl_start = alloc_pcl(lynx); - lynx->async.pcl = alloc_pcl(lynx); - lynx->async.pcl_start = alloc_pcl(lynx); - lynx->iso_send.pcl = alloc_pcl(lynx); - lynx->iso_send.pcl_start = alloc_pcl(lynx); - - for (i = 0; i < NUM_ISORCV_PCL; i++) { - lynx->iso_rcv.pcl[i] = alloc_pcl(lynx); - } - lynx->iso_rcv.pcl_start = alloc_pcl(lynx); - - /* all allocations successful - simple init stuff follows */ - - reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); - - tasklet_init(&lynx->iso_rcv.tq, (void (*)(unsigned long))iso_rcv_bh, - (unsigned long)lynx); - - spin_lock_init(&lynx->iso_rcv.lock); - - spin_lock_init(&lynx->async.queue_lock); - lynx->async.channel = CHANNEL_ASYNC_SEND; - spin_lock_init(&lynx->iso_send.queue_lock); - lynx->iso_send.channel = CHANNEL_ISO_SEND; - - PRINT(KERN_INFO, lynx->id, "remapped memory spaces reg 0x%p, rom 0x%p, " - "ram 0x%p, aux 0x%p", lynx->registers, lynx->local_rom, - lynx->local_ram, lynx->aux_port); - - /* now, looking for PHY register set */ - if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) { - lynx->phyic.reg_1394a = 1; - PRINT(KERN_INFO, lynx->id, - "found 1394a conform PHY (using extended register set)"); - lynx->phyic.vendor = get_phy_vendorid(lynx); - lynx->phyic.product = get_phy_productid(lynx); - } else { - lynx->phyic.reg_1394a = 0; - PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); - } - - lynx->selfid_size = -1; - lynx->phy_reg0 = -1; - - INIT_LIST_HEAD(&lynx->async.queue); - INIT_LIST_HEAD(&lynx->async.pcl_queue); - INIT_LIST_HEAD(&lynx->iso_send.queue); - INIT_LIST_HEAD(&lynx->iso_send.pcl_queue); - - pcl.next = pcl_bus(lynx, lynx->rcv_pcl); - put_pcl(lynx, lynx->rcv_pcl_start, &pcl); - - pcl.next = PCL_NEXT_INVALID; - pcl.async_error_next = PCL_NEXT_INVALID; - - pcl.buffer[0].control = PCL_CMD_RCV | 16; -#ifndef __BIG_ENDIAN - pcl.buffer[0].control |= PCL_BIGENDIAN; -#endif - pcl.buffer[1].control = PCL_LAST_BUFF | 4080; - - pcl.buffer[0].pointer = lynx->rcv_page_dma; - pcl.buffer[1].pointer = lynx->rcv_page_dma + 16; - put_pcl(lynx, lynx->rcv_pcl, &pcl); - - pcl.next = pcl_bus(lynx, lynx->async.pcl); - pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl); - put_pcl(lynx, lynx->async.pcl_start, &pcl); - - pcl.next = pcl_bus(lynx, lynx->iso_send.pcl); - pcl.async_error_next = PCL_NEXT_INVALID; - put_pcl(lynx, lynx->iso_send.pcl_start, &pcl); - - pcl.next = PCL_NEXT_INVALID; - pcl.async_error_next = PCL_NEXT_INVALID; - pcl.buffer[0].control = PCL_CMD_RCV | 4; -#ifndef __BIG_ENDIAN - pcl.buffer[0].control |= PCL_BIGENDIAN; -#endif - pcl.buffer[1].control = PCL_LAST_BUFF | 2044; - - for (i = 0; i < NUM_ISORCV_PCL; i++) { - int page = i / ISORCV_PER_PAGE; - int sec = i % ISORCV_PER_PAGE; - - pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page] - + sec * MAX_ISORCV_SIZE; - pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4; - put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl); - } - - pcli = (u32 *)&pcl; - for (i = 0; i < NUM_ISORCV_PCL; i++) { - pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]); - } - put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl); - - /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */ - reg_write(lynx, FIFO_SIZES, 0x003030a0); - /* 20 byte threshold before triggering PCI transfer */ - reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24); - /* threshold on both send FIFOs before transmitting: - FIFO size - cache line size - 1 */ - i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff; - i = 0x30 - i - 1; - reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i); - - reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394); - - reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT - | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET - | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK - | LINK_INT_SENT_REJECT | LINK_INT_TX_INVALID_TC - | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW - | LINK_INT_ATF_UNDERFLOW); - - reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0); - reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4); - reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0); - reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV), - DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST - | DMA_WORD1_CMP_MATCH_EXACT | DMA_WORD1_CMP_MATCH_BUS_BCAST - | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER); - - run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV); - - reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0); - reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4); - reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0); - reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0); - - run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV); - - reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID - | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN - | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN - | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX); - - if (!lynx->phyic.reg_1394a) { - if (!hpsb_disable_irm) { - /* attempt to enable contender bit -FIXME- would this - * work elsewhere? */ - reg_set_bits(lynx, GPIO_CTRL_A, 0x1); - reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1); - } - } else { - /* set the contender (if appropriate) and LCtrl bit in the - * extended PHY register set. (Should check that PHY_02_EXTENDED - * is set in register 2?) - */ - i = get_phy_reg(lynx, 4); - i |= PHY_04_LCTRL; - if (hpsb_disable_irm) - i &= ~PHY_04_CONTENDER; - else - i |= PHY_04_CONTENDER; - if (i != -1) set_phy_reg(lynx, 4, i); - } - - if (!skip_eeprom) - { - /* needed for i2c communication with serial eeprom */ - struct i2c_adapter *i2c_ad; - struct i2c_algo_bit_data i2c_adapter_data; - - error = -ENOMEM; - i2c_ad = kzalloc(sizeof(*i2c_ad), GFP_KERNEL); - if (!i2c_ad) FAIL("failed to allocate I2C adapter memory"); - - strlcpy(i2c_ad->name, "PCILynx I2C", sizeof(i2c_ad->name)); - i2c_adapter_data = bit_data; - i2c_ad->algo_data = &i2c_adapter_data; - i2c_adapter_data.data = lynx; - i2c_ad->dev.parent = &dev->dev; - - PRINTD(KERN_DEBUG, lynx->id,"original eeprom control: %d", - reg_read(lynx, SERIAL_EEPROM_CONTROL)); - - /* reset hardware to sane state */ - lynx->i2c_driven_state = 0x00000070; - reg_write(lynx, SERIAL_EEPROM_CONTROL, lynx->i2c_driven_state); - - if (i2c_bit_add_bus(i2c_ad) < 0) - { - kfree(i2c_ad); - error = -ENXIO; - FAIL("unable to register i2c"); - } - else - { - /* do i2c stuff */ - unsigned char i2c_cmd = 0x10; - struct i2c_msg msg[2] = { { 0x50, 0, 1, &i2c_cmd }, - { 0x50, I2C_M_RD, 20, (unsigned char*) lynx->bus_info_block } - }; - - /* we use i2c_transfer because we have no i2c_client - at hand */ - if (i2c_transfer(i2c_ad, msg, 2) < 0) { - PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c"); - } else { - PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom"); - /* FIXME: probably we should rewrite the max_rec, max_ROM(1394a), - * generation(1394a) and link_spd(1394a) field and recalculate - * the CRC */ - - for (i = 0; i < 5 ; i++) - PRINTD(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x", - i, be32_to_cpu(lynx->bus_info_block[i])); - - /* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */ - if (((be32_to_cpu(lynx->bus_info_block[0]) & 0xffff0000) == 0x04040000) && - (lynx->bus_info_block[1] == IEEE1394_BUSID_MAGIC)) - { - PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from"); - } else { - kfree(i2c_ad); - error = -ENXIO; - FAIL("read something from serial eeprom, but it does not seem to be a valid bus info block"); - } - - } - - i2c_del_adapter(i2c_ad); - kfree(i2c_ad); - } - } - - host->csr.guid_hi = be32_to_cpu(lynx->bus_info_block[3]); - host->csr.guid_lo = be32_to_cpu(lynx->bus_info_block[4]); - host->csr.cyc_clk_acc = (be32_to_cpu(lynx->bus_info_block[2]) >> 16) & 0xff; - host->csr.max_rec = (be32_to_cpu(lynx->bus_info_block[2]) >> 12) & 0xf; - if (!lynx->phyic.reg_1394a) - host->csr.lnk_spd = (get_phy_reg(lynx, 2) & 0xc0) >> 6; - else - host->csr.lnk_spd = be32_to_cpu(lynx->bus_info_block[2]) & 0x7; - - if (hpsb_add_host(host)) { - error = -ENOMEM; - FAIL("Failed to register host with highlevel"); - } - - lynx->state = is_host; - - return 0; -#undef FAIL -} - - -static struct pci_device_id pci_table[] = { - { - .vendor = PCI_VENDOR_ID_TI, - .device = PCI_DEVICE_ID_TI_PCILYNX, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { } /* Terminating entry */ -}; - -static struct pci_driver lynx_pci_driver = { - .name = PCILYNX_DRIVER_NAME, - .id_table = pci_table, - .probe = add_card, - .remove = remove_card, -}; - -static struct hpsb_host_driver lynx_driver = { - .owner = THIS_MODULE, - .name = PCILYNX_DRIVER_NAME, - .set_hw_config_rom = NULL, - .transmit_packet = lynx_transmit, - .devctl = lynx_devctl, - .isoctl = NULL, -}; - -MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>"); -MODULE_DESCRIPTION("driver for Texas Instruments PCI Lynx IEEE-1394 controller"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("pcilynx"); -MODULE_DEVICE_TABLE(pci, pci_table); - -static int __init pcilynx_init(void) -{ - int ret; - - ret = pci_register_driver(&lynx_pci_driver); - if (ret < 0) { - PRINT_G(KERN_ERR, "PCI module init failed"); - return ret; - } - - return 0; -} - -static void __exit pcilynx_cleanup(void) -{ - pci_unregister_driver(&lynx_pci_driver); -} - - -module_init(pcilynx_init); -module_exit(pcilynx_cleanup); diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h deleted file mode 100644 index 693a169acea..00000000000 --- a/drivers/ieee1394/pcilynx.h +++ /dev/null @@ -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 diff --git a/drivers/ieee1394/raw1394-private.h b/drivers/ieee1394/raw1394-private.h deleted file mode 100644 index 7a225a40598..00000000000 --- a/drivers/ieee1394/raw1394-private.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c deleted file mode 100644 index f3401427404..00000000000 --- a/drivers/ieee1394/raw1394.c +++ /dev/null @@ -1,3096 +0,0 @@ -/* - * IEEE 1394 for Linux - * - * Raw interface to the bus - * - * Copyright (C) 1999, 2000 Andreas E. Bombe - * 2001, 2002 Manfred Weihs <weihs@ict.tuwien.ac.at> - * 2002 Christian Toegel <christian.toegel@gmx.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 - * address range mapping - * adaptation for new (transparent) loopback mechanism - * sending of arbitrary async packets - * Christian Toegel <christian.toegel@gmx.at> - * address range mapping - * lock64 request - * transmit physical packet - * busreset notification control (switch on/off) - * busreset with selection of type (short/long) - * request_reply - */ - -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/fs.h> -#include <linux/poll.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/vmalloc.h> -#include <linux/cdev.h> -#include <asm/uaccess.h> -#include <asm/atomic.h> -#include <linux/compat.h> - -#include "csr1212.h" -#include "highlevel.h" -#include "hosts.h" -#include "ieee1394.h" -#include "ieee1394_core.h" -#include "ieee1394_hotplug.h" -#include "ieee1394_transactions.h" -#include "ieee1394_types.h" -#include "iso.h" -#include "nodemgr.h" -#include "raw1394.h" -#include "raw1394-private.h" - -#define int2ptr(x) ((void __user *)(unsigned long)x) -#define ptr2int(x) ((u64)(unsigned long)(void __user *)x) - -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG -#define RAW1394_DEBUG -#endif - -#ifdef RAW1394_DEBUG -#define DBGMSG(fmt, args...) \ -printk(KERN_INFO "raw1394:" fmt "\n" , ## args) -#else -#define DBGMSG(fmt, args...) do {} while (0) -#endif - -static LIST_HEAD(host_info_list); -static int host_count; -static DEFINE_SPINLOCK(host_info_lock); -static atomic_t internal_generation = ATOMIC_INIT(0); - -static atomic_t iso_buffer_size; -static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */ - -static struct hpsb_highlevel raw1394_highlevel; - -static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer, - u64 addr, size_t length, u16 flags); -static int arm_write(struct hpsb_host *host, int nodeid, int destid, - quadlet_t * data, u64 addr, size_t length, u16 flags); -static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store, - u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, - u16 flags); -static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store, - u64 addr, octlet_t data, octlet_t arg, int ext_tcode, - u16 flags); -static const struct hpsb_address_ops arm_ops = { - .read = arm_read, - .write = arm_write, - .lock = arm_lock, - .lock64 = arm_lock64, -}; - -static void queue_complete_cb(struct pending_request *req); - -static struct pending_request *__alloc_pending_request(gfp_t flags) -{ - struct pending_request *req; - - req = kzalloc(sizeof(*req), flags); - if (req) - INIT_LIST_HEAD(&req->list); - - return req; -} - -static inline struct pending_request *alloc_pending_request(void) -{ - return __alloc_pending_request(GFP_KERNEL); -} - -static void free_pending_request(struct pending_request *req) -{ - if (req->ibs) { - if (atomic_dec_and_test(&req->ibs->refcount)) { - atomic_sub(req->ibs->data_size, &iso_buffer_size); - kfree(req->ibs); - } - } else if (req->free_data) { - kfree(req->data); - } - hpsb_free_packet(req->packet); - kfree(req); -} - -/* fi->reqlists_lock must be taken */ -static void __queue_complete_req(struct pending_request *req) -{ - struct file_info *fi = req->file_info; - - list_move_tail(&req->list, &fi->req_complete); - wake_up(&fi->wait_complete); -} - -static void queue_complete_req(struct pending_request *req) -{ - unsigned long flags; - struct file_info *fi = req->file_info; - - spin_lock_irqsave(&fi->reqlists_lock, flags); - __queue_complete_req(req); - spin_unlock_irqrestore(&fi->reqlists_lock, flags); -} - -static void queue_complete_cb(struct pending_request *req) -{ - struct hpsb_packet *packet = req->packet; - int rcode = (packet->header[1] >> 12) & 0xf; - - switch (packet->ack_code) { - case ACKX_NONE: - case ACKX_SEND_ERROR: - req->req.error = RAW1394_ERROR_SEND_ERROR; - break; - case ACKX_ABORTED: - req->req.error = RAW1394_ERROR_ABORTED; - break; - case ACKX_TIMEOUT: - req->req.error = RAW1394_ERROR_TIMEOUT; - break; - default: - req->req.error = (packet->ack_code << 16) | rcode; - break; - } - - if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) { - req->req.length = 0; - } - - if ((req->req.type == RAW1394_REQ_ASYNC_READ) || - (req->req.type == RAW1394_REQ_ASYNC_WRITE) || - (req->req.type == RAW1394_REQ_ASYNC_STREAM) || - (req->req.type == RAW1394_REQ_LOCK) || - (req->req.type == RAW1394_REQ_LOCK64)) - hpsb_free_tlabel(packet); - - queue_complete_req(req); -} - -static void add_host(struct hpsb_host *host) -{ - struct host_info *hi; - unsigned long flags; - - hi = kmalloc(sizeof(*hi), GFP_KERNEL); - - if (hi) { - INIT_LIST_HEAD(&hi->list); - hi->host = host; - INIT_LIST_HEAD(&hi->file_info_list); - - spin_lock_irqsave(&host_info_lock, flags); - list_add_tail(&hi->list, &host_info_list); - host_count++; - spin_unlock_irqrestore(&host_info_lock, flags); - } - - atomic_inc(&internal_generation); -} - -static struct host_info *find_host_info(struct hpsb_host *host) -{ - struct host_info *hi; - - list_for_each_entry(hi, &host_info_list, list) - if (hi->host == host) - return hi; - - return NULL; -} - -static void remove_host(struct hpsb_host *host) -{ - struct host_info *hi; - unsigned long flags; - - spin_lock_irqsave(&host_info_lock, flags); - hi = find_host_info(host); - - if (hi != NULL) { - list_del(&hi->list); - host_count--; - /* - FIXME: address ranges should be removed - and fileinfo states should be initialized - (including setting generation to - internal-generation ...) - */ - } - spin_unlock_irqrestore(&host_info_lock, flags); - - if (hi == NULL) { - printk(KERN_ERR "raw1394: attempt to remove unknown host " - "0x%p\n", host); - return; - } - - kfree(hi); - - atomic_inc(&internal_generation); -} - -static void host_reset(struct hpsb_host *host) -{ - unsigned long flags; - struct host_info *hi; - struct file_info *fi; - struct pending_request *req; - - spin_lock_irqsave(&host_info_lock, flags); - hi = find_host_info(host); - - if (hi != NULL) { - list_for_each_entry(fi, &hi->file_info_list, list) { - if (fi->notification == RAW1394_NOTIFY_ON) { - req = __alloc_pending_request(GFP_ATOMIC); - - if (req != NULL) { - req->file_info = fi; - req->req.type = RAW1394_REQ_BUS_RESET; - req->req.generation = - get_hpsb_generation(host); - req->req.misc = (host->node_id << 16) - | host->node_count; - if (fi->protocol_version > 3) { - req->req.misc |= - (NODEID_TO_NODE - (host->irm_id) - << 8); - } - - queue_complete_req(req); - } - } - } - } - spin_unlock_irqrestore(&host_info_lock, flags); -} - -static void fcp_request(struct hpsb_host *host, int nodeid, int direction, - int cts, u8 * data, size_t length) -{ - unsigned long flags; - struct host_info *hi; - struct file_info *fi; - struct pending_request *req, *req_next; - struct iso_block_store *ibs = NULL; - LIST_HEAD(reqs); - - if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) { - HPSB_INFO("dropped fcp request"); - return; - } - - spin_lock_irqsave(&host_info_lock, flags); - hi = find_host_info(host); - - if (hi != NULL) { - list_for_each_entry(fi, &hi->file_info_list, list) { - if (!fi->fcp_buffer) - continue; - - req = __alloc_pending_request(GFP_ATOMIC); - if (!req) - break; - - if (!ibs) { - ibs = kmalloc(sizeof(*ibs) + length, - GFP_ATOMIC); - if (!ibs) { - kfree(req); - break; - } - - atomic_add(length, &iso_buffer_size); - atomic_set(&ibs->refcount, 0); - ibs->data_size = length; - memcpy(ibs->data, data, length); - } - - atomic_inc(&ibs->refcount); - - req->file_info = fi; - req->ibs = ibs; - req->data = ibs->data; - req->req.type = RAW1394_REQ_FCP_REQUEST; - req->req.generation = get_hpsb_generation(host); - req->req.misc = nodeid | (direction << 16); - req->req.recvb = ptr2int(fi->fcp_buffer); - req->req.length = length; - - list_add_tail(&req->list, &reqs); - } - } - spin_unlock_irqrestore(&host_info_lock, flags); - - list_for_each_entry_safe(req, req_next, &reqs, list) - queue_complete_req(req); -} - -#ifdef CONFIG_COMPAT -struct compat_raw1394_req { - __u32 type; - __s32 error; - __u32 misc; - - __u32 generation; - __u32 length; - - __u64 address; - - __u64 tag; - - __u64 sendb; - __u64 recvb; -} -#if defined(CONFIG_X86_64) || defined(CONFIG_IA64) -__attribute__((packed)) -#endif -; - -static const char __user *raw1394_compat_write(const char __user *buf) -{ - struct compat_raw1394_req __user *cr = (typeof(cr)) buf; - struct raw1394_request __user *r; - - r = compat_alloc_user_space(sizeof(struct raw1394_request)); - -#define C(x) __copy_in_user(&r->x, &cr->x, sizeof(r->x)) - - if (copy_in_user(r, cr, sizeof(struct compat_raw1394_req)) || - C(address) || - C(tag) || - C(sendb) || - C(recvb)) - return (__force const char __user *)ERR_PTR(-EFAULT); - - return (const char __user *)r; -} -#undef C - -#define P(x) __put_user(r->x, &cr->x) - -static int -raw1394_compat_read(const char __user *buf, struct raw1394_request *r) -{ - struct compat_raw1394_req __user *cr = (typeof(cr)) buf; - - if (!access_ok(VERIFY_WRITE, cr, sizeof(struct compat_raw1394_req)) || - P(type) || - P(error) || - P(misc) || - P(generation) || - P(length) || - P(address) || - P(tag) || - P(sendb) || - P(recvb)) - return -EFAULT; - - return sizeof(struct compat_raw1394_req); -} -#undef P - -#endif - -/* get next completed request (caller must hold fi->reqlists_lock) */ -static inline struct pending_request *__next_complete_req(struct file_info *fi) -{ - struct list_head *lh; - struct pending_request *req = NULL; - - if (!list_empty(&fi->req_complete)) { - lh = fi->req_complete.next; - list_del(lh); - req = list_entry(lh, struct pending_request, list); - } - return req; -} - -/* atomically get next completed request */ -static struct pending_request *next_complete_req(struct file_info *fi) -{ - unsigned long flags; - struct pending_request *req; - - spin_lock_irqsave(&fi->reqlists_lock, flags); - req = __next_complete_req(fi); - spin_unlock_irqrestore(&fi->reqlists_lock, flags); - return req; -} - -static ssize_t raw1394_read(struct file *file, char __user * buffer, - size_t count, loff_t * offset_is_ignored) -{ - struct file_info *fi = file->private_data; - struct pending_request *req; - ssize_t ret; - -#ifdef CONFIG_COMPAT - if (count == sizeof(struct compat_raw1394_req)) { - /* ok */ - } else -#endif - if (count != sizeof(struct raw1394_request)) { - return -EINVAL; - } - - if (!access_ok(VERIFY_WRITE, buffer, count)) { - return -EFAULT; - } - - if (file->f_flags & O_NONBLOCK) { - if (!(req = next_complete_req(fi))) - return -EAGAIN; - } else { - /* - * NB: We call the macro wait_event_interruptible() 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. - */ - if (wait_event_interruptible(fi->wait_complete, - (req = next_complete_req(fi)))) - return -ERESTARTSYS; - } - - if (req->req.length) { - if (copy_to_user(int2ptr(req->req.recvb), req->data, - req->req.length)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - } - } - -#ifdef CONFIG_COMPAT - if (count == sizeof(struct compat_raw1394_req) && - sizeof(struct compat_raw1394_req) != - sizeof(struct raw1394_request)) { - ret = raw1394_compat_read(buffer, &req->req); - } else -#endif - { - if (copy_to_user(buffer, &req->req, sizeof(req->req))) { - ret = -EFAULT; - goto out; - } - ret = (ssize_t) sizeof(struct raw1394_request); - } - out: - free_pending_request(req); - return ret; -} - -static int state_opened(struct file_info *fi, struct pending_request *req) -{ - if (req->req.type == RAW1394_REQ_INITIALIZE) { - switch (req->req.misc) { - case RAW1394_KERNELAPI_VERSION: - case 3: - fi->state = initialized; - fi->protocol_version = req->req.misc; - req->req.error = RAW1394_ERROR_NONE; - req->req.generation = atomic_read(&internal_generation); - break; - - default: - req->req.error = RAW1394_ERROR_COMPAT; - req->req.misc = RAW1394_KERNELAPI_VERSION; - } - } else { - req->req.error = RAW1394_ERROR_STATE_ORDER; - } - - req->req.length = 0; - queue_complete_req(req); - return 0; -} - -static int state_initialized(struct file_info *fi, struct pending_request *req) -{ - unsigned long flags; - struct host_info *hi; - struct raw1394_khost_list *khl; - - if (req->req.generation != atomic_read(&internal_generation)) { - req->req.error = RAW1394_ERROR_GENERATION; - req->req.generation = atomic_read(&internal_generation); - req->req.length = 0; - queue_complete_req(req); - return 0; - } - - switch (req->req.type) { - case RAW1394_REQ_LIST_CARDS: - spin_lock_irqsave(&host_info_lock, flags); - khl = kmalloc(sizeof(*khl) * host_count, GFP_ATOMIC); - - if (khl) { - req->req.misc = host_count; - req->data = (quadlet_t *) khl; - - list_for_each_entry(hi, &host_info_list, list) { - khl->nodes = hi->host->node_count; - strcpy(khl->name, hi->host->driver->name); - khl++; - } - } - spin_unlock_irqrestore(&host_info_lock, flags); - - if (khl) { - req->req.error = RAW1394_ERROR_NONE; - req->req.length = min(req->req.length, - (u32) (sizeof - (struct raw1394_khost_list) - * req->req.misc)); - req->free_data = 1; - } else { - return -ENOMEM; - } - break; - - case RAW1394_REQ_SET_CARD: - spin_lock_irqsave(&host_info_lock, flags); - if (req->req.misc >= host_count) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - goto out_set_card; - } - list_for_each_entry(hi, &host_info_list, list) - if (!req->req.misc--) - break; - get_device(&hi->host->device); /* FIXME handle failure case */ - list_add_tail(&fi->list, &hi->file_info_list); - - /* prevent unloading of the host's low-level driver */ - if (!try_module_get(hi->host->driver->owner)) { - req->req.error = RAW1394_ERROR_ABORTED; - goto out_set_card; - } - WARN_ON(fi->host); - fi->host = hi->host; - fi->state = connected; - - req->req.error = RAW1394_ERROR_NONE; - req->req.generation = get_hpsb_generation(fi->host); - req->req.misc = (fi->host->node_id << 16) - | fi->host->node_count; - if (fi->protocol_version > 3) - req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8; -out_set_card: - spin_unlock_irqrestore(&host_info_lock, flags); - - req->req.length = 0; - break; - - default: - req->req.error = RAW1394_ERROR_STATE_ORDER; - req->req.length = 0; - break; - } - - queue_complete_req(req); - return 0; -} - -static void handle_fcp_listen(struct file_info *fi, struct pending_request *req) -{ - if (req->req.misc) { - if (fi->fcp_buffer) { - req->req.error = RAW1394_ERROR_ALREADY; - } else { - fi->fcp_buffer = int2ptr(req->req.recvb); - } - } else { - if (!fi->fcp_buffer) { - req->req.error = RAW1394_ERROR_ALREADY; - } else { - fi->fcp_buffer = NULL; - } - } - - req->req.length = 0; - queue_complete_req(req); -} - -static int handle_async_request(struct file_info *fi, - struct pending_request *req, int node) -{ - unsigned long flags; - struct hpsb_packet *packet = NULL; - u64 addr = req->req.address & 0xffffffffffffULL; - - switch (req->req.type) { - case RAW1394_REQ_ASYNC_READ: - DBGMSG("read_request called"); - packet = - hpsb_make_readpacket(fi->host, node, addr, req->req.length); - - if (!packet) - return -ENOMEM; - - if (req->req.length == 4) - req->data = &packet->header[3]; - else - req->data = packet->data; - - break; - - case RAW1394_REQ_ASYNC_WRITE: - DBGMSG("write_request called"); - - packet = hpsb_make_writepacket(fi->host, node, addr, NULL, - req->req.length); - if (!packet) - return -ENOMEM; - - if (req->req.length == 4) { - if (copy_from_user - (&packet->header[3], int2ptr(req->req.sendb), - req->req.length)) - req->req.error = RAW1394_ERROR_MEMFAULT; - } else { - if (copy_from_user - (packet->data, int2ptr(req->req.sendb), - req->req.length)) - req->req.error = RAW1394_ERROR_MEMFAULT; - } - - req->req.length = 0; - break; - - case RAW1394_REQ_ASYNC_STREAM: - DBGMSG("stream_request called"); - - packet = - hpsb_make_streampacket(fi->host, NULL, req->req.length, - node & 0x3f /*channel */ , - (req->req.misc >> 16) & 0x3, - req->req.misc & 0xf); - if (!packet) - return -ENOMEM; - - if (copy_from_user(packet->data, int2ptr(req->req.sendb), - req->req.length)) - req->req.error = RAW1394_ERROR_MEMFAULT; - - req->req.length = 0; - break; - - case RAW1394_REQ_LOCK: - DBGMSG("lock_request called"); - if ((req->req.misc == EXTCODE_FETCH_ADD) - || (req->req.misc == EXTCODE_LITTLE_ADD)) { - if (req->req.length != 4) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - break; - } - } else { - if (req->req.length != 8) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - break; - } - } - - packet = hpsb_make_lockpacket(fi->host, node, addr, - req->req.misc, NULL, 0); - if (!packet) - return -ENOMEM; - - if (copy_from_user(packet->data, int2ptr(req->req.sendb), - req->req.length)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - break; - } - - req->data = packet->data; - req->req.length = 4; - break; - - case RAW1394_REQ_LOCK64: - DBGMSG("lock64_request called"); - if ((req->req.misc == EXTCODE_FETCH_ADD) - || (req->req.misc == EXTCODE_LITTLE_ADD)) { - if (req->req.length != 8) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - break; - } - } else { - if (req->req.length != 16) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - break; - } - } - packet = hpsb_make_lock64packet(fi->host, node, addr, - req->req.misc, NULL, 0); - if (!packet) - return -ENOMEM; - - if (copy_from_user(packet->data, int2ptr(req->req.sendb), - req->req.length)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - break; - } - - req->data = packet->data; - req->req.length = 8; - break; - - default: - req->req.error = RAW1394_ERROR_STATE_ORDER; - } - - req->packet = packet; - - if (req->req.error) { - req->req.length = 0; - queue_complete_req(req); - return 0; - } - - hpsb_set_packet_complete_task(packet, - (void (*)(void *))queue_complete_cb, req); - - spin_lock_irqsave(&fi->reqlists_lock, flags); - list_add_tail(&req->list, &fi->req_pending); - spin_unlock_irqrestore(&fi->reqlists_lock, flags); - - packet->generation = req->req.generation; - - if (hpsb_send_packet(packet) < 0) { - req->req.error = RAW1394_ERROR_SEND_ERROR; - req->req.length = 0; - hpsb_free_tlabel(packet); - queue_complete_req(req); - } - return 0; -} - -static int handle_async_send(struct file_info *fi, struct pending_request *req) -{ - unsigned long flags; - struct hpsb_packet *packet; - int header_length = req->req.misc & 0xffff; - int expect_response = req->req.misc >> 16; - size_t data_size; - - if (header_length > req->req.length || header_length < 12 || - header_length > FIELD_SIZEOF(struct hpsb_packet, header)) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - req->req.length = 0; - queue_complete_req(req); - return 0; - } - - data_size = req->req.length - header_length; - packet = hpsb_alloc_packet(data_size); - req->packet = packet; - if (!packet) - return -ENOMEM; - - if (copy_from_user(packet->header, int2ptr(req->req.sendb), - header_length)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - req->req.length = 0; - queue_complete_req(req); - return 0; - } - - if (copy_from_user - (packet->data, int2ptr(req->req.sendb) + header_length, - data_size)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - req->req.length = 0; - queue_complete_req(req); - return 0; - } - - packet->type = hpsb_async; - packet->node_id = packet->header[0] >> 16; - packet->tcode = (packet->header[0] >> 4) & 0xf; - packet->tlabel = (packet->header[0] >> 10) & 0x3f; - packet->host = fi->host; - packet->expect_response = expect_response; - packet->header_size = header_length; - packet->data_size = data_size; - - req->req.length = 0; - hpsb_set_packet_complete_task(packet, - (void (*)(void *))queue_complete_cb, req); - - spin_lock_irqsave(&fi->reqlists_lock, flags); - list_add_tail(&req->list, &fi->req_pending); - spin_unlock_irqrestore(&fi->reqlists_lock, flags); - - /* Update the generation of the packet just before sending. */ - packet->generation = req->req.generation; - - if (hpsb_send_packet(packet) < 0) { - req->req.error = RAW1394_ERROR_SEND_ERROR; - queue_complete_req(req); - } - - return 0; -} - -static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer, - u64 addr, size_t length, u16 flags) -{ - unsigned long irqflags; - struct pending_request *req; - struct host_info *hi; - struct file_info *fi = NULL; - struct list_head *entry; - struct arm_addr *arm_addr = NULL; - struct arm_request *arm_req = NULL; - struct arm_response *arm_resp = NULL; - int found = 0, size = 0, rcode = -1; - struct arm_request_response *arm_req_resp = NULL; - - DBGMSG("arm_read called by node: %X " - "addr: %4.4x %8.8x length: %Zu", nodeid, - (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), - length); - spin_lock_irqsave(&host_info_lock, irqflags); - hi = find_host_info(host); /* search address-entry */ - if (hi != NULL) { - list_for_each_entry(fi, &hi->file_info_list, list) { - entry = fi->addr_list.next; - while (entry != &(fi->addr_list)) { - arm_addr = - list_entry(entry, struct arm_addr, - addr_list); - if (((arm_addr->start) <= (addr)) - && ((arm_addr->end) >= (addr + length))) { - found = 1; - break; - } - entry = entry->next; - } - if (found) { - break; - } - } - } - rcode = -1; - if (!found) { - printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found" - " -> rcode_address_error\n"); - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (RCODE_ADDRESS_ERROR); - } else { - DBGMSG("arm_read addr_entry FOUND"); - } - if (arm_addr->rec_length < length) { - DBGMSG("arm_read blocklength too big -> rcode_data_error"); - rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */ - } - if (rcode == -1) { - if (arm_addr->access_rights & ARM_READ) { - if (!(arm_addr->client_transactions & ARM_READ)) { - memcpy(buffer, - (arm_addr->addr_space_buffer) + (addr - - (arm_addr-> - start)), - length); - DBGMSG("arm_read -> (rcode_complete)"); - rcode = RCODE_COMPLETE; - } - } else { - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - DBGMSG("arm_read -> rcode_type_error (access denied)"); - } - } - if (arm_addr->notification_options & ARM_READ) { - DBGMSG("arm_read -> entering notification-section"); - req = __alloc_pending_request(GFP_ATOMIC); - if (!req) { - DBGMSG("arm_read -> rcode_conflict_error"); - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - if (rcode == RCODE_COMPLETE) { - size = - sizeof(struct arm_request) + - sizeof(struct arm_response) + - length * sizeof(byte_t) + - sizeof(struct arm_request_response); - } else { - size = - sizeof(struct arm_request) + - sizeof(struct arm_response) + - sizeof(struct arm_request_response); - } - req->data = kmalloc(size, GFP_ATOMIC); - if (!(req->data)) { - free_pending_request(req); - DBGMSG("arm_read -> rcode_conflict_error"); - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - req->free_data = 1; - req->file_info = fi; - req->req.type = RAW1394_REQ_ARM; - req->req.generation = get_hpsb_generation(host); - req->req.misc = - (((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF)); - req->req.tag = arm_addr->arm_tag; - req->req.recvb = arm_addr->recvb; - req->req.length = size; - arm_req_resp = (struct arm_request_response *)(req->data); - arm_req = (struct arm_request *)((byte_t *) (req->data) + - (sizeof - (struct - arm_request_response))); - arm_resp = - (struct arm_response *)((byte_t *) (arm_req) + - (sizeof(struct arm_request))); - arm_req->buffer = NULL; - arm_resp->buffer = NULL; - if (rcode == RCODE_COMPLETE) { - byte_t *buf = - (byte_t *) arm_resp + sizeof(struct arm_response); - memcpy(buf, - (arm_addr->addr_space_buffer) + (addr - - (arm_addr-> - start)), - length); - arm_resp->buffer = - int2ptr((arm_addr->recvb) + - sizeof(struct arm_request_response) + - sizeof(struct arm_request) + - sizeof(struct arm_response)); - } - arm_resp->buffer_length = - (rcode == RCODE_COMPLETE) ? length : 0; - arm_resp->response_code = rcode; - arm_req->buffer_length = 0; - arm_req->generation = req->req.generation; - arm_req->extended_transaction_code = 0; - arm_req->destination_offset = addr; - arm_req->source_nodeid = nodeid; - arm_req->destination_nodeid = host->node_id; - arm_req->tlabel = (flags >> 10) & 0x3f; - arm_req->tcode = (flags >> 4) & 0x0f; - arm_req_resp->request = int2ptr((arm_addr->recvb) + - sizeof(struct - arm_request_response)); - arm_req_resp->response = - int2ptr((arm_addr->recvb) + - sizeof(struct arm_request_response) + - sizeof(struct arm_request)); - queue_complete_req(req); - } - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (rcode); -} - -static int arm_write(struct hpsb_host *host, int nodeid, int destid, - quadlet_t * data, u64 addr, size_t length, u16 flags) -{ - unsigned long irqflags; - struct pending_request *req; - struct host_info *hi; - struct file_info *fi = NULL; - struct list_head *entry; - struct arm_addr *arm_addr = NULL; - struct arm_request *arm_req = NULL; - struct arm_response *arm_resp = NULL; - int found = 0, size = 0, rcode = -1; - struct arm_request_response *arm_req_resp = NULL; - - DBGMSG("arm_write called by node: %X " - "addr: %4.4x %8.8x length: %Zu", nodeid, - (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), - length); - spin_lock_irqsave(&host_info_lock, irqflags); - hi = find_host_info(host); /* search address-entry */ - if (hi != NULL) { - list_for_each_entry(fi, &hi->file_info_list, list) { - entry = fi->addr_list.next; - while (entry != &(fi->addr_list)) { - arm_addr = - list_entry(entry, struct arm_addr, - addr_list); - if (((arm_addr->start) <= (addr)) - && ((arm_addr->end) >= (addr + length))) { - found = 1; - break; - } - entry = entry->next; - } - if (found) { - break; - } - } - } - rcode = -1; - if (!found) { - printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found" - " -> rcode_address_error\n"); - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (RCODE_ADDRESS_ERROR); - } else { - DBGMSG("arm_write addr_entry FOUND"); - } - if (arm_addr->rec_length < length) { - DBGMSG("arm_write blocklength too big -> rcode_data_error"); - rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */ - } - if (rcode == -1) { - if (arm_addr->access_rights & ARM_WRITE) { - if (!(arm_addr->client_transactions & ARM_WRITE)) { - memcpy((arm_addr->addr_space_buffer) + - (addr - (arm_addr->start)), data, - length); - DBGMSG("arm_write -> (rcode_complete)"); - rcode = RCODE_COMPLETE; - } - } else { - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - DBGMSG("arm_write -> rcode_type_error (access denied)"); - } - } - if (arm_addr->notification_options & ARM_WRITE) { - DBGMSG("arm_write -> entering notification-section"); - req = __alloc_pending_request(GFP_ATOMIC); - if (!req) { - DBGMSG("arm_write -> rcode_conflict_error"); - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request my be retried */ - } - size = - sizeof(struct arm_request) + sizeof(struct arm_response) + - (length) * sizeof(byte_t) + - sizeof(struct arm_request_response); - req->data = kmalloc(size, GFP_ATOMIC); - if (!(req->data)) { - free_pending_request(req); - DBGMSG("arm_write -> rcode_conflict_error"); - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - req->free_data = 1; - req->file_info = fi; - req->req.type = RAW1394_REQ_ARM; - req->req.generation = get_hpsb_generation(host); - req->req.misc = - (((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF)); - req->req.tag = arm_addr->arm_tag; - req->req.recvb = arm_addr->recvb; - req->req.length = size; - arm_req_resp = (struct arm_request_response *)(req->data); - arm_req = (struct arm_request *)((byte_t *) (req->data) + - (sizeof - (struct - arm_request_response))); - arm_resp = - (struct arm_response *)((byte_t *) (arm_req) + - (sizeof(struct arm_request))); - arm_resp->buffer = NULL; - memcpy((byte_t *) arm_resp + sizeof(struct arm_response), - data, length); - arm_req->buffer = int2ptr((arm_addr->recvb) + - sizeof(struct arm_request_response) + - sizeof(struct arm_request) + - sizeof(struct arm_response)); - arm_req->buffer_length = length; - arm_req->generation = req->req.generation; - arm_req->extended_transaction_code = 0; - arm_req->destination_offset = addr; - arm_req->source_nodeid = nodeid; - arm_req->destination_nodeid = destid; - arm_req->tlabel = (flags >> 10) & 0x3f; - arm_req->tcode = (flags >> 4) & 0x0f; - arm_resp->buffer_length = 0; - arm_resp->response_code = rcode; - arm_req_resp->request = int2ptr((arm_addr->recvb) + - sizeof(struct - arm_request_response)); - arm_req_resp->response = - int2ptr((arm_addr->recvb) + - sizeof(struct arm_request_response) + - sizeof(struct arm_request)); - queue_complete_req(req); - } - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (rcode); -} - -static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store, - u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, - u16 flags) -{ - unsigned long irqflags; - struct pending_request *req; - struct host_info *hi; - struct file_info *fi = NULL; - struct list_head *entry; - struct arm_addr *arm_addr = NULL; - struct arm_request *arm_req = NULL; - struct arm_response *arm_resp = NULL; - int found = 0, size = 0, rcode = -1; - quadlet_t old, new; - struct arm_request_response *arm_req_resp = NULL; - - if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || - ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { - DBGMSG("arm_lock called by node: %X " - "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X", - nodeid, (u16) ((addr >> 32) & 0xFFFF), - (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF, - be32_to_cpu(data)); - } else { - DBGMSG("arm_lock called by node: %X " - "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X", - nodeid, (u16) ((addr >> 32) & 0xFFFF), - (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF, - be32_to_cpu(data), be32_to_cpu(arg)); - } - spin_lock_irqsave(&host_info_lock, irqflags); - hi = find_host_info(host); /* search address-entry */ - if (hi != NULL) { - list_for_each_entry(fi, &hi->file_info_list, list) { - entry = fi->addr_list.next; - while (entry != &(fi->addr_list)) { - arm_addr = - list_entry(entry, struct arm_addr, - addr_list); - if (((arm_addr->start) <= (addr)) - && ((arm_addr->end) >= - (addr + sizeof(*store)))) { - found = 1; - break; - } - entry = entry->next; - } - if (found) { - break; - } - } - } - rcode = -1; - if (!found) { - printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found" - " -> rcode_address_error\n"); - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (RCODE_ADDRESS_ERROR); - } else { - DBGMSG("arm_lock addr_entry FOUND"); - } - if (rcode == -1) { - if (arm_addr->access_rights & ARM_LOCK) { - if (!(arm_addr->client_transactions & ARM_LOCK)) { - memcpy(&old, - (arm_addr->addr_space_buffer) + (addr - - (arm_addr-> - start)), - sizeof(old)); - switch (ext_tcode) { - case (EXTCODE_MASK_SWAP): - new = data | (old & ~arg); - break; - case (EXTCODE_COMPARE_SWAP): - if (old == arg) { - new = data; - } else { - new = old; - } - break; - case (EXTCODE_FETCH_ADD): - new = - cpu_to_be32(be32_to_cpu(data) + - be32_to_cpu(old)); - break; - case (EXTCODE_LITTLE_ADD): - new = - cpu_to_le32(le32_to_cpu(data) + - le32_to_cpu(old)); - break; - case (EXTCODE_BOUNDED_ADD): - if (old != arg) { - new = - cpu_to_be32(be32_to_cpu - (data) + - be32_to_cpu - (old)); - } else { - new = old; - } - break; - case (EXTCODE_WRAP_ADD): - if (old != arg) { - new = - cpu_to_be32(be32_to_cpu - (data) + - be32_to_cpu - (old)); - } else { - new = data; - } - break; - default: - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - printk(KERN_ERR - "raw1394: arm_lock FAILED " - "ext_tcode not allowed -> rcode_type_error\n"); - break; - } /*switch */ - if (rcode == -1) { - DBGMSG("arm_lock -> (rcode_complete)"); - rcode = RCODE_COMPLETE; - memcpy(store, &old, sizeof(*store)); - memcpy((arm_addr->addr_space_buffer) + - (addr - (arm_addr->start)), - &new, sizeof(*store)); - } - } - } else { - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - DBGMSG("arm_lock -> rcode_type_error (access denied)"); - } - } - if (arm_addr->notification_options & ARM_LOCK) { - byte_t *buf1, *buf2; - DBGMSG("arm_lock -> entering notification-section"); - req = __alloc_pending_request(GFP_ATOMIC); - if (!req) { - DBGMSG("arm_lock -> rcode_conflict_error"); - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response); /* maximum */ - req->data = kmalloc(size, GFP_ATOMIC); - if (!(req->data)) { - free_pending_request(req); - DBGMSG("arm_lock -> rcode_conflict_error"); - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - req->free_data = 1; - arm_req_resp = (struct arm_request_response *)(req->data); - arm_req = (struct arm_request *)((byte_t *) (req->data) + - (sizeof - (struct - arm_request_response))); - arm_resp = - (struct arm_response *)((byte_t *) (arm_req) + - (sizeof(struct arm_request))); - buf1 = (byte_t *) arm_resp + sizeof(struct arm_response); - buf2 = buf1 + 2 * sizeof(*store); - if ((ext_tcode == EXTCODE_FETCH_ADD) || - (ext_tcode == EXTCODE_LITTLE_ADD)) { - arm_req->buffer_length = sizeof(*store); - memcpy(buf1, &data, sizeof(*store)); - - } else { - arm_req->buffer_length = 2 * sizeof(*store); - memcpy(buf1, &arg, sizeof(*store)); - memcpy(buf1 + sizeof(*store), &data, sizeof(*store)); - } - if (rcode == RCODE_COMPLETE) { - arm_resp->buffer_length = sizeof(*store); - memcpy(buf2, &old, sizeof(*store)); - } else { - arm_resp->buffer_length = 0; - } - req->file_info = fi; - req->req.type = RAW1394_REQ_ARM; - req->req.generation = get_hpsb_generation(host); - req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) | - (ARM_LOCK & 0xFF)); - req->req.tag = arm_addr->arm_tag; - req->req.recvb = arm_addr->recvb; - req->req.length = size; - arm_req->generation = req->req.generation; - arm_req->extended_transaction_code = ext_tcode; - arm_req->destination_offset = addr; - arm_req->source_nodeid = nodeid; - arm_req->destination_nodeid = host->node_id; - arm_req->tlabel = (flags >> 10) & 0x3f; - arm_req->tcode = (flags >> 4) & 0x0f; - arm_resp->response_code = rcode; - arm_req_resp->request = int2ptr((arm_addr->recvb) + - sizeof(struct - arm_request_response)); - arm_req_resp->response = - int2ptr((arm_addr->recvb) + - sizeof(struct arm_request_response) + - sizeof(struct arm_request)); - arm_req->buffer = - int2ptr((arm_addr->recvb) + - sizeof(struct arm_request_response) + - sizeof(struct arm_request) + - sizeof(struct arm_response)); - arm_resp->buffer = - int2ptr((arm_addr->recvb) + - sizeof(struct arm_request_response) + - sizeof(struct arm_request) + - sizeof(struct arm_response) + 2 * sizeof(*store)); - queue_complete_req(req); - } - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (rcode); -} - -static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store, - u64 addr, octlet_t data, octlet_t arg, int ext_tcode, - u16 flags) -{ - unsigned long irqflags; - struct pending_request *req; - struct host_info *hi; - struct file_info *fi = NULL; - struct list_head *entry; - struct arm_addr *arm_addr = NULL; - struct arm_request *arm_req = NULL; - struct arm_response *arm_resp = NULL; - int found = 0, size = 0, rcode = -1; - octlet_t old, new; - struct arm_request_response *arm_req_resp = NULL; - - if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || - ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { - DBGMSG("arm_lock64 called by node: %X " - "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ", - nodeid, (u16) ((addr >> 32) & 0xFFFF), - (u32) (addr & 0xFFFFFFFF), - ext_tcode & 0xFF, - (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), - (u32) (be64_to_cpu(data) & 0xFFFFFFFF)); - } else { - DBGMSG("arm_lock64 called by node: %X " - "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: " - "%8.8X %8.8X ", - nodeid, (u16) ((addr >> 32) & 0xFFFF), - (u32) (addr & 0xFFFFFFFF), - ext_tcode & 0xFF, - (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), - (u32) (be64_to_cpu(data) & 0xFFFFFFFF), - (u32) ((be64_to_cpu(arg) >> 32) & 0xFFFFFFFF), - (u32) (be64_to_cpu(arg) & 0xFFFFFFFF)); - } - spin_lock_irqsave(&host_info_lock, irqflags); - hi = find_host_info(host); /* search addressentry in file_info's for host */ - if (hi != NULL) { - list_for_each_entry(fi, &hi->file_info_list, list) { - entry = fi->addr_list.next; - while (entry != &(fi->addr_list)) { - arm_addr = - list_entry(entry, struct arm_addr, - addr_list); - if (((arm_addr->start) <= (addr)) - && ((arm_addr->end) >= - (addr + sizeof(*store)))) { - found = 1; - break; - } - entry = entry->next; - } - if (found) { - break; - } - } - } - rcode = -1; - if (!found) { - printk(KERN_ERR - "raw1394: arm_lock64 FAILED addr_entry not found" - " -> rcode_address_error\n"); - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (RCODE_ADDRESS_ERROR); - } else { - DBGMSG("arm_lock64 addr_entry FOUND"); - } - if (rcode == -1) { - if (arm_addr->access_rights & ARM_LOCK) { - if (!(arm_addr->client_transactions & ARM_LOCK)) { - memcpy(&old, - (arm_addr->addr_space_buffer) + (addr - - (arm_addr-> - start)), - sizeof(old)); - switch (ext_tcode) { - case (EXTCODE_MASK_SWAP): - new = data | (old & ~arg); - break; - case (EXTCODE_COMPARE_SWAP): - if (old == arg) { - new = data; - } else { - new = old; - } - break; - case (EXTCODE_FETCH_ADD): - new = - cpu_to_be64(be64_to_cpu(data) + - be64_to_cpu(old)); - break; - case (EXTCODE_LITTLE_ADD): - new = - cpu_to_le64(le64_to_cpu(data) + - le64_to_cpu(old)); - break; - case (EXTCODE_BOUNDED_ADD): - if (old != arg) { - new = - cpu_to_be64(be64_to_cpu - (data) + - be64_to_cpu - (old)); - } else { - new = old; - } - break; - case (EXTCODE_WRAP_ADD): - if (old != arg) { - new = - cpu_to_be64(be64_to_cpu - (data) + - be64_to_cpu - (old)); - } else { - new = data; - } - break; - default: - printk(KERN_ERR - "raw1394: arm_lock64 FAILED " - "ext_tcode not allowed -> rcode_type_error\n"); - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - break; - } /*switch */ - if (rcode == -1) { - DBGMSG - ("arm_lock64 -> (rcode_complete)"); - rcode = RCODE_COMPLETE; - memcpy(store, &old, sizeof(*store)); - memcpy((arm_addr->addr_space_buffer) + - (addr - (arm_addr->start)), - &new, sizeof(*store)); - } - } - } else { - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - DBGMSG - ("arm_lock64 -> rcode_type_error (access denied)"); - } - } - if (arm_addr->notification_options & ARM_LOCK) { - byte_t *buf1, *buf2; - DBGMSG("arm_lock64 -> entering notification-section"); - req = __alloc_pending_request(GFP_ATOMIC); - if (!req) { - spin_unlock_irqrestore(&host_info_lock, irqflags); - DBGMSG("arm_lock64 -> rcode_conflict_error"); - return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response); /* maximum */ - req->data = kmalloc(size, GFP_ATOMIC); - if (!(req->data)) { - free_pending_request(req); - spin_unlock_irqrestore(&host_info_lock, irqflags); - DBGMSG("arm_lock64 -> rcode_conflict_error"); - return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - req->free_data = 1; - arm_req_resp = (struct arm_request_response *)(req->data); - arm_req = (struct arm_request *)((byte_t *) (req->data) + - (sizeof - (struct - arm_request_response))); - arm_resp = - (struct arm_response *)((byte_t *) (arm_req) + - (sizeof(struct arm_request))); - buf1 = (byte_t *) arm_resp + sizeof(struct arm_response); - buf2 = buf1 + 2 * sizeof(*store); - if ((ext_tcode == EXTCODE_FETCH_ADD) || - (ext_tcode == EXTCODE_LITTLE_ADD)) { - arm_req->buffer_length = sizeof(*store); - memcpy(buf1, &data, sizeof(*store)); - - } else { - arm_req->buffer_length = 2 * sizeof(*store); - memcpy(buf1, &arg, sizeof(*store)); - memcpy(buf1 + sizeof(*store), &data, sizeof(*store)); - } - if (rcode == RCODE_COMPLETE) { - arm_resp->buffer_length = sizeof(*store); - memcpy(buf2, &old, sizeof(*store)); - } else { - arm_resp->buffer_length = 0; - } - req->file_info = fi; - req->req.type = RAW1394_REQ_ARM; - req->req.generation = get_hpsb_generation(host); - req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) | - (ARM_LOCK & 0xFF)); - req->req.tag = arm_addr->arm_tag; - req->req.recvb = arm_addr->recvb; - req->req.length = size; - arm_req->generation = req->req.generation; - arm_req->extended_transaction_code = ext_tcode; - arm_req->destination_offset = addr; - arm_req->source_nodeid = nodeid; - arm_req->destination_nodeid = host->node_id; - arm_req->tlabel = (flags >> 10) & 0x3f; - arm_req->tcode = (flags >> 4) & 0x0f; - arm_resp->response_code = rcode; - arm_req_resp->request = int2ptr((arm_addr->recvb) + - sizeof(struct - arm_request_response)); - arm_req_resp->response = - int2ptr((arm_addr->recvb) + - sizeof(struct arm_request_response) + - sizeof(struct arm_request)); - arm_req->buffer = - int2ptr((arm_addr->recvb) + - sizeof(struct arm_request_response) + - sizeof(struct arm_request) + - sizeof(struct arm_response)); - arm_resp->buffer = - int2ptr((arm_addr->recvb) + - sizeof(struct arm_request_response) + - sizeof(struct arm_request) + - sizeof(struct arm_response) + 2 * sizeof(*store)); - queue_complete_req(req); - } - spin_unlock_irqrestore(&host_info_lock, irqflags); - return (rcode); -} - -static int arm_register(struct file_info *fi, struct pending_request *req) -{ - int retval; - struct arm_addr *addr; - struct host_info *hi; - struct file_info *fi_hlp = NULL; - struct list_head *entry; - struct arm_addr *arm_addr = NULL; - int same_host, another_host; - unsigned long flags; - - DBGMSG("arm_register called " - "addr(Offset): %8.8x %8.8x length: %u " - "rights: %2.2X notify: %2.2X " - "max_blk_len: %4.4X", - (u32) ((req->req.address >> 32) & 0xFFFF), - (u32) (req->req.address & 0xFFFFFFFF), - req->req.length, ((req->req.misc >> 8) & 0xFF), - (req->req.misc & 0xFF), ((req->req.misc >> 16) & 0xFFFF)); - /* check addressrange */ - if ((((req->req.address) & ~(0xFFFFFFFFFFFFULL)) != 0) || - (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFFULL)) != - 0)) { - req->req.length = 0; - return (-EINVAL); - } - /* addr-list-entry for fileinfo */ - addr = kmalloc(sizeof(*addr), GFP_KERNEL); - if (!addr) { - req->req.length = 0; - return (-ENOMEM); - } - /* allocation of addr_space_buffer */ - addr->addr_space_buffer = vmalloc(req->req.length); - if (!(addr->addr_space_buffer)) { - kfree(addr); - req->req.length = 0; - return (-ENOMEM); - } - /* initialization of addr_space_buffer */ - if ((req->req.sendb) == (unsigned long)NULL) { - /* init: set 0 */ - memset(addr->addr_space_buffer, 0, req->req.length); - } else { - /* init: user -> kernel */ - if (copy_from_user - (addr->addr_space_buffer, int2ptr(req->req.sendb), - req->req.length)) { - vfree(addr->addr_space_buffer); - kfree(addr); - return (-EFAULT); - } - } - INIT_LIST_HEAD(&addr->addr_list); - addr->arm_tag = req->req.tag; - addr->start = req->req.address; - addr->end = req->req.address + req->req.length; - addr->access_rights = (u8) (req->req.misc & 0x0F); - addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F); - addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F); - addr->access_rights |= addr->client_transactions; - addr->notification_options |= addr->client_transactions; - addr->recvb = req->req.recvb; - addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF); - - spin_lock_irqsave(&host_info_lock, flags); - hi = find_host_info(fi->host); - same_host = 0; - another_host = 0; - /* same host with address-entry containing same addressrange ? */ - list_for_each_entry(fi_hlp, &hi->file_info_list, list) { - entry = fi_hlp->addr_list.next; - while (entry != &(fi_hlp->addr_list)) { - arm_addr = - list_entry(entry, struct arm_addr, addr_list); - if ((arm_addr->start == addr->start) - && (arm_addr->end == addr->end)) { - DBGMSG("same host ownes same " - "addressrange -> EALREADY"); - same_host = 1; - break; - } - entry = entry->next; - } - if (same_host) { - break; - } - } - if (same_host) { - /* addressrange occupied by same host */ - spin_unlock_irqrestore(&host_info_lock, flags); - vfree(addr->addr_space_buffer); - kfree(addr); - return (-EALREADY); - } - /* another host with valid address-entry containing same addressrange */ - list_for_each_entry(hi, &host_info_list, list) { - if (hi->host != fi->host) { - list_for_each_entry(fi_hlp, &hi->file_info_list, list) { - entry = fi_hlp->addr_list.next; - while (entry != &(fi_hlp->addr_list)) { - arm_addr = - list_entry(entry, struct arm_addr, - addr_list); - if ((arm_addr->start == addr->start) - && (arm_addr->end == addr->end)) { - DBGMSG - ("another host ownes same " - "addressrange"); - another_host = 1; - break; - } - entry = entry->next; - } - if (another_host) { - break; - } - } - } - } - spin_unlock_irqrestore(&host_info_lock, flags); - - if (another_host) { - DBGMSG("another hosts entry is valid -> SUCCESS"); - if (copy_to_user(int2ptr(req->req.recvb), - &addr->start, sizeof(u64))) { - printk(KERN_ERR "raw1394: arm_register failed " - " address-range-entry is invalid -> EFAULT !!!\n"); - vfree(addr->addr_space_buffer); - kfree(addr); - return (-EFAULT); - } - free_pending_request(req); /* immediate success or fail */ - /* INSERT ENTRY */ - spin_lock_irqsave(&host_info_lock, flags); - list_add_tail(&addr->addr_list, &fi->addr_list); - spin_unlock_irqrestore(&host_info_lock, flags); - return 0; - } - retval = - hpsb_register_addrspace(&raw1394_highlevel, fi->host, &arm_ops, - req->req.address, - req->req.address + req->req.length); - if (retval) { - /* INSERT ENTRY */ - spin_lock_irqsave(&host_info_lock, flags); - list_add_tail(&addr->addr_list, &fi->addr_list); - spin_unlock_irqrestore(&host_info_lock, flags); - } else { - DBGMSG("arm_register failed errno: %d \n", retval); - vfree(addr->addr_space_buffer); - kfree(addr); - return (-EALREADY); - } - free_pending_request(req); /* immediate success or fail */ - return 0; -} - -static int arm_unregister(struct file_info *fi, struct pending_request *req) -{ - int found = 0; - int retval = 0; - struct list_head *entry; - struct arm_addr *addr = NULL; - struct host_info *hi; - struct file_info *fi_hlp = NULL; - struct arm_addr *arm_addr = NULL; - int another_host; - unsigned long flags; - - DBGMSG("arm_Unregister called addr(Offset): " - "%8.8x %8.8x", - (u32) ((req->req.address >> 32) & 0xFFFF), - (u32) (req->req.address & 0xFFFFFFFF)); - spin_lock_irqsave(&host_info_lock, flags); - /* get addr */ - entry = fi->addr_list.next; - while (entry != &(fi->addr_list)) { - addr = list_entry(entry, struct arm_addr, addr_list); - if (addr->start == req->req.address) { - found = 1; - break; - } - entry = entry->next; - } - if (!found) { - DBGMSG("arm_Unregister addr not found"); - spin_unlock_irqrestore(&host_info_lock, flags); - return (-EINVAL); - } - DBGMSG("arm_Unregister addr found"); - another_host = 0; - /* another host with valid address-entry containing - same addressrange */ - list_for_each_entry(hi, &host_info_list, list) { - if (hi->host != fi->host) { - list_for_each_entry(fi_hlp, &hi->file_info_list, list) { - entry = fi_hlp->addr_list.next; - while (entry != &(fi_hlp->addr_list)) { - arm_addr = list_entry(entry, - struct arm_addr, - addr_list); - if (arm_addr->start == addr->start) { - DBGMSG("another host ownes " - "same addressrange"); - another_host = 1; - break; - } - entry = entry->next; - } - if (another_host) { - break; - } - } - } - } - if (another_host) { - DBGMSG("delete entry from list -> success"); - list_del(&addr->addr_list); - spin_unlock_irqrestore(&host_info_lock, flags); - vfree(addr->addr_space_buffer); - kfree(addr); - free_pending_request(req); /* immediate success or fail */ - return 0; - } - retval = - hpsb_unregister_addrspace(&raw1394_highlevel, fi->host, - addr->start); - if (!retval) { - printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n"); - spin_unlock_irqrestore(&host_info_lock, flags); - return (-EINVAL); - } - DBGMSG("delete entry from list -> success"); - list_del(&addr->addr_list); - spin_unlock_irqrestore(&host_info_lock, flags); - vfree(addr->addr_space_buffer); - kfree(addr); - free_pending_request(req); /* immediate success or fail */ - return 0; -} - -/* Copy data from ARM buffer(s) to user buffer. */ -static int arm_get_buf(struct file_info *fi, struct pending_request *req) -{ - struct arm_addr *arm_addr = NULL; - unsigned long flags; - unsigned long offset; - - struct list_head *entry; - - DBGMSG("arm_get_buf " - "addr(Offset): %04X %08X length: %u", - (u32) ((req->req.address >> 32) & 0xFFFF), - (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length); - - spin_lock_irqsave(&host_info_lock, flags); - entry = fi->addr_list.next; - while (entry != &(fi->addr_list)) { - arm_addr = list_entry(entry, struct arm_addr, addr_list); - if ((arm_addr->start <= req->req.address) && - (arm_addr->end > req->req.address)) { - if (req->req.address + req->req.length <= arm_addr->end) { - offset = req->req.address - arm_addr->start; - spin_unlock_irqrestore(&host_info_lock, flags); - - DBGMSG - ("arm_get_buf copy_to_user( %08X, %p, %u )", - (u32) req->req.recvb, - arm_addr->addr_space_buffer + offset, - (u32) req->req.length); - if (copy_to_user - (int2ptr(req->req.recvb), - arm_addr->addr_space_buffer + offset, - req->req.length)) - return (-EFAULT); - - /* We have to free the request, because we - * queue no response, and therefore nobody - * will free it. */ - free_pending_request(req); - return 0; - } else { - DBGMSG("arm_get_buf request exceeded mapping"); - spin_unlock_irqrestore(&host_info_lock, flags); - return (-EINVAL); - } - } - entry = entry->next; - } - spin_unlock_irqrestore(&host_info_lock, flags); - return (-EINVAL); -} - -/* Copy data from user buffer to ARM buffer(s). */ -static int arm_set_buf(struct file_info *fi, struct pending_request *req) -{ - struct arm_addr *arm_addr = NULL; - unsigned long flags; - unsigned long offset; - - struct list_head *entry; - - DBGMSG("arm_set_buf " - "addr(Offset): %04X %08X length: %u", - (u32) ((req->req.address >> 32) & 0xFFFF), - (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length); - - spin_lock_irqsave(&host_info_lock, flags); - entry = fi->addr_list.next; - while (entry != &(fi->addr_list)) { - arm_addr = list_entry(entry, struct arm_addr, addr_list); - if ((arm_addr->start <= req->req.address) && - (arm_addr->end > req->req.address)) { - if (req->req.address + req->req.length <= arm_addr->end) { - offset = req->req.address - arm_addr->start; - spin_unlock_irqrestore(&host_info_lock, flags); - - DBGMSG - ("arm_set_buf copy_from_user( %p, %08X, %u )", - arm_addr->addr_space_buffer + offset, - (u32) req->req.sendb, - (u32) req->req.length); - if (copy_from_user - (arm_addr->addr_space_buffer + offset, - int2ptr(req->req.sendb), - req->req.length)) - return (-EFAULT); - - /* We have to free the request, because we - * queue no response, and therefore nobody - * will free it. */ - free_pending_request(req); - return 0; - } else { - DBGMSG("arm_set_buf request exceeded mapping"); - spin_unlock_irqrestore(&host_info_lock, flags); - return (-EINVAL); - } - } - entry = entry->next; - } - spin_unlock_irqrestore(&host_info_lock, flags); - return (-EINVAL); -} - -static int reset_notification(struct file_info *fi, struct pending_request *req) -{ - DBGMSG("reset_notification called - switch %s ", - (req->req.misc == RAW1394_NOTIFY_OFF) ? "OFF" : "ON"); - if ((req->req.misc == RAW1394_NOTIFY_OFF) || - (req->req.misc == RAW1394_NOTIFY_ON)) { - fi->notification = (u8) req->req.misc; - free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ - return 0; - } - /* error EINVAL (22) invalid argument */ - return (-EINVAL); -} - -static int write_phypacket(struct file_info *fi, struct pending_request *req) -{ - struct hpsb_packet *packet = NULL; - int retval = 0; - quadlet_t data; - unsigned long flags; - - data = be32_to_cpu((u32) req->req.sendb); - DBGMSG("write_phypacket called - quadlet 0x%8.8x ", data); - packet = hpsb_make_phypacket(fi->host, data); - if (!packet) - return -ENOMEM; - req->req.length = 0; - req->packet = packet; - hpsb_set_packet_complete_task(packet, - (void (*)(void *))queue_complete_cb, req); - spin_lock_irqsave(&fi->reqlists_lock, flags); - list_add_tail(&req->list, &fi->req_pending); - spin_unlock_irqrestore(&fi->reqlists_lock, flags); - packet->generation = req->req.generation; - retval = hpsb_send_packet(packet); - DBGMSG("write_phypacket send_packet called => retval: %d ", retval); - if (retval < 0) { - req->req.error = RAW1394_ERROR_SEND_ERROR; - req->req.length = 0; - queue_complete_req(req); - } - return 0; -} - -static int get_config_rom(struct file_info *fi, struct pending_request *req) -{ - int ret = 0; - quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL); - int status; - - if (!data) - return -ENOMEM; - - status = - csr1212_read(fi->host->csr.rom, CSR1212_CONFIG_ROM_SPACE_OFFSET, - data, req->req.length); - if (copy_to_user(int2ptr(req->req.recvb), data, req->req.length)) - ret = -EFAULT; - if (copy_to_user - (int2ptr(req->req.tag), &fi->host->csr.rom->cache_head->len, - sizeof(fi->host->csr.rom->cache_head->len))) - ret = -EFAULT; - if (copy_to_user(int2ptr(req->req.address), &fi->host->csr.generation, - sizeof(fi->host->csr.generation))) - ret = -EFAULT; - if (copy_to_user(int2ptr(req->req.sendb), &status, sizeof(status))) - ret = -EFAULT; - kfree(data); - if (ret >= 0) { - free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ - } - return ret; -} - -static int update_config_rom(struct file_info *fi, struct pending_request *req) -{ - int ret = 0; - quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL); - if (!data) - return -ENOMEM; - if (copy_from_user(data, int2ptr(req->req.sendb), req->req.length)) { - ret = -EFAULT; - } else { - int status = hpsb_update_config_rom(fi->host, - data, req->req.length, - (unsigned char)req->req. - misc); - if (copy_to_user - (int2ptr(req->req.recvb), &status, sizeof(status))) - ret = -ENOMEM; - } - kfree(data); - if (ret >= 0) { - free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ - fi->cfgrom_upd = 1; - } - return ret; -} - -static int modify_config_rom(struct file_info *fi, struct pending_request *req) -{ - struct csr1212_keyval *kv; - struct csr1212_csr_rom_cache *cache; - struct csr1212_dentry *dentry; - u32 dr; - int ret = 0; - - if (req->req.misc == ~0) { - if (req->req.length == 0) - return -EINVAL; - - /* Find an unused slot */ - for (dr = 0; - dr < RAW1394_MAX_USER_CSR_DIRS && fi->csr1212_dirs[dr]; - dr++) ; - - if (dr == RAW1394_MAX_USER_CSR_DIRS) - return -ENOMEM; - - fi->csr1212_dirs[dr] = - csr1212_new_directory(CSR1212_KV_ID_VENDOR); - if (!fi->csr1212_dirs[dr]) - return -ENOMEM; - } else { - dr = req->req.misc; - if (!fi->csr1212_dirs[dr]) - return -EINVAL; - - /* Delete old stuff */ - for (dentry = - fi->csr1212_dirs[dr]->value.directory.dentries_head; - dentry; dentry = dentry->next) { - csr1212_detach_keyval_from_directory(fi->host->csr.rom-> - root_kv, - dentry->kv); - } - - if (req->req.length == 0) { - csr1212_release_keyval(fi->csr1212_dirs[dr]); - fi->csr1212_dirs[dr] = NULL; - - hpsb_update_config_rom_image(fi->host); - free_pending_request(req); - return 0; - } - } - - cache = csr1212_rom_cache_malloc(0, req->req.length); - if (!cache) { - csr1212_release_keyval(fi->csr1212_dirs[dr]); - fi->csr1212_dirs[dr] = NULL; - return -ENOMEM; - } - - cache->filled_head = kmalloc(sizeof(*cache->filled_head), GFP_KERNEL); - if (!cache->filled_head) { - csr1212_release_keyval(fi->csr1212_dirs[dr]); - fi->csr1212_dirs[dr] = NULL; - CSR1212_FREE(cache); - return -ENOMEM; - } - cache->filled_tail = cache->filled_head; - - if (copy_from_user(cache->data, int2ptr(req->req.sendb), - req->req.length)) { - csr1212_release_keyval(fi->csr1212_dirs[dr]); - fi->csr1212_dirs[dr] = NULL; - ret = -EFAULT; - } else { - cache->len = req->req.length; - cache->filled_head->offset_start = 0; - cache->filled_head->offset_end = cache->size - 1; - - cache->layout_head = cache->layout_tail = fi->csr1212_dirs[dr]; - - ret = CSR1212_SUCCESS; - /* parse all the items */ - for (kv = cache->layout_head; ret == CSR1212_SUCCESS && kv; - kv = kv->next) { - ret = csr1212_parse_keyval(kv, cache); - } - - /* attach top level items to the root directory */ - for (dentry = - fi->csr1212_dirs[dr]->value.directory.dentries_head; - ret == CSR1212_SUCCESS && dentry; dentry = dentry->next) { - ret = - csr1212_attach_keyval_to_directory(fi->host->csr. - rom->root_kv, - dentry->kv); - } - - if (ret == CSR1212_SUCCESS) { - ret = hpsb_update_config_rom_image(fi->host); - - if (ret >= 0 && copy_to_user(int2ptr(req->req.recvb), - &dr, sizeof(dr))) { - ret = -ENOMEM; - } - } - } - kfree(cache->filled_head); - CSR1212_FREE(cache); - - if (ret >= 0) { - /* we have to free the request, because we queue no response, - * and therefore nobody will free it */ - free_pending_request(req); - return 0; - } else { - for (dentry = - fi->csr1212_dirs[dr]->value.directory.dentries_head; - dentry; dentry = dentry->next) { - csr1212_detach_keyval_from_directory(fi->host->csr.rom-> - root_kv, - dentry->kv); - } - csr1212_release_keyval(fi->csr1212_dirs[dr]); - fi->csr1212_dirs[dr] = NULL; - return ret; - } -} - -static int state_connected(struct file_info *fi, struct pending_request *req) -{ - int node = req->req.address >> 48; - - req->req.error = RAW1394_ERROR_NONE; - - switch (req->req.type) { - - case RAW1394_REQ_ECHO: - queue_complete_req(req); - return 0; - - case RAW1394_REQ_ARM_REGISTER: - return arm_register(fi, req); - - case RAW1394_REQ_ARM_UNREGISTER: - return arm_unregister(fi, req); - - case RAW1394_REQ_ARM_SET_BUF: - return arm_set_buf(fi, req); - - case RAW1394_REQ_ARM_GET_BUF: - return arm_get_buf(fi, req); - - case RAW1394_REQ_RESET_NOTIFY: - return reset_notification(fi, req); - - case RAW1394_REQ_ISO_SEND: - case RAW1394_REQ_ISO_LISTEN: - printk(KERN_DEBUG "raw1394: old iso ABI has been removed\n"); - req->req.error = RAW1394_ERROR_COMPAT; - req->req.misc = RAW1394_KERNELAPI_VERSION; - queue_complete_req(req); - return 0; - - case RAW1394_REQ_FCP_LISTEN: - handle_fcp_listen(fi, req); - return 0; - - case RAW1394_REQ_RESET_BUS: - if (req->req.misc == RAW1394_LONG_RESET) { - DBGMSG("busreset called (type: LONG)"); - hpsb_reset_bus(fi->host, LONG_RESET); - free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ - return 0; - } - if (req->req.misc == RAW1394_SHORT_RESET) { - DBGMSG("busreset called (type: SHORT)"); - hpsb_reset_bus(fi->host, SHORT_RESET); - free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ - return 0; - } - /* error EINVAL (22) invalid argument */ - return (-EINVAL); - case RAW1394_REQ_GET_ROM: - return get_config_rom(fi, req); - - case RAW1394_REQ_UPDATE_ROM: - return update_config_rom(fi, req); - - case RAW1394_REQ_MODIFY_ROM: - return modify_config_rom(fi, req); - } - - if (req->req.generation != get_hpsb_generation(fi->host)) { - req->req.error = RAW1394_ERROR_GENERATION; - req->req.generation = get_hpsb_generation(fi->host); - req->req.length = 0; - queue_complete_req(req); - return 0; - } - - switch (req->req.type) { - case RAW1394_REQ_PHYPACKET: - return write_phypacket(fi, req); - case RAW1394_REQ_ASYNC_SEND: - return handle_async_send(fi, req); - } - - if (req->req.length == 0) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - queue_complete_req(req); - return 0; - } - - return handle_async_request(fi, req, node); -} - -static ssize_t raw1394_write(struct file *file, const char __user * buffer, - size_t count, loff_t * offset_is_ignored) -{ - struct file_info *fi = file->private_data; - struct pending_request *req; - ssize_t retval = -EBADFD; - -#ifdef CONFIG_COMPAT - if (count == sizeof(struct compat_raw1394_req) && - sizeof(struct compat_raw1394_req) != - sizeof(struct raw1394_request)) { - buffer = raw1394_compat_write(buffer); - if (IS_ERR((__force void *)buffer)) - return PTR_ERR((__force void *)buffer); - } else -#endif - if (count != sizeof(struct raw1394_request)) { - return -EINVAL; - } - - req = alloc_pending_request(); - if (req == NULL) { - return -ENOMEM; - } - req->file_info = fi; - - if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) { - free_pending_request(req); - return -EFAULT; - } - - if (!mutex_trylock(&fi->state_mutex)) { - free_pending_request(req); - return -EAGAIN; - } - - switch (fi->state) { - case opened: - retval = state_opened(fi, req); - break; - - case initialized: - retval = state_initialized(fi, req); - break; - - case connected: - retval = state_connected(fi, req); - break; - } - - mutex_unlock(&fi->state_mutex); - - if (retval < 0) { - free_pending_request(req); - } else { - BUG_ON(retval); - retval = count; - } - - return retval; -} - -/* rawiso operations */ - -/* check if any RAW1394_REQ_RAWISO_ACTIVITY event is already in the - * completion queue (reqlists_lock must be taken) */ -static inline int __rawiso_event_in_queue(struct file_info *fi) -{ - struct pending_request *req; - - list_for_each_entry(req, &fi->req_complete, list) - if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY) - return 1; - - return 0; -} - -/* put a RAWISO_ACTIVITY event in the queue, if one isn't there already */ -static void queue_rawiso_event(struct file_info *fi) -{ - unsigned long flags; - - spin_lock_irqsave(&fi->reqlists_lock, flags); - - /* only one ISO activity event may be in the queue */ - if (!__rawiso_event_in_queue(fi)) { - struct pending_request *req = - __alloc_pending_request(GFP_ATOMIC); - - if (req) { - req->file_info = fi; - req->req.type = RAW1394_REQ_RAWISO_ACTIVITY; - req->req.generation = get_hpsb_generation(fi->host); - __queue_complete_req(req); - } else { - /* on allocation failure, signal an overflow */ - if (fi->iso_handle) { - atomic_inc(&fi->iso_handle->overflows); - } - } - } - spin_unlock_irqrestore(&fi->reqlists_lock, flags); -} - -static void rawiso_activity_cb(struct hpsb_iso *iso) -{ - unsigned long flags; - struct host_info *hi; - struct file_info *fi; - - spin_lock_irqsave(&host_info_lock, flags); - hi = find_host_info(iso->host); - - if (hi != NULL) { - list_for_each_entry(fi, &hi->file_info_list, list) { - if (fi->iso_handle == iso) - queue_rawiso_event(fi); - } - } - - spin_unlock_irqrestore(&host_info_lock, flags); -} - -/* helper function - gather all the kernel iso status bits for returning to user-space */ -static void raw1394_iso_fill_status(struct hpsb_iso *iso, - struct raw1394_iso_status *stat) -{ - int overflows = atomic_read(&iso->overflows); - int skips = atomic_read(&iso->skips); - - stat->config.data_buf_size = iso->buf_size; - stat->config.buf_packets = iso->buf_packets; - stat->config.channel = iso->channel; - stat->config.speed = iso->speed; - stat->config.irq_interval = iso->irq_interval; - stat->n_packets = hpsb_iso_n_ready(iso); - stat->overflows = ((skips & 0xFFFF) << 16) | ((overflows & 0xFFFF)); - stat->xmit_cycle = iso->xmit_cycle; -} - -static int raw1394_iso_xmit_init(struct file_info *fi, void __user * uaddr) -{ - struct raw1394_iso_status stat; - - if (!fi->host) - return -EINVAL; - - if (copy_from_user(&stat, uaddr, sizeof(stat))) - return -EFAULT; - - fi->iso_handle = hpsb_iso_xmit_init(fi->host, - stat.config.data_buf_size, - stat.config.buf_packets, - stat.config.channel, - stat.config.speed, - stat.config.irq_interval, - rawiso_activity_cb); - if (!fi->iso_handle) - return -ENOMEM; - - fi->iso_state = RAW1394_ISO_XMIT; - - raw1394_iso_fill_status(fi->iso_handle, &stat); - if (copy_to_user(uaddr, &stat, sizeof(stat))) - return -EFAULT; - - /* queue an event to get things started */ - rawiso_activity_cb(fi->iso_handle); - - return 0; -} - -static int raw1394_iso_recv_init(struct file_info *fi, void __user * uaddr) -{ - struct raw1394_iso_status stat; - - if (!fi->host) - return -EINVAL; - - if (copy_from_user(&stat, uaddr, sizeof(stat))) - return -EFAULT; - - fi->iso_handle = hpsb_iso_recv_init(fi->host, - stat.config.data_buf_size, - stat.config.buf_packets, - stat.config.channel, - stat.config.dma_mode, - stat.config.irq_interval, - rawiso_activity_cb); - if (!fi->iso_handle) - return -ENOMEM; - - fi->iso_state = RAW1394_ISO_RECV; - - raw1394_iso_fill_status(fi->iso_handle, &stat); - if (copy_to_user(uaddr, &stat, sizeof(stat))) - return -EFAULT; - return 0; -} - -static int raw1394_iso_get_status(struct file_info *fi, void __user * uaddr) -{ - struct raw1394_iso_status stat; - struct hpsb_iso *iso = fi->iso_handle; - - raw1394_iso_fill_status(fi->iso_handle, &stat); - if (copy_to_user(uaddr, &stat, sizeof(stat))) - return -EFAULT; - - /* reset overflow counter */ - atomic_set(&iso->overflows, 0); - /* reset skip counter */ - atomic_set(&iso->skips, 0); - - return 0; -} - -/* copy N packet_infos out of the ringbuffer into user-supplied array */ -static int raw1394_iso_recv_packets(struct file_info *fi, void __user * uaddr) -{ - struct raw1394_iso_packets upackets; - unsigned int packet = fi->iso_handle->first_packet; - int i; - - if (copy_from_user(&upackets, uaddr, sizeof(upackets))) - return -EFAULT; - - if (upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle)) - return -EINVAL; - - /* ensure user-supplied buffer is accessible and big enough */ - if (!access_ok(VERIFY_WRITE, upackets.infos, - upackets.n_packets * - sizeof(struct raw1394_iso_packet_info))) - return -EFAULT; - - /* copy the packet_infos out */ - for (i = 0; i < upackets.n_packets; i++) { - if (__copy_to_user(&upackets.infos[i], - &fi->iso_handle->infos[packet], - sizeof(struct raw1394_iso_packet_info))) - return -EFAULT; - - packet = (packet + 1) % fi->iso_handle->buf_packets; - } - - return 0; -} - -/* copy N packet_infos from user to ringbuffer, and queue them for transmission */ -static int raw1394_iso_send_packets(struct file_info *fi, void __user * uaddr) -{ - struct raw1394_iso_packets upackets; - int i, rv; - - if (copy_from_user(&upackets, uaddr, sizeof(upackets))) - return -EFAULT; - - if (upackets.n_packets >= fi->iso_handle->buf_packets) - return -EINVAL; - - if (upackets.n_packets >= hpsb_iso_n_ready(fi->iso_handle)) - return -EAGAIN; - - /* ensure user-supplied buffer is accessible and big enough */ - if (!access_ok(VERIFY_READ, upackets.infos, - upackets.n_packets * - sizeof(struct raw1394_iso_packet_info))) - return -EFAULT; - - /* copy the infos structs in and queue the packets */ - for (i = 0; i < upackets.n_packets; i++) { - struct raw1394_iso_packet_info info; - - if (__copy_from_user(&info, &upackets.infos[i], - sizeof(struct raw1394_iso_packet_info))) - return -EFAULT; - - rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset, - info.len, info.tag, info.sy); - if (rv) - return rv; - } - - return 0; -} - -static void raw1394_iso_shutdown(struct file_info *fi) -{ - if (fi->iso_handle) - hpsb_iso_shutdown(fi->iso_handle); - - fi->iso_handle = NULL; - fi->iso_state = RAW1394_ISO_INACTIVE; -} - -static int raw1394_read_cycle_timer(struct file_info *fi, void __user * uaddr) -{ - struct raw1394_cycle_timer ct; - int err; - - err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time); - if (!err) - if (copy_to_user(uaddr, &ct, sizeof(ct))) - err = -EFAULT; - return err; -} - -/* mmap the rawiso xmit/recv buffer */ -static int raw1394_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct file_info *fi = file->private_data; - int ret; - - if (!mutex_trylock(&fi->state_mutex)) - return -EAGAIN; - - if (fi->iso_state == RAW1394_ISO_INACTIVE) - ret = -EINVAL; - else - ret = dma_region_mmap(&fi->iso_handle->data_buf, file, vma); - - mutex_unlock(&fi->state_mutex); - - return ret; -} - -static long raw1394_ioctl_inactive(struct file_info *fi, unsigned int cmd, - void __user *argp) -{ - switch (cmd) { - case RAW1394_IOC_ISO_XMIT_INIT: - return raw1394_iso_xmit_init(fi, argp); - case RAW1394_IOC_ISO_RECV_INIT: - return raw1394_iso_recv_init(fi, argp); - default: - return -EINVAL; - } -} - -static long raw1394_ioctl_recv(struct file_info *fi, unsigned int cmd, - unsigned long arg) -{ - void __user *argp = (void __user *)arg; - - switch (cmd) { - case RAW1394_IOC_ISO_RECV_START:{ - int args[3]; - - if (copy_from_user(&args[0], argp, sizeof(args))) - return -EFAULT; - return hpsb_iso_recv_start(fi->iso_handle, - args[0], args[1], args[2]); - } - case RAW1394_IOC_ISO_XMIT_RECV_STOP: - hpsb_iso_stop(fi->iso_handle); - return 0; - case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL: - return hpsb_iso_recv_listen_channel(fi->iso_handle, arg); - case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL: - return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg); - case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:{ - u64 mask; - - if (copy_from_user(&mask, argp, sizeof(mask))) - return -EFAULT; - return hpsb_iso_recv_set_channel_mask(fi->iso_handle, - mask); - } - case RAW1394_IOC_ISO_GET_STATUS: - return raw1394_iso_get_status(fi, argp); - case RAW1394_IOC_ISO_RECV_PACKETS: - return raw1394_iso_recv_packets(fi, argp); - case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS: - return hpsb_iso_recv_release_packets(fi->iso_handle, arg); - case RAW1394_IOC_ISO_RECV_FLUSH: - return hpsb_iso_recv_flush(fi->iso_handle); - case RAW1394_IOC_ISO_SHUTDOWN: - raw1394_iso_shutdown(fi); - return 0; - case RAW1394_IOC_ISO_QUEUE_ACTIVITY: - queue_rawiso_event(fi); - return 0; - default: - return -EINVAL; - } -} - -static long raw1394_ioctl_xmit(struct file_info *fi, unsigned int cmd, - void __user *argp) -{ - switch (cmd) { - case RAW1394_IOC_ISO_XMIT_START:{ - int args[2]; - - if (copy_from_user(&args[0], argp, sizeof(args))) - return -EFAULT; - return hpsb_iso_xmit_start(fi->iso_handle, - args[0], args[1]); - } - case RAW1394_IOC_ISO_XMIT_SYNC: - return hpsb_iso_xmit_sync(fi->iso_handle); - case RAW1394_IOC_ISO_XMIT_RECV_STOP: - hpsb_iso_stop(fi->iso_handle); - return 0; - case RAW1394_IOC_ISO_GET_STATUS: - return raw1394_iso_get_status(fi, argp); - case RAW1394_IOC_ISO_XMIT_PACKETS: - return raw1394_iso_send_packets(fi, argp); - case RAW1394_IOC_ISO_SHUTDOWN: - raw1394_iso_shutdown(fi); - return 0; - case RAW1394_IOC_ISO_QUEUE_ACTIVITY: - queue_rawiso_event(fi); - return 0; - default: - return -EINVAL; - } -} - -/* ioctl is only used for rawiso operations */ -static long raw1394_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct file_info *fi = file->private_data; - void __user *argp = (void __user *)arg; - long ret; - - /* state-independent commands */ - switch(cmd) { - case RAW1394_IOC_GET_CYCLE_TIMER: - return raw1394_read_cycle_timer(fi, argp); - default: - break; - } - - if (!mutex_trylock(&fi->state_mutex)) - return -EAGAIN; - - switch (fi->iso_state) { - case RAW1394_ISO_INACTIVE: - ret = raw1394_ioctl_inactive(fi, cmd, argp); - break; - case RAW1394_ISO_RECV: - ret = raw1394_ioctl_recv(fi, cmd, arg); - break; - case RAW1394_ISO_XMIT: - ret = raw1394_ioctl_xmit(fi, cmd, argp); - break; - default: - ret = -EINVAL; - break; - } - - mutex_unlock(&fi->state_mutex); - - return ret; -} - -#ifdef CONFIG_COMPAT -struct raw1394_iso_packets32 { - __u32 n_packets; - compat_uptr_t infos; -} __attribute__((packed)); - -struct raw1394_cycle_timer32 { - __u32 cycle_timer; - __u64 local_time; -} -#if defined(CONFIG_X86_64) || defined(CONFIG_IA64) -__attribute__((packed)) -#endif -; - -#define RAW1394_IOC_ISO_RECV_PACKETS32 \ - _IOW ('#', 0x25, struct raw1394_iso_packets32) -#define RAW1394_IOC_ISO_XMIT_PACKETS32 \ - _IOW ('#', 0x27, struct raw1394_iso_packets32) -#define RAW1394_IOC_GET_CYCLE_TIMER32 \ - _IOR ('#', 0x30, struct raw1394_cycle_timer32) - -static long raw1394_iso_xmit_recv_packets32(struct file *file, unsigned int cmd, - struct raw1394_iso_packets32 __user *arg) -{ - compat_uptr_t infos32; - void __user *infos; - long err = -EFAULT; - struct raw1394_iso_packets __user *dst = compat_alloc_user_space(sizeof(struct raw1394_iso_packets)); - - if (!copy_in_user(&dst->n_packets, &arg->n_packets, sizeof arg->n_packets) && - !copy_from_user(&infos32, &arg->infos, sizeof infos32)) { - infos = compat_ptr(infos32); - if (!copy_to_user(&dst->infos, &infos, sizeof infos)) - err = raw1394_ioctl(file, cmd, (unsigned long)dst); - } - return err; -} - -static long raw1394_read_cycle_timer32(struct file_info *fi, void __user * uaddr) -{ - struct raw1394_cycle_timer32 ct; - int err; - - err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time); - if (!err) - if (copy_to_user(uaddr, &ct, sizeof(ct))) - err = -EFAULT; - return err; -} - -static long raw1394_compat_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct file_info *fi = file->private_data; - void __user *argp = (void __user *)arg; - long err; - - switch (cmd) { - /* These requests have same format as long as 'int' has same size. */ - case RAW1394_IOC_ISO_RECV_INIT: - case RAW1394_IOC_ISO_RECV_START: - case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL: - case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL: - case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK: - case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS: - case RAW1394_IOC_ISO_RECV_FLUSH: - case RAW1394_IOC_ISO_XMIT_RECV_STOP: - case RAW1394_IOC_ISO_XMIT_INIT: - case RAW1394_IOC_ISO_XMIT_START: - case RAW1394_IOC_ISO_XMIT_SYNC: - case RAW1394_IOC_ISO_GET_STATUS: - case RAW1394_IOC_ISO_SHUTDOWN: - case RAW1394_IOC_ISO_QUEUE_ACTIVITY: - err = raw1394_ioctl(file, cmd, arg); - break; - /* These request have different format. */ - case RAW1394_IOC_ISO_RECV_PACKETS32: - err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_RECV_PACKETS, argp); - break; - case RAW1394_IOC_ISO_XMIT_PACKETS32: - err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_XMIT_PACKETS, argp); - break; - case RAW1394_IOC_GET_CYCLE_TIMER32: - err = raw1394_read_cycle_timer32(fi, argp); - break; - default: - err = -EINVAL; - break; - } - - return err; -} -#endif - -static unsigned int raw1394_poll(struct file *file, poll_table * pt) -{ - struct file_info *fi = file->private_data; - unsigned int mask = POLLOUT | POLLWRNORM; - unsigned long flags; - - poll_wait(file, &fi->wait_complete, pt); - - spin_lock_irqsave(&fi->reqlists_lock, flags); - if (!list_empty(&fi->req_complete)) { - mask |= POLLIN | POLLRDNORM; - } - spin_unlock_irqrestore(&fi->reqlists_lock, flags); - - return mask; -} - -static int raw1394_open(struct inode *inode, struct file *file) -{ - struct file_info *fi; - - fi = kzalloc(sizeof(*fi), GFP_KERNEL); - if (!fi) - return -ENOMEM; - - fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */ - - INIT_LIST_HEAD(&fi->list); - mutex_init(&fi->state_mutex); - fi->state = opened; - INIT_LIST_HEAD(&fi->req_pending); - INIT_LIST_HEAD(&fi->req_complete); - spin_lock_init(&fi->reqlists_lock); - init_waitqueue_head(&fi->wait_complete); - INIT_LIST_HEAD(&fi->addr_list); - - file->private_data = fi; - - return nonseekable_open(inode, file); -} - -static int raw1394_release(struct inode *inode, struct file *file) -{ - struct file_info *fi = file->private_data; - struct list_head *lh; - struct pending_request *req; - int i, fail; - int retval = 0; - struct list_head *entry; - struct arm_addr *addr = NULL; - struct host_info *hi; - struct file_info *fi_hlp = NULL; - struct arm_addr *arm_addr = NULL; - int another_host; - int csr_mod = 0; - unsigned long flags; - - if (fi->iso_state != RAW1394_ISO_INACTIVE) - raw1394_iso_shutdown(fi); - - spin_lock_irqsave(&host_info_lock, flags); - - fail = 0; - /* set address-entries invalid */ - - while (!list_empty(&fi->addr_list)) { - another_host = 0; - lh = fi->addr_list.next; - addr = list_entry(lh, struct arm_addr, addr_list); - /* another host with valid address-entry containing - same addressrange? */ - list_for_each_entry(hi, &host_info_list, list) { - if (hi->host != fi->host) { - list_for_each_entry(fi_hlp, &hi->file_info_list, - list) { - entry = fi_hlp->addr_list.next; - while (entry != &(fi_hlp->addr_list)) { - arm_addr = list_entry(entry, struct - arm_addr, - addr_list); - if (arm_addr->start == - addr->start) { - DBGMSG - ("raw1394_release: " - "another host ownes " - "same addressrange"); - another_host = 1; - break; - } - entry = entry->next; - } - if (another_host) { - break; - } - } - } - } - if (!another_host) { - DBGMSG("raw1394_release: call hpsb_arm_unregister"); - retval = - hpsb_unregister_addrspace(&raw1394_highlevel, - fi->host, addr->start); - if (!retval) { - ++fail; - printk(KERN_ERR - "raw1394_release arm_Unregister failed\n"); - } - } - DBGMSG("raw1394_release: delete addr_entry from list"); - list_del(&addr->addr_list); - vfree(addr->addr_space_buffer); - kfree(addr); - } /* while */ - spin_unlock_irqrestore(&host_info_lock, flags); - if (fail > 0) { - printk(KERN_ERR "raw1394: during addr_list-release " - "error(s) occurred \n"); - } - - for (;;) { - /* This locked section guarantees that neither - * complete nor pending requests exist once i!=0 */ - spin_lock_irqsave(&fi->reqlists_lock, flags); - while ((req = __next_complete_req(fi))) - free_pending_request(req); - - i = list_empty(&fi->req_pending); - spin_unlock_irqrestore(&fi->reqlists_lock, flags); - - if (i) - break; - /* - * Sleep until more requests can be freed. - * - * NB: We call the macro wait_event() 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() won't evaluate the condition again after that. - */ - wait_event(fi->wait_complete, (req = next_complete_req(fi))); - free_pending_request(req); - } - - /* Remove any sub-trees left by user space programs */ - for (i = 0; i < RAW1394_MAX_USER_CSR_DIRS; i++) { - struct csr1212_dentry *dentry; - if (!fi->csr1212_dirs[i]) - continue; - for (dentry = - fi->csr1212_dirs[i]->value.directory.dentries_head; dentry; - dentry = dentry->next) { - csr1212_detach_keyval_from_directory(fi->host->csr.rom-> - root_kv, - dentry->kv); - } - csr1212_release_keyval(fi->csr1212_dirs[i]); - fi->csr1212_dirs[i] = NULL; - csr_mod = 1; - } - - if ((csr_mod || fi->cfgrom_upd) - && hpsb_update_config_rom_image(fi->host) < 0) - HPSB_ERR - ("Failed to generate Configuration ROM image for host %d", - fi->host->id); - - if (fi->state == connected) { - spin_lock_irqsave(&host_info_lock, flags); - list_del(&fi->list); - spin_unlock_irqrestore(&host_info_lock, flags); - - put_device(&fi->host->device); - } - - spin_lock_irqsave(&host_info_lock, flags); - if (fi->host) - module_put(fi->host->driver->owner); - spin_unlock_irqrestore(&host_info_lock, flags); - - kfree(fi); - - return 0; -} - -/*** HOTPLUG STUFF **********************************************************/ -/* - * Export information about protocols/devices supported by this driver. - */ -#ifdef MODULE -static const struct ieee1394_device_id raw1394_id_table[] = { - { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, - .version = AVC_SW_VERSION_ENTRY & 0xffffff}, - { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, - .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, - .version = CAMERA_SW_VERSION_ENTRY & 0xffffff}, - { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, - .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, - .version = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff}, - { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, - .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, - .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff}, - {} -}; - -MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table); -#endif /* MODULE */ - -static struct hpsb_protocol_driver raw1394_driver = { - .name = "raw1394", -}; - -/******************************************************************************/ - -static struct hpsb_highlevel raw1394_highlevel = { - .name = RAW1394_DEVICE_NAME, - .add_host = add_host, - .remove_host = remove_host, - .host_reset = host_reset, - .fcp_request = fcp_request, -}; - -static struct cdev raw1394_cdev; -static const struct file_operations raw1394_fops = { - .owner = THIS_MODULE, - .read = raw1394_read, - .write = raw1394_write, - .mmap = raw1394_mmap, - .unlocked_ioctl = raw1394_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = raw1394_compat_ioctl, -#endif - .poll = raw1394_poll, - .open = raw1394_open, - .release = raw1394_release, - .llseek = no_llseek, -}; - -static int __init init_raw1394(void) -{ - int ret = 0; - - hpsb_register_highlevel(&raw1394_highlevel); - - if (IS_ERR - (device_create(hpsb_protocol_class, NULL, - MKDEV(IEEE1394_MAJOR, - IEEE1394_MINOR_BLOCK_RAW1394 * 16), - NULL, RAW1394_DEVICE_NAME))) { - ret = -EFAULT; - goto out_unreg; - } - - cdev_init(&raw1394_cdev, &raw1394_fops); - raw1394_cdev.owner = THIS_MODULE; - ret = cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1); - if (ret) { - HPSB_ERR("raw1394 failed to register minor device block"); - goto out_dev; - } - - HPSB_INFO("raw1394: /dev/%s device initialized", RAW1394_DEVICE_NAME); - - ret = hpsb_register_protocol(&raw1394_driver); - if (ret) { - HPSB_ERR("raw1394: failed to register protocol"); - cdev_del(&raw1394_cdev); - goto out_dev; - } - - goto out; - - out_dev: - device_destroy(hpsb_protocol_class, - MKDEV(IEEE1394_MAJOR, - IEEE1394_MINOR_BLOCK_RAW1394 * 16)); - out_unreg: - hpsb_unregister_highlevel(&raw1394_highlevel); - out: - return ret; -} - -static void __exit cleanup_raw1394(void) -{ - device_destroy(hpsb_protocol_class, - MKDEV(IEEE1394_MAJOR, - IEEE1394_MINOR_BLOCK_RAW1394 * 16)); - cdev_del(&raw1394_cdev); - hpsb_unregister_highlevel(&raw1394_highlevel); - hpsb_unregister_protocol(&raw1394_driver); -} - -module_init(init_raw1394); -module_exit(cleanup_raw1394); -MODULE_LICENSE("GPL"); diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h deleted file mode 100644 index 963ac20373d..00000000000 --- a/drivers/ieee1394/raw1394.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c deleted file mode 100644 index d6e251a300c..00000000000 --- a/drivers/ieee1394/sbp2.c +++ /dev/null @@ -1,2138 +0,0 @@ -/* - * sbp2.c - SBP-2 protocol driver for IEEE-1394 - * - * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com) - * jamesg@filanet.com (JSG) - * - * Copyright (C) 2003 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. - */ - -/* - * Brief Description: - * - * This driver implements the Serial Bus Protocol 2 (SBP-2) over IEEE-1394 - * under Linux. The SBP-2 driver is implemented as an IEEE-1394 high-level - * driver. It also registers as a SCSI lower-level driver in order to accept - * SCSI commands for transport using SBP-2. - * - * You may access any attached SBP-2 (usually storage devices) as regular - * SCSI devices. E.g. mount /dev/sda1, fdisk, mkfs, etc.. - * - * See http://www.t10.org/drafts.htm#sbp2 for the final draft of the SBP-2 - * specification and for where to purchase the official standard. - * - * TODO: - * - look into possible improvements of the SCSI error handlers - * - handle Unit_Characteristics.mgt_ORB_timeout and .ORB_size - * - handle Logical_Unit_Number.ordered - * - handle src == 1 in status blocks - * - reimplement the DMA mapping in absence of physical DMA so that - * bus_to_virt is no longer required - * - debug the handling of absent physical DMA - * - replace CONFIG_IEEE1394_SBP2_PHYS_DMA by automatic detection - * (this is easy but depends on the previous two TODO items) - * - make the parameter serialize_io configurable per device - * - move all requests to fetch agent registers into non-atomic context, - * replace all usages of sbp2util_node_write_no_wait by true transactions - * Grep for inline FIXME comments below. - */ - -#include <linux/blkdev.h> -#include <linux/compiler.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/stat.h> -#include <linux/string.h> -#include <linux/stringify.h> -#include <linux/types.h> -#include <linux/wait.h> -#include <linux/workqueue.h> -#include <linux/scatterlist.h> - -#include <asm/byteorder.h> -#include <asm/errno.h> -#include <asm/param.h> -#include <asm/system.h> -#include <asm/types.h> - -#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA -#include <asm/io.h> /* for bus_to_virt */ -#endif - -#include <scsi/scsi.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_dbg.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi_host.h> - -#include "csr1212.h" -#include "highlevel.h" -#include "hosts.h" -#include "ieee1394.h" -#include "ieee1394_core.h" -#include "ieee1394_hotplug.h" -#include "ieee1394_transactions.h" -#include "ieee1394_types.h" -#include "nodemgr.h" -#include "sbp2.h" - -/* - * Module load parameter definitions - */ - -/* - * Change max_speed on module load if you have a bad IEEE-1394 - * controller that has trouble running 2KB packets at 400mb. - * - * NOTE: On certain OHCI parts I have seen short packets on async transmit - * (probably due to PCI latency/throughput issues with the part). You can - * bump down the speed if you are running into problems. - */ -static int sbp2_max_speed = IEEE1394_SPEED_MAX; -module_param_named(max_speed, sbp2_max_speed, int, 0644); -MODULE_PARM_DESC(max_speed, "Limit data transfer speed (5 <= 3200, " - "4 <= 1600, 3 <= 800, 2 <= 400, 1 <= 200, 0 = 100 Mb/s)"); - -/* - * Set serialize_io to 0 or N to use dynamically appended lists of command ORBs. - * This is and always has been buggy in multiple subtle ways. See above TODOs. - */ -static int sbp2_serialize_io = 1; -module_param_named(serialize_io, sbp2_serialize_io, bool, 0444); -MODULE_PARM_DESC(serialize_io, "Serialize requests coming from SCSI drivers " - "(default = Y, faster but buggy = N)"); - -/* - * Adjust max_sectors if you'd like to influence how many sectors each SCSI - * command can transfer at most. Please note that some older SBP-2 bridge - * chips are broken for transfers greater or equal to 128KB, therefore - * max_sectors used to be a safe 255 sectors for many years. We now have a - * default of 0 here which means that we let the SCSI stack choose a limit. - * - * The SBP2_WORKAROUND_128K_MAX_TRANS flag, if set either in the workarounds - * module parameter or in the sbp2_workarounds_table[], will override the - * value of max_sectors. We should use sbp2_workarounds_table[] to cover any - * bridge chip which becomes known to need the 255 sectors limit. - */ -static int sbp2_max_sectors; -module_param_named(max_sectors, sbp2_max_sectors, int, 0444); -MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported " - "(default = 0 = use SCSI stack's default)"); - -/* - * Exclusive login to sbp2 device? In most cases, the sbp2 driver should - * do an exclusive login, as it's generally unsafe to have two hosts - * talking to a single sbp2 device at the same time (filesystem coherency, - * etc.). If you're running an sbp2 device that supports multiple logins, - * and you're either running read-only filesystems or some sort of special - * filesystem supporting multiple hosts, e.g. OpenGFS, Oracle Cluster - * File System, or Lustre, then set exclusive_login to zero. - * - * So far only bridges from Oxford Semiconductor are known to support - * concurrent logins. Depending on firmware, four or two concurrent logins - * are possible on OXFW911 and newer Oxsemi bridges. - */ -static int sbp2_exclusive_login = 1; -module_param_named(exclusive_login, sbp2_exclusive_login, bool, 0644); -MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " - "(default = Y, use N for concurrent initiators)"); - -/* - * If any of the following workarounds is required for your device to work, - * please submit the kernel messages logged by sbp2 to the linux1394-devel - * mailing list. - * - * - 128kB max transfer - * Limit transfer size. Necessary for some old bridges. - * - * - 36 byte inquiry - * When scsi_mod probes the device, let the inquiry command look like that - * from MS Windows. - * - * - skip mode page 8 - * Suppress sending of mode_sense for mode page 8 if the device pretends to - * support the SCSI Primary Block commands instead of Reduced Block Commands. - * - * - fix capacity - * Tell sd_mod to correct the last sector number reported by read_capacity. - * Avoids access beyond actual disk limits on devices with an off-by-one bug. - * Don't use this with devices which don't have this bug. - * - * - delay inquiry - * Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry. - * - * - power condition - * Set the power condition field in the START STOP UNIT commands sent by - * sd_mod on suspend, resume, and shutdown (if manage_start_stop is on). - * Some disks need this to spin down or to resume properly. - * - * - override internal blacklist - * Instead of adding to the built-in blacklist, use only the workarounds - * specified in the module load parameter. - * Useful if a blacklist entry interfered with a non-broken device. - */ -static int sbp2_default_workarounds; -module_param_named(workarounds, sbp2_default_workarounds, int, 0644); -MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0" - ", 128kB max transfer = " __stringify(SBP2_WORKAROUND_128K_MAX_TRANS) - ", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36) - ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8) - ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY) - ", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY) - ", set power condition in start stop unit = " - __stringify(SBP2_WORKAROUND_POWER_CONDITION) - ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) - ", or a combination)"); - -/* - * This influences the format of the sysfs attribute - * /sys/bus/scsi/devices/.../ieee1394_id. - * - * The default format is like in older kernels: %016Lx:%d:%d - * It contains the target's EUI-64, a number given to the logical unit by - * the ieee1394 driver's nodemgr (starting at 0), and the LUN. - * - * The long format is: %016Lx:%06x:%04x - * It contains the target's EUI-64, the unit directory's directory_ID as per - * IEEE 1212 clause 7.7.19, and the LUN. This format comes closest to the - * format of SBP(-3) target port and logical unit identifier as per SAM (SCSI - * Architecture Model) rev.2 to 4 annex A. Therefore and because it is - * independent of the implementation of the ieee1394 nodemgr, the longer format - * is recommended for future use. - */ -static int sbp2_long_sysfs_ieee1394_id; -module_param_named(long_ieee1394_id, sbp2_long_sysfs_ieee1394_id, bool, 0644); -MODULE_PARM_DESC(long_ieee1394_id, "8+3+2 bytes format of ieee1394_id in sysfs " - "(default = backwards-compatible = N, SAM-conforming = Y)"); - - -#define SBP2_INFO(fmt, args...) HPSB_INFO("sbp2: "fmt, ## args) -#define SBP2_ERR(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args) - -/* - * Globals - */ -static void sbp2scsi_complete_all_commands(struct sbp2_lu *, u32); -static void sbp2scsi_complete_command(struct sbp2_lu *, u32, struct scsi_cmnd *, - void (*)(struct scsi_cmnd *)); -static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *); -static int sbp2_start_device(struct sbp2_lu *); -static void sbp2_remove_device(struct sbp2_lu *); -static int sbp2_login_device(struct sbp2_lu *); -static int sbp2_reconnect_device(struct sbp2_lu *); -static int sbp2_logout_device(struct sbp2_lu *); -static void sbp2_host_reset(struct hpsb_host *); -static int sbp2_handle_status_write(struct hpsb_host *, int, int, quadlet_t *, - u64, size_t, u16); -static int sbp2_agent_reset(struct sbp2_lu *, int); -static void sbp2_parse_unit_directory(struct sbp2_lu *, - struct unit_directory *); -static int sbp2_set_busy_timeout(struct sbp2_lu *); -static int sbp2_max_speed_and_size(struct sbp2_lu *); - - -static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xa, 0xa, 0xa }; - -static DEFINE_RWLOCK(sbp2_hi_logical_units_lock); - -static struct hpsb_highlevel sbp2_highlevel = { - .name = SBP2_DEVICE_NAME, - .host_reset = sbp2_host_reset, -}; - -static const struct hpsb_address_ops sbp2_ops = { - .write = sbp2_handle_status_write -}; - -#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA -static int sbp2_handle_physdma_write(struct hpsb_host *, int, int, quadlet_t *, - u64, size_t, u16); -static int sbp2_handle_physdma_read(struct hpsb_host *, int, quadlet_t *, u64, - size_t, u16); - -static const struct hpsb_address_ops sbp2_physdma_ops = { - .read = sbp2_handle_physdma_read, - .write = sbp2_handle_physdma_write, -}; -#endif - - -/* - * Interface to driver core and IEEE 1394 core - */ -static const struct ieee1394_device_id sbp2_id_table[] = { - { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, - .specifier_id = SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff, - .version = SBP2_SW_VERSION_ENTRY & 0xffffff}, - {} -}; -MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table); - -static int sbp2_probe(struct device *); -static int sbp2_remove(struct device *); -static int sbp2_update(struct unit_directory *); - -static struct hpsb_protocol_driver sbp2_driver = { - .name = SBP2_DEVICE_NAME, - .id_table = sbp2_id_table, - .update = sbp2_update, - .driver = { - .probe = sbp2_probe, - .remove = sbp2_remove, - }, -}; - - -/* - * Interface to SCSI core - */ -static int sbp2scsi_queuecommand(struct scsi_cmnd *, - void (*)(struct scsi_cmnd *)); -static int sbp2scsi_abort(struct scsi_cmnd *); -static int sbp2scsi_reset(struct scsi_cmnd *); -static int sbp2scsi_slave_alloc(struct scsi_device *); -static int sbp2scsi_slave_configure(struct scsi_device *); -static void sbp2scsi_slave_destroy(struct scsi_device *); -static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *, - struct device_attribute *, char *); - -static DEVICE_ATTR(ieee1394_id, S_IRUGO, sbp2_sysfs_ieee1394_id_show, NULL); - -static struct device_attribute *sbp2_sysfs_sdev_attrs[] = { - &dev_attr_ieee1394_id, - NULL -}; - -static struct scsi_host_template sbp2_shost_template = { - .module = THIS_MODULE, - .name = "SBP-2 IEEE-1394", - .proc_name = SBP2_DEVICE_NAME, - .queuecommand = sbp2scsi_queuecommand, - .eh_abort_handler = sbp2scsi_abort, - .eh_device_reset_handler = sbp2scsi_reset, - .slave_alloc = sbp2scsi_slave_alloc, - .slave_configure = sbp2scsi_slave_configure, - .slave_destroy = sbp2scsi_slave_destroy, - .this_id = -1, - .sg_tablesize = SG_ALL, - .use_clustering = ENABLE_CLUSTERING, - .cmd_per_lun = SBP2_MAX_CMDS, - .can_queue = SBP2_MAX_CMDS, - .sdev_attrs = sbp2_sysfs_sdev_attrs, -}; - -#define SBP2_ROM_VALUE_WILDCARD ~0 /* match all */ -#define SBP2_ROM_VALUE_MISSING 0xff000000 /* not present in the unit dir. */ - -/* - * List of devices with known bugs. - * - * The firmware_revision field, masked with 0xffff00, is the best indicator - * for the type of bridge chip of a device. It yields a few false positives - * but this did not break correctly behaving devices so far. - */ -static const struct { - u32 firmware_revision; - u32 model; - unsigned workarounds; -} sbp2_workarounds_table[] = { - /* DViCO Momobay CX-1 with TSB42AA9 bridge */ { - .firmware_revision = 0x002800, - .model = 0x001010, - .workarounds = SBP2_WORKAROUND_INQUIRY_36 | - SBP2_WORKAROUND_MODE_SENSE_8 | - SBP2_WORKAROUND_POWER_CONDITION, - }, - /* DViCO Momobay FX-3A with TSB42AA9A bridge */ { - .firmware_revision = 0x002800, - .model = 0x000000, - .workarounds = SBP2_WORKAROUND_POWER_CONDITION, - }, - /* Initio bridges, actually only needed for some older ones */ { - .firmware_revision = 0x000200, - .model = SBP2_ROM_VALUE_WILDCARD, - .workarounds = SBP2_WORKAROUND_INQUIRY_36, - }, - /* PL-3507 bridge with Prolific firmware */ { - .firmware_revision = 0x012800, - .model = SBP2_ROM_VALUE_WILDCARD, - .workarounds = SBP2_WORKAROUND_POWER_CONDITION, - }, - /* Symbios bridge */ { - .firmware_revision = 0xa0b800, - .model = SBP2_ROM_VALUE_WILDCARD, - .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, - }, - /* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ { - .firmware_revision = 0x002600, - .model = SBP2_ROM_VALUE_WILDCARD, - .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, - }, - /* - * iPod 2nd generation: needs 128k max transfer size workaround - * iPod 3rd generation: needs fix capacity workaround - */ - { - .firmware_revision = 0x0a2700, - .model = 0x000000, - .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS | - SBP2_WORKAROUND_FIX_CAPACITY, - }, - /* iPod 4th generation */ { - .firmware_revision = 0x0a2700, - .model = 0x000021, - .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, - }, - /* iPod mini */ { - .firmware_revision = 0x0a2700, - .model = 0x000022, - .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, - }, - /* iPod mini */ { - .firmware_revision = 0x0a2700, - .model = 0x000023, - .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, - }, - /* iPod Photo */ { - .firmware_revision = 0x0a2700, - .model = 0x00007e, - .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, - } -}; - -/************************************** - * General utility functions - **************************************/ - -#ifndef __BIG_ENDIAN -/* - * Converts a buffer from be32 to cpu byte ordering. Length is in bytes. - */ -static inline void sbp2util_be32_to_cpu_buffer(void *buffer, int length) -{ - u32 *temp = buffer; - - for (length = (length >> 2); length--; ) - temp[length] = be32_to_cpu(temp[length]); -} - -/* - * Converts a buffer from cpu to be32 byte ordering. Length is in bytes. - */ -static inline void sbp2util_cpu_to_be32_buffer(void *buffer, int length) -{ - u32 *temp = buffer; - - for (length = (length >> 2); length--; ) - temp[length] = cpu_to_be32(temp[length]); -} -#else /* BIG_ENDIAN */ -/* Why waste the cpu cycles? */ -#define sbp2util_be32_to_cpu_buffer(x,y) do {} while (0) -#define sbp2util_cpu_to_be32_buffer(x,y) do {} while (0) -#endif - -static DECLARE_WAIT_QUEUE_HEAD(sbp2_access_wq); - -/* - * Waits for completion of an SBP-2 access request. - * Returns nonzero if timed out or prematurely interrupted. - */ -static int sbp2util_access_timeout(struct sbp2_lu *lu, int timeout) -{ - long leftover; - - leftover = wait_event_interruptible_timeout( - sbp2_access_wq, lu->access_complete, timeout); - lu->access_complete = 0; - return leftover <= 0; -} - -static void sbp2_free_packet(void *packet) -{ - hpsb_free_tlabel(packet); - hpsb_free_packet(packet); -} - -/* - * This is much like hpsb_node_write(), except it ignores the response - * subaction and returns immediately. Can be used from atomic context. - */ -static int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr, - quadlet_t *buf, size_t len) -{ - struct hpsb_packet *packet; - - packet = hpsb_make_writepacket(ne->host, ne->nodeid, addr, buf, len); - if (!packet) - return -ENOMEM; - - hpsb_set_packet_complete_task(packet, sbp2_free_packet, packet); - hpsb_node_fill_packet(ne, packet); - if (hpsb_send_packet(packet) < 0) { - sbp2_free_packet(packet); - return -EIO; - } - return 0; -} - -static void sbp2util_notify_fetch_agent(struct sbp2_lu *lu, u64 offset, - quadlet_t *data, size_t len) -{ - /* There is a small window after a bus reset within which the node - * entry's generation is current but the reconnect wasn't completed. */ - if (unlikely(atomic_read(&lu->state) == SBP2LU_STATE_IN_RESET)) - return; - - if (hpsb_node_write(lu->ne, lu->command_block_agent_addr + offset, - data, len)) - SBP2_ERR("sbp2util_notify_fetch_agent failed."); - - /* Now accept new SCSI commands, unless a bus reset happended during - * hpsb_node_write. */ - if (likely(atomic_read(&lu->state) != SBP2LU_STATE_IN_RESET)) - scsi_unblock_requests(lu->shost); -} - -static void sbp2util_write_orb_pointer(struct work_struct *work) -{ - struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work); - quadlet_t data[2]; - - data[0] = ORB_SET_NODE_ID(lu->hi->host->node_id); - data[1] = lu->last_orb_dma; - sbp2util_cpu_to_be32_buffer(data, 8); - sbp2util_notify_fetch_agent(lu, SBP2_ORB_POINTER_OFFSET, data, 8); -} - -static void sbp2util_write_doorbell(struct work_struct *work) -{ - struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work); - - sbp2util_notify_fetch_agent(lu, SBP2_DOORBELL_OFFSET, NULL, 4); -} - -static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu) -{ - struct sbp2_command_info *cmd; - struct device *dmadev = lu->hi->host->device.parent; - int i, orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS; - - for (i = 0; i < orbs; i++) { - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - goto failed_alloc; - - cmd->command_orb_dma = - dma_map_single(dmadev, &cmd->command_orb, - sizeof(struct sbp2_command_orb), - DMA_TO_DEVICE); - if (dma_mapping_error(dmadev, cmd->command_orb_dma)) - goto failed_orb; - - cmd->sge_dma = - dma_map_single(dmadev, &cmd->scatter_gather_element, - sizeof(cmd->scatter_gather_element), - DMA_TO_DEVICE); - if (dma_mapping_error(dmadev, cmd->sge_dma)) - goto failed_sge; - - INIT_LIST_HEAD(&cmd->list); - list_add_tail(&cmd->list, &lu->cmd_orb_completed); - } - return 0; - -failed_sge: - dma_unmap_single(dmadev, cmd->command_orb_dma, - sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); -failed_orb: - kfree(cmd); -failed_alloc: - return -ENOMEM; -} - -static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu, - struct hpsb_host *host) -{ - struct list_head *lh, *next; - struct sbp2_command_info *cmd; - unsigned long flags; - - spin_lock_irqsave(&lu->cmd_orb_lock, flags); - if (!list_empty(&lu->cmd_orb_completed)) - list_for_each_safe(lh, next, &lu->cmd_orb_completed) { - cmd = list_entry(lh, struct sbp2_command_info, list); - dma_unmap_single(host->device.parent, - cmd->command_orb_dma, - sizeof(struct sbp2_command_orb), - DMA_TO_DEVICE); - dma_unmap_single(host->device.parent, cmd->sge_dma, - sizeof(cmd->scatter_gather_element), - DMA_TO_DEVICE); - kfree(cmd); - } - spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); - return; -} - -/* - * Finds the sbp2_command for a given outstanding command ORB. - * Only looks at the in-use list. - */ -static struct sbp2_command_info *sbp2util_find_command_for_orb( - struct sbp2_lu *lu, dma_addr_t orb) -{ - struct sbp2_command_info *cmd; - unsigned long flags; - - spin_lock_irqsave(&lu->cmd_orb_lock, flags); - if (!list_empty(&lu->cmd_orb_inuse)) - list_for_each_entry(cmd, &lu->cmd_orb_inuse, list) - if (cmd->command_orb_dma == orb) { - spin_unlock_irqrestore( - &lu->cmd_orb_lock, flags); - return cmd; - } - spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); - return NULL; -} - -/* - * Finds the sbp2_command for a given outstanding SCpnt. - * Only looks at the in-use list. - * Must be called with lu->cmd_orb_lock held. - */ -static struct sbp2_command_info *sbp2util_find_command_for_SCpnt( - struct sbp2_lu *lu, void *SCpnt) -{ - struct sbp2_command_info *cmd; - - if (!list_empty(&lu->cmd_orb_inuse)) - list_for_each_entry(cmd, &lu->cmd_orb_inuse, list) - if (cmd->Current_SCpnt == SCpnt) - return cmd; - return NULL; -} - -static struct sbp2_command_info *sbp2util_allocate_command_orb( - struct sbp2_lu *lu, - struct scsi_cmnd *Current_SCpnt, - void (*Current_done)(struct scsi_cmnd *)) -{ - struct list_head *lh; - struct sbp2_command_info *cmd = NULL; - unsigned long flags; - - spin_lock_irqsave(&lu->cmd_orb_lock, flags); - if (!list_empty(&lu->cmd_orb_completed)) { - lh = lu->cmd_orb_completed.next; - list_del(lh); - cmd = list_entry(lh, struct sbp2_command_info, list); - cmd->Current_done = Current_done; - cmd->Current_SCpnt = Current_SCpnt; - list_add_tail(&cmd->list, &lu->cmd_orb_inuse); - } else - SBP2_ERR("%s: no orbs available", __func__); - spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); - return cmd; -} - -/* - * Unmaps the DMAs of a command and moves the command to the completed ORB list. - * Must be called with lu->cmd_orb_lock held. - */ -static void sbp2util_mark_command_completed(struct sbp2_lu *lu, - struct sbp2_command_info *cmd) -{ - if (scsi_sg_count(cmd->Current_SCpnt)) - dma_unmap_sg(lu->ud->ne->host->device.parent, - scsi_sglist(cmd->Current_SCpnt), - scsi_sg_count(cmd->Current_SCpnt), - cmd->Current_SCpnt->sc_data_direction); - list_move_tail(&cmd->list, &lu->cmd_orb_completed); -} - -/* - * Is lu valid? Is the 1394 node still present? - */ -static inline int sbp2util_node_is_available(struct sbp2_lu *lu) -{ - return lu && lu->ne && !lu->ne->in_limbo; -} - -/********************************************* - * IEEE-1394 core driver stack related section - *********************************************/ - -static int sbp2_probe(struct device *dev) -{ - struct unit_directory *ud; - struct sbp2_lu *lu; - - ud = container_of(dev, struct unit_directory, device); - - /* Don't probe UD's that have the LUN flag. We'll probe the LUN(s) - * instead. */ - if (ud->flags & UNIT_DIRECTORY_HAS_LUN_DIRECTORY) - return -ENODEV; - - lu = sbp2_alloc_device(ud); - if (!lu) - return -ENOMEM; - - sbp2_parse_unit_directory(lu, ud); - return sbp2_start_device(lu); -} - -static int sbp2_remove(struct device *dev) -{ - struct unit_directory *ud; - struct sbp2_lu *lu; - struct scsi_device *sdev; - - ud = container_of(dev, struct unit_directory, device); - lu = dev_get_drvdata(&ud->device); - if (!lu) - return 0; - - if (lu->shost) { - /* Get rid of enqueued commands if there is no chance to - * send them. */ - if (!sbp2util_node_is_available(lu)) - sbp2scsi_complete_all_commands(lu, DID_NO_CONNECT); - /* scsi_remove_device() may trigger shutdown functions of SCSI - * highlevel drivers which would deadlock if blocked. */ - atomic_set(&lu->state, SBP2LU_STATE_IN_SHUTDOWN); - scsi_unblock_requests(lu->shost); - } - sdev = lu->sdev; - if (sdev) { - lu->sdev = NULL; - scsi_remove_device(sdev); - } - - sbp2_logout_device(lu); - sbp2_remove_device(lu); - - return 0; -} - -static int sbp2_update(struct unit_directory *ud) -{ - struct sbp2_lu *lu = dev_get_drvdata(&ud->device); - - if (sbp2_reconnect_device(lu) != 0) { - /* - * Reconnect failed. If another bus reset happened, - * let nodemgr proceed and call sbp2_update again later - * (or sbp2_remove if this node went away). - */ - if (!hpsb_node_entry_valid(lu->ne)) - return 0; - /* - * Or the target rejected the reconnect because we weren't - * fast enough. Try a regular login, but first log out - * just in case of any weirdness. - */ - sbp2_logout_device(lu); - - if (sbp2_login_device(lu) != 0) { - if (!hpsb_node_entry_valid(lu->ne)) - return 0; - - /* Maybe another initiator won the login. */ - SBP2_ERR("Failed to reconnect to sbp2 device!"); - return -EBUSY; - } - } - - sbp2_set_busy_timeout(lu); - sbp2_agent_reset(lu, 1); - sbp2_max_speed_and_size(lu); - - /* Complete any pending commands with busy (so they get retried) - * and remove them from our queue. */ - sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY); - - /* Accept new commands unless there was another bus reset in the - * meantime. */ - if (hpsb_node_entry_valid(lu->ne)) { - atomic_set(&lu->state, SBP2LU_STATE_RUNNING); - scsi_unblock_requests(lu->shost); - } - return 0; -} - -static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud) -{ - struct sbp2_fwhost_info *hi; - struct Scsi_Host *shost = NULL; - struct sbp2_lu *lu = NULL; - unsigned long flags; - - lu = kzalloc(sizeof(*lu), GFP_KERNEL); - if (!lu) { - SBP2_ERR("failed to create lu"); - goto failed_alloc; - } - - lu->ne = ud->ne; - lu->ud = ud; - lu->speed_code = IEEE1394_SPEED_100; - lu->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100]; - lu->status_fifo_addr = CSR1212_INVALID_ADDR_SPACE; - INIT_LIST_HEAD(&lu->cmd_orb_inuse); - INIT_LIST_HEAD(&lu->cmd_orb_completed); - INIT_LIST_HEAD(&lu->lu_list); - spin_lock_init(&lu->cmd_orb_lock); - atomic_set(&lu->state, SBP2LU_STATE_RUNNING); - INIT_WORK(&lu->protocol_work, NULL); - - dev_set_drvdata(&ud->device, lu); - - hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host); - if (!hi) { - hi = hpsb_create_hostinfo(&sbp2_highlevel, ud->ne->host, - sizeof(*hi)); - if (!hi) { - SBP2_ERR("failed to allocate hostinfo"); - goto failed_alloc; - } - hi->host = ud->ne->host; - INIT_LIST_HEAD(&hi->logical_units); - -#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA - /* Handle data movement if physical dma is not - * enabled or not supported on host controller */ - if (!hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host, - &sbp2_physdma_ops, - 0x0ULL, 0xfffffffcULL)) { - SBP2_ERR("failed to register lower 4GB address range"); - goto failed_alloc; - } -#endif - } - - if (dma_get_max_seg_size(hi->host->device.parent) > SBP2_MAX_SEG_SIZE) - BUG_ON(dma_set_max_seg_size(hi->host->device.parent, - SBP2_MAX_SEG_SIZE)); - - /* Prevent unloading of the 1394 host */ - if (!try_module_get(hi->host->driver->owner)) { - SBP2_ERR("failed to get a reference on 1394 host driver"); - goto failed_alloc; - } - - lu->hi = hi; - - write_lock_irqsave(&sbp2_hi_logical_units_lock, flags); - list_add_tail(&lu->lu_list, &hi->logical_units); - write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags); - - /* Register the status FIFO address range. We could use the same FIFO - * for targets at different nodes. However we need different FIFOs per - * target in order to support multi-unit devices. - * The FIFO is located out of the local host controller's physical range - * but, if possible, within the posted write area. Status writes will - * then be performed as unified transactions. This slightly reduces - * bandwidth usage, and some Prolific based devices seem to require it. - */ - lu->status_fifo_addr = hpsb_allocate_and_register_addrspace( - &sbp2_highlevel, ud->ne->host, &sbp2_ops, - sizeof(struct sbp2_status_block), sizeof(quadlet_t), - ud->ne->host->low_addr_space, CSR1212_ALL_SPACE_END); - if (lu->status_fifo_addr == CSR1212_INVALID_ADDR_SPACE) { - SBP2_ERR("failed to allocate status FIFO address range"); - goto failed_alloc; - } - - shost = scsi_host_alloc(&sbp2_shost_template, sizeof(unsigned long)); - if (!shost) { - SBP2_ERR("failed to register scsi host"); - goto failed_alloc; - } - - shost->hostdata[0] = (unsigned long)lu; - shost->max_cmd_len = SBP2_MAX_CDB_SIZE; - - if (!scsi_add_host(shost, &ud->device)) { - lu->shost = shost; - return lu; - } - - SBP2_ERR("failed to add scsi host"); - scsi_host_put(shost); - -failed_alloc: - sbp2_remove_device(lu); - return NULL; -} - -static void sbp2_host_reset(struct hpsb_host *host) -{ - struct sbp2_fwhost_info *hi; - struct sbp2_lu *lu; - unsigned long flags; - - hi = hpsb_get_hostinfo(&sbp2_highlevel, host); - if (!hi) - return; - - read_lock_irqsave(&sbp2_hi_logical_units_lock, flags); - - list_for_each_entry(lu, &hi->logical_units, lu_list) - if (atomic_cmpxchg(&lu->state, - SBP2LU_STATE_RUNNING, SBP2LU_STATE_IN_RESET) - == SBP2LU_STATE_RUNNING) - scsi_block_requests(lu->shost); - - read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags); -} - -static int sbp2_start_device(struct sbp2_lu *lu) -{ - struct sbp2_fwhost_info *hi = lu->hi; - int error; - - lu->login_response = dma_alloc_coherent(hi->host->device.parent, - sizeof(struct sbp2_login_response), - &lu->login_response_dma, GFP_KERNEL); - if (!lu->login_response) - goto alloc_fail; - - lu->query_logins_orb = dma_alloc_coherent(hi->host->device.parent, - sizeof(struct sbp2_query_logins_orb), - &lu->query_logins_orb_dma, GFP_KERNEL); - if (!lu->query_logins_orb) - goto alloc_fail; - - lu->query_logins_response = dma_alloc_coherent(hi->host->device.parent, - sizeof(struct sbp2_query_logins_response), - &lu->query_logins_response_dma, GFP_KERNEL); - if (!lu->query_logins_response) - goto alloc_fail; - - lu->reconnect_orb = dma_alloc_coherent(hi->host->device.parent, - sizeof(struct sbp2_reconnect_orb), - &lu->reconnect_orb_dma, GFP_KERNEL); - if (!lu->reconnect_orb) - goto alloc_fail; - - lu->logout_orb = dma_alloc_coherent(hi->host->device.parent, - sizeof(struct sbp2_logout_orb), - &lu->logout_orb_dma, GFP_KERNEL); - if (!lu->logout_orb) - goto alloc_fail; - - lu->login_orb = dma_alloc_coherent(hi->host->device.parent, - sizeof(struct sbp2_login_orb), - &lu->login_orb_dma, GFP_KERNEL); - if (!lu->login_orb) - goto alloc_fail; - - if (sbp2util_create_command_orb_pool(lu)) - goto alloc_fail; - - /* Wait a second before trying to log in. Previously logged in - * initiators need a chance to reconnect. */ - if (msleep_interruptible(1000)) { - sbp2_remove_device(lu); - return -EINTR; - } - - if (sbp2_login_device(lu)) { - sbp2_remove_device(lu); - return -EBUSY; - } - - sbp2_set_busy_timeout(lu); - sbp2_agent_reset(lu, 1); - sbp2_max_speed_and_size(lu); - - if (lu->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY) - ssleep(SBP2_INQUIRY_DELAY); - - error = scsi_add_device(lu->shost, 0, lu->ud->id, 0); - if (error) { - SBP2_ERR("scsi_add_device failed"); - sbp2_logout_device(lu); - sbp2_remove_device(lu); - return error; - } - - return 0; - -alloc_fail: - SBP2_ERR("Could not allocate memory for lu"); - sbp2_remove_device(lu); - return -ENOMEM; -} - -static void sbp2_remove_device(struct sbp2_lu *lu) -{ - struct sbp2_fwhost_info *hi; - unsigned long flags; - - if (!lu) - return; - hi = lu->hi; - if (!hi) - goto no_hi; - - if (lu->shost) { - scsi_remove_host(lu->shost); - scsi_host_put(lu->shost); - } - flush_scheduled_work(); - sbp2util_remove_command_orb_pool(lu, hi->host); - - write_lock_irqsave(&sbp2_hi_logical_units_lock, flags); - list_del(&lu->lu_list); - write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags); - - if (lu->login_response) - dma_free_coherent(hi->host->device.parent, - sizeof(struct sbp2_login_response), - lu->login_response, - lu->login_response_dma); - if (lu->login_orb) - dma_free_coherent(hi->host->device.parent, - sizeof(struct sbp2_login_orb), - lu->login_orb, - lu->login_orb_dma); - if (lu->reconnect_orb) - dma_free_coherent(hi->host->device.parent, - sizeof(struct sbp2_reconnect_orb), - lu->reconnect_orb, - lu->reconnect_orb_dma); - if (lu->logout_orb) - dma_free_coherent(hi->host->device.parent, - sizeof(struct sbp2_logout_orb), - lu->logout_orb, - lu->logout_orb_dma); - if (lu->query_logins_orb) - dma_free_coherent(hi->host->device.parent, - sizeof(struct sbp2_query_logins_orb), - lu->query_logins_orb, - lu->query_logins_orb_dma); - if (lu->query_logins_response) - dma_free_coherent(hi->host->device.parent, - sizeof(struct sbp2_query_logins_response), - lu->query_logins_response, - lu->query_logins_response_dma); - - if (lu->status_fifo_addr != CSR1212_INVALID_ADDR_SPACE) - hpsb_unregister_addrspace(&sbp2_highlevel, hi->host, - lu->status_fifo_addr); - - dev_set_drvdata(&lu->ud->device, NULL); - - module_put(hi->host->driver->owner); -no_hi: - kfree(lu); -} - -#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA -/* - * Deal with write requests on adapters which do not support physical DMA or - * have it switched off. - */ -static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, - int destid, quadlet_t *data, u64 addr, - size_t length, u16 flags) -{ - memcpy(bus_to_virt((u32) addr), data, length); - return RCODE_COMPLETE; -} - -/* - * Deal with read requests on adapters which do not support physical DMA or - * have it switched off. - */ -static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, - quadlet_t *data, u64 addr, size_t length, - u16 flags) -{ - memcpy(data, bus_to_virt((u32) addr), length); - return RCODE_COMPLETE; -} -#endif - -/************************************** - * SBP-2 protocol related section - **************************************/ - -static int sbp2_query_logins(struct sbp2_lu *lu) -{ - struct sbp2_fwhost_info *hi = lu->hi; - quadlet_t data[2]; - int max_logins; - int active_logins; - - lu->query_logins_orb->reserved1 = 0x0; - lu->query_logins_orb->reserved2 = 0x0; - - lu->query_logins_orb->query_response_lo = lu->query_logins_response_dma; - lu->query_logins_orb->query_response_hi = - ORB_SET_NODE_ID(hi->host->node_id); - lu->query_logins_orb->lun_misc = - ORB_SET_FUNCTION(SBP2_QUERY_LOGINS_REQUEST); - lu->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1); - lu->query_logins_orb->lun_misc |= ORB_SET_LUN(lu->lun); - - lu->query_logins_orb->reserved_resp_length = - ORB_SET_QUERY_LOGINS_RESP_LENGTH( - sizeof(struct sbp2_query_logins_response)); - - lu->query_logins_orb->status_fifo_hi = - ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id); - lu->query_logins_orb->status_fifo_lo = - ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr); - - sbp2util_cpu_to_be32_buffer(lu->query_logins_orb, - sizeof(struct sbp2_query_logins_orb)); - - memset(lu->query_logins_response, 0, - sizeof(struct sbp2_query_logins_response)); - - data[0] = ORB_SET_NODE_ID(hi->host->node_id); - data[1] = lu->query_logins_orb_dma; - sbp2util_cpu_to_be32_buffer(data, 8); - - hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8); - - if (sbp2util_access_timeout(lu, 2*HZ)) { - SBP2_INFO("Error querying logins to SBP-2 device - timed out"); - return -EIO; - } - - if (lu->status_block.ORB_offset_lo != lu->query_logins_orb_dma) { - SBP2_INFO("Error querying logins to SBP-2 device - timed out"); - return -EIO; - } - - if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) { - SBP2_INFO("Error querying logins to SBP-2 device - failed"); - return -EIO; - } - - sbp2util_cpu_to_be32_buffer(lu->query_logins_response, - sizeof(struct sbp2_query_logins_response)); - - max_logins = RESPONSE_GET_MAX_LOGINS( - lu->query_logins_response->length_max_logins); - SBP2_INFO("Maximum concurrent logins supported: %d", max_logins); - - active_logins = RESPONSE_GET_ACTIVE_LOGINS( - lu->query_logins_response->length_max_logins); - SBP2_INFO("Number of active logins: %d", active_logins); - - if (active_logins >= max_logins) { - return -EIO; - } - - return 0; -} - -static int sbp2_login_device(struct sbp2_lu *lu) -{ - struct sbp2_fwhost_info *hi = lu->hi; - quadlet_t data[2]; - - if (!lu->login_orb) - return -EIO; - - if (!sbp2_exclusive_login && sbp2_query_logins(lu)) { - SBP2_INFO("Device does not support any more concurrent logins"); - return -EIO; - } - - /* assume no password */ - lu->login_orb->password_hi = 0; - lu->login_orb->password_lo = 0; - - lu->login_orb->login_response_lo = lu->login_response_dma; - lu->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id); - lu->login_orb->lun_misc = ORB_SET_FUNCTION(SBP2_LOGIN_REQUEST); - - /* one second reconnect time */ - lu->login_orb->lun_misc |= ORB_SET_RECONNECT(0); - lu->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(sbp2_exclusive_login); - lu->login_orb->lun_misc |= ORB_SET_NOTIFY(1); - lu->login_orb->lun_misc |= ORB_SET_LUN(lu->lun); - - lu->login_orb->passwd_resp_lengths = - ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response)); - - lu->login_orb->status_fifo_hi = - ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id); - lu->login_orb->status_fifo_lo = - ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr); - - sbp2util_cpu_to_be32_buffer(lu->login_orb, - sizeof(struct sbp2_login_orb)); - - memset(lu->login_response, 0, sizeof(struct sbp2_login_response)); - - data[0] = ORB_SET_NODE_ID(hi->host->node_id); - data[1] = lu->login_orb_dma; - sbp2util_cpu_to_be32_buffer(data, 8); - - hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8); - - /* wait up to 20 seconds for login status */ - if (sbp2util_access_timeout(lu, 20*HZ)) { - SBP2_ERR("Error logging into SBP-2 device - timed out"); - return -EIO; - } - - /* make sure that the returned status matches the login ORB */ - if (lu->status_block.ORB_offset_lo != lu->login_orb_dma) { - SBP2_ERR("Error logging into SBP-2 device - timed out"); - return -EIO; - } - - if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) { - SBP2_ERR("Error logging into SBP-2 device - failed"); - return -EIO; - } - - sbp2util_cpu_to_be32_buffer(lu->login_response, - sizeof(struct sbp2_login_response)); - lu->command_block_agent_addr = - ((u64)lu->login_response->command_block_agent_hi) << 32; - lu->command_block_agent_addr |= - ((u64)lu->login_response->command_block_agent_lo); - lu->command_block_agent_addr &= 0x0000ffffffffffffULL; - - SBP2_INFO("Logged into SBP-2 device"); - return 0; -} - -static int sbp2_logout_device(struct sbp2_lu *lu) -{ - struct sbp2_fwhost_info *hi = lu->hi; - quadlet_t data[2]; - int error; - - lu->logout_orb->reserved1 = 0x0; - lu->logout_orb->reserved2 = 0x0; - lu->logout_orb->reserved3 = 0x0; - lu->logout_orb->reserved4 = 0x0; - - lu->logout_orb->login_ID_misc = ORB_SET_FUNCTION(SBP2_LOGOUT_REQUEST); - lu->logout_orb->login_ID_misc |= - ORB_SET_LOGIN_ID(lu->login_response->length_login_ID); - lu->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1); - - lu->logout_orb->reserved5 = 0x0; - lu->logout_orb->status_fifo_hi = - ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id); - lu->logout_orb->status_fifo_lo = - ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr); - - sbp2util_cpu_to_be32_buffer(lu->logout_orb, - sizeof(struct sbp2_logout_orb)); - - data[0] = ORB_SET_NODE_ID(hi->host->node_id); - data[1] = lu->logout_orb_dma; - sbp2util_cpu_to_be32_buffer(data, 8); - - error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8); - if (error) - return error; - - /* wait up to 1 second for the device to complete logout */ - if (sbp2util_access_timeout(lu, HZ)) - return -EIO; - - SBP2_INFO("Logged out of SBP-2 device"); - return 0; -} - -static int sbp2_reconnect_device(struct sbp2_lu *lu) -{ - struct sbp2_fwhost_info *hi = lu->hi; - quadlet_t data[2]; - int error; - - lu->reconnect_orb->reserved1 = 0x0; - lu->reconnect_orb->reserved2 = 0x0; - lu->reconnect_orb->reserved3 = 0x0; - lu->reconnect_orb->reserved4 = 0x0; - - lu->reconnect_orb->login_ID_misc = - ORB_SET_FUNCTION(SBP2_RECONNECT_REQUEST); - lu->reconnect_orb->login_ID_misc |= - ORB_SET_LOGIN_ID(lu->login_response->length_login_ID); - lu->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1); - - lu->reconnect_orb->reserved5 = 0x0; - lu->reconnect_orb->status_fifo_hi = - ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id); - lu->reconnect_orb->status_fifo_lo = - ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr); - - sbp2util_cpu_to_be32_buffer(lu->reconnect_orb, - sizeof(struct sbp2_reconnect_orb)); - - data[0] = ORB_SET_NODE_ID(hi->host->node_id); - data[1] = lu->reconnect_orb_dma; - sbp2util_cpu_to_be32_buffer(data, 8); - - error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8); - if (error) - return error; - - /* wait up to 1 second for reconnect status */ - if (sbp2util_access_timeout(lu, HZ)) { - SBP2_ERR("Error reconnecting to SBP-2 device - timed out"); - return -EIO; - } - - /* make sure that the returned status matches the reconnect ORB */ - if (lu->status_block.ORB_offset_lo != lu->reconnect_orb_dma) { - SBP2_ERR("Error reconnecting to SBP-2 device - timed out"); - return -EIO; - } - - if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) { - SBP2_ERR("Error reconnecting to SBP-2 device - failed"); - return -EIO; - } - - SBP2_INFO("Reconnected to SBP-2 device"); - return 0; -} - -/* - * Set the target node's Single Phase Retry limit. Affects the target's retry - * behaviour if our node is too busy to accept requests. - */ -static int sbp2_set_busy_timeout(struct sbp2_lu *lu) -{ - quadlet_t data; - - data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE); - if (hpsb_node_write(lu->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) - SBP2_ERR("%s error", __func__); - return 0; -} - -static void sbp2_parse_unit_directory(struct sbp2_lu *lu, - struct unit_directory *ud) -{ - struct csr1212_keyval *kv; - struct csr1212_dentry *dentry; - u64 management_agent_addr; - u32 firmware_revision, model; - unsigned workarounds; - int i; - - management_agent_addr = 0; - firmware_revision = SBP2_ROM_VALUE_MISSING; - model = ud->flags & UNIT_DIRECTORY_MODEL_ID ? - ud->model_id : SBP2_ROM_VALUE_MISSING; - - csr1212_for_each_dir_entry(ud->ne->csr, kv, ud->ud_kv, dentry) { - switch (kv->key.id) { - case CSR1212_KV_ID_DEPENDENT_INFO: - if (kv->key.type == CSR1212_KV_TYPE_CSR_OFFSET) - management_agent_addr = - CSR1212_REGISTER_SPACE_BASE + - (kv->value.csr_offset << 2); - - else if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) - lu->lun = ORB_SET_LUN(kv->value.immediate); - break; - - - case SBP2_FIRMWARE_REVISION_KEY: - firmware_revision = kv->value.immediate; - break; - - default: - /* FIXME: Check for SBP2_UNIT_CHARACTERISTICS_KEY - * mgt_ORB_timeout and ORB_size, SBP-2 clause 7.4.8. */ - - /* FIXME: Check for SBP2_DEVICE_TYPE_AND_LUN_KEY. - * Its "ordered" bit has consequences for command ORB - * list handling. See SBP-2 clauses 4.6, 7.4.11, 10.2 */ - break; - } - } - - workarounds = sbp2_default_workarounds; - - if (!(workarounds & SBP2_WORKAROUND_OVERRIDE)) - for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) { - if (sbp2_workarounds_table[i].firmware_revision != - SBP2_ROM_VALUE_WILDCARD && - sbp2_workarounds_table[i].firmware_revision != - (firmware_revision & 0xffff00)) - continue; - if (sbp2_workarounds_table[i].model != - SBP2_ROM_VALUE_WILDCARD && - sbp2_workarounds_table[i].model != model) - continue; - workarounds |= sbp2_workarounds_table[i].workarounds; - break; - } - - if (workarounds) - SBP2_INFO("Workarounds for node " NODE_BUS_FMT ": 0x%x " - "(firmware_revision 0x%06x, vendor_id 0x%06x," - " model_id 0x%06x)", - NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid), - workarounds, firmware_revision, ud->vendor_id, - model); - - /* We would need one SCSI host template for each target to adjust - * max_sectors on the fly, therefore warn only. */ - if (workarounds & SBP2_WORKAROUND_128K_MAX_TRANS && - (sbp2_max_sectors * 512) > (128 * 1024)) - SBP2_INFO("Node " NODE_BUS_FMT ": Bridge only supports 128KB " - "max transfer size. WARNING: Current max_sectors " - "setting is larger than 128KB (%d sectors)", - NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid), - sbp2_max_sectors); - - /* If this is a logical unit directory entry, process the parent - * to get the values. */ - if (ud->flags & UNIT_DIRECTORY_LUN_DIRECTORY) { - struct unit_directory *parent_ud = container_of( - ud->device.parent, struct unit_directory, device); - sbp2_parse_unit_directory(lu, parent_ud); - } else { - lu->management_agent_addr = management_agent_addr; - lu->workarounds = workarounds; - if (ud->flags & UNIT_DIRECTORY_HAS_LUN) - lu->lun = ORB_SET_LUN(ud->lun); - } -} - -#define SBP2_PAYLOAD_TO_BYTES(p) (1 << ((p) + 2)) - -/* - * This function is called in order to determine the max speed and packet - * size we can use in our ORBs. Note, that we (the driver and host) only - * initiate the transaction. The SBP-2 device actually transfers the data - * (by reading from the DMA area we tell it). This means that the SBP-2 - * device decides the actual maximum data it can transfer. We just tell it - * the speed that it needs to use, and the max_rec the host supports, and - * it takes care of the rest. - */ -static int sbp2_max_speed_and_size(struct sbp2_lu *lu) -{ - struct sbp2_fwhost_info *hi = lu->hi; - u8 payload; - - lu->speed_code = hi->host->speed[NODEID_TO_NODE(lu->ne->nodeid)]; - - if (lu->speed_code > sbp2_max_speed) { - lu->speed_code = sbp2_max_speed; - SBP2_INFO("Reducing speed to %s", - hpsb_speedto_str[sbp2_max_speed]); - } - - /* Payload size is the lesser of what our speed supports and what - * our host supports. */ - payload = min(sbp2_speedto_max_payload[lu->speed_code], - (u8) (hi->host->csr.max_rec - 1)); - - /* If physical DMA is off, work around limitation in ohci1394: - * packet size must not exceed PAGE_SIZE */ - if (lu->ne->host->low_addr_space < (1ULL << 32)) - while (SBP2_PAYLOAD_TO_BYTES(payload) + 24 > PAGE_SIZE && - payload) - payload--; - - SBP2_INFO("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]", - NODE_BUS_ARGS(hi->host, lu->ne->nodeid), - hpsb_speedto_str[lu->speed_code], - SBP2_PAYLOAD_TO_BYTES(payload)); - - lu->max_payload_size = payload; - return 0; -} - -static int sbp2_agent_reset(struct sbp2_lu *lu, int wait) -{ - quadlet_t data; - u64 addr; - int retval; - unsigned long flags; - - /* flush lu->protocol_work */ - if (wait) - flush_scheduled_work(); - - data = ntohl(SBP2_AGENT_RESET_DATA); - addr = lu->command_block_agent_addr + SBP2_AGENT_RESET_OFFSET; - - if (wait) - retval = hpsb_node_write(lu->ne, addr, &data, 4); - else - retval = sbp2util_node_write_no_wait(lu->ne, addr, &data, 4); - - if (retval < 0) { - SBP2_ERR("hpsb_node_write failed.\n"); - return -EIO; - } - - /* make sure that the ORB_POINTER is written on next command */ - spin_lock_irqsave(&lu->cmd_orb_lock, flags); - lu->last_orb = NULL; - spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); - - return 0; -} - -static int sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb, - struct sbp2_fwhost_info *hi, - struct sbp2_command_info *cmd, - unsigned int sg_count, - struct scatterlist *sg, - u32 orb_direction, - enum dma_data_direction dma_dir) -{ - struct device *dmadev = hi->host->device.parent; - struct sbp2_unrestricted_page_table *pt; - int i, n; - - n = dma_map_sg(dmadev, sg, sg_count, dma_dir); - if (n == 0) - return -ENOMEM; - - orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); - orb->misc |= ORB_SET_DIRECTION(orb_direction); - - /* special case if only one element (and less than 64KB in size) */ - if (n == 1) { - orb->misc |= ORB_SET_DATA_SIZE(sg_dma_len(sg)); - orb->data_descriptor_lo = sg_dma_address(sg); - } else { - pt = &cmd->scatter_gather_element[0]; - - dma_sync_single_for_cpu(dmadev, cmd->sge_dma, - sizeof(cmd->scatter_gather_element), - DMA_TO_DEVICE); - - for_each_sg(sg, sg, n, i) { - pt[i].high = cpu_to_be32(sg_dma_len(sg) << 16); - pt[i].low = cpu_to_be32(sg_dma_address(sg)); - } - - orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1) | - ORB_SET_DATA_SIZE(n); - orb->data_descriptor_lo = cmd->sge_dma; - - dma_sync_single_for_device(dmadev, cmd->sge_dma, - sizeof(cmd->scatter_gather_element), - DMA_TO_DEVICE); - } - return 0; -} - -static int sbp2_create_command_orb(struct sbp2_lu *lu, - struct sbp2_command_info *cmd, - struct scsi_cmnd *SCpnt) -{ - struct device *dmadev = lu->hi->host->device.parent; - struct sbp2_command_orb *orb = &cmd->command_orb; - unsigned int scsi_request_bufflen = scsi_bufflen(SCpnt); - enum dma_data_direction dma_dir = SCpnt->sc_data_direction; - u32 orb_direction; - int ret; - - dma_sync_single_for_cpu(dmadev, cmd->command_orb_dma, - sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); - /* - * Set-up our command ORB. - * - * NOTE: We're doing unrestricted page tables (s/g), as this is - * best performance (at least with the devices I have). This means - * that data_size becomes the number of s/g elements, and - * page_size should be zero (for unrestricted). - */ - orb->next_ORB_hi = ORB_SET_NULL_PTR(1); - orb->next_ORB_lo = 0x0; - orb->misc = ORB_SET_MAX_PAYLOAD(lu->max_payload_size); - orb->misc |= ORB_SET_SPEED(lu->speed_code); - orb->misc |= ORB_SET_NOTIFY(1); - - if (dma_dir == DMA_NONE) - orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER; - else if (dma_dir == DMA_TO_DEVICE && scsi_request_bufflen) - orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA; - else if (dma_dir == DMA_FROM_DEVICE && scsi_request_bufflen) - orb_direction = ORB_DIRECTION_READ_FROM_MEDIA; - else { - SBP2_INFO("Falling back to DMA_NONE"); - orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER; - } - - /* set up our page table stuff */ - if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) { - orb->data_descriptor_hi = 0x0; - orb->data_descriptor_lo = 0x0; - orb->misc |= ORB_SET_DIRECTION(1); - ret = 0; - } else { - ret = sbp2_prep_command_orb_sg(orb, lu->hi, cmd, - scsi_sg_count(SCpnt), - scsi_sglist(SCpnt), - orb_direction, dma_dir); - } - sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb)); - - memset(orb->cdb, 0, sizeof(orb->cdb)); - memcpy(orb->cdb, SCpnt->cmnd, SCpnt->cmd_len); - - dma_sync_single_for_device(dmadev, cmd->command_orb_dma, - sizeof(struct sbp2_command_orb), DMA_TO_DEVICE); - return ret; -} - -static void sbp2_link_orb_command(struct sbp2_lu *lu, - struct sbp2_command_info *cmd) -{ - struct sbp2_fwhost_info *hi = lu->hi; - struct sbp2_command_orb *last_orb; - dma_addr_t last_orb_dma; - u64 addr = lu->command_block_agent_addr; - quadlet_t data[2]; - size_t length; - unsigned long flags; - - /* check to see if there are any previous orbs to use */ - spin_lock_irqsave(&lu->cmd_orb_lock, flags); - last_orb = lu->last_orb; - last_orb_dma = lu->last_orb_dma; - if (!last_orb) { - /* - * last_orb == NULL means: We know that the target's fetch agent - * is not active right now. - */ - addr += SBP2_ORB_POINTER_OFFSET; - data[0] = ORB_SET_NODE_ID(hi->host->node_id); - data[1] = cmd->command_orb_dma; - sbp2util_cpu_to_be32_buffer(data, 8); - length = 8; - } else { - /* - * last_orb != NULL means: We know that the target's fetch agent - * is (very probably) not dead or in reset state right now. - * We have an ORB already sent that we can append a new one to. - * The target's fetch agent may or may not have read this - * previous ORB yet. - */ - dma_sync_single_for_cpu(hi->host->device.parent, last_orb_dma, - sizeof(struct sbp2_command_orb), - DMA_TO_DEVICE); - last_orb->next_ORB_lo = cpu_to_be32(cmd->command_orb_dma); - wmb(); - /* Tells hardware that this pointer is valid */ - last_orb->next_ORB_hi = 0; - dma_sync_single_for_device(hi->host->device.parent, - last_orb_dma, - sizeof(struct sbp2_command_orb), - DMA_TO_DEVICE); - addr += SBP2_DOORBELL_OFFSET; - data[0] = 0; - length = 4; - } - lu->last_orb = &cmd->command_orb; - lu->last_orb_dma = cmd->command_orb_dma; - spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); - - if (sbp2util_node_write_no_wait(lu->ne, addr, data, length)) { - /* - * sbp2util_node_write_no_wait failed. We certainly ran out - * of transaction labels, perhaps just because there were no - * context switches which gave khpsbpkt a chance to collect - * free tlabels. Try again in non-atomic context. If necessary, - * the workqueue job will sleep to guaranteedly get a tlabel. - * We do not accept new commands until the job is over. - */ - scsi_block_requests(lu->shost); - PREPARE_WORK(&lu->protocol_work, - last_orb ? sbp2util_write_doorbell: - sbp2util_write_orb_pointer); - schedule_work(&lu->protocol_work); - } -} - -static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) -{ - struct sbp2_command_info *cmd; - - cmd = sbp2util_allocate_command_orb(lu, SCpnt, done); - if (!cmd) - return -EIO; - - if (sbp2_create_command_orb(lu, cmd, SCpnt)) - return -ENOMEM; - - sbp2_link_orb_command(lu, cmd); - return 0; -} - -/* - * Translates SBP-2 status into SCSI sense data for check conditions - */ -static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, - unchar *sense_data) -{ - /* OK, it's pretty ugly... ;-) */ - sense_data[0] = 0x70; - sense_data[1] = 0x0; - sense_data[2] = sbp2_status[9]; - sense_data[3] = sbp2_status[12]; - sense_data[4] = sbp2_status[13]; - sense_data[5] = sbp2_status[14]; - sense_data[6] = sbp2_status[15]; - sense_data[7] = 10; - sense_data[8] = sbp2_status[16]; - sense_data[9] = sbp2_status[17]; - sense_data[10] = sbp2_status[18]; - sense_data[11] = sbp2_status[19]; - sense_data[12] = sbp2_status[10]; - sense_data[13] = sbp2_status[11]; - sense_data[14] = sbp2_status[20]; - sense_data[15] = sbp2_status[21]; - - return sbp2_status[8] & 0x3f; -} - -static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, - int destid, quadlet_t *data, u64 addr, - size_t length, u16 fl) -{ - struct sbp2_fwhost_info *hi; - struct sbp2_lu *lu = NULL, *lu_tmp; - struct scsi_cmnd *SCpnt = NULL; - struct sbp2_status_block *sb; - u32 scsi_status = SBP2_SCSI_STATUS_GOOD; - struct sbp2_command_info *cmd; - unsigned long flags; - - if (unlikely(length < 8 || length > sizeof(struct sbp2_status_block))) { - SBP2_ERR("Wrong size of status block"); - return RCODE_ADDRESS_ERROR; - } - if (unlikely(!host)) { - SBP2_ERR("host is NULL - this is bad!"); - return RCODE_ADDRESS_ERROR; - } - hi = hpsb_get_hostinfo(&sbp2_highlevel, host); - if (unlikely(!hi)) { - SBP2_ERR("host info is NULL - this is bad!"); - return RCODE_ADDRESS_ERROR; - } - - /* Find the unit which wrote the status. */ - read_lock_irqsave(&sbp2_hi_logical_units_lock, flags); - list_for_each_entry(lu_tmp, &hi->logical_units, lu_list) { - if (lu_tmp->ne->nodeid == nodeid && - lu_tmp->status_fifo_addr == addr) { - lu = lu_tmp; - break; - } - } - read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags); - - if (unlikely(!lu)) { - SBP2_ERR("lu is NULL - device is gone?"); - return RCODE_ADDRESS_ERROR; - } - - /* Put response into lu status fifo buffer. The first two bytes - * come in big endian bit order. Often the target writes only a - * truncated status block, minimally the first two quadlets. The rest - * is implied to be zeros. */ - sb = &lu->status_block; - memset(sb->command_set_dependent, 0, sizeof(sb->command_set_dependent)); - memcpy(sb, data, length); - sbp2util_be32_to_cpu_buffer(sb, 8); - - /* Ignore unsolicited status. Handle command ORB status. */ - if (unlikely(STATUS_GET_SRC(sb->ORB_offset_hi_misc) == 2)) - cmd = NULL; - else - cmd = sbp2util_find_command_for_orb(lu, sb->ORB_offset_lo); - if (cmd) { - /* Grab SCSI command pointers and check status. */ - /* - * FIXME: If the src field in the status is 1, the ORB DMA must - * not be reused until status for a subsequent ORB is received. - */ - SCpnt = cmd->Current_SCpnt; - spin_lock_irqsave(&lu->cmd_orb_lock, flags); - sbp2util_mark_command_completed(lu, cmd); - spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); - - if (SCpnt) { - u32 h = sb->ORB_offset_hi_misc; - u32 r = STATUS_GET_RESP(h); - - if (r != RESP_STATUS_REQUEST_COMPLETE) { - SBP2_INFO("resp 0x%x, sbp_status 0x%x", - r, STATUS_GET_SBP_STATUS(h)); - scsi_status = - r == RESP_STATUS_TRANSPORT_FAILURE ? - SBP2_SCSI_STATUS_BUSY : - SBP2_SCSI_STATUS_COMMAND_TERMINATED; - } - - if (STATUS_GET_LEN(h) > 1) - scsi_status = sbp2_status_to_sense_data( - (unchar *)sb, SCpnt->sense_buffer); - - if (STATUS_TEST_DEAD(h)) - sbp2_agent_reset(lu, 0); - } - - /* Check here to see if there are no commands in-use. If there - * are none, we know that the fetch agent left the active state - * _and_ that we did not reactivate it yet. Therefore clear - * last_orb so that next time we write directly to the - * ORB_POINTER register. That way the fetch agent does not need - * to refetch the next_ORB. */ - spin_lock_irqsave(&lu->cmd_orb_lock, flags); - if (list_empty(&lu->cmd_orb_inuse)) - lu->last_orb = NULL; - spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); - - } else { - /* It's probably status after a management request. */ - if ((sb->ORB_offset_lo == lu->reconnect_orb_dma) || - (sb->ORB_offset_lo == lu->login_orb_dma) || - (sb->ORB_offset_lo == lu->query_logins_orb_dma) || - (sb->ORB_offset_lo == lu->logout_orb_dma)) { - lu->access_complete = 1; - wake_up_interruptible(&sbp2_access_wq); - } - } - - if (SCpnt) - sbp2scsi_complete_command(lu, scsi_status, SCpnt, - cmd->Current_done); - return RCODE_COMPLETE; -} - -/************************************** - * SCSI interface related section - **************************************/ - -static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) -{ - struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0]; - struct sbp2_fwhost_info *hi; - int result = DID_NO_CONNECT << 16; - - if (unlikely(!sbp2util_node_is_available(lu))) - goto done; - - hi = lu->hi; - - if (unlikely(!hi)) { - SBP2_ERR("sbp2_fwhost_info is NULL - this is bad!"); - goto done; - } - - /* Multiple units are currently represented to the SCSI core as separate - * targets, not as one target with multiple LUs. Therefore return - * selection time-out to any IO directed at non-zero LUNs. */ - if (unlikely(SCpnt->device->lun)) - goto done; - - if (unlikely(!hpsb_node_entry_valid(lu->ne))) { - SBP2_ERR("Bus reset in progress - rejecting command"); - result = DID_BUS_BUSY << 16; - goto done; - } - - /* Bidirectional commands are not yet implemented, - * and unknown transfer direction not handled. */ - if (unlikely(SCpnt->sc_data_direction == DMA_BIDIRECTIONAL)) { - SBP2_ERR("Cannot handle DMA_BIDIRECTIONAL - rejecting command"); - result = DID_ERROR << 16; - goto done; - } - - if (sbp2_send_command(lu, SCpnt, done)) { - SBP2_ERR("Error sending SCSI command"); - sbp2scsi_complete_command(lu, - SBP2_SCSI_STATUS_SELECTION_TIMEOUT, - SCpnt, done); - } - return 0; - -done: - SCpnt->result = result; - done(SCpnt); - return 0; -} - -static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status) -{ - struct list_head *lh; - struct sbp2_command_info *cmd; - unsigned long flags; - - spin_lock_irqsave(&lu->cmd_orb_lock, flags); - while (!list_empty(&lu->cmd_orb_inuse)) { - lh = lu->cmd_orb_inuse.next; - cmd = list_entry(lh, struct sbp2_command_info, list); - sbp2util_mark_command_completed(lu, cmd); - if (cmd->Current_SCpnt) { - cmd->Current_SCpnt->result = status << 16; - cmd->Current_done(cmd->Current_SCpnt); - } - } - spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); - - return; -} - -/* - * Complete a regular SCSI command. Can be called in atomic context. - */ -static void sbp2scsi_complete_command(struct sbp2_lu *lu, u32 scsi_status, - struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) -{ - if (!SCpnt) { - SBP2_ERR("SCpnt is NULL"); - return; - } - - switch (scsi_status) { - case SBP2_SCSI_STATUS_GOOD: - SCpnt->result = DID_OK << 16; - break; - - case SBP2_SCSI_STATUS_BUSY: - SBP2_ERR("SBP2_SCSI_STATUS_BUSY"); - SCpnt->result = DID_BUS_BUSY << 16; - break; - - case SBP2_SCSI_STATUS_CHECK_CONDITION: - SCpnt->result = CHECK_CONDITION << 1 | DID_OK << 16; - break; - - case SBP2_SCSI_STATUS_SELECTION_TIMEOUT: - SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT"); - SCpnt->result = DID_NO_CONNECT << 16; - scsi_print_command(SCpnt); - break; - - case SBP2_SCSI_STATUS_CONDITION_MET: - case SBP2_SCSI_STATUS_RESERVATION_CONFLICT: - case SBP2_SCSI_STATUS_COMMAND_TERMINATED: - SBP2_ERR("Bad SCSI status = %x", scsi_status); - SCpnt->result = DID_ERROR << 16; - scsi_print_command(SCpnt); - break; - - default: - SBP2_ERR("Unsupported SCSI status = %x", scsi_status); - SCpnt->result = DID_ERROR << 16; - } - - /* If a bus reset is in progress and there was an error, complete - * the command as busy so that it will get retried. */ - if (!hpsb_node_entry_valid(lu->ne) - && (scsi_status != SBP2_SCSI_STATUS_GOOD)) { - SBP2_ERR("Completing command with busy (bus reset)"); - SCpnt->result = DID_BUS_BUSY << 16; - } - - /* Tell the SCSI stack that we're done with this command. */ - done(SCpnt); -} - -static int sbp2scsi_slave_alloc(struct scsi_device *sdev) -{ - struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0]; - - if (sdev->lun != 0 || sdev->id != lu->ud->id || sdev->channel != 0) - return -ENODEV; - - lu->sdev = sdev; - sdev->allow_restart = 1; - - /* SBP-2 requires quadlet alignment of the data buffers. */ - blk_queue_update_dma_alignment(sdev->request_queue, 4 - 1); - - if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36) - sdev->inquiry_len = 36; - return 0; -} - -static int sbp2scsi_slave_configure(struct scsi_device *sdev) -{ - struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0]; - - sdev->use_10_for_rw = 1; - - if (sbp2_exclusive_login) - sdev->manage_start_stop = 1; - if (sdev->type == TYPE_ROM) - sdev->use_10_for_ms = 1; - if (sdev->type == TYPE_DISK && - lu->workarounds & SBP2_WORKAROUND_MODE_SENSE_8) - sdev->skip_ms_page_8 = 1; - if (lu->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) - sdev->fix_capacity = 1; - if (lu->workarounds & SBP2_WORKAROUND_POWER_CONDITION) - sdev->start_stop_pwr_cond = 1; - if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS) - blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512); - - blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE); - return 0; -} - -static void sbp2scsi_slave_destroy(struct scsi_device *sdev) -{ - ((struct sbp2_lu *)sdev->host->hostdata[0])->sdev = NULL; - return; -} - -/* - * Called by scsi stack when something has really gone wrong. - * Usually called when a command has timed-out for some reason. - */ -static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) -{ - struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0]; - struct sbp2_command_info *cmd; - unsigned long flags; - - SBP2_INFO("aborting sbp2 command"); - scsi_print_command(SCpnt); - - if (sbp2util_node_is_available(lu)) { - sbp2_agent_reset(lu, 1); - - /* Return a matching command structure to the free pool. */ - spin_lock_irqsave(&lu->cmd_orb_lock, flags); - cmd = sbp2util_find_command_for_SCpnt(lu, SCpnt); - if (cmd) { - sbp2util_mark_command_completed(lu, cmd); - if (cmd->Current_SCpnt) { - cmd->Current_SCpnt->result = DID_ABORT << 16; - cmd->Current_done(cmd->Current_SCpnt); - } - } - spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); - - sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY); - } - - return SUCCESS; -} - -/* - * Called by scsi stack when something has really gone wrong. - */ -static int sbp2scsi_reset(struct scsi_cmnd *SCpnt) -{ - struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0]; - - SBP2_INFO("reset requested"); - - if (sbp2util_node_is_available(lu)) { - SBP2_INFO("generating sbp2 fetch agent reset"); - sbp2_agent_reset(lu, 1); - } - - return SUCCESS; -} - -static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct scsi_device *sdev; - struct sbp2_lu *lu; - - if (!(sdev = to_scsi_device(dev))) - return 0; - - if (!(lu = (struct sbp2_lu *)sdev->host->hostdata[0])) - return 0; - - if (sbp2_long_sysfs_ieee1394_id) - return sprintf(buf, "%016Lx:%06x:%04x\n", - (unsigned long long)lu->ne->guid, - lu->ud->directory_id, ORB_SET_LUN(lu->lun)); - else - return sprintf(buf, "%016Lx:%d:%d\n", - (unsigned long long)lu->ne->guid, - lu->ud->id, ORB_SET_LUN(lu->lun)); -} - -MODULE_AUTHOR("Ben Collins <bcollins@debian.org>"); -MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver"); -MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME); -MODULE_LICENSE("GPL"); - -static int sbp2_module_init(void) -{ - int ret; - - if (sbp2_serialize_io) { - sbp2_shost_template.can_queue = 1; - sbp2_shost_template.cmd_per_lun = 1; - } - - sbp2_shost_template.max_sectors = sbp2_max_sectors; - - hpsb_register_highlevel(&sbp2_highlevel); - ret = hpsb_register_protocol(&sbp2_driver); - if (ret) { - SBP2_ERR("Failed to register protocol"); - hpsb_unregister_highlevel(&sbp2_highlevel); - return ret; - } - return 0; -} - -static void __exit sbp2_module_exit(void) -{ - hpsb_unregister_protocol(&sbp2_driver); - hpsb_unregister_highlevel(&sbp2_highlevel); -} - -module_init(sbp2_module_init); -module_exit(sbp2_module_exit); diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h deleted file mode 100644 index 64a3a66a8a3..00000000000 --- a/drivers/ieee1394/sbp2.h +++ /dev/null @@ -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 */ diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c deleted file mode 100644 index 5c74f796d7f..00000000000 --- a/drivers/ieee1394/video1394.c +++ /dev/null @@ -1,1528 +0,0 @@ -/* - * video1394.c - video 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. - * - * NOTES: - * - * ioctl return codes: - * EFAULT is only for invalid address for the argp - * EINVAL for out of range values - * EBUSY when trying to use an already used resource - * ESRCH when trying to free/stop a not used resource - * EAGAIN for resource allocation failure that could perhaps succeed later - * ENOTTY for unsupported ioctl request - * - */ -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/wait.h> -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/fs.h> -#include <linux/poll.h> -#include <linux/delay.h> -#include <linux/bitops.h> -#include <linux/types.h> -#include <linux/vmalloc.h> -#include <linux/timex.h> -#include <linux/mm.h> -#include <linux/compat.h> -#include <linux/cdev.h> - -#include "dma.h" -#include "highlevel.h" -#include "hosts.h" -#include "ieee1394.h" -#include "ieee1394_core.h" -#include "ieee1394_hotplug.h" -#include "ieee1394_types.h" -#include "nodemgr.h" -#include "ohci1394.h" -#include "video1394.h" - -#define ISO_CHANNELS 64 - -struct it_dma_prg { - struct dma_cmd begin; - quadlet_t data[4]; - struct dma_cmd end; - quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */ -}; - -struct dma_iso_ctx { - struct ti_ohci *ohci; - int type; /* OHCI_ISO_TRANSMIT or OHCI_ISO_RECEIVE */ - struct ohci1394_iso_tasklet iso_tasklet; - int channel; - int ctx; - int last_buffer; - int * next_buffer; /* For ISO Transmit of video packets - to write the correct SYT field - into the next block */ - unsigned int num_desc; - unsigned int buf_size; - unsigned int frame_size; - unsigned int packet_size; - unsigned int left_size; - unsigned int nb_cmd; - - struct dma_region dma; - - struct dma_prog_region *prg_reg; - - struct dma_cmd **ir_prg; - struct it_dma_prg **it_prg; - - unsigned int *buffer_status; - unsigned int *buffer_prg_assignment; - struct timeval *buffer_time; /* time when the buffer was received */ - unsigned int *last_used_cmd; /* For ISO Transmit with - variable sized packets only ! */ - int ctrlClear; - int ctrlSet; - int cmdPtr; - int ctxMatch; - wait_queue_head_t waitq; - spinlock_t lock; - unsigned int syt_offset; - int flags; - - struct list_head link; -}; - - -struct file_ctx { - struct ti_ohci *ohci; - struct list_head context_list; - struct dma_iso_ctx *current_ctx; -}; - -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG -#define VIDEO1394_DEBUG -#endif - -#ifdef DBGMSG -#undef DBGMSG -#endif - -#ifdef VIDEO1394_DEBUG -#define DBGMSG(card, fmt, args...) \ -printk(KERN_INFO "video1394_%d: " fmt "\n" , card , ## args) -#else -#define DBGMSG(card, fmt, args...) do {} while (0) -#endif - -/* print general (card independent) information */ -#define PRINT_G(level, fmt, args...) \ -printk(level "video1394: " fmt "\n" , ## args) - -/* print card specific information */ -#define PRINT(level, card, fmt, args...) \ -printk(level "video1394_%d: " fmt "\n" , card , ## args) - -static void wakeup_dma_ir_ctx(unsigned long l); -static void wakeup_dma_it_ctx(unsigned long l); - -static struct hpsb_highlevel video1394_highlevel; - -static int free_dma_iso_ctx(struct dma_iso_ctx *d) -{ - int i; - - DBGMSG(d->ohci->host->id, "Freeing dma_iso_ctx %d", d->ctx); - - ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - if (d->iso_tasklet.link.next != NULL) - ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet); - - dma_region_free(&d->dma); - - if (d->prg_reg) { - for (i = 0; i < d->num_desc; i++) - dma_prog_region_free(&d->prg_reg[i]); - kfree(d->prg_reg); - } - - kfree(d->ir_prg); - kfree(d->it_prg); - kfree(d->buffer_status); - kfree(d->buffer_prg_assignment); - kfree(d->buffer_time); - kfree(d->last_used_cmd); - kfree(d->next_buffer); - list_del(&d->link); - kfree(d); - - return 0; -} - -static struct dma_iso_ctx * -alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, - int buf_size, int channel, unsigned int packet_size) -{ - struct dma_iso_ctx *d; - int i; - - d = kzalloc(sizeof(*d), GFP_KERNEL); - if (!d) { - PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma_iso_ctx"); - return NULL; - } - - d->ohci = ohci; - d->type = type; - d->channel = channel; - d->num_desc = num_desc; - d->frame_size = buf_size; - d->buf_size = PAGE_ALIGN(buf_size); - d->last_buffer = -1; - INIT_LIST_HEAD(&d->link); - init_waitqueue_head(&d->waitq); - - /* Init the regions for easy cleanup */ - dma_region_init(&d->dma); - - if (dma_region_alloc(&d->dma, (d->num_desc - 1) * d->buf_size, ohci->dev, - PCI_DMA_BIDIRECTIONAL)) { - PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma buffer"); - free_dma_iso_ctx(d); - return NULL; - } - - if (type == OHCI_ISO_RECEIVE) - ohci1394_init_iso_tasklet(&d->iso_tasklet, type, - wakeup_dma_ir_ctx, - (unsigned long) d); - else - ohci1394_init_iso_tasklet(&d->iso_tasklet, type, - wakeup_dma_it_ctx, - (unsigned long) d); - - if (ohci1394_register_iso_tasklet(ohci, &d->iso_tasklet) < 0) { - PRINT(KERN_ERR, ohci->host->id, "no free iso %s contexts", - type == OHCI_ISO_RECEIVE ? "receive" : "transmit"); - free_dma_iso_ctx(d); - return NULL; - } - d->ctx = d->iso_tasklet.context; - - d->prg_reg = kmalloc(d->num_desc * sizeof(*d->prg_reg), GFP_KERNEL); - if (!d->prg_reg) { - PRINT(KERN_ERR, ohci->host->id, "Failed to allocate ir prg regs"); - free_dma_iso_ctx(d); - return NULL; - } - /* Makes for easier cleanup */ - for (i = 0; i < d->num_desc; i++) - dma_prog_region_init(&d->prg_reg[i]); - - if (type == OHCI_ISO_RECEIVE) { - d->ctrlSet = OHCI1394_IsoRcvContextControlSet+32*d->ctx; - d->ctrlClear = OHCI1394_IsoRcvContextControlClear+32*d->ctx; - d->cmdPtr = OHCI1394_IsoRcvCommandPtr+32*d->ctx; - d->ctxMatch = OHCI1394_IsoRcvContextMatch+32*d->ctx; - - d->ir_prg = kzalloc(d->num_desc * sizeof(*d->ir_prg), - GFP_KERNEL); - - if (!d->ir_prg) { - PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg"); - free_dma_iso_ctx(d); - return NULL; - } - - d->nb_cmd = d->buf_size / PAGE_SIZE + 1; - d->left_size = (d->frame_size % PAGE_SIZE) ? - d->frame_size % PAGE_SIZE : PAGE_SIZE; - - for (i = 0;i < d->num_desc; i++) { - if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd * - sizeof(struct dma_cmd), ohci->dev)) { - PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg"); - free_dma_iso_ctx(d); - return NULL; - } - d->ir_prg[i] = (struct dma_cmd *)d->prg_reg[i].kvirt; - } - - } else { /* OHCI_ISO_TRANSMIT */ - d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx; - d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx; - d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx; - - d->it_prg = kzalloc(d->num_desc * sizeof(*d->it_prg), - GFP_KERNEL); - - if (!d->it_prg) { - PRINT(KERN_ERR, ohci->host->id, - "Failed to allocate dma it prg"); - free_dma_iso_ctx(d); - return NULL; - } - - d->packet_size = packet_size; - - if (PAGE_SIZE % packet_size || packet_size>4096) { - PRINT(KERN_ERR, ohci->host->id, - "Packet size %d (page_size: %ld) " - "not yet supported\n", - packet_size, PAGE_SIZE); - free_dma_iso_ctx(d); - return NULL; - } - - d->nb_cmd = d->frame_size / d->packet_size; - if (d->frame_size % d->packet_size) { - d->nb_cmd++; - d->left_size = d->frame_size % d->packet_size; - } else - d->left_size = d->packet_size; - - for (i = 0; i < d->num_desc; i++) { - if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd * - sizeof(struct it_dma_prg), ohci->dev)) { - PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma it prg"); - free_dma_iso_ctx(d); - return NULL; - } - d->it_prg[i] = (struct it_dma_prg *)d->prg_reg[i].kvirt; - } - } - - d->buffer_status = - kzalloc(d->num_desc * sizeof(*d->buffer_status), GFP_KERNEL); - d->buffer_prg_assignment = - kzalloc(d->num_desc * sizeof(*d->buffer_prg_assignment), GFP_KERNEL); - d->buffer_time = - kzalloc(d->num_desc * sizeof(*d->buffer_time), GFP_KERNEL); - d->last_used_cmd = - kzalloc(d->num_desc * sizeof(*d->last_used_cmd), GFP_KERNEL); - d->next_buffer = - kzalloc(d->num_desc * sizeof(*d->next_buffer), GFP_KERNEL); - - if (!d->buffer_status || !d->buffer_prg_assignment || !d->buffer_time || - !d->last_used_cmd || !d->next_buffer) { - PRINT(KERN_ERR, ohci->host->id, - "Failed to allocate dma_iso_ctx member"); - free_dma_iso_ctx(d); - return NULL; - } - - spin_lock_init(&d->lock); - - DBGMSG(ohci->host->id, "Iso %s DMA: %d buffers " - "of size %d allocated for a frame size %d, each with %d prgs", - (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit", - d->num_desc - 1, d->buf_size, d->frame_size, d->nb_cmd); - - return d; -} - -static void reset_ir_status(struct dma_iso_ctx *d, int n) -{ - int i; - d->ir_prg[n][0].status = cpu_to_le32(4); - d->ir_prg[n][1].status = cpu_to_le32(PAGE_SIZE-4); - for (i = 2; i < d->nb_cmd - 1; i++) - d->ir_prg[n][i].status = cpu_to_le32(PAGE_SIZE); - d->ir_prg[n][i].status = cpu_to_le32(d->left_size); -} - -static void reprogram_dma_ir_prg(struct dma_iso_ctx *d, int n, int buffer, int flags) -{ - struct dma_cmd *ir_prg = d->ir_prg[n]; - unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size; - int i; - - d->buffer_prg_assignment[n] = buffer; - - ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf - - (unsigned long)d->dma.kvirt)); - ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, - (buf + 4) - (unsigned long)d->dma.kvirt)); - - for (i=2;i<d->nb_cmd-1;i++) { - ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, - (buf+(i-1)*PAGE_SIZE) - - (unsigned long)d->dma.kvirt)); - } - - ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size); - ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, - (buf+(i-1)*PAGE_SIZE) - (unsigned long)d->dma.kvirt)); -} - -static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags) -{ - struct dma_cmd *ir_prg = d->ir_prg[n]; - struct dma_prog_region *ir_reg = &d->prg_reg[n]; - unsigned long buf = (unsigned long)d->dma.kvirt; - int i; - - /* the first descriptor will read only 4 bytes */ - ir_prg[0].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_BRANCH | 4); - - /* set the sync flag */ - if (flags & VIDEO1394_SYNC_FRAMES) - ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT); - - ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf - - (unsigned long)d->dma.kvirt)); - ir_prg[0].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg, - 1 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1); - - /* If there is *not* only one DMA page per frame (hence, d->nb_cmd==2) */ - if (d->nb_cmd > 2) { - /* The second descriptor will read PAGE_SIZE-4 bytes */ - ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_BRANCH | (PAGE_SIZE-4)); - ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf + 4) - - (unsigned long)d->dma.kvirt)); - ir_prg[1].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg, - 2 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1); - - for (i = 2; i < d->nb_cmd - 1; i++) { - ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_BRANCH | PAGE_SIZE); - ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, - (buf+(i-1)*PAGE_SIZE) - - (unsigned long)d->dma.kvirt)); - - ir_prg[i].branchAddress = - cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg, - (i + 1) * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1); - } - - /* The last descriptor will generate an interrupt */ - ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size); - ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, - (buf+(i-1)*PAGE_SIZE) - - (unsigned long)d->dma.kvirt)); - } else { - /* Only one DMA page is used. Read d->left_size immediately and */ - /* generate an interrupt as this is also the last page. */ - ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_IRQ | DMA_CTL_BRANCH | (d->left_size-4)); - ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, - (buf + 4) - (unsigned long)d->dma.kvirt)); - } -} - -static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags) -{ - struct ti_ohci *ohci = (struct ti_ohci *)d->ohci; - int i; - - d->flags = flags; - - ohci1394_stop_context(ohci, d->ctrlClear, NULL); - - for (i=0;i<d->num_desc;i++) { - initialize_dma_ir_prg(d, i, flags); - reset_ir_status(d, i); - } - - /* reset the ctrl register */ - reg_write(ohci, d->ctrlClear, 0xf0000000); - - /* Set bufferFill */ - reg_write(ohci, d->ctrlSet, 0x80000000); - - /* Set isoch header */ - if (flags & VIDEO1394_INCLUDE_ISO_HEADERS) - reg_write(ohci, d->ctrlSet, 0x40000000); - - /* Set the context match register to match on all tags, - sync for sync tag, and listen to d->channel */ - reg_write(ohci, d->ctxMatch, 0xf0000000|((tag&0xf)<<8)|d->channel); - - /* Set up isoRecvIntMask to generate interrupts */ - reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1<<d->ctx); -} - -/* find which context is listening to this channel */ -static struct dma_iso_ctx * -find_ctx(struct list_head *list, int type, int channel) -{ - struct dma_iso_ctx *ctx; - - list_for_each_entry(ctx, list, link) { - if (ctx->type == type && ctx->channel == channel) - return ctx; - } - - return NULL; -} - -static void wakeup_dma_ir_ctx(unsigned long l) -{ - struct dma_iso_ctx *d = (struct dma_iso_ctx *) l; - int i; - - spin_lock(&d->lock); - - for (i = 0; i < d->num_desc; i++) { - if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) { - reset_ir_status(d, i); - d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY; - do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]); - dma_region_sync_for_cpu(&d->dma, - d->buffer_prg_assignment[i] * d->buf_size, - d->buf_size); - } - } - - spin_unlock(&d->lock); - - if (waitqueue_active(&d->waitq)) - wake_up_interruptible(&d->waitq); -} - -static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d, - int n) -{ - unsigned char* buf = d->dma.kvirt + n * d->buf_size; - u32 cycleTimer; - u32 timeStamp; - - if (n == -1) { - return; - } - - cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer); - - timeStamp = ((cycleTimer & 0x0fff) + d->syt_offset); /* 11059 = 450 us */ - timeStamp = (timeStamp % 3072 + ((timeStamp / 3072) << 12) - + (cycleTimer & 0xf000)) & 0xffff; - - buf[6] = timeStamp >> 8; - buf[7] = timeStamp & 0xff; - - /* if first packet is empty packet, then put timestamp into the next full one too */ - if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) { - buf += d->packet_size; - buf[6] = timeStamp >> 8; - buf[7] = timeStamp & 0xff; - } - - /* do the next buffer frame too in case of irq latency */ - n = d->next_buffer[n]; - if (n == -1) { - return; - } - buf = d->dma.kvirt + n * d->buf_size; - - timeStamp += (d->last_used_cmd[n] << 12) & 0xffff; - - buf[6] = timeStamp >> 8; - buf[7] = timeStamp & 0xff; - - /* if first packet is empty packet, then put timestamp into the next full one too */ - if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) { - buf += d->packet_size; - buf[6] = timeStamp >> 8; - buf[7] = timeStamp & 0xff; - } - -#if 0 - printk("curr: %d, next: %d, cycleTimer: %08x timeStamp: %08x\n", - curr, n, cycleTimer, timeStamp); -#endif -} - -static void wakeup_dma_it_ctx(unsigned long l) -{ - struct dma_iso_ctx *d = (struct dma_iso_ctx *) l; - struct ti_ohci *ohci = d->ohci; - int i; - - spin_lock(&d->lock); - - for (i = 0; i < d->num_desc; i++) { - if (d->it_prg[i][d->last_used_cmd[i]].end.status & - cpu_to_le32(0xFFFF0000)) { - int next = d->next_buffer[i]; - put_timestamp(ohci, d, next); - d->it_prg[i][d->last_used_cmd[i]].end.status = 0; - d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY; - } - } - - spin_unlock(&d->lock); - - if (waitqueue_active(&d->waitq)) - wake_up_interruptible(&d->waitq); -} - -static void reprogram_dma_it_prg(struct dma_iso_ctx *d, int n, int buffer) -{ - struct it_dma_prg *it_prg = d->it_prg[n]; - unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size; - int i; - - d->buffer_prg_assignment[n] = buffer; - for (i=0;i<d->nb_cmd;i++) { - it_prg[i].end.address = - cpu_to_le32(dma_region_offset_to_bus(&d->dma, - (buf+i*d->packet_size) - (unsigned long)d->dma.kvirt)); - } -} - -static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) -{ - struct it_dma_prg *it_prg = d->it_prg[n]; - struct dma_prog_region *it_reg = &d->prg_reg[n]; - unsigned long buf = (unsigned long)d->dma.kvirt; - int i; - d->last_used_cmd[n] = d->nb_cmd - 1; - for (i=0;i<d->nb_cmd;i++) { - - it_prg[i].begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE | - DMA_CTL_IMMEDIATE | 8) ; - it_prg[i].begin.address = 0; - - it_prg[i].begin.status = 0; - - it_prg[i].data[0] = cpu_to_le32( - (IEEE1394_SPEED_100 << 16) - | (/* tag */ 1 << 14) - | (d->channel << 8) - | (TCODE_ISO_DATA << 4)); - if (i==0) it_prg[i].data[0] |= cpu_to_le32(sync_tag); - it_prg[i].data[1] = cpu_to_le32(d->packet_size << 16); - it_prg[i].data[2] = 0; - it_prg[i].data[3] = 0; - - it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | - DMA_CTL_BRANCH); - it_prg[i].end.address = - cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf+i*d->packet_size) - - (unsigned long)d->dma.kvirt)); - - if (i<d->nb_cmd-1) { - it_prg[i].end.control |= cpu_to_le32(d->packet_size); - it_prg[i].begin.branchAddress = - cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) * - sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3); - it_prg[i].end.branchAddress = - cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) * - sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3); - } else { - /* the last prg generates an interrupt */ - it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | - DMA_CTL_IRQ | d->left_size); - /* the last prg doesn't branch */ - it_prg[i].begin.branchAddress = 0; - it_prg[i].end.branchAddress = 0; - } - it_prg[i].end.status = 0; - } -} - -static void initialize_dma_it_prg_var_packet_queue( - struct dma_iso_ctx *d, int n, unsigned int * packet_sizes, - struct ti_ohci *ohci) -{ - struct it_dma_prg *it_prg = d->it_prg[n]; - struct dma_prog_region *it_reg = &d->prg_reg[n]; - int i; - -#if 0 - if (n != -1) { - put_timestamp(ohci, d, n); - } -#endif - d->last_used_cmd[n] = d->nb_cmd - 1; - - for (i = 0; i < d->nb_cmd; i++) { - unsigned int size; - if (packet_sizes[i] > d->packet_size) { - size = d->packet_size; - } else { - size = packet_sizes[i]; - } - it_prg[i].data[1] = cpu_to_le32(size << 16); - it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH); - - if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) { - it_prg[i].end.control |= cpu_to_le32(size); - it_prg[i].begin.branchAddress = - cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) * - sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3); - it_prg[i].end.branchAddress = - cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) * - sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3); - } else { - /* the last prg generates an interrupt */ - it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | - DMA_CTL_IRQ | size); - /* the last prg doesn't branch */ - it_prg[i].begin.branchAddress = 0; - it_prg[i].end.branchAddress = 0; - d->last_used_cmd[n] = i; - break; - } - } -} - -static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag, - unsigned int syt_offset, int flags) -{ - struct ti_ohci *ohci = (struct ti_ohci *)d->ohci; - int i; - - d->flags = flags; - d->syt_offset = (syt_offset == 0 ? 11000 : syt_offset); - - ohci1394_stop_context(ohci, d->ctrlClear, NULL); - - for (i=0;i<d->num_desc;i++) - initialize_dma_it_prg(d, i, sync_tag); - - /* Set up isoRecvIntMask to generate interrupts */ - reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx); -} - -static inline unsigned video1394_buffer_state(struct dma_iso_ctx *d, - unsigned int buffer) -{ - unsigned long flags; - unsigned int ret; - spin_lock_irqsave(&d->lock, flags); - ret = d->buffer_status[buffer]; - spin_unlock_irqrestore(&d->lock, flags); - return ret; -} - -static long video1394_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct file_ctx *ctx = file->private_data; - struct ti_ohci *ohci = ctx->ohci; - unsigned long flags; - void __user *argp = (void __user *)arg; - - switch(cmd) - { - case VIDEO1394_IOC_LISTEN_CHANNEL: - case VIDEO1394_IOC_TALK_CHANNEL: - { - struct video1394_mmap v; - u64 mask; - struct dma_iso_ctx *d; - int i; - - if (copy_from_user(&v, argp, sizeof(v))) - return -EFAULT; - - /* if channel < 0, find lowest available one */ - if (v.channel < 0) { - mask = (u64)0x1; - for (i=0; ; i++) { - if (i == ISO_CHANNELS) { - PRINT(KERN_ERR, ohci->host->id, - "No free channel found"); - return -EAGAIN; - } - if (!(ohci->ISO_channel_usage & mask)) { - v.channel = i; - PRINT(KERN_INFO, ohci->host->id, "Found free channel %d", i); - break; - } - mask = mask << 1; - } - } else if (v.channel >= ISO_CHANNELS) { - PRINT(KERN_ERR, ohci->host->id, - "Iso channel %d out of bounds", v.channel); - return -EINVAL; - } else { - mask = (u64)0x1<<v.channel; - } - DBGMSG(ohci->host->id, "mask: %08X%08X usage: %08X%08X\n", - (u32)(mask>>32),(u32)(mask&0xffffffff), - (u32)(ohci->ISO_channel_usage>>32), - (u32)(ohci->ISO_channel_usage&0xffffffff)); - if (ohci->ISO_channel_usage & mask) { - PRINT(KERN_ERR, ohci->host->id, - "Channel %d is already taken", v.channel); - return -EBUSY; - } - - if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) { - PRINT(KERN_ERR, ohci->host->id, - "Invalid %d length buffer requested",v.buf_size); - return -EINVAL; - } - - if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) { - PRINT(KERN_ERR, ohci->host->id, - "Invalid %d buffers requested",v.nb_buffers); - return -EINVAL; - } - - if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) { - PRINT(KERN_ERR, ohci->host->id, - "%d buffers of size %d bytes is too big", - v.nb_buffers, v.buf_size); - return -EINVAL; - } - - if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) { - d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE, - v.nb_buffers + 1, v.buf_size, - v.channel, 0); - - if (d == NULL) { - PRINT(KERN_ERR, ohci->host->id, - "Couldn't allocate ir context"); - return -EAGAIN; - } - initialize_dma_ir_ctx(d, v.sync_tag, v.flags); - - ctx->current_ctx = d; - - v.buf_size = d->buf_size; - list_add_tail(&d->link, &ctx->context_list); - - DBGMSG(ohci->host->id, - "iso context %d listen on channel %d", - d->ctx, v.channel); - } - else { - d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT, - v.nb_buffers + 1, v.buf_size, - v.channel, v.packet_size); - - if (d == NULL) { - PRINT(KERN_ERR, ohci->host->id, - "Couldn't allocate it context"); - return -EAGAIN; - } - initialize_dma_it_ctx(d, v.sync_tag, - v.syt_offset, v.flags); - - ctx->current_ctx = d; - - v.buf_size = d->buf_size; - - list_add_tail(&d->link, &ctx->context_list); - - DBGMSG(ohci->host->id, - "Iso context %d talk on channel %d", d->ctx, - v.channel); - } - - if (copy_to_user(argp, &v, sizeof(v))) { - /* FIXME : free allocated dma resources */ - return -EFAULT; - } - - ohci->ISO_channel_usage |= mask; - - return 0; - } - case VIDEO1394_IOC_UNLISTEN_CHANNEL: - case VIDEO1394_IOC_UNTALK_CHANNEL: - { - int channel; - u64 mask; - struct dma_iso_ctx *d; - - if (copy_from_user(&channel, argp, sizeof(int))) - return -EFAULT; - - if (channel < 0 || channel >= ISO_CHANNELS) { - PRINT(KERN_ERR, ohci->host->id, - "Iso channel %d out of bound", channel); - return -EINVAL; - } - mask = (u64)0x1<<channel; - if (!(ohci->ISO_channel_usage & mask)) { - PRINT(KERN_ERR, ohci->host->id, - "Channel %d is not being used", channel); - return -ESRCH; - } - - /* Mark this channel as unused */ - ohci->ISO_channel_usage &= ~mask; - - if (cmd == VIDEO1394_IOC_UNLISTEN_CHANNEL) - d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, channel); - else - d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel); - - if (d == NULL) return -ESRCH; - DBGMSG(ohci->host->id, "Iso context %d " - "stop talking on channel %d", d->ctx, channel); - free_dma_iso_ctx(d); - - return 0; - } - case VIDEO1394_IOC_LISTEN_QUEUE_BUFFER: - { - struct video1394_wait v; - struct dma_iso_ctx *d; - int next_prg; - - if (unlikely(copy_from_user(&v, argp, sizeof(v)))) - return -EFAULT; - - d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); - if (unlikely(d == NULL)) - return -EFAULT; - - if (unlikely(v.buffer >= d->num_desc - 1)) { - PRINT(KERN_ERR, ohci->host->id, - "Buffer %d out of range",v.buffer); - return -EINVAL; - } - - spin_lock_irqsave(&d->lock,flags); - - if (unlikely(d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED)) { - PRINT(KERN_ERR, ohci->host->id, - "Buffer %d is already used",v.buffer); - spin_unlock_irqrestore(&d->lock,flags); - return -EBUSY; - } - - d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED; - - next_prg = (d->last_buffer + 1) % d->num_desc; - if (d->last_buffer>=0) - d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = - cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) - & 0xfffffff0) | 0x1); - - d->last_buffer = next_prg; - reprogram_dma_ir_prg(d, d->last_buffer, v.buffer, d->flags); - - d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0; - - spin_unlock_irqrestore(&d->lock,flags); - - if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) - { - DBGMSG(ohci->host->id, "Starting iso DMA ctx=%d",d->ctx); - - /* Tell the controller where the first program is */ - reg_write(ohci, d->cmdPtr, - dma_prog_region_offset_to_bus(&d->prg_reg[d->last_buffer], 0) | 0x1); - - /* Run IR context */ - reg_write(ohci, d->ctrlSet, 0x8000); - } - else { - /* Wake up dma context if necessary */ - if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { - DBGMSG(ohci->host->id, - "Waking up iso dma ctx=%d", d->ctx); - reg_write(ohci, d->ctrlSet, 0x1000); - } - } - return 0; - - } - case VIDEO1394_IOC_LISTEN_WAIT_BUFFER: - case VIDEO1394_IOC_LISTEN_POLL_BUFFER: - { - struct video1394_wait v; - struct dma_iso_ctx *d; - int i = 0; - - if (unlikely(copy_from_user(&v, argp, sizeof(v)))) - return -EFAULT; - - d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel); - if (unlikely(d == NULL)) - return -EFAULT; - - if (unlikely(v.buffer > d->num_desc - 1)) { - PRINT(KERN_ERR, ohci->host->id, - "Buffer %d out of range",v.buffer); - return -EINVAL; - } - - /* - * I change the way it works so that it returns - * the last received frame. - */ - spin_lock_irqsave(&d->lock, flags); - switch(d->buffer_status[v.buffer]) { - case VIDEO1394_BUFFER_READY: - d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; - break; - case VIDEO1394_BUFFER_QUEUED: - if (cmd == VIDEO1394_IOC_LISTEN_POLL_BUFFER) { - /* for polling, return error code EINTR */ - spin_unlock_irqrestore(&d->lock, flags); - return -EINTR; - } - - spin_unlock_irqrestore(&d->lock, flags); - wait_event_interruptible(d->waitq, - video1394_buffer_state(d, v.buffer) == - VIDEO1394_BUFFER_READY); - if (signal_pending(current)) - return -EINTR; - spin_lock_irqsave(&d->lock, flags); - d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; - break; - default: - PRINT(KERN_ERR, ohci->host->id, - "Buffer %d is not queued",v.buffer); - spin_unlock_irqrestore(&d->lock, flags); - return -ESRCH; - } - - /* set time of buffer */ - v.filltime = d->buffer_time[v.buffer]; - - /* - * Look ahead to see how many more buffers have been received - */ - i=0; - while (d->buffer_status[(v.buffer+1)%(d->num_desc - 1)]== - VIDEO1394_BUFFER_READY) { - v.buffer=(v.buffer+1)%(d->num_desc - 1); - i++; - } - spin_unlock_irqrestore(&d->lock, flags); - - v.buffer=i; - if (unlikely(copy_to_user(argp, &v, sizeof(v)))) - return -EFAULT; - - return 0; - } - case VIDEO1394_IOC_TALK_QUEUE_BUFFER: - { - struct video1394_wait v; - unsigned int *psizes = NULL; - struct dma_iso_ctx *d; - int next_prg; - - if (copy_from_user(&v, argp, sizeof(v))) - return -EFAULT; - - d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); - if (d == NULL) return -EFAULT; - - if (v.buffer >= d->num_desc - 1) { - PRINT(KERN_ERR, ohci->host->id, - "Buffer %d out of range",v.buffer); - return -EINVAL; - } - - if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) { - int buf_size = d->nb_cmd * sizeof(*psizes); - struct video1394_queue_variable __user *p = argp; - unsigned int __user *qv; - - if (get_user(qv, &p->packet_sizes)) - return -EFAULT; - - psizes = memdup_user(qv, buf_size); - if (IS_ERR(psizes)) - return PTR_ERR(psizes); - } - - spin_lock_irqsave(&d->lock,flags); - - /* last_buffer is last_prg */ - next_prg = (d->last_buffer + 1) % d->num_desc; - if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { - PRINT(KERN_ERR, ohci->host->id, - "Buffer %d is already used",v.buffer); - spin_unlock_irqrestore(&d->lock,flags); - kfree(psizes); - return -EBUSY; - } - - if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) { - initialize_dma_it_prg_var_packet_queue( - d, next_prg, psizes, ohci); - } - - d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED; - - if (d->last_buffer >= 0) { - d->it_prg[d->last_buffer] - [ d->last_used_cmd[d->last_buffer] ].end.branchAddress = - cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], - 0) & 0xfffffff0) | 0x3); - - d->it_prg[d->last_buffer] - [ d->last_used_cmd[d->last_buffer] ].begin.branchAddress = - cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], - 0) & 0xfffffff0) | 0x3); - d->next_buffer[d->last_buffer] = (v.buffer + 1) % (d->num_desc - 1); - } - d->last_buffer = next_prg; - reprogram_dma_it_prg(d, d->last_buffer, v.buffer); - d->next_buffer[d->last_buffer] = -1; - - d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0; - - spin_unlock_irqrestore(&d->lock,flags); - - if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) - { - DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d", - d->ctx); - put_timestamp(ohci, d, d->last_buffer); - dma_region_sync_for_device(&d->dma, - v.buffer * d->buf_size, d->buf_size); - - /* Tell the controller where the first program is */ - reg_write(ohci, d->cmdPtr, - dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) | 0x3); - - /* Run IT context */ - reg_write(ohci, d->ctrlSet, 0x8000); - } - else { - /* Wake up dma context if necessary */ - if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { - DBGMSG(ohci->host->id, - "Waking up iso transmit dma ctx=%d", - d->ctx); - put_timestamp(ohci, d, d->last_buffer); - dma_region_sync_for_device(&d->dma, - v.buffer * d->buf_size, d->buf_size); - - reg_write(ohci, d->ctrlSet, 0x1000); - } - } - - kfree(psizes); - return 0; - - } - case VIDEO1394_IOC_TALK_WAIT_BUFFER: - { - struct video1394_wait v; - struct dma_iso_ctx *d; - - if (copy_from_user(&v, argp, sizeof(v))) - return -EFAULT; - - d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); - if (d == NULL) return -EFAULT; - - if (v.buffer >= d->num_desc - 1) { - PRINT(KERN_ERR, ohci->host->id, - "Buffer %d out of range",v.buffer); - return -EINVAL; - } - - switch(d->buffer_status[v.buffer]) { - case VIDEO1394_BUFFER_READY: - d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; - return 0; - case VIDEO1394_BUFFER_QUEUED: - wait_event_interruptible(d->waitq, - (d->buffer_status[v.buffer] == VIDEO1394_BUFFER_READY)); - if (signal_pending(current)) - return -EINTR; - d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; - return 0; - default: - PRINT(KERN_ERR, ohci->host->id, - "Buffer %d is not queued",v.buffer); - return -ESRCH; - } - } - default: - return -ENOTTY; - } -} - -/* - * This maps the vmalloced and reserved buffer to user space. - * - * FIXME: - * - PAGE_READONLY should suffice!? - * - remap_pfn_range is kind of inefficient for page by page remapping. - * But e.g. pte_alloc() does not work in modules ... :-( - */ - -static int video1394_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct file_ctx *ctx = file->private_data; - - if (ctx->current_ctx == NULL) { - PRINT(KERN_ERR, ctx->ohci->host->id, - "Current iso context not set"); - return -EINVAL; - } - - return dma_region_mmap(&ctx->current_ctx->dma, file, vma); -} - -static unsigned int video1394_poll(struct file *file, poll_table *pt) -{ - struct file_ctx *ctx; - unsigned int mask = 0; - unsigned long flags; - struct dma_iso_ctx *d; - int i; - - ctx = file->private_data; - d = ctx->current_ctx; - if (d == NULL) { - PRINT(KERN_ERR, ctx->ohci->host->id, - "Current iso context not set"); - return POLLERR; - } - - poll_wait(file, &d->waitq, pt); - - spin_lock_irqsave(&d->lock, flags); - for (i = 0; i < d->num_desc; i++) { - if (d->buffer_status[i] == VIDEO1394_BUFFER_READY) { - mask |= POLLIN | POLLRDNORM; - break; - } - } - spin_unlock_irqrestore(&d->lock, flags); - - return mask; -} - -static int video1394_open(struct inode *inode, struct file *file) -{ - int i = ieee1394_file_to_instance(file); - struct ti_ohci *ohci; - struct file_ctx *ctx; - - ohci = hpsb_get_hostinfo_bykey(&video1394_highlevel, i); - if (ohci == NULL) - return -EIO; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) { - PRINT(KERN_ERR, ohci->host->id, "Cannot malloc file_ctx"); - return -ENOMEM; - } - - ctx->ohci = ohci; - INIT_LIST_HEAD(&ctx->context_list); - ctx->current_ctx = NULL; - file->private_data = ctx; - - return nonseekable_open(inode, file); -} - -static int video1394_release(struct inode *inode, struct file *file) -{ - struct file_ctx *ctx = file->private_data; - struct ti_ohci *ohci = ctx->ohci; - struct list_head *lh, *next; - u64 mask; - - list_for_each_safe(lh, next, &ctx->context_list) { - struct dma_iso_ctx *d; - d = list_entry(lh, struct dma_iso_ctx, link); - mask = (u64) 1 << d->channel; - - if (!(ohci->ISO_channel_usage & mask)) - PRINT(KERN_ERR, ohci->host->id, "On release: Channel %d " - "is not being used", d->channel); - else - ohci->ISO_channel_usage &= ~mask; - DBGMSG(ohci->host->id, "On release: Iso %s context " - "%d stop listening on channel %d", - d->type == OHCI_ISO_RECEIVE ? "receive" : "transmit", - d->ctx, d->channel); - free_dma_iso_ctx(d); - } - - kfree(ctx); - file->private_data = NULL; - - return 0; -} - -#ifdef CONFIG_COMPAT -static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg); -#endif - -static struct cdev video1394_cdev; -static const struct file_operations video1394_fops= -{ - .owner = THIS_MODULE, - .unlocked_ioctl = video1394_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = video1394_compat_ioctl, -#endif - .poll = video1394_poll, - .mmap = video1394_mmap, - .open = video1394_open, - .release = video1394_release, - .llseek = no_llseek, -}; - -/*** HOTPLUG STUFF **********************************************************/ -/* - * Export information about protocols/devices supported by this driver. - */ -#ifdef MODULE -static const struct ieee1394_device_id video1394_id_table[] = { - { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, - .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, - .version = CAMERA_SW_VERSION_ENTRY & 0xffffff - }, - { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, - .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, - .version = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff - }, - { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, - .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, - .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff - }, - { } -}; - -MODULE_DEVICE_TABLE(ieee1394, video1394_id_table); -#endif /* MODULE */ - -static struct hpsb_protocol_driver video1394_driver = { - .name = VIDEO1394_DRIVER_NAME, -}; - - -static void video1394_add_host (struct hpsb_host *host) -{ - struct ti_ohci *ohci; - int minor; - - /* We only work with the OHCI-1394 driver */ - if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) - return; - - ohci = (struct ti_ohci *)host->hostdata; - - if (!hpsb_create_hostinfo(&video1394_highlevel, host, 0)) { - PRINT(KERN_ERR, ohci->host->id, "Cannot allocate hostinfo"); - return; - } - - hpsb_set_hostinfo(&video1394_highlevel, host, ohci); - hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id); - - minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id; - device_create(hpsb_protocol_class, NULL, MKDEV(IEEE1394_MAJOR, minor), - NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id); -} - - -static void video1394_remove_host (struct hpsb_host *host) -{ - struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host); - - if (ohci) - device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR, - IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id)); - return; -} - - -static struct hpsb_highlevel video1394_highlevel = { - .name = VIDEO1394_DRIVER_NAME, - .add_host = video1394_add_host, - .remove_host = video1394_remove_host, -}; - -MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>"); -MODULE_DESCRIPTION("driver for digital video on OHCI board"); -MODULE_SUPPORTED_DEVICE(VIDEO1394_DRIVER_NAME); -MODULE_LICENSE("GPL"); - -#ifdef CONFIG_COMPAT - -#define VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER \ - _IOW ('#', 0x12, struct video1394_wait32) -#define VIDEO1394_IOC32_LISTEN_WAIT_BUFFER \ - _IOWR('#', 0x13, struct video1394_wait32) -#define VIDEO1394_IOC32_TALK_WAIT_BUFFER \ - _IOW ('#', 0x17, struct video1394_wait32) -#define VIDEO1394_IOC32_LISTEN_POLL_BUFFER \ - _IOWR('#', 0x18, struct video1394_wait32) - -struct video1394_wait32 { - u32 channel; - u32 buffer; - struct compat_timeval filltime; -}; - -static int video1394_wr_wait32(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct video1394_wait32 __user *argp = (void __user *)arg; - struct video1394_wait32 wait32; - struct video1394_wait wait; - mm_segment_t old_fs; - int ret; - - if (copy_from_user(&wait32, argp, sizeof(wait32))) - return -EFAULT; - - wait.channel = wait32.channel; - wait.buffer = wait32.buffer; - wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec; - wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - if (cmd == VIDEO1394_IOC32_LISTEN_WAIT_BUFFER) - ret = video1394_ioctl(file, - VIDEO1394_IOC_LISTEN_WAIT_BUFFER, - (unsigned long) &wait); - else - ret = video1394_ioctl(file, - VIDEO1394_IOC_LISTEN_POLL_BUFFER, - (unsigned long) &wait); - set_fs(old_fs); - - if (!ret) { - wait32.channel = wait.channel; - wait32.buffer = wait.buffer; - wait32.filltime.tv_sec = (int)wait.filltime.tv_sec; - wait32.filltime.tv_usec = (int)wait.filltime.tv_usec; - - if (copy_to_user(argp, &wait32, sizeof(wait32))) - ret = -EFAULT; - } - - return ret; -} - -static int video1394_w_wait32(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct video1394_wait32 wait32; - struct video1394_wait wait; - mm_segment_t old_fs; - int ret; - - if (copy_from_user(&wait32, (void __user *)arg, sizeof(wait32))) - return -EFAULT; - - wait.channel = wait32.channel; - wait.buffer = wait32.buffer; - wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec; - wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - if (cmd == VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER) - ret = video1394_ioctl(file, - VIDEO1394_IOC_LISTEN_QUEUE_BUFFER, - (unsigned long) &wait); - else - ret = video1394_ioctl(file, - VIDEO1394_IOC_TALK_WAIT_BUFFER, - (unsigned long) &wait); - set_fs(old_fs); - - return ret; -} - -static int video1394_queue_buf32(struct file *file, unsigned int cmd, unsigned long arg) -{ - return -EFAULT; /* ??? was there before. */ - - return video1394_ioctl(file, - VIDEO1394_IOC_TALK_QUEUE_BUFFER, arg); -} - -static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg) -{ - switch (cmd) { - case VIDEO1394_IOC_LISTEN_CHANNEL: - case VIDEO1394_IOC_UNLISTEN_CHANNEL: - case VIDEO1394_IOC_TALK_CHANNEL: - case VIDEO1394_IOC_UNTALK_CHANNEL: - return video1394_ioctl(f, cmd, arg); - - case VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER: - return video1394_w_wait32(f, cmd, arg); - case VIDEO1394_IOC32_LISTEN_WAIT_BUFFER: - return video1394_wr_wait32(f, cmd, arg); - case VIDEO1394_IOC_TALK_QUEUE_BUFFER: - return video1394_queue_buf32(f, cmd, arg); - case VIDEO1394_IOC32_TALK_WAIT_BUFFER: - return video1394_w_wait32(f, cmd, arg); - case VIDEO1394_IOC32_LISTEN_POLL_BUFFER: - return video1394_wr_wait32(f, cmd, arg); - default: - return -ENOIOCTLCMD; - } -} - -#endif /* CONFIG_COMPAT */ - -static void __exit video1394_exit_module (void) -{ - hpsb_unregister_protocol(&video1394_driver); - hpsb_unregister_highlevel(&video1394_highlevel); - cdev_del(&video1394_cdev); - PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module"); -} - -static int __init video1394_init_module (void) -{ - int ret; - - hpsb_init_highlevel(&video1394_highlevel); - - cdev_init(&video1394_cdev, &video1394_fops); - video1394_cdev.owner = THIS_MODULE; - ret = cdev_add(&video1394_cdev, IEEE1394_VIDEO1394_DEV, 16); - if (ret) { - PRINT_G(KERN_ERR, "video1394: unable to get minor device block"); - return ret; - } - - hpsb_register_highlevel(&video1394_highlevel); - - ret = hpsb_register_protocol(&video1394_driver); - if (ret) { - PRINT_G(KERN_ERR, "video1394: failed to register protocol"); - hpsb_unregister_highlevel(&video1394_highlevel); - cdev_del(&video1394_cdev); - return ret; - } - - PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module"); - return 0; -} - - -module_init(video1394_init_module); -module_exit(video1394_exit_module); diff --git a/drivers/ieee1394/video1394.h b/drivers/ieee1394/video1394.h deleted file mode 100644 index 9a89d9cc3c8..00000000000 --- a/drivers/ieee1394/video1394.h +++ /dev/null @@ -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 |