Commit a27bb86b authored by Ben Collins's avatar Ben Collins Committed by Linus Torvalds

[PATCH] Linux IEEE-1394 Updates

 - Cleanup (purge) some of our old compat code (never thouched)
 - Fix dv1394 compilation warnings without devfs
 - Added new config-rom handling features. Allows for on-the-fly
   config-rom generation for dynamic functionality of the host nodes.
 - Convert to workqueue from taskqueue interfaces. This is actually
   abstracted compatibility code between tqueue/workqueue.
parent 34d3616d
......@@ -199,7 +199,7 @@ static void cmp_remove_host(struct hpsb_host *host)
}
static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
u64 addr, unsigned int length)
u64 addr, unsigned int length, u16 flags)
{
int csraddr = addr - CSR_REGISTER_BASE;
int plug;
......@@ -235,7 +235,7 @@ static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
}
static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
u64 addr, quadlet_t data, quadlet_t arg, int extcode)
u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 flags)
{
int csraddr = addr - CSR_REGISTER_BASE;
int plug;
......
......@@ -4,20 +4,33 @@
* 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/string.h>
#include <linux/module.h> /* needed for MODULE_PARM */
#include "ieee1394_types.h"
#include "hosts.h"
#include "ieee1394.h"
#include "highlevel.h"
/* Module Parameters */
/* this module parameter can be used to disable mapping of the FCP registers */
MODULE_PARM(fcp,"i");
MODULE_PARM_DESC(fcp, "FCP-registers");
static int fcp = 1;
/* FIXME: this one won't work on little endian with big endian data */
static u16 csr_crc16(unsigned *data, int length)
{
int check=0, i;
......@@ -25,7 +38,7 @@ static u16 csr_crc16(unsigned *data, int length)
for (i = length; i; i--) {
for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
sum = ((next >> 12) ^ (*data >> shift)) & 0xf;
sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
}
check = next & 0xffff;
......@@ -60,6 +73,8 @@ static void host_reset(struct hpsb_host *host)
| csr_crc16(host->csr.topology_map + 1,
host->selfid_count + 2));
host->csr.speed_map[1] =
cpu_to_be32(be32_to_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));
......@@ -71,7 +86,7 @@ static void add_host(struct hpsb_host *host)
host->csr.lock = SPIN_LOCK_UNLOCKED;
host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom);
host->csr.rom_version = 0;
host->csr.state = 0;
host->csr.node_ids = 0;
host->csr.split_timeout_hi = 0;
......@@ -84,13 +99,52 @@ static void add_host(struct hpsb_host *host)
host->csr.channels_available_lo = ~0;
}
int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
size_t size, unsigned char rom_version)
{
int ret,flags;
spin_lock_irqsave(&host->csr.lock, flags);
if (rom_version != host->csr.rom_version)
ret = -1;
else if (size > (CSR_CONFIG_ROM_SIZE << 2))
ret = -2;
else {
memcpy(host->csr.rom,new_rom,size);
host->csr.rom_size=size;
host->csr.rom_version++;
ret=0;
}
spin_unlock_irqrestore(&host->csr.lock, flags);
return ret;
}
int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
size_t buffersize, size_t *rom_size, unsigned char *rom_version)
{
int ret,flags;
spin_lock_irqsave(&host->csr.lock, flags);
*rom_version=host->csr.rom_version;
*rom_size=host->csr.rom_size;
if (buffersize < host->csr.rom_size)
ret = -1;
else {
memcpy(buffer,host->csr.rom,host->csr.rom_size);
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, unsigned int length)
u64 addr, unsigned int length, u16 fl)
{
int csraddr = addr - CSR_REGISTER_BASE;
const char *src;
int flags;
spin_lock_irqsave(&host->csr.lock, flags);
if (csraddr < CSR_TOPOLOGY_MAP) {
if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) {
......@@ -105,6 +159,7 @@ static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
}
memcpy(buffer, src, length);
spin_unlock_irqrestore(&host->csr.lock, flags);
return RCODE_COMPLETE;
}
......@@ -112,7 +167,7 @@ static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
#define out if (--length == 0) break
static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
u64 addr, unsigned int length)
u64 addr, unsigned int length, u16 flags)
{
int csraddr = addr - CSR_REGISTER_BASE;
int oldcycle;
......@@ -222,7 +277,7 @@ static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
}
static int write_regs(struct hpsb_host *host, int nodeid, int destid,
quadlet_t *data, u64 addr, unsigned int length)
quadlet_t *data, u64 addr, unsigned int length, u16 flags)
{
int csraddr = addr - CSR_REGISTER_BASE;
......@@ -302,7 +357,7 @@ static int write_regs(struct hpsb_host *host, int nodeid, int destid,
static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
u64 addr, quadlet_t data, quadlet_t arg, int extcode)
u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
{
int csraddr = addr - CSR_REGISTER_BASE;
unsigned long flags;
......@@ -379,7 +434,7 @@ static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
}
static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
quadlet_t *data, u64 addr, unsigned int length)
quadlet_t *data, u64 addr, unsigned int length, u16 flags)
{
int csraddr = addr - CSR_REGISTER_BASE;
......@@ -436,9 +491,11 @@ void init_csr(void)
hpsb_register_addrspace(hl, &map_ops,
CSR_REGISTER_BASE + CSR_CONFIG_ROM,
CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
hpsb_register_addrspace(hl, &fcp_ops,
if (fcp) {
hpsb_register_addrspace(hl, &fcp_ops,
CSR_REGISTER_BASE + CSR_FCP_COMMAND,
CSR_REGISTER_BASE + CSR_FCP_END);
}
hpsb_register_addrspace(hl, &map_ops,
CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
......
......@@ -41,8 +41,10 @@ struct csr_control {
quadlet_t bandwidth_available;
quadlet_t channels_available_hi, channels_available_lo;
const quadlet_t *rom;
quadlet_t *rom;
size_t rom_size;
unsigned char rom_version;
quadlet_t topology_map[256];
quadlet_t speed_map[1024];
......
......@@ -97,7 +97,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/tqueue.h>
#include <linux/delay.h>
#include <asm/pgtable.h>
#include <asm/page.h>
......@@ -2587,6 +2586,7 @@ dv1394_devfs_find( char *name)
return p;
}
#ifdef CONFIG_DEVFS_FS
static int dv1394_devfs_add_entry(struct video_card *video)
{
char buf[32];
......@@ -2694,6 +2694,7 @@ void dv1394_devfs_del( char *name)
kfree(p);
}
}
#endif /* CONFIG_DEVFS_FS */
/*** IEEE1394 HPSB CALLBACKS ***********************************************/
......@@ -2852,7 +2853,6 @@ static void dv1394_add_host (struct hpsb_host *host)
{
struct ti_ohci *ohci;
char buf[16];
struct dv1394_devfs_entry *devfs_entry;
/* We only work with the OHCI-1394 driver */
if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
......@@ -2874,13 +2874,15 @@ static void dv1394_add_host (struct hpsb_host *host)
#endif
#ifdef CONFIG_DEVFS_FS
devfs_entry = dv1394_devfs_find("dv");
{
struct dv1394_devfs_entry = devfs_entry = dv1394_devfs_find("dv");
if (devfs_entry != NULL) {
snprintf(buf, sizeof(buf), "host%d", ohci->id);
dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry);
dv1394_devfs_add_dir("NTSC", devfs_entry, NULL);
dv1394_devfs_add_dir("PAL", devfs_entry, NULL);
}
}
#endif
dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
......
......@@ -77,7 +77,7 @@
printk(KERN_ERR fmt, ## args)
static char version[] __devinitdata =
"$Rev: 546 $ Ben Collins <bcollins@debian.org>";
"$Rev: 601 $ Ben Collins <bcollins@debian.org>";
/* Our ieee1394 highlevel driver */
#define ETHER1394_DRIVER_NAME "ether1394"
......@@ -522,7 +522,7 @@ static inline unsigned short ether1394_parse_encap (struct sk_buff *skb, struct
* ethernet header, and fill it with some of our other fields. This is
* an incoming packet from the 1394 bus. */
static int ether1394_write (struct hpsb_host *host, int srcid, int destid,
quadlet_t *data, u64 addr, unsigned int len)
quadlet_t *data, u64 addr, unsigned int len, u16 fl)
{
struct sk_buff *skb;
char *buf = (char *)data;
......@@ -682,8 +682,8 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
ptask->skb = skb;
ptask->addr = addr;
ptask->dest_node = dest_node;
INIT_TQUEUE(&ptask->tq, hpsb_write_sched, ptask);
schedule_task(&ptask->tq);
HPSB_INIT_WORK(&ptask->tq, hpsb_write_sched, ptask);
hpsb_schedule_work(&ptask->tq);
return 0;
fail:
......
......@@ -56,7 +56,7 @@ struct packet_task {
struct sk_buff *skb; /* Socket buffer we are sending */
nodeid_t dest_node; /* Destination of the packet */
u64 addr; /* Address */
struct tq_struct tq; /* The task */
struct hpsb_queue_struct tq; /* The task */
};
/* IP1394 headers */
......
......@@ -5,6 +5,16 @@
*
* 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/config.h>
......@@ -129,6 +139,32 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl,
return retval;
}
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start)
{
int retval = 0;
struct hpsb_address_serve *as;
struct list_head *entry;
write_lock_irq(&addr_space_lock);
entry = hl->addr_list.next;
while (entry != &hl->addr_list) {
as = list_entry(entry, struct hpsb_address_serve, addr_list);
entry = entry->next;
if (as->start == start) {
list_del(&as->as_list);
list_del(&as->addr_list);
kfree(as);
retval = 1;
break;
}
}
write_unlock_irq(&addr_space_lock);
return retval;
}
void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel)
......@@ -243,7 +279,7 @@ void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
}
int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64 addr, unsigned int length)
u64 addr, unsigned int length, u16 flags)
{
struct hpsb_address_serve *as;
struct list_head *entry;
......@@ -261,7 +297,7 @@ int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
if (as->op->read != NULL) {
rcode = as->op->read(host, nodeid, buffer,
addr, partlength);
addr, partlength, flags);
} else {
rcode = RCODE_TYPE_ERROR;
}
......@@ -288,7 +324,7 @@ int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
}
int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
quadlet_t *data, u64 addr, unsigned int length)
quadlet_t *data, u64 addr, unsigned int length, u16 flags)
{
struct hpsb_address_serve *as;
struct list_head *entry;
......@@ -306,7 +342,7 @@ int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
if (as->op->write != NULL) {
rcode = as->op->write(host, nodeid, destid,
data, addr, partlength);
data, addr, partlength, flags);
} else {
rcode = RCODE_TYPE_ERROR;
}
......@@ -334,7 +370,7 @@ int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode)
u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
{
struct hpsb_address_serve *as;
struct list_head *entry;
......@@ -349,7 +385,7 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
if (as->end > addr) {
if (as->op->lock != NULL) {
rcode = as->op->lock(host, nodeid, store, addr,
data, arg, ext_tcode);
data, arg, ext_tcode, flags);
} else {
rcode = RCODE_TYPE_ERROR;
}
......@@ -367,7 +403,7 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
}
int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
u64 addr, octlet_t data, octlet_t arg, int ext_tcode)
u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
{
struct hpsb_address_serve *as;
struct list_head *entry;
......@@ -383,7 +419,7 @@ int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
if (as->op->lock64 != NULL) {
rcode = as->op->lock64(host, nodeid, store,
addr, data, arg,
ext_tcode);
ext_tcode, flags);
} else {
rcode = RCODE_TYPE_ERROR;
}
......
......@@ -74,17 +74,22 @@ struct hpsb_address_ops {
*/
/* 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
later case, no response will be sent and the driver, that handled the request
will send the response itself
*/
int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64 addr, unsigned int length);
u64 addr, unsigned int length, u16 flags);
int (*write) (struct hpsb_host *host, int nodeid, int destid,
quadlet_t *data, u64 addr, unsigned int length);
quadlet_t *data, u64 addr, unsigned int 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);
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);
u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
};
......@@ -94,14 +99,23 @@ void highlevel_add_host(struct hpsb_host *host);
void highlevel_remove_host(struct hpsb_host *host);
void highlevel_host_reset(struct hpsb_host *host);
/* 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
later case, no response will be sent and the driver, that handled the request
will send the response itself.
*/
int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64 addr, unsigned int length);
u64 addr, unsigned int length, u16 flags);
int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
quadlet_t *data, u64 addr, unsigned int length);
quadlet_t *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);
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);
u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
unsigned int length);
......@@ -130,6 +144,8 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
int hpsb_register_addrspace(struct hpsb_highlevel *hl,
struct hpsb_address_ops *ops, u64 start, u64 end);
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start);
/*
* Enable or disable receving a certain isochronous channel through the
* iso_receive op.
......
......@@ -138,7 +138,7 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra)
atomic_set(&h->generation, 0);
INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
HPSB_INIT_WORK(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
h->topology_map = h->csr.topology_map + 3;
h->speed_map = (u8 *)(h->csr.speed_map + 2);
......
......@@ -2,13 +2,20 @@
#define _IEEE1394_HOSTS_H
#include <linux/wait.h>
#include <linux/tqueue.h>
#include <linux/list.h>
#include <asm/semaphore.h>
#include "ieee1394_types.h"
#include "csr.h"
/* size of the array used to store config rom (in quadlets)
maximum is 0x100. About 0x40 is needed for the default
entries. So 0x80 should provide enough space for additional
directories etc.
Note: All lowlevel drivers are required to allocate at least
this amount of memory for the configuration rom!
*/
#define CSR_CONFIG_ROM_SIZE 0x100
struct hpsb_packet;
......@@ -23,7 +30,7 @@ struct hpsb_host {
struct list_head pending_packets;
spinlock_t pending_pkt_lock;
struct tq_struct timeout_tq;
struct hpsb_queue_struct timeout_tq;
/* A bitmask where a set bit means that this tlabel is in use.
* FIXME - should be handled per node instead of per bus. */
......@@ -119,7 +126,7 @@ struct hpsb_host_driver {
* may not fail. If any allocation is required, it must be done
* earlier.
*/
size_t (*get_rom) (struct hpsb_host *host, const quadlet_t **pointer);
size_t (*get_rom) (struct hpsb_host *host, quadlet_t **pointer);
/* This function shall implement packet transmission based on
* packet->type. It shall CRC both parts of the packet (unless
......@@ -172,4 +179,24 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra);
void hpsb_add_host(struct hpsb_host *host);
void hpsb_remove_host(struct hpsb_host *h);
/* updates the configuration rom of a host.
* rom_version must be the current version,
* otherwise it will fail with return value -1.
* Return value -2 indicates that the new
* rom version is too big.
* Return value 0 indicates success
*/
int hpsb_update_config_rom(struct hpsb_host *host,
const quadlet_t *new_rom, size_t size, unsigned char rom_version);
/* reads the current version of the configuration rom of a host.
* buffersize is the size of the buffer, rom_size
* returns the size of the current rom image.
* rom_version is the version number of the fetched rom.
* return value -1 indicates, that the buffer was
* too small, 0 indicates success.
*/
int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
size_t buffersize, size_t *rom_size, unsigned char *rom_version);
#endif /* _IEEE1394_HOSTS_H */
......@@ -5,9 +5,19 @@
* 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/config.h>
......@@ -19,7 +29,6 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/tqueue.h>
#include <asm/bitops.h>
#include <asm/byteorder.h>
#include <asm/semaphore.h>
......@@ -72,9 +81,10 @@ static void process_complete_tasks(struct hpsb_packet *packet)
struct list_head *lh, *next;
list_for_each_safe(lh, next, &packet->complete_tq) {
struct tq_struct *tq = list_entry(lh, struct tq_struct, list);
list_del(&tq->list);
schedule_task(tq);
struct hpsb_queue_struct *tq =
list_entry(lh, struct hpsb_queue_struct, hpsb_queue_list);
list_del(&tq->hpsb_queue_list);
hpsb_schedule_work(tq);
}
return;
......@@ -83,11 +93,11 @@ static void process_complete_tasks(struct hpsb_packet *packet)
/**
* hpsb_add_packet_complete_task - add a new task for when a packet completes
* @packet: the packet whose completion we want the task added to
* @tq: the tq_struct describing the task to add
* @tq: the hpsb_queue_struct describing the task to add
*/
void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq)
void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq)
{
list_add_tail(&tq->list, &packet->complete_tq);
list_add_tail(&tq->hpsb_queue_list, &packet->complete_tq);
return;
}
......@@ -372,12 +382,19 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
build_speed_map(host, host->node_count);
}
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
HPSB_INFO("selfid_complete called with successful SelfID stage "
"... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);
#endif
/* irm_id is kept up to date by check_selfids() */
if (host->irm_id == host->node_id) {
host->is_irm = 1;
host->is_busmgr = 1;
host->busmgr_id = host->node_id;
host->csr.bus_manager_id = host->node_id;
} else {
host->is_busmgr = 0;
host->is_irm = 0;
}
host->reset_retries = 0;
......@@ -420,7 +437,7 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
up(&packet->state_change);
schedule_task(&host->timeout_tq);
hpsb_schedule_work(&host->timeout_tq);
}
/**
......@@ -448,6 +465,45 @@ int hpsb_send_packet(struct hpsb_packet *packet)
packet->state = hpsb_queued;
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;
int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
data = kmalloc(packet->header_size + packet->data_size, kmflags);
if (!data) {
HPSB_ERR("unable to allocate memory for concatenating header and data");
return 0;
}
memcpy(data, packet->header, packet->header_size);
if (packet->data_size)
{
if (packet->data_be) {
memcpy(((u8*)data)+packet->header_size, packet->data, packet->data_size);
} else {
int i;
quadlet_t *my_data=(quadlet_t*) ((u8*) data + packet->data_size);
for (i=0; i < packet->data_size/4; i++) {
my_data[i] = cpu_to_be32(packet->data[i]);
}
}
}
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
dump_packet("send packet local:", packet->header,
packet->header_size);
#endif
hpsb_packet_sent(host, packet, packet->expect_response?ACK_PENDING:ACK_COMPLETE);
hpsb_packet_received(host, data, size, 0);
kfree(data);
return 1;
}
if (packet->type == hpsb_async && packet->node_id != ALL_NODES) {
packet->speed_code =
host->speed_map[(host->node_id & NODE_MASK) * 64
......@@ -600,8 +656,10 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
{
struct hpsb_packet *packet;
int length, rcode, extcode;
quadlet_t buffer;
nodeid_t source = data[1] >> 16;
nodeid_t dest = data[0] >> 16;
nodeid_t dest = data[0] >> 16;
u16 flags = (u16) data[0];
u64 addr;
/* big FIXME - no error checking is done for an out of bounds length */
......@@ -610,10 +668,11 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
case TCODE_WRITEQ:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_write(host, source, dest, data+3,
addr, 4);
addr, 4, flags);
if (!write_acked
&& ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
&& (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
&& (rcode >= 0)) {
/* not a broadcast write, reply */
PREP_REPLY_PACKET(0);
fill_async_write_resp(packet, rcode);
......@@ -624,10 +683,11 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
case TCODE_WRITEB:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_write(host, source, dest, data+4,
addr, data[3]>>16);
addr, data[3]>>16, flags);
if (!write_acked
&& ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
&& (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
&& (rcode >= 0)) {
/* not a broadcast write, reply */
PREP_REPLY_PACKET(0);
fill_async_write_resp(packet, rcode);
......@@ -636,12 +696,14 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
break;
case TCODE_READQ:
PREP_REPLY_PACKET(0);
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_read(host, source, data, addr, 4);
fill_async_readquad_resp(packet, rcode, *data);
send_packet_nocare(packet);
rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
if (rcode >= 0) {
PREP_REPLY_PACKET(0);
fill_async_readquad_resp(packet, rcode, buffer);
send_packet_nocare(packet);
}
break;
case TCODE_READB:
......@@ -650,9 +712,12 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_read(host, source, packet->data, addr,
length);
fill_async_readblock_resp(packet, rcode, length);
send_packet_nocare(packet);
length, flags);
if (rcode >= 0) {
fill_async_readblock_resp(packet, rcode, length);
send_packet_nocare(packet);
}
break;
case TCODE_LOCK_REQUEST:
......@@ -670,7 +735,7 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
switch (length) {
case 4:
rcode = highlevel_lock(host, source, packet->data, addr,
data[4], 0, extcode);
data[4], 0, extcode,flags);
fill_async_lock_resp(packet, rcode, extcode, 4);
break;
case 8:
......@@ -679,13 +744,13 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
rcode = highlevel_lock(host, source,
packet->data, addr,
data[5], data[4],
extcode);
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);
extcode, flags);
fill_async_lock_resp(packet, rcode, extcode, 8);
}
break;
......@@ -694,15 +759,20 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
(octlet_t *)packet->data, addr,
*(octlet_t *)(data + 6),
*(octlet_t *)(data + 4),
extcode);
extcode, flags);
fill_async_lock_resp(packet, rcode, extcode, 8);
break;
default:
fill_async_lock_resp(packet, RCODE_TYPE_ERROR,
rcode = RCODE_TYPE_ERROR;
fill_async_lock_resp(packet, rcode,
extcode, 0);
}
send_packet_nocare(packet);
if (rcode >= 0) {
send_packet_nocare(packet);
} else {
free_hpsb_packet(packet);
}
break;
}
......@@ -811,7 +881,7 @@ void abort_timedouts(struct hpsb_host *host)
}
if (!list_empty(&host->pending_packets))
schedule_task(&host->timeout_tq);
hpsb_schedule_work(&host->timeout_tq);
spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
......@@ -1109,6 +1179,7 @@ EXPORT_SYMBOL(hpsb_make_readbpacket);
EXPORT_SYMBOL(hpsb_make_writeqpacket);
EXPORT_SYMBOL(hpsb_make_writebpacket);
EXPORT_SYMBOL(hpsb_make_lockpacket);
EXPORT_SYMBOL(hpsb_make_lock64packet);
EXPORT_SYMBOL(hpsb_make_phypacket);
EXPORT_SYMBOL(hpsb_packet_success);
EXPORT_SYMBOL(hpsb_make_packet);
......@@ -1119,6 +1190,7 @@ EXPORT_SYMBOL(hpsb_lock);
EXPORT_SYMBOL(hpsb_register_highlevel);
EXPORT_SYMBOL(hpsb_unregister_highlevel);
EXPORT_SYMBOL(hpsb_register_addrspace);
EXPORT_SYMBOL(hpsb_unregister_addrspace);
EXPORT_SYMBOL(hpsb_listen_channel);
EXPORT_SYMBOL(hpsb_unlisten_channel);
EXPORT_SYMBOL(highlevel_read);
......@@ -1135,6 +1207,8 @@ EXPORT_SYMBOL(hpsb_node_fill_packet);
EXPORT_SYMBOL(hpsb_node_read);
EXPORT_SYMBOL(hpsb_node_write);
EXPORT_SYMBOL(hpsb_node_lock);
EXPORT_SYMBOL(hpsb_update_config_rom);
EXPORT_SYMBOL(hpsb_get_config_rom);
EXPORT_SYMBOL(hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
EXPORT_SYMBOL(hpsb_release_unit_directory);
......
......@@ -2,7 +2,6 @@
#ifndef _IEEE1394_CORE_H
#define _IEEE1394_CORE_H
#include <linux/tqueue.h>
#include <linux/slab.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/proc_fs.h>
......@@ -78,7 +77,7 @@ struct hpsb_packet {
};
/* add a new task for when a packet completes */
void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq);
void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq);
static inline struct hpsb_packet *driver_packet(struct list_head *l)
{
......
......@@ -297,14 +297,6 @@ int hpsb_packet_success(struct hpsb_packet *packet)
HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__);
}
int hpsb_read_trylocal(struct hpsb_host *host, nodeid_t node, u64 addr,
quadlet_t *buffer, size_t length)
{
if (host->node_id != node) return -1;
return highlevel_read(host, node, buffer, addr, length);
}
struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node,
u64 addr)
{
......@@ -400,6 +392,31 @@ struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
return p;
}
struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
u64 addr, int extcode)
{
struct hpsb_packet *p;
p = alloc_hpsb_packet(16);
if (!p) return NULL;
p->host = host;
p->tlabel = get_tlabel(host, node, 1);
p->node_id = node;
switch (extcode) {
case EXTCODE_FETCH_ADD:
case EXTCODE_LITTLE_ADD:
fill_async_lock(p, addr, extcode, 8);
break;
default:
fill_async_lock(p, addr, extcode, 16);
break;
}
return p;
}
struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
quadlet_t data)
{
......@@ -429,18 +446,6 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
return -EINVAL;
}
if (host->node_id == node) {
switch(highlevel_read(host, node, buffer, addr, length)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
return -EACCES;
case RCODE_ADDRESS_ERROR:
default:
return -EINVAL;
}
}
if (length == 4) {
packet = hpsb_make_readqpacket(host, node, addr);
} else {
......@@ -509,18 +514,6 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
if (length == 0)
return -EINVAL;
if (host->node_id == node) {
switch(highlevel_write(host, node, node, buffer, addr, length)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
return -EACCES;
case RCODE_ADDRESS_ERROR:
default:
return -EINVAL;
}
}
packet = hpsb_make_packet (host, node, addr, buffer, length);
if (!packet)
......@@ -551,19 +544,6 @@ int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
struct hpsb_packet *packet;
int retval = 0, length;
if (host->node_id == node) {
switch(highlevel_lock(host, node, data, addr, *data, arg,
extcode)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
return -EACCES;
case RCODE_ADDRESS_ERROR:
default:
return -EINVAL;
}
}
packet = alloc_hpsb_packet(8);
if (!packet) {
return -ENOMEM;
......
......@@ -42,6 +42,8 @@ struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host,
size_t length);
struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
u64 addr, int extcode);
struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
u64 addr, int extcode);
struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
quadlet_t data) ;
......
......@@ -20,23 +20,6 @@
#define __devexit_p(x) x
#endif
/* This showed up around this time */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,12)
# ifndef MODULE_LICENSE
# define MODULE_LICENSE(x)
# endif
# ifndef min
# define min(x,y) ({ \
const typeof(x) _x = (x); \
const typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; })
# endif
#endif /* Linux version < 2.4.12 */
#include <linux/spinlock.h>
#ifndef list_for_each_safe
......@@ -58,10 +41,35 @@
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
/* Compatibility for task/work queues */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,42)
/* Use task queue */
#include <linux/tqueue.h>
#define hpsb_queue_struct tq_struct
#define hpsb_queue_list list
#define hpsb_schedule_work(x) schedule_task(x)
#define HPSB_INIT_WORK(x,y,z) INIT_TQUEUE(x,y,z)
#define HPSB_PREPARE_WORK(x,y,z) PREPARE_TQUEUE(x,y,z)
#else
/* Use work queue */
#include <linux/workqueue.h>
#define hpsb_queue_struct work_struct
#define hpsb_queue_list entry
#define hpsb_schedule_work(x) schedule_work(x)
#define HPSB_INIT_WORK(x,y,z) INIT_WORK(x,y,z)
#define HPSB_PREPARE_WORK(x,y,z) PREPARE_WORK(x,y,z)
#endif
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 NODE_MASK 0x003f
#define LOCAL_BUS 0xffc0
......
......@@ -91,7 +91,6 @@
#include <asm/byteorder.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <linux/tqueue.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
......@@ -154,7 +153,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
static char version[] __devinitdata =
"$Rev: 578 $ Ben Collins <bcollins@debian.org>";
"$Rev: 601 $ Ben Collins <bcollins@debian.org>";
/* Module Parameters */
MODULE_PARM(attempt_root,"i");
......@@ -1905,7 +1904,7 @@ static void ohci_init_config_rom(struct ti_ohci *ohci)
ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;
}
static size_t ohci_get_rom(struct hpsb_host *host, const quadlet_t **ptr)
static size_t ohci_get_rom(struct hpsb_host *host, quadlet_t **ptr)
{
struct ti_ohci *ohci=host->hostdata;
......
......@@ -1677,7 +1677,7 @@ static int __devinit add_card(struct pci_dev *dev,
static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
static size_t get_lynx_rom(struct hpsb_host *host, quadlet_t **ptr)
{
struct ti_lynx *lynx = host->hostdata;
*ptr = lynx->config_rom;
......
......@@ -4,9 +4,27 @@
* 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>
......@@ -40,6 +58,16 @@
#define ptr2int(x) ((u64)(u32)x)
#endif
#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...)
#endif
static devfs_handle_t devfs_handle;
......@@ -53,6 +81,21 @@ static struct hpsb_highlevel *hl_handle;
static atomic_t iso_buffer_size;
static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */
static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64 addr, unsigned int length, u16 flags);
static int arm_write (struct hpsb_host *host, int nodeid, int destid,
quadlet_t *data, u64 addr, unsigned int 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 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(int flags)
......@@ -64,7 +107,7 @@ static struct pending_request *__alloc_pending_request(int flags)
if (req != NULL) {
memset(req, 0, sizeof(struct pending_request));
INIT_LIST_HEAD(&req->list);
INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL);
HPSB_INIT_WORK(&req->tq, (void(*)(void*))queue_complete_cb, NULL);
}
return req;
......@@ -128,7 +171,8 @@ static void queue_complete_cb(struct pending_request *req)
req->req.length = 0;
}
free_tlabel(packet->host, packet->node_id, packet->tlabel);
if (req->req.type != RAW1394_REQ_PHYPACKET)
free_tlabel(packet->host, packet->node_id, packet->tlabel);
queue_complete_req(req);
}
......@@ -137,6 +181,7 @@ static void queue_complete_cb(struct pending_request *req)
static void add_host(struct hpsb_host *host)
{
struct host_info *hi;
unsigned long flags;
hi = (struct host_info *)kmalloc(sizeof(struct host_info), SLAB_KERNEL);
if (hi != NULL) {
......@@ -144,10 +189,10 @@ static void add_host(struct hpsb_host *host)
hi->host = host;
INIT_LIST_HEAD(&hi->file_info_list);
spin_lock_irq(&host_info_lock);
spin_lock_irqsave(&host_info_lock, flags);
list_add_tail(&hi->list, &host_info_list);
host_count++;
spin_unlock_irq(&host_info_lock);
spin_unlock_irqrestore(&host_info_lock, flags);
}
atomic_inc(&internal_generation);
......@@ -172,15 +217,22 @@ static struct host_info *find_host_info(struct hpsb_host *host)
static void remove_host(struct hpsb_host *host)
{
struct host_info *hi;
unsigned long flags;
spin_lock_irq(&host_info_lock);
spin_lock_irqsave(&host_info_lock, flags);
hi = find_host_info(host);
if (hi != NULL) {
list_del(&hi->list);
host_count--;
/*
FIXME: adressranges should be removed
and fileinfo states should be initialized
(including setting generation to
internal-generation ...)
*/
}
spin_unlock_irq(&host_info_lock);
spin_unlock_irqrestore(&host_info_lock, flags);
if (hi == NULL) {
printk(KERN_ERR "raw1394: attempt to remove unknown host "
......@@ -207,20 +259,22 @@ static void host_reset(struct hpsb_host *host)
if (hi != NULL) {
list_for_each(lh, &hi->file_info_list) {
fi = list_entry(lh, struct file_info, list);
req = __alloc_pending_request(SLAB_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 |= ((host->irm_id
& NODE_MASK) << 8);
if (fi->notification == RAW1394_NOTIFY_ON) {
req = __alloc_pending_request(SLAB_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 |= ((host->irm_id
& NODE_MASK) << 8);
}
queue_complete_req(req);
}
queue_complete_req(req);
}
}
}
......@@ -529,7 +583,7 @@ static void handle_iso_listen(struct file_info *fi, struct pending_request *req)
{
int channel = req->req.misc;
spin_lock(&host_info_lock);
spin_lock_irq(&host_info_lock);
if ((channel > 63) || (channel < -64)) {
req->req.error = RAW1394_ERROR_INVALID_ARG;
} else if (channel >= 0) {
......@@ -556,7 +610,7 @@ static void handle_iso_listen(struct file_info *fi, struct pending_request *req)
req->req.length = 0;
queue_complete_req(req);
spin_unlock(&host_info_lock);
spin_unlock_irq(&host_info_lock);
}
static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
......@@ -579,84 +633,9 @@ static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
queue_complete_req(req);
}
static int handle_local_request(struct file_info *fi,
struct pending_request *req, int node)
{
u64 addr = req->req.address & 0xffffffffffffULL;
req->data = kmalloc(req->req.length, SLAB_KERNEL);
if (!req->data) return -ENOMEM;
req->free_data = 1;
switch (req->req.type) {
case RAW1394_REQ_ASYNC_READ:
req->req.error = highlevel_read(fi->host, node, req->data, addr,
req->req.length);
break;
case RAW1394_REQ_ASYNC_WRITE:
if (copy_from_user(req->data, int2ptr(req->req.sendb),
req->req.length)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
break;
}
req->req.error = highlevel_write(fi->host, node, node, req->data,
addr, req->req.length);
req->req.length = 0;
break;
case RAW1394_REQ_LOCK:
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;
}
}
if (copy_from_user(req->data, int2ptr(req->req.sendb),
req->req.length)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
break;
}
if (req->req.length == 8) {
req->req.error = highlevel_lock(fi->host, node,
req->data, addr,
req->data[1],
req->data[0],
req->req.misc);
req->req.length = 4;
} else {
req->req.error = highlevel_lock(fi->host, node,
req->data, addr,
req->data[0], 0,
req->req.misc);
}
break;
case RAW1394_REQ_LOCK64:
default:
req->req.error = RAW1394_ERROR_STATE_ORDER;
}
if (req->req.error)
req->req.length = 0;
if (req->req.error >= 0)
req->req.error |= ACK_PENDING << 16;
queue_complete_req(req);
return sizeof(struct raw1394_request);
}
static int handle_remote_request(struct file_info *fi,
struct pending_request *req, int node)
static int handle_async_request(struct file_info *fi,
struct pending_request *req, int node)
{
struct hpsb_packet *packet = NULL;
u64 addr = req->req.address & 0xffffffffffffULL;
......@@ -664,11 +643,13 @@ static int handle_remote_request(struct file_info *fi,
switch (req->req.type) {
case RAW1394_REQ_ASYNC_READ:
if (req->req.length == 4) {
DBGMSG("quadlet_read_request called");
packet = hpsb_make_readqpacket(fi->host, node, addr);
if (!packet) return -ENOMEM;
req->data = &packet->header[3];
} else {
DBGMSG("block_read_request called");
packet = hpsb_make_readbpacket(fi->host, node, addr,
req->req.length);
if (!packet) return -ENOMEM;
......@@ -681,6 +662,7 @@ static int handle_remote_request(struct file_info *fi,
if (req->req.length == 4) {
quadlet_t x;
DBGMSG("quadlet_write_request called");
if (copy_from_user(&x, int2ptr(req->req.sendb), 4)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
}
......@@ -689,6 +671,7 @@ static int handle_remote_request(struct file_info *fi,
x);
if (!packet) return -ENOMEM;
} else {
DBGMSG("block_write_request called");
packet = hpsb_make_writebpacket(fi->host, node, addr,
req->req.length);
if (!packet) return -ENOMEM;
......@@ -702,6 +685,7 @@ static int handle_remote_request(struct file_info *fi,
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) {
......@@ -730,6 +714,33 @@ static int handle_remote_request(struct file_info *fi,
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);
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;
}
......@@ -783,8 +794,7 @@ static int handle_iso_send(struct file_info *fi, struct pending_request *req,
return sizeof(struct raw1394_request);
}
req->tq.data = req;
req->tq.routine = (void (*)(void*))queue_complete_req;
HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req);
req->req.length = 0;
hpsb_add_packet_complete_task(packet, &req->tq);
......@@ -803,25 +813,1092 @@ static int handle_iso_send(struct file_info *fi, struct pending_request *req,
return sizeof(struct raw1394_request);
}
static int state_connected(struct file_info *fi, struct pending_request *req)
static int handle_async_send(struct file_info *fi, struct pending_request *req)
{
int node = req->req.address >> 48;
struct hpsb_packet *packet;
int header_length = req->req.misc & 0xffff;
int expect_response = req->req.misc >> 16;
req->req.error = RAW1394_ERROR_NONE;
if ((header_length > req->req.length) ||
(header_length < 12))
{
req->req.error = RAW1394_ERROR_INVALID_ARG;
req->req.length = 0;
queue_complete_req(req);
return sizeof(struct raw1394_request);
}
if (req->req.type == RAW1394_REQ_ISO_SEND) {
return handle_iso_send(fi, req, node);
packet = alloc_hpsb_packet(req->req.length-header_length);
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 sizeof(struct raw1394_request);
}
if (req->req.generation != get_hpsb_generation(fi->host)) {
req->req.error = RAW1394_ERROR_GENERATION;
req->req.generation = get_hpsb_generation(fi->host);
if (copy_from_user(packet->data, ((u8*) int2ptr(req->req.sendb)) + header_length,
packet->data_size)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
req->req.length = 0;
queue_complete_req(req);
return sizeof(struct raw1394_request);
}
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=req->req.length-header_length;
HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req);
req->req.length = 0;
hpsb_add_packet_complete_task(packet, &req->tq);
spin_lock_irq(&fi->reqlists_lock);
list_add_tail(&req->list, &fi->req_pending);
spin_unlock_irq(&fi->reqlists_lock);
/* Update the generation of the packet just before sending. */
packet->generation = get_hpsb_generation(fi->host);
if (!hpsb_send_packet(packet)) {
req->req.error = RAW1394_ERROR_SEND_ERROR;
queue_complete_req(req);
}
return sizeof(struct raw1394_request);
}
static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64 addr, unsigned int length, u16 flags)
{
struct pending_request *req;
struct list_head *lh;
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: %u", nodeid,
(u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
length);
spin_lock(&host_info_lock);
hi = find_host_info(host); /* search address-entry */
if (hi != NULL) {
list_for_each(lh, &hi->file_info_list) {
fi = list_entry(lh, struct file_info, 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(&host_info_lock);
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(SLAB_ATOMIC);
if (!req) {
DBGMSG("arm_read -> rcode_conflict_error");
spin_unlock(&host_info_lock);
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, SLAB_ATOMIC);
if (!(req->data)) {
free_pending_request(req);
DBGMSG("arm_read -> rcode_conflict_error");
spin_unlock(&host_info_lock);
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) {
arm_resp->buffer = ((byte_t *)(arm_resp) +
(sizeof(struct arm_response)));
memcpy (arm_resp->buffer,
(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(&host_info_lock);
return(rcode);
}
static int arm_write (struct hpsb_host *host, int nodeid, int destid,
quadlet_t *data, u64 addr, unsigned int length, u16 flags)
{
struct pending_request *req;
struct list_head *lh;
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, length_conflict=0;
struct arm_request_response *arm_req_resp = NULL;
DBGMSG("arm_write called by node: %X"
"addr: %4.4x %8.8x length: %u", nodeid,
(u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
length);
spin_lock(&host_info_lock);
hi = find_host_info(host); /* search address-entry */
if (hi != NULL) {
list_for_each(lh, &hi->file_info_list) {
fi = list_entry(lh, struct file_info, 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(&host_info_lock);
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");
length_conflict = 1;
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(SLAB_ATOMIC);
if (!req) {
DBGMSG("arm_write -> rcode_conflict_error");
spin_unlock(&host_info_lock);
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, SLAB_ATOMIC);
if (!(req->data)) {
free_pending_request(req);
DBGMSG("arm_write -> rcode_conflict_error");
spin_unlock(&host_info_lock);
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_req->buffer = ((byte_t *)(arm_resp) +
(sizeof(struct arm_response)));
arm_resp->buffer = NULL;
memcpy (arm_req->buffer, 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(&host_info_lock);
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)
{
struct pending_request *req;
struct list_head *lh;
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(&host_info_lock);
hi = find_host_info(host); /* search address-entry */
if (hi != NULL) {
list_for_each(lh, &hi->file_info_list) {
fi = list_entry(lh, struct file_info, 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(&host_info_lock);
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) {
DBGMSG("arm_lock -> entering notification-section");
req = __alloc_pending_request(SLAB_ATOMIC);
if (!req) {
DBGMSG("arm_lock -> rcode_conflict_error");
spin_unlock(&host_info_lock);
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, SLAB_ATOMIC);
if (!(req->data)) {
free_pending_request(req);
DBGMSG("arm_lock -> rcode_conflict_error");
spin_unlock(&host_info_lock);
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)));
arm_req->buffer = ((byte_t *)(arm_resp) +
(sizeof(struct arm_response)));
arm_resp->buffer = ((byte_t *)(arm_req->buffer) +
(2* sizeof(*store)));
if ((ext_tcode == EXTCODE_FETCH_ADD) ||
(ext_tcode == EXTCODE_LITTLE_ADD)) {
arm_req->buffer_length = sizeof(*store);
memcpy (arm_req->buffer, &data, sizeof(*store));
} else {
arm_req->buffer_length = 2 * sizeof(*store);
memcpy (arm_req->buffer, &arg, sizeof(*store));
memcpy (((arm_req->buffer) + sizeof(*store)),
&data, sizeof(*store));
}
if (rcode == RCODE_COMPLETE) {
arm_resp->buffer_length = sizeof(*store);
memcpy (arm_resp->buffer, &old, sizeof(*store));
} else {
arm_resp->buffer = NULL;
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(&host_info_lock);
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)
{
struct pending_request *req;
struct list_head *lh;
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(&host_info_lock);
hi = find_host_info(host); /* search addressentry in file_info's for host */
if (hi != NULL) {
list_for_each(lh, &hi->file_info_list) {
fi = list_entry(lh, struct file_info, 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(&host_info_lock);
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) {
DBGMSG("arm_lock64 -> entering notification-section");
req = __alloc_pending_request(SLAB_ATOMIC);
if (!req) {
spin_unlock(&host_info_lock);
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, SLAB_ATOMIC);
if (!(req->data)) {
free_pending_request(req);
spin_unlock(&host_info_lock);
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)));
arm_req->buffer = ((byte_t *)(arm_resp) +
(sizeof(struct arm_response)));
arm_resp->buffer = ((byte_t *)(arm_req->buffer) +
(2* sizeof(*store)));
if ((ext_tcode == EXTCODE_FETCH_ADD) ||
(ext_tcode == EXTCODE_LITTLE_ADD)) {
arm_req->buffer_length = sizeof(*store);
memcpy (arm_req->buffer, &data, sizeof(*store));
} else {
arm_req->buffer_length = 2 * sizeof(*store);
memcpy (arm_req->buffer, &arg, sizeof(*store));
memcpy (((arm_req->buffer) + sizeof(*store)),
&data, sizeof(*store));
}
if (rcode == RCODE_COMPLETE) {
arm_resp->buffer_length = sizeof(*store);
memcpy (arm_resp->buffer, &old, sizeof(*store));
} else {
arm_resp->buffer = NULL;
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(&host_info_lock);
return(rcode);
}
static int arm_register(struct file_info *fi, struct pending_request *req)
{
int retval;
struct arm_addr *addr;
struct list_head *lh, *lh_1, *lh_2;
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) & ~(0xFFFFFFFFFFFF)) != 0) ||
(((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFF)) != 0)) {
req->req.length = 0;
return (-EINVAL);
}
/* addr-list-entry for fileinfo */
addr = (struct arm_addr *)kmalloc(sizeof(struct arm_addr), SLAB_KERNEL);
if (!addr) {
req->req.length = 0;
return (-ENOMEM);
}
/* allocation of addr_space_buffer */
addr->addr_space_buffer = (u8 *)kmalloc(req->req.length,SLAB_KERNEL);
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)) {
kfree(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(lh, &hi->file_info_list) {
fi_hlp = list_entry(lh, struct file_info, 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 */
kfree(addr->addr_space_buffer);
kfree(addr);
spin_unlock_irqrestore(&host_info_lock, flags);
return (-EALREADY);
}
/* another host with valid address-entry containing same addressrange */
list_for_each(lh_1, &host_info_list) {
hi = list_entry(lh_1, struct host_info, list);
if (hi->host != fi->host) {
list_for_each(lh_2, &hi->file_info_list) {
fi_hlp = list_entry(lh_2, struct file_info, 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;
}
}
}
}
if (another_host) {
DBGMSG("another hosts entry is valid -> SUCCESS");
if (copy_to_user(int2ptr(req->req.recvb),
int2ptr(&addr->start),sizeof(u64))) {
printk(KERN_ERR "raw1394: arm_register failed "
" address-range-entry is invalid -> EFAULT !!!\n");
kfree(addr->addr_space_buffer);
kfree(addr);
spin_unlock_irqrestore(&host_info_lock, flags);
return (-EFAULT);
}
free_pending_request(req); /* immediate success or fail */
/* INSERT ENTRY */
list_add_tail(&addr->addr_list, &fi->addr_list);
spin_unlock_irqrestore(&host_info_lock, flags);
return sizeof(struct raw1394_request);
}
retval = hpsb_register_addrspace(hl_handle, &arm_ops, req->req.address,
req->req.address + req->req.length);
if (retval) {
/* INSERT ENTRY */
list_add_tail(&addr->addr_list, &fi->addr_list);
} else {
DBGMSG("arm_register failed errno: %d \n",retval);
kfree(addr->addr_space_buffer);
kfree(addr);
spin_unlock_irqrestore(&host_info_lock, flags);
return (-EALREADY);
}
spin_unlock_irqrestore(&host_info_lock, flags);
free_pending_request(req); /* immediate success or fail */
return sizeof(struct raw1394_request);
}
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 list_head *lh_1, *lh_2;
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(lh_1, &host_info_list) {
hi = list_entry(lh_1, struct host_info, list);
if (hi->host != fi->host) {
list_for_each(lh_2, &hi->file_info_list) {
fi_hlp = list_entry(lh_2, struct file_info, 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);
kfree(addr->addr_space_buffer);
kfree(addr);
free_pending_request(req); /* immediate success or fail */
spin_unlock_irqrestore(&host_info_lock, flags);
return sizeof(struct raw1394_request);
}
retval = hpsb_unregister_addrspace(hl_handle, 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);
kfree(addr->addr_space_buffer);
kfree(addr);
free_pending_request(req); /* immediate success or fail */
return sizeof(struct raw1394_request);
}
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 sizeof(struct raw1394_request);
}
/* 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;
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;
req->tq.data=req;
hpsb_add_packet_complete_task(packet, &req->tq);
spin_lock_irq(&fi->reqlists_lock);
list_add_tail(&req->list, &fi->req_pending);
spin_unlock_irq(&fi->reqlists_lock);
packet->generation = req->req.generation;
retval = hpsb_send_packet(packet);
DBGMSG("write_phypacket send_packet called => retval: %d ",
retval);
if (! retval) {
req->req.error = RAW1394_ERROR_SEND_ERROR;
req->req.length = 0;
queue_complete_req(req);
}
return sizeof(struct raw1394_request);
}
static int get_config_rom(struct file_info *fi, struct pending_request *req)
{
size_t return_size;
unsigned char rom_version;
int ret=sizeof(struct raw1394_request);
quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
int status;
if (!data) return -ENOMEM;
status = hpsb_get_config_rom(fi->host, data,
req->req.length, &return_size, &rom_version);
if (copy_to_user(int2ptr(req->req.recvb), data,
req->req.length))
ret = -EFAULT;
if (copy_to_user(int2ptr(req->req.tag), &return_size,
sizeof(return_size)))
ret = -EFAULT;
if (copy_to_user(int2ptr(req->req.address), &rom_version,
sizeof(rom_version)))
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=sizeof(struct raw1394_request);
quadlet_t *data = kmalloc(req->req.length, SLAB_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 */
}
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 sizeof(struct raw1394_request);
case RAW1394_REQ_ISO_SEND:
return handle_iso_send(fi, req, node);
case RAW1394_REQ_ARM_REGISTER:
return arm_register(fi, req);
case RAW1394_REQ_ARM_UNREGISTER:
return arm_unregister(fi, req);
case RAW1394_REQ_RESET_NOTIFY:
return reset_notification(fi, req);
case RAW1394_REQ_ISO_LISTEN:
handle_iso_listen(fi, req);
return sizeof(struct raw1394_request);
......@@ -831,21 +1908,49 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
return sizeof(struct raw1394_request);
case RAW1394_REQ_RESET_BUS:
hpsb_reset_bus(fi->host, LONG_RESET);
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 sizeof(struct raw1394_request);
}
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 sizeof(struct raw1394_request);
}
/* 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);
}
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 sizeof(struct raw1394_request);
}
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 sizeof(struct raw1394_request);
}
if (fi->host->node_id == node) {
return handle_local_request(fi, req, node);
}
return handle_remote_request(fi, req, node);
return handle_async_request(fi, req, node);
}
......@@ -921,6 +2026,7 @@ static int raw1394_open(struct inode *inode, struct file *file)
return -ENOMEM;
memset(fi, 0, sizeof(struct file_info));
fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */
INIT_LIST_HEAD(&fi->list);
fi->state = opened;
......@@ -929,6 +2035,7 @@ static int raw1394_open(struct inode *inode, struct file *file)
sema_init(&fi->complete_sem, 0);
spin_lock_init(&fi->reqlists_lock);
init_waitqueue_head(&fi->poll_wait_complete);
INIT_LIST_HEAD(&fi->addr_list);
file->private_data = fi;
......@@ -940,7 +2047,15 @@ 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 done = 0, i;
int done = 0, i, fail = 0;
int retval = 0;
struct list_head *entry;
struct arm_addr *addr = NULL;
struct list_head *lh_1, *lh_2;
struct host_info *hi;
struct file_info *fi_hlp = NULL;
struct arm_addr *arm_addr = NULL;
int another_host;
for (i = 0; i < 64; i++) {
if (fi->listen_channels & (1ULL << i)) {
......@@ -948,9 +2063,63 @@ static int raw1394_release(struct inode *inode, struct file *file)
}
}
spin_lock(&host_info_lock);
spin_lock_irq(&host_info_lock);
fi->listen_channels = 0;
spin_unlock(&host_info_lock);
spin_unlock_irq(&host_info_lock);
fail = 0;
/* set address-entries invalid */
spin_lock_irq(&host_info_lock);
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(lh_1, &host_info_list) {
hi = list_entry(lh_1, struct host_info, list);
if (hi->host != fi->host) {
list_for_each(lh_2, &hi->file_info_list) {
fi_hlp = list_entry(lh_2, struct file_info, 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(hl_handle, 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);
kfree(addr->addr_space_buffer);
kfree(addr);
} /* while */
spin_unlock_irq(&host_info_lock);
if (fail > 0) {
printk(KERN_ERR "raw1394: during addr_list-release "
"error(s) occured \n");
}
while (!done) {
spin_lock_irq(&fi->reqlists_lock);
......@@ -1009,28 +2178,28 @@ static int __init init_raw1394(void)
return -ENOMEM;
}
devfs_handle = devfs_register(NULL,
RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
devfs_handle = devfs_register(NULL,
RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
IEEE1394_MAJOR,
IEEE1394_MINOR_BLOCK_RAW1394 * 16,
IEEE1394_MINOR_BLOCK_RAW1394 * 16,
S_IFCHR | S_IRUSR | S_IWUSR, &file_ops,
NULL);
if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
THIS_MODULE, &file_ops)) {
THIS_MODULE, &file_ops)) {
HPSB_ERR("raw1394 failed to register minor device block");
devfs_unregister(devfs_handle);
hpsb_unregister_highlevel(hl_handle);
devfs_unregister(devfs_handle);
hpsb_unregister_highlevel(hl_handle);
return -EBUSY;
}
printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
return 0;
}
static void __exit cleanup_raw1394(void)
{
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
devfs_unregister(devfs_handle);
devfs_unregister(devfs_handle);
hpsb_unregister_highlevel(hl_handle);
}
......
......@@ -14,20 +14,32 @@
#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
#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
#define RAW1394_REQ_ASYNC_SEND 105
#define RAW1394_REQ_ISO_LISTEN 200
#define RAW1394_REQ_FCP_LISTEN 201
#define RAW1394_REQ_RESET_BUS 202
#define RAW1394_REQ_ISO_LISTEN 200
#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_ARM_REGISTER 300
#define RAW1394_REQ_ARM_UNREGISTER 301
#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
/* error codes */
#define RAW1394_ERROR_NONE 0
......@@ -45,6 +57,17 @@
#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>
......@@ -69,6 +92,29 @@ struct raw1394_khost_list {
__u8 name[32];
};
typedef struct arm_request {
nodeid_t destination_nodeid;
nodeid_t source_nodeid;
nodeaddr_t destination_offset;
u8 tlabel;
u8 tcode;
u_int8_t extended_transaction_code;
u_int32_t generation;
arm_length_t buffer_length;
byte_t *buffer;
} *arm_request_t;
typedef struct arm_response {
int response_code;
arm_length_t buffer_length;
byte_t *buffer;
} *arm_response_t;
typedef struct arm_request_response {
struct arm_request *request;
struct arm_response *response;
} *arm_request_response_t;
#ifdef __KERNEL__
struct iso_block_store {
......@@ -91,18 +137,34 @@ struct file_info {
spinlock_t reqlists_lock;
wait_queue_head_t poll_wait_complete;
struct list_head addr_list;
u8 *fcp_buffer;
u64 listen_channels;
quadlet_t *iso_buffer;
size_t iso_buffer_length;
u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
};
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 */
};
struct pending_request {
struct list_head list;
struct file_info *file_info;
struct hpsb_packet *packet;
struct tq_struct tq;
struct hpsb_queue_struct tq;
struct iso_block_store *ibs;
quadlet_t *data;
int free_data;
......
......@@ -351,7 +351,7 @@
#include "sbp2.h"
static char version[] __devinitdata =
"$Rev: 584 $ James Goodwin <jamesg@filanet.com>";
"$Rev: 601 $ James Goodwin <jamesg@filanet.com>";
/*
* Module load parameter definitions
......@@ -421,8 +421,9 @@ static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN;
* 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, then set sbp2_exclusive_login to
* zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
* filesystem supporting multiple hosts (one such filesystem is OpenGFS,
* see opengfs.sourceforge.net for more info), then set sbp2_exclusive_login
* to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
* concurrent logins.
*/
MODULE_PARM(sbp2_exclusive_login,"i");
......@@ -800,8 +801,9 @@ sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi,
* Set up a task queue completion routine, which returns
* the packet to the free list and releases the tlabel.
*/
request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet;
request_packet->tq.data = request_packet;
HPSB_PREPARE_WORK(&request_packet->tq,
(void (*)(void*))sbp2util_free_request_packet,
request_packet);
request_packet->hi_context = hi;
hpsb_add_packet_complete_task(packet, &request_packet->tq);
......@@ -1007,13 +1009,8 @@ static void sbp2util_free_command_dma(struct sbp2_command_info *command)
command->dma_size, command->dma_dir);
SBP2_DMA_FREE("single bulk");
} else if (command->dma_type == CMD_DMA_PAGE) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
pci_unmap_single(hi->host->pdev, command->cmd_dma,
command->dma_size, command->dma_dir);
#else
pci_unmap_page(hi->host->pdev, command->cmd_dma,
command->dma_size, command->dma_dir);
#endif /* Linux version < 2.4.13 */
SBP2_DMA_FREE("single page");
} /* XXX: Check for CMD_DMA_NONE bug */
command->dma_type = CMD_DMA_NONE;
......@@ -2146,17 +2143,11 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
command->dma_dir = dma_dir;
command->dma_size = sgpnt[0].length;
command->dma_type = CMD_DMA_PAGE;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address,
command->dma_size,
command->dma_dir);
#else
command->cmd_dma = pci_map_page(hi->host->pdev,
sgpnt[0].page,
sgpnt[0].offset,
command->dma_size,
command->dma_dir);
#endif /* Linux version < 2.4.13 */
SBP2_DMA_ALLOC("single page scatter element");
command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
......@@ -2702,7 +2693,7 @@ static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id,
* This function deals with status writes from the SBP-2 device
*/
static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
quadlet_t *data, u64 addr, unsigned int length)
quadlet_t *data, u64 addr, unsigned int length, u16 fl)
{
struct sbp2scsi_host_info *hi = NULL;
struct scsi_id_instance_data *scsi_id = NULL;
......@@ -3161,7 +3152,6 @@ static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int ge
heads = 64;
sectors = 32;
cylinders = (int)disk->capacity / (heads * sectors);
if (cylinders > 1024) {
heads = 255;
......
......@@ -324,7 +324,7 @@ struct sbp2_request_packet {
struct list_head list;
struct hpsb_packet *packet;
struct tq_struct tq;
struct hpsb_queue_struct tq;
void *hi_context;
};
......@@ -510,9 +510,9 @@ static void sbp2_remove_device(struct sbp2scsi_host_info *hi,
#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
u64 addr, unsigned int length);
u64 addr, unsigned int length, u16 flags);
static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
u64 addr, unsigned int length);
u64 addr, unsigned int length, u16 flags);
#endif
/*
......@@ -522,7 +522,7 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_insta
static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
quadlet_t *data, u64 addr, unsigned int length);
quadlet_t *data, u64 addr, unsigned int length, u16 flags);
static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags);
static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
struct scsi_id_instance_data *scsi_id,
......
......@@ -35,7 +35,6 @@
#include <linux/poll.h>
#include <linux/smp_lock.h>
#include <linux/proc_fs.h>
#include <linux/tqueue.h>
#include <linux/delay.h>
#include <linux/devfs_fs_kernel.h>
......@@ -1455,12 +1454,7 @@ static int __init video1394_init_module (void)
return -EIO;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME,
strlen(VIDEO1394_DRIVER_NAME), NULL);
#else
devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME, NULL);
#endif
hl_handle = hpsb_register_highlevel (VIDEO1394_DRIVER_NAME, &hl_ops);
if (hl_handle == NULL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment