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

[PATCH] IEEE-1394/Firewire updates

- Cleaned up hostinfo usage in all drivers and created a central API to
  handle them all.
- Fixup some spinlock mis-usage.
- Remove devfs_handle mis-usage.
- Cleaned up some heavy handed spinlocking to use mutexes instead.
- Add function to send PHY config packets and use to to settle
  IRM/cycle-master/root descrepancies.
parent 77ad1af8
......@@ -266,12 +266,10 @@ struct amdtp_host {
struct ti_ohci *ohci;
struct list_head stream_list;
spinlock_t stream_list_lock;
struct list_head link;
};
static struct hpsb_highlevel *amdtp_highlevel;
static LIST_HEAD(host_list);
static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
/* FIXME: This doesn't belong here... */
......@@ -347,7 +345,7 @@ static void stream_start_dma(struct stream *s, struct packet_list *pl)
{
u32 syt_cycle, cycle_count, start_cycle;
cycle_count = reg_read(s->host->host->hostdata,
cycle_count = reg_read(s->host->ohci,
OHCI1394_IsochronousCycleTimer) >> 12;
syt_cycle = (pl->last_cycle_count - PACKET_LIST_SIZE + 1) & 0x0f;
......@@ -1169,15 +1167,9 @@ static unsigned int amdtp_poll(struct file *file, poll_table *pt)
static int amdtp_open(struct inode *inode, struct file *file)
{
struct amdtp_host *host;
int i = ieee1394_file_to_instance(file);
/* FIXME: We just grab the first registered host */
spin_lock(&host_list_lock);
if (!list_empty(&host_list))
host = list_entry(host_list.next, struct amdtp_host, link);
else
host = NULL;
spin_unlock(&host_list_lock);
host = hpsb_get_hostinfo_bykey(amdtp_highlevel, i);
if (host == NULL)
return -ENODEV;
......@@ -1209,44 +1201,45 @@ static struct file_operations amdtp_fops =
/* IEEE1394 Subsystem functions */
static void amdtp_add_host(struct hpsb_host *host)
static void amdtp_add_host(struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct amdtp_host *ah;
int minor;
char name[16];
if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME) != 0)
return;
ah = kmalloc(sizeof *ah, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
ah = hpsb_create_hostinfo(hl, host, sizeof(*ah));
if (!ah) {
HPSB_ERR("amdtp: Unable able to alloc hostinfo");
return;
}
ah->host = host;
ah->ohci = host->hostdata;
hpsb_set_hostinfo_key(hl, host, ah->ohci->id);
minor = IEEE1394_MINOR_BLOCK_AMDTP * 16 + ah->ohci->id;
sprintf(name, "amdtp/%d", ah->ohci->id);
INIT_LIST_HEAD(&ah->stream_list);
spin_lock_init(&ah->stream_list_lock);
spin_lock_irq(&host_list_lock);
list_add_tail(&ah->link, &host_list);
spin_unlock_irq(&host_list_lock);
devfs_register(NULL, name, 0, IEEE1394_MAJOR, minor,
S_IFCHR | S_IRUSR | S_IWUSR, &amdtp_fops, NULL);
}
static void amdtp_remove_host(struct hpsb_host *host)
{
struct list_head *lh;
struct amdtp_host *ah;
struct amdtp_host *ah = hpsb_get_hostinfo(amdtp_highlevel, host);
spin_lock_irq(&host_list_lock);
list_for_each(lh, &host_list) {
if (list_entry(lh, struct amdtp_host, link)->host == host) {
list_del(lh);
break;
}
}
spin_unlock_irq(&host_list_lock);
if (lh != &host_list) {
ah = list_entry(lh, struct amdtp_host, link);
kfree(ah);
}
else
HPSB_ERR("remove_host: bogus ohci host: %p", host);
if (ah)
devfs_remove("amdtp/%d", ah->ohci->id);
return;
}
static struct hpsb_highlevel_ops amdtp_highlevel_ops = {
......@@ -1273,10 +1266,13 @@ static int __init amdtp_init_module (void)
return -EIO;
}
devfs_mk_dir("amdtp");
amdtp_highlevel = hpsb_register_highlevel ("amdtp",
&amdtp_highlevel_ops);
if (amdtp_highlevel == NULL) {
HPSB_ERR("amdtp: unable to register highlevel ops");
devfs_remove("amdtp");
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
return -EIO;
}
......@@ -1309,6 +1305,7 @@ static void __exit amdtp_exit_module (void)
#endif
hpsb_unregister_highlevel(amdtp_highlevel);
devfs_remove("amdtp");
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
HPSB_INFO("Unloaded AMDTP driver");
......
......@@ -65,8 +65,6 @@ struct cmp_host {
quadlet_t impr_quadlet;
} v;
struct plug ipcr[2];
struct list_head link;
};
enum {
......@@ -79,31 +77,6 @@ enum {
static struct hpsb_highlevel *cmp_highlevel;
static LIST_HEAD(host_list);
static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
static struct cmp_host *
lookup_cmp_host(struct hpsb_host *host)
{
struct cmp_host *ch;
struct list_head *lh;
unsigned long flags;
ch = NULL;
spin_lock_irqsave(&host_list_lock, flags);
list_for_each(lh, &host_list) {
ch = list_entry(lh, struct cmp_host, link);
if (ch->host == host)
break;
}
spin_unlock_irqrestore(&host_list_lock, flags);
if (lh == &host_list)
return NULL;
else
return ch;
}
struct cmp_pcr *
cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload,
void (*update)(struct cmp_pcr *pcr, void *data),
......@@ -112,7 +85,7 @@ cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload,
struct cmp_host *ch;
struct plug *plug;
ch = lookup_cmp_host(host);
ch = hpsb_get_hostinfo(cmp_highlevel, host);
if (opcr_number >= ch->u.ompr.nplugs ||
ch->opcr[opcr_number].update != NULL)
......@@ -135,7 +108,7 @@ void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *opcr)
struct cmp_host *ch;
struct plug *plug;
ch = lookup_cmp_host(host);
ch = hpsb_get_hostinfo(cmp_highlevel, host);
plug = (struct plug *)opcr;
if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG();
......@@ -155,48 +128,34 @@ static void reset_plugs(struct cmp_host *ch)
}
}
static void cmp_add_host(struct hpsb_host *host)
static void cmp_add_host(struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct cmp_host *ch;
struct cmp_host *ch = hpsb_create_hostinfo(hl, host, sizeof (*ch));
ch = kmalloc(sizeof *ch, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
if (ch == NULL) {
HPSB_ERR("Failed to allocate cmp_host");
return;
}
memset(ch, 0, sizeof *ch);
ch->host = host;
ch->u.ompr.rate = SPEED_100;
ch->u.ompr.bcast_channel_base = 63;
ch->u.ompr.nplugs = 2;
reset_plugs(ch);
spin_lock_irq(&host_list_lock);
list_add_tail(&ch->link, &host_list);
spin_unlock_irq(&host_list_lock);
}
static void cmp_host_reset(struct hpsb_host *host)
{
struct cmp_host *ch;
ch = lookup_cmp_host(host);
if (ch == NULL) BUG();
reset_plugs(ch);
}
static void cmp_remove_host(struct hpsb_host *host)
static void cmp_host_reset(struct hpsb_host *host)
{
struct cmp_host *ch;
ch = lookup_cmp_host(host);
if (ch == NULL) BUG();
spin_lock_irq(&host_list_lock);
list_del(&ch->link);
spin_unlock_irq(&host_list_lock);
ch = hpsb_get_hostinfo(cmp_highlevel, host);
if (ch == NULL) {
HPSB_ERR("cmp: Tried to reset unknown host");
return;
}
kfree(ch);
reset_plugs(ch);
}
static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
......@@ -209,7 +168,7 @@ static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
if (length != 4)
return RCODE_TYPE_ERROR;
ch = lookup_cmp_host(host);
ch = hpsb_get_hostinfo(cmp_highlevel, host);
if (csraddr == 0x900) {
*buf = cpu_to_be32(ch->u.ompr_quadlet);
return RCODE_COMPLETE;
......@@ -242,7 +201,7 @@ static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
int plug;
struct cmp_host *ch;
ch = lookup_cmp_host(host);
ch = hpsb_get_hostinfo(cmp_highlevel, host);
if (extcode != EXTCODE_COMPARE_SWAP)
return RCODE_TYPE_ERROR;
......@@ -301,7 +260,6 @@ static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
static struct hpsb_highlevel_ops cmp_highlevel_ops = {
.add_host = cmp_add_host,
.remove_host = cmp_remove_host,
.host_reset = cmp_host_reset,
};
......
......@@ -90,7 +90,7 @@ static void host_reset(struct hpsb_host *host)
}
static void add_host(struct hpsb_host *host)
static void add_host(struct hpsb_host *host, struct hpsb_highlevel *hl)
{
host->csr.lock = SPIN_LOCK_UNLOCKED;
......@@ -118,7 +118,9 @@ static void add_host(struct hpsb_host *host)
int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
size_t size, unsigned char rom_version)
{
int ret,flags;
unsigned long flags;
int ret;
spin_lock_irqsave(&host->csr.lock, flags);
if (rom_version != host->csr.rom_version)
ret = -1;
......@@ -137,7 +139,9 @@ int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
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;
unsigned long flags;
int ret;
spin_lock_irqsave(&host->csr.lock, flags);
*rom_version=host->csr.rom_version;
*rom_size=host->csr.rom_size;
......@@ -156,9 +160,9 @@ int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64 addr, unsigned int length, u16 fl)
{
unsigned long flags;
int csraddr = addr - CSR_REGISTER_BASE;
const char *src;
int flags;
spin_lock_irqsave(&host->csr.lock, flags);
......
......@@ -403,9 +403,6 @@ struct video_card {
/* entry in dv1394_cards */
struct list_head list;
/* handle to /dev/ieee1394/dv/N, NULL if devfs not in use */
devfs_handle_t devfs_handle;
/* OHCI card IT DMA context number, -1 if not in use */
int ohci_it_ctx;
struct ohci1394_iso_tasklet it_tasklet;
......
......@@ -2458,14 +2458,9 @@ static int dv1394_devfs_add_entry(struct video_card *video)
(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
(video->mode == MODE_RECEIVE ? "in" : "out"));
video->devfs_handle = devfs_register(NULL, buf, 0, IEEE1394_MAJOR,
IEEE1394_MINOR_BLOCK_DV1394*16 + video->id,
S_IFCHR | S_IRUGO | S_IWUGO,
&dv1394_fops, video);
if (video->devfs_handle == NULL) {
printk(KERN_ERR "dv1394: unable to create /dev/%s\n", buf);
return -ENOMEM;
}
devfs_register(NULL, buf, 0, IEEE1394_MAJOR,
IEEE1394_MINOR_BLOCK_DV1394*16 + video->id,
S_IFCHR | S_IRUGO | S_IWUGO, &dv1394_fops, video);
return 0;
}
#endif /* CONFIG_DEVFS_FS */
......@@ -2650,7 +2645,7 @@ static void dv1394_remove_host (struct hpsb_host *host)
#endif
}
static void dv1394_add_host (struct hpsb_host *host)
static void dv1394_add_host (struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct ti_ohci *ohci;
char buf[16];
......
......@@ -78,7 +78,7 @@
printk(KERN_ERR fmt, ## args)
static char version[] __devinitdata =
"$Rev: 806 $ Ben Collins <bcollins@debian.org>";
"$Rev: 886 $ Ben Collins <bcollins@debian.org>";
/* Our ieee1394 highlevel driver */
#define ETHER1394_DRIVER_NAME "ether1394"
......@@ -86,9 +86,6 @@ static char version[] __devinitdata =
static kmem_cache_t *packet_task_cache;
static struct hpsb_highlevel *hl_handle = NULL;
/* Card handling */
static LIST_HEAD (host_info_list);
static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
/* Use common.lf to determine header len */
static int hdr_type_len[] = {
......@@ -105,40 +102,6 @@ MODULE_LICENSE("GPL");
static void ether1394_iso(struct hpsb_iso *iso);
/* Find our host_info struct for a given host pointer. Must be called
* under spinlock. */
static inline struct host_info *find_host_info (struct hpsb_host *host)
{
struct list_head *lh;
struct host_info *hi;
lh = host_info_list.next;
while (lh != &host_info_list) {
hi = list_entry (lh, struct host_info, list);
if (hi->host == host)
return hi;
lh = lh->next;
}
return NULL;
}
/* Find the network device for our host */
static inline struct net_device *ether1394_find_dev (struct hpsb_host *host)
{
struct host_info *hi;
spin_lock_irq (&host_info_lock);
hi = find_host_info (host);
spin_unlock_irq (&host_info_lock);
if (hi == NULL)
return NULL;
return hi->dev;
}
/* This is called after an "ifup" */
static int ether1394_open (struct net_device *dev)
{
......@@ -355,7 +318,7 @@ static int ether1394_init_dev (struct net_device *dev)
* 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)
static void ether1394_add_host (struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct host_info *hi = NULL;
struct net_device *dev = NULL;
......@@ -378,30 +341,22 @@ static void ether1394_add_host (struct hpsb_host *host)
priv->host = host;
hi = (struct host_info *)kmalloc (sizeof (struct host_info),
in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
hi = hpsb_create_hostinfo(hl, host, sizeof(*hi));
if (hi == NULL)
goto out;
if (register_netdev (dev)) {
ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n");
kfree (dev);
kfree (hi);
return;
goto out;
}
ETH1394_PRINT (KERN_ERR, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (%s)\n",
host->driver->name);
INIT_LIST_HEAD (&hi->list);
hi->host = host;
hi->dev = dev;
spin_lock_irq (&host_info_lock);
list_add_tail (&hi->list, &host_info_list);
spin_unlock_irq (&host_info_lock);
/* Ignore validity in hopes that it will be set in the future. It'll
* check it on transmit. */
priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
......@@ -416,6 +371,9 @@ static void ether1394_add_host (struct hpsb_host *host)
out:
if (dev != NULL)
kfree (dev);
if (hi)
hpsb_destroy_hostinfo(hl, host);
ETH1394_PRINT_G (KERN_ERR, "Out of memory\n");
return;
......@@ -424,20 +382,17 @@ static void ether1394_add_host (struct hpsb_host *host)
/* Remove a card from our list */
static void ether1394_remove_host (struct hpsb_host *host)
{
struct eth1394_priv *priv;
struct host_info *hi;
struct host_info *hi = hpsb_get_hostinfo(hl_handle, host);
spin_lock_irq (&host_info_lock);
hi = find_host_info (host);
if (hi != NULL) {
priv = (struct eth1394_priv *)hi->dev->priv;
struct eth1394_priv *priv = (struct eth1394_priv *)hi->dev->priv;
priv->bc_state = ETHER1394_BC_CLOSED;
unregister_netdev (hi->dev);
hpsb_iso_shutdown(priv->iso);
kfree (hi->dev);
list_del (&hi->list);
kfree (hi);
}
spin_unlock_irq (&host_info_lock);
return;
}
......@@ -445,12 +400,15 @@ static void ether1394_remove_host (struct hpsb_host *host)
/* A reset has just arisen */
static void ether1394_host_reset (struct hpsb_host *host)
{
struct net_device *dev = ether1394_find_dev(host);
struct host_info *hi = hpsb_get_hostinfo(hl_handle, host);
struct net_device *dev;
/* This can happen for hosts that we don't use */
if (dev == NULL)
if (hi == NULL)
return;
dev = hi->dev;
/* Reset our private host data, but not our mtu */
netif_stop_queue (dev);
ether1394_reset_priv (dev, 0);
......@@ -559,15 +517,18 @@ static int ether1394_write (struct hpsb_host *host, int srcid, int destid,
struct sk_buff *skb;
char *buf = (char *)data;
unsigned long flags;
struct net_device *dev = ether1394_find_dev (host);
struct host_info *hi = hpsb_get_hostinfo(hl_handle, host);
struct net_device *dev;
struct eth1394_priv *priv;
if (dev == NULL) {
if (hi == NULL) {
ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %p\n",
host);
return RCODE_ADDRESS_ERROR;
}
dev = hi->dev;
priv = (struct eth1394_priv *)dev->priv;
/* A packet has been received by the ieee1394 bus. Build an skbuff
......@@ -627,8 +588,9 @@ static void ether1394_iso(struct hpsb_iso *iso)
struct sk_buff *skb;
quadlet_t *data;
char *buf;
int flags;
struct net_device *dev = ether1394_find_dev(iso->host);
unsigned long flags;
struct host_info *hi = hpsb_get_hostinfo(hl_handle, iso->host);
struct net_device *dev;
struct eth1394_priv *priv;
unsigned int len;
u32 specifier_id;
......@@ -636,12 +598,14 @@ static void ether1394_iso(struct hpsb_iso *iso)
int i;
int nready;
if (dev == NULL) {
if (hi == NULL) {
ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %s\n",
iso->host->driver->name);
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];
......@@ -941,19 +905,6 @@ static int __init ether1394_init_module (void)
static void __exit ether1394_exit_module (void)
{
struct list_head *lh;
struct host_info *hi;
struct eth1394_priv *priv;
lh = host_info_list.next;
while (lh != &host_info_list) {
hi = list_entry (lh, struct host_info, list);
priv = (struct eth1394_priv*)hi->dev->priv;
if (priv->bc_state != ETHER1394_BC_CLOSED) {
hpsb_iso_shutdown(priv->iso);
}
lh = lh->next;
}
hpsb_unregister_highlevel (hl_handle);
kmem_cache_destroy(packet_task_cache);
}
......
......@@ -56,7 +56,6 @@ struct eth1394_priv {
};
struct host_info {
struct list_head list;
struct hpsb_host *host;
struct net_device *dev;
};
......
......@@ -19,6 +19,7 @@
#include <linux/config.h>
#include <linux/slab.h>
#include <linux/list.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
......@@ -27,20 +28,192 @@
#include "highlevel.h"
LIST_HEAD(hl_drivers);
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_MUTEX(hl_drivers_lock);
LIST_HEAD(addr_space);
rwlock_t addr_space_lock = RW_LOCK_UNLOCKED;
static LIST_HEAD(addr_space);
static rwlock_t addr_space_lock = RW_LOCK_UNLOCKED;
/* addr_space list will have zero and max already included as bounds */
static struct hpsb_address_ops dummy_ops = { NULL, NULL, NULL, NULL };
static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr;
/* Internal usage. Must be called with hl_drivers_lock held */
static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
struct hpsb_host *host)
{
struct hl_host_info *hi;
struct list_head *lh;
list_for_each (lh, &hl->host_info_list) {
hi = list_entry(lh, struct hl_host_info, list);
if (hi->host == host)
return hi;
}
return NULL;
}
/* Returns a per host/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;
void *data = NULL;
read_lock(&hl_drivers_lock);
hi = hl_get_hostinfo(hl, host);
if (hi)
data = hi->data;
read_unlock(&hl_drivers_lock);
return data;
}
/* If 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;
read_lock(&hl_drivers_lock);
hi = hl_get_hostinfo(hl, host);
read_unlock(&hl_drivers_lock);
if (hi) {
HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already exists",
hl->name);
return NULL;
}
hi = kmalloc(sizeof(*hi) + data_size, GFP_KERNEL);
if (!hi)
return NULL;
memset(hi, 0, sizeof(*hi) + data_size);
if (data_size) {
data = hi->data = hi + 1;
hi->size = data_size;
} else
data = hi;
hi->host = host;
write_lock_irq(&hl_drivers_lock);
list_add_tail(&hi->list, &hl->host_info_list);
write_unlock_irq(&hl_drivers_lock);
return data;
}
int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
void *data)
{
struct hl_host_info *hi;
int ret = -EINVAL;
write_lock_irq(&hl_drivers_lock);
hi = hl_get_hostinfo(hl, host);
if (hi) {
if (!hi->size && !hi->data) {
hi->data = data;
ret = 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);
write_unlock_irq(&hl_drivers_lock);
return ret;
}
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
{
struct hl_host_info *hi;
write_lock_irq(&hl_drivers_lock);
hi = hl_get_hostinfo(hl, host);
if (hi) {
list_del(&hi->list);
kfree(hi);
}
write_unlock_irq(&hl_drivers_lock);
return;
}
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key)
{
struct hl_host_info *hi;
write_lock(&hl_drivers_lock);
hi = hl_get_hostinfo(hl, host);
if (hi)
hi->key = key;
write_unlock(&hl_drivers_lock);
return;
}
unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host)
{
struct hl_host_info *hi;
unsigned long key = 0;
read_lock(&hl_drivers_lock);
hi = hl_get_hostinfo(hl, host);
if (hi)
key = hi->key;
read_unlock(&hl_drivers_lock);
return key;
}
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
{
struct list_head *lh;
struct hl_host_info *hi;
void *data = NULL;
read_lock(&hl_drivers_lock);
list_for_each (lh, &hl->host_info_list) {
hi = list_entry(lh, struct hl_host_info, list);
if (hi->key == key) {
data = hi->data;
break;
}
}
read_unlock(&hl_drivers_lock);
return data;
}
struct hpsb_highlevel *hpsb_register_highlevel(const char *name,
struct hpsb_highlevel_ops *ops)
{
struct hpsb_highlevel *hl;
struct list_head *lh;
hl = (struct hpsb_highlevel *)kmalloc(sizeof(struct hpsb_highlevel),
GFP_KERNEL);
......@@ -50,6 +223,8 @@ struct hpsb_highlevel *hpsb_register_highlevel(const char *name,
INIT_LIST_HEAD(&hl->hl_list);
INIT_LIST_HEAD(&hl->addr_list);
INIT_LIST_HEAD(&hl->host_info_list);
hl->name = name;
hl->op = ops;
......@@ -57,15 +232,21 @@ struct hpsb_highlevel *hpsb_register_highlevel(const char *name,
list_add_tail(&hl->hl_list, &hl_drivers);
up(&hl_drivers_lock);
if (hl->op->add_host)
hl_all_hosts(hl->op->add_host);
if (hl->op->add_host) {
down(&hpsb_hosts_lock);
list_for_each (lh, &hpsb_hosts) {
struct hpsb_host *host = list_entry(lh, struct hpsb_host, host_list);
hl->op->add_host(host, hl);
}
up(&hpsb_hosts_lock);
}
return hl;
}
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
{
struct list_head *entry;
struct list_head *lh, *next;
struct hpsb_address_serve *as;
if (hl == NULL) {
......@@ -73,12 +254,9 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
}
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);
list_for_each_safe (lh, next, &hl->addr_list) {
as = list_entry(lh, struct hpsb_address_serve, addr_list);
list_del(&as->as_list);
entry = entry->next;
kfree(as);
}
write_unlock_irq(&addr_space_lock);
......@@ -87,8 +265,16 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
list_del(&hl->hl_list);
up(&hl_drivers_lock);
if (hl->op->remove_host)
hl_all_hosts(hl->op->remove_host);
if (hl->op->remove_host) {
down(&hpsb_hosts_lock);
list_for_each(lh, &hpsb_hosts) {
struct hpsb_host *host = list_entry(lh, struct hpsb_host, host_list);
hl->op->remove_host(host);
hpsb_destroy_hostinfo(hl, host);
}
up(&hpsb_hosts_lock);
}
kfree(hl);
}
......@@ -206,7 +392,7 @@ void highlevel_add_host(struct hpsb_host *host)
hl = list_entry(entry, struct hpsb_highlevel, hl_list);
if (hl->op->add_host)
hl->op->add_host(host);
hl->op->add_host(host, hl);
}
up(&hl_drivers_lock);
}
......@@ -220,8 +406,10 @@ void highlevel_remove_host(struct hpsb_host *host)
list_for_each(entry, &hl_drivers) {
hl = list_entry(entry, struct hpsb_highlevel, hl_list);
if (hl->op->remove_host)
if (hl->op->remove_host) {
hl->op->remove_host(host);
hpsb_destroy_hostinfo(hl, host);
}
}
up(&hl_drivers_lock);
}
......
......@@ -11,6 +11,9 @@ struct hpsb_highlevel {
const char *name;
struct hpsb_highlevel_ops *op;
/* Used by the highlevel drivers to store data per host */
struct list_head host_info_list;
};
......@@ -38,7 +41,7 @@ struct hpsb_highlevel_ops {
/* New host initialized. Will also be called during
* hpsb_register_highlevel for all hosts already installed. */
void (*add_host) (struct hpsb_host *host);
void (*add_host) (struct hpsb_host *host, struct hpsb_highlevel *hl);
/* Host about to be removed. Will also be called during
* hpsb_unregister_highlevel once for each host. */
......@@ -155,4 +158,23 @@ int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel);
/* Retrieve a hostinfo pointer bound to this driver/host */
void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
/* Allocate a hostinfo pointer of data_size bound to this driver/host */
void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
size_t data_size);
/* Free and remove the hostinfo pointer bound to this driver/host */
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
/* Set an alternate lookup key for the hostinfo bound to this driver/host */
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key);
/* Retrieve the alternate lookup key for the hostinfo bound to this driver/host */
unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host);
/* Retrive a hostinfo pointer bound to this driver using its alternate key */
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
/* 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);
#endif /* IEEE1394_HIGHLEVEL_H */
......@@ -22,12 +22,8 @@
#include "ieee1394_core.h"
#include "highlevel.h"
static struct list_head hosts = LIST_HEAD_INIT(hosts);
static struct list_head host_drivers = LIST_HEAD_INIT(host_drivers);
spinlock_t hosts_lock = SPIN_LOCK_UNLOCKED;
spinlock_t host_drivers_lock = SPIN_LOCK_UNLOCKED;
LIST_HEAD(hpsb_hosts);
DECLARE_MUTEX(hpsb_hosts_lock);
static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
{
......@@ -64,11 +60,10 @@ static struct hpsb_host_driver dummy_driver = {
int hpsb_ref_host(struct hpsb_host *host)
{
struct list_head *lh;
unsigned long flags;
int retval = 0;
spin_lock_irqsave(&hosts_lock, flags);
list_for_each(lh, &hosts) {
down(&hpsb_hosts_lock);
list_for_each(lh, &hpsb_hosts) {
if (host == list_entry(lh, struct hpsb_host, host_list)) {
if (try_module_get(host->driver->owner)) {
host->refcount++;
......@@ -77,7 +72,7 @@ int hpsb_ref_host(struct hpsb_host *host)
break;
}
}
spin_unlock_irqrestore(&hosts_lock, flags);
up(&hpsb_hosts_lock);
return retval;
}
......@@ -93,16 +88,14 @@ int hpsb_ref_host(struct hpsb_host *host)
void hpsb_unref_host(struct hpsb_host *host)
{
unsigned long flags;
module_put(host->driver->owner);
spin_lock_irqsave(&hosts_lock, flags);
down(&hpsb_hosts_lock);
host->refcount--;
if (!host->refcount && host->is_shutdown)
kfree(host);
spin_unlock_irqrestore(&hosts_lock, flags);
up(&hpsb_hosts_lock);
}
/**
......@@ -157,11 +150,9 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra)
void hpsb_add_host(struct hpsb_host *host)
{
unsigned long flags;
spin_lock_irqsave(&hosts_lock, flags);
list_add_tail(&host->host_list, &hosts);
spin_unlock_irqrestore(&hosts_lock, flags);
down(&hpsb_hosts_lock);
list_add_tail(&host->host_list, &hpsb_hosts);
up(&hpsb_hosts_lock);
highlevel_add_host(host);
host->driver->devctl(host, RESET_BUS, LONG_RESET);
......@@ -169,29 +160,11 @@ void hpsb_add_host(struct hpsb_host *host)
void hpsb_remove_host(struct hpsb_host *host)
{
unsigned long flags;
down(&hpsb_hosts_lock);
host->is_shutdown = 1;
host->driver = &dummy_driver;
highlevel_remove_host(host);
list_del(&host->host_list);
up(&hpsb_hosts_lock);
spin_lock_irqsave(&hosts_lock, flags);
list_del(&host->host_list);
spin_unlock_irqrestore(&hosts_lock, flags);
}
/*
* This function calls the given function for every host currently registered.
*/
void hl_all_hosts(void (*function)(struct hpsb_host*))
{
struct list_head *lh;
struct hpsb_host *host;
spin_lock_irq(&hosts_lock);
list_for_each (lh, &hosts) {
host = list_entry(lh, struct hpsb_host, host_list);
function(host);
}
spin_unlock_irq(&hosts_lock);
highlevel_remove_host(host);
}
......@@ -188,9 +188,9 @@ struct hpsb_host_driver {
quadlet_t data, quadlet_t compare);
};
/* high level internal use */
struct hpsb_highlevel;
void hl_all_hosts(void (*function)(struct hpsb_host*));
extern struct list_head hpsb_hosts;
extern struct semaphore hpsb_hosts_lock;
/*
......
......@@ -404,29 +404,6 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
atomic_inc(&host->generation);
host->in_bus_reset = 0;
highlevel_host_reset(host);
/* check for common cycle master error */
hpsb_check_cycle_master(host);
}
void hpsb_check_cycle_master(struct hpsb_host *host)
{
/* check if host is IRM and not ROOT */
if (host->is_irm && !host->is_root) {
HPSB_NOTICE("Host is IRM but not root, resetting");
if (host->reset_retries++ < 4) {
/* selfid stage did not yield valid cycle master */
hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
} else {
host->reset_retries = 0;
HPSB_NOTICE("Stopping out-of-control reset loop");
HPSB_NOTICE("Warning - Cycle Master not set correctly");
}
return;
}
host->reset_retries = 0;
}
......@@ -462,6 +439,63 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
hpsb_schedule_work(&host->timeout_tq);
}
/**
* 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 error number otherwise.
*/
int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
{
struct hpsb_packet *packet;
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;
}
packet = alloc_hpsb_packet(0);
if (!packet)
return -ENOMEM;
packet->host = host;
packet->header_size = 16;
packet->data_size = 0;
packet->expect_response = 0;
packet->no_waiter = 0;
packet->type = hpsb_raw;
packet->header[0] = 0;
if(rootid != -1)
packet->header[0] |= rootid << 24 | 1 << 23;
if(gapcnt != -1)
packet->header[0] |= gapcnt << 16 | 1 << 22;
packet->header[1] = ~packet->header[0];
packet->generation = get_hpsb_generation(host);
HPSB_DEBUG("Sending PHY configuration packet (I hope)...");
if (!hpsb_send_packet(packet)) {
retval = -EINVAL;
goto fail;
}
down(&packet->state_change);
down(&packet->state_change);
fail:
free_hpsb_packet(packet);
return retval;
}
/**
* hpsb_send_packet - transmit a packet on the bus
* @packet: packet to send
......@@ -983,9 +1017,6 @@ static struct file_operations ieee1394_chardev_ops = {
.open = ieee1394_dispatch_open,
};
devfs_handle_t ieee1394_devfs_handle;
/* claim a block of minor numbers */
int ieee1394_register_chardev(int blocknum,
struct module *module,
......@@ -1150,11 +1181,11 @@ static int __init ieee1394_init(void)
hpsb_packet_cache = kmem_cache_create("hpsb_packet", sizeof(struct hpsb_packet),
0, 0, NULL, NULL);
ieee1394_devfs_handle = devfs_mk_dir("ieee1394");
devfs_mk_dir("ieee1394");
if (register_chrdev(IEEE1394_MAJOR, "ieee1394", &ieee1394_chardev_ops)) {
HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
devfs_unregister(ieee1394_devfs_handle);
devfs_remove("ieee1394");
return -ENODEV;
}
......@@ -1165,7 +1196,7 @@ static int __init ieee1394_init(void)
if (ieee1394_procfs_entry == NULL) {
HPSB_ERR("unable to create /proc/bus/ieee1394\n");
unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
devfs_unregister(ieee1394_devfs_handle);
devfs_remove("ieee1394");
return -ENOMEM;
}
ieee1394_procfs_entry->owner = THIS_MODULE;
......@@ -1190,10 +1221,7 @@ static void __exit ieee1394_cleanup(void)
kmem_cache_destroy(hpsb_packet_cache);
unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
/* it's ok to pass a NULL devfs_handle to devfs_unregister */
devfs_unregister(ieee1394_devfs_handle);
devfs_remove("ieee1394");
remove_proc_entry("ieee1394", proc_bus);
}
......@@ -1214,17 +1242,16 @@ EXPORT_SYMBOL(hpsb_speedto_str);
EXPORT_SYMBOL(hpsb_set_packet_complete_task);
EXPORT_SYMBOL(alloc_hpsb_packet);
EXPORT_SYMBOL(free_hpsb_packet);
EXPORT_SYMBOL(hpsb_send_phy_config);
EXPORT_SYMBOL(hpsb_send_packet);
EXPORT_SYMBOL(hpsb_reset_bus);
EXPORT_SYMBOL(hpsb_bus_reset);
EXPORT_SYMBOL(hpsb_selfid_received);
EXPORT_SYMBOL(hpsb_selfid_complete);
EXPORT_SYMBOL(hpsb_check_cycle_master);
EXPORT_SYMBOL(hpsb_packet_sent);
EXPORT_SYMBOL(hpsb_packet_received);
EXPORT_SYMBOL(ieee1394_register_chardev);
EXPORT_SYMBOL(ieee1394_unregister_chardev);
EXPORT_SYMBOL(ieee1394_devfs_handle);
EXPORT_SYMBOL(ieee1394_procfs_entry);
/** ieee1394_transactions.c **/
......@@ -1250,6 +1277,13 @@ EXPORT_SYMBOL(hpsb_register_addrspace);
EXPORT_SYMBOL(hpsb_unregister_addrspace);
EXPORT_SYMBOL(hpsb_listen_channel);
EXPORT_SYMBOL(hpsb_unlisten_channel);
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_key);
EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
EXPORT_SYMBOL(hpsb_set_hostinfo);
EXPORT_SYMBOL(highlevel_read);
EXPORT_SYMBOL(highlevel_write);
EXPORT_SYMBOL(highlevel_lock);
......@@ -1302,4 +1336,3 @@ EXPORT_SYMBOL(hpsb_iso_n_ready);
EXPORT_SYMBOL(hpsb_iso_packet_sent);
EXPORT_SYMBOL(hpsb_iso_packet_received);
EXPORT_SYMBOL(hpsb_iso_wake);
......@@ -108,6 +108,11 @@ static inline unsigned int get_hpsb_generation(struct hpsb_host *host)
return atomic_read(&host->generation);
}
/*
* Send a PHY configuration packet.
*/
int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt);
/*
* Queue packet for transmitting, return 0 for failure.
*/
......@@ -140,12 +145,6 @@ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
*/
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
/*
* Check bus reset results to find cycle master
*/
void hpsb_check_cycle_master(struct hpsb_host *host);
/*
* 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
......@@ -225,9 +224,6 @@ int ieee1394_register_chardev(int blocknum, /* 0-15 */
/* release a block of minor numbers */
void ieee1394_unregister_chardev(int blocknum);
/* the devfs handle for /dev/ieee1394; NULL if devfs is not in use */
extern devfs_handle_t ieee1394_devfs_handle;
/* the proc_fs entry for /proc/ieee1394 */
extern struct proc_dir_entry *ieee1394_procfs_entry;
......
......@@ -70,8 +70,7 @@ static char *nodemgr_find_oui_name(int oui)
static DECLARE_MUTEX(nodemgr_serialize);
static LIST_HEAD(host_info_list);
static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
static struct hpsb_highlevel *nodemgr_hl;
struct host_info {
struct hpsb_host *host;
......@@ -917,7 +916,7 @@ static void nodemgr_process_unit_directory(struct host_info *hi, struct node_ent
address += 4;
infop = (quadlet_t *) ud->quadlets;
for (; length > 0; length--, address += 4, infop++) {
for (; length > 0; length--, address += 4) {
int code;
quadlet_t value;
quadlet_t *quadp;
......@@ -990,7 +989,7 @@ static void nodemgr_process_unit_directory(struct host_info *hi, struct node_ent
CSR offsets for now. */
code &= CONFIG_ROM_KEY_TYPE_MASK;
if ((code & 0x80) == 0)
*infop = quad;
*infop++ = quad;
break;
}
}
......@@ -1140,30 +1139,10 @@ static int nodemgr_hotplug(struct device *dev, char **envp, int num_envp,
static int nodemgr_alloc_host_num(void)
{
int hostnum = 0;
unsigned long flags;
struct list_head *lh;
spin_lock_irqsave (&host_info_lock, flags);
while (1) {
int found = 0;
list_for_each(lh, &host_info_list) {
struct host_info *hi = list_entry(lh, struct host_info, list);
if (hi->id == hostnum) {
found = 1;
break;
}
}
int hostnum;
if (!found)
break;
hostnum++;
}
spin_unlock_irqrestore (&host_info_lock, flags);
for (hostnum = 0; hpsb_get_hostinfo_bykey(nodemgr_hl, hostnum); hostnum++)
/* Do nothing */;
return hostnum;
}
......@@ -1491,7 +1470,7 @@ static void nodemgr_node_probe(struct host_info *hi, int generation)
/* Because we are a 1394a-2000 compliant IRM, we need to inform all the other
* nodes of the broadcast channel. (Really we're only setting the validity
* bit). */
* bit). Other IRM responsibilities go in here as well. */
static void nodemgr_do_irm_duties(struct hpsb_host *host)
{
quadlet_t bc;
......@@ -1506,12 +1485,30 @@ static void nodemgr_do_irm_duties(struct hpsb_host *host)
hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host),
(CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
&bc, sizeof(quadlet_t));
/* 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 == 0x3f && host->node_count > 1)
{
u16 root_node = host->node_count - 1;
struct node_entry *ne = hpsb_nodeid_get_entry(host, root_node);
if(ne->busopt.cmc)
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...");
hpsb_send_phy_config(host, host->node_id, -1);
hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
}
}
}
/* 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_root_capability(struct hpsb_host *host)
static int nodemgr_check_irm_capability(struct hpsb_host *host)
{
quadlet_t bc;
int status;
......@@ -1525,9 +1522,10 @@ static int nodemgr_check_root_capability(struct hpsb_host *host)
&bc, sizeof(quadlet_t));
if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) {
/* The root node does not have a valid BROADCAST_CHANNEL
/* 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("Remote root is not IRM capable, resetting...");
HPSB_DEBUG("Current remote IRM is not 1394a-2000 compliant, resetting...");
hpsb_send_phy_config(host, host->node_id, -1);
hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
return 0;
}
......@@ -1565,7 +1563,7 @@ static int nodemgr_host_thread(void *__hi)
* 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(hi->host);
generation = get_hpsb_generation(host);
/* If we get a reset before we are done waiting, then
* start the the waiting over again */
......@@ -1573,7 +1571,7 @@ static int nodemgr_host_thread(void *__hi)
i = HZ/4;
}
if (!nodemgr_check_root_capability(host)) {
if (!nodemgr_check_irm_capability(host)) {
/* Do nothing, we are resetting */
up(&nodemgr_serialize);
continue;
......@@ -1683,12 +1681,11 @@ int hpsb_node_lock(struct node_entry *ne, u64 addr,
addr, extcode, data, arg);
}
static void nodemgr_add_host(struct hpsb_host *host)
static void nodemgr_add_host(struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct host_info *hi;
unsigned long flags;
hi = kmalloc(sizeof (struct host_info), in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
hi = hpsb_create_hostinfo(hl, host, sizeof(*hi));
if (!hi) {
HPSB_ERR ("NodeMgr: out of memory in add host");
......@@ -1698,14 +1695,14 @@ static void nodemgr_add_host(struct hpsb_host *host)
/* Initialize the hostinfo here and start the thread. The
* thread blocks on the reset semaphore until a bus reset
* happens. */
memset(hi, 0, sizeof(*hi));
hi->host = host;
INIT_LIST_HEAD(&hi->list);
init_completion(&hi->exited);
sema_init(&hi->reset_sem, 0);
hi->id = nodemgr_alloc_host_num();
hpsb_set_hostinfo_key(hl, host, hi->id);
memcpy(&host->device, &nodemgr_dev_template_host,
sizeof(host->device));
host->device.parent = &host->pdev->dev;
......@@ -1715,40 +1712,22 @@ static void nodemgr_add_host(struct hpsb_host *host)
sprintf(hi->daemon_name, "knodemgrd_%d", hi->id);
spin_lock_irqsave (&host_info_lock, flags);
hi->pid = kernel_thread(nodemgr_host_thread, hi,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
if (hi->pid < 0) {
HPSB_ERR ("NodeMgr: failed to start %s thread for %s",
hi->daemon_name, host->driver->name);
kfree(hi);
spin_unlock_irqrestore (&host_info_lock, flags);
hpsb_destroy_hostinfo(hl, host);
return;
}
list_add_tail (&hi->list, &host_info_list);
spin_unlock_irqrestore (&host_info_lock, flags);
return;
}
static void nodemgr_host_reset(struct hpsb_host *host)
{
struct list_head *lh;
struct host_info *hi = NULL;
unsigned long flags;
spin_lock_irqsave (&host_info_lock, flags);
list_for_each(lh, &host_info_list) {
struct host_info *myhi = list_entry(lh, struct host_info, list);
if (myhi->host == host) {
hi = myhi;
break;
}
}
struct host_info *hi = hpsb_get_hostinfo(nodemgr_hl, host);
if (hi != NULL) {
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
......@@ -1756,29 +1735,14 @@ static void nodemgr_host_reset(struct hpsb_host *host)
#endif
up(&hi->reset_sem);
} else
HPSB_ERR ("NodeMgr: could not process reset of non-existent host");
spin_unlock_irqrestore (&host_info_lock, flags);
HPSB_ERR ("NodeMgr: could not process reset of unused host");
return;
}
static void nodemgr_remove_host(struct hpsb_host *host)
{
struct list_head *lh, *next;
unsigned long flags;
struct host_info *hi = NULL;
spin_lock_irqsave (&host_info_lock, flags);
list_for_each_safe(lh, next, &host_info_list) {
struct host_info *myhi = list_entry(lh, struct host_info, list);
if (myhi->host == host) {
list_del(&myhi->list);
hi = myhi;
break;
}
}
spin_unlock_irqrestore (&host_info_lock, flags);
struct host_info *hi = hpsb_get_hostinfo(nodemgr_hl, host);
if (hi) {
if (hi->pid >= 0) {
......@@ -1787,7 +1751,6 @@ static void nodemgr_remove_host(struct hpsb_host *host)
nodemgr_remove_host_dev(&host->device);
device_unregister(&host->device);
}
kfree(hi);
} else
HPSB_ERR("NodeMgr: host %s does not exist, cannot remove",
host->driver->name);
......@@ -1801,21 +1764,19 @@ static struct hpsb_highlevel_ops nodemgr_ops = {
.remove_host = nodemgr_remove_host,
};
static struct hpsb_highlevel *hl;
void init_ieee1394_nodemgr(void)
{
bus_register(&ieee1394_bus_type);
hl = hpsb_register_highlevel("Node manager", &nodemgr_ops);
if (!hl) {
nodemgr_hl = hpsb_register_highlevel("Node manager", &nodemgr_ops);
if (!nodemgr_hl) {
HPSB_ERR("NodeMgr: out of memory during ieee1394 initialization");
}
}
void cleanup_ieee1394_nodemgr(void)
{
hpsb_unregister_highlevel(hl);
hpsb_unregister_highlevel(nodemgr_hl);
bus_unregister(&ieee1394_bus_type);
}
......@@ -165,7 +165,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: 858 $ Ben Collins <bcollins@debian.org>";
"$Rev: 866 $ Ben Collins <bcollins@debian.org>";
/* Module Parameters */
static int phys_dma = 1;
......
......@@ -72,8 +72,6 @@ printk(KERN_INFO "raw1394:" fmt "\n" , ## args)
#define DBGMSG(fmt, args...)
#endif
static devfs_handle_t devfs_handle;
static LIST_HEAD(host_info_list);
static int host_count;
static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
......@@ -190,13 +188,13 @@ static void queue_complete_cb(struct pending_request *req)
}
static void add_host(struct hpsb_host *host)
static void add_host(struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct host_info *hi;
unsigned long flags;
hi = (struct host_info *)kmalloc(sizeof(struct host_info),
in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
hi = (struct host_info *)kmalloc(sizeof(struct host_info), GFP_KERNEL);
if (hi != NULL) {
INIT_LIST_HEAD(&hi->list);
hi->host = host;
......@@ -2536,17 +2534,14 @@ static int __init init_raw1394(void)
return -ENOMEM;
}
devfs_handle = devfs_register(NULL,
RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
IEEE1394_MAJOR,
IEEE1394_MINOR_BLOCK_RAW1394 * 16,
S_IFCHR | S_IRUSR | S_IWUSR, &file_ops,
NULL);
devfs_register(NULL, RAW1394_DEVICE_NAME, 0,
IEEE1394_MAJOR, 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)) {
HPSB_ERR("raw1394 failed to register minor device block");
devfs_unregister(devfs_handle);
devfs_remove(RAW1394_DEVICE_NAME);
hpsb_unregister_highlevel(hl_handle);
return -EBUSY;
}
......@@ -2562,7 +2557,7 @@ static void __exit cleanup_raw1394(void)
{
hpsb_unregister_protocol(&raw1394_driver);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
devfs_unregister(devfs_handle);
devfs_remove(RAW1394_DEVICE_NAME);
hpsb_unregister_highlevel(hl_handle);
}
......
......@@ -298,7 +298,7 @@
#include "sbp2.h"
static char version[] __devinitdata =
"$Rev: 846 $ James Goodwin <jamesg@filanet.com>";
"$Rev: 884 $ James Goodwin <jamesg@filanet.com>";
/*
* Module load parameter definitions
......@@ -456,10 +456,6 @@ static Scsi_Host_Template scsi_driver_template;
static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };
static LIST_HEAD(sbp2_host_info_list);
static spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED;
static struct hpsb_highlevel *sbp2_hl_handle = NULL;
static struct hpsb_highlevel_ops sbp2_hl_ops = {
......@@ -779,10 +775,9 @@ static struct sbp2_command_info *sbp2util_allocate_command_orb(
static void sbp2util_free_command_dma(struct sbp2_command_info *command)
{
struct sbp2scsi_host_info *hi;
hi = (struct sbp2scsi_host_info *)&command->Current_SCpnt->device->host->hostdata;
if (hi == NULL) {
hi = hpsb_get_hostinfo_bykey(sbp2_hl_handle, (unsigned long)command->Current_SCpnt->device->host);
if (!hi) {
printk(KERN_ERR "%s: hi == NULL\n", __FUNCTION__);
return;
}
......@@ -911,87 +906,47 @@ static void sbp2_update(struct unit_directory *ud)
static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host)
{
struct sbp2scsi_host_info *hi;
unsigned long flags;
struct Scsi_Host *scsi_host;
SBP2_DEBUG("sbp2_add_host");
hi = sbp2_find_host_info(host);
hi = hpsb_get_hostinfo(sbp2_hl_handle, host);
if (hi)
return hi;
/* Register our host with the SCSI stack. */
scsi_host = scsi_register (&scsi_driver_template, sizeof(struct sbp2scsi_host_info));
scsi_host = scsi_register (&scsi_driver_template, 0);
if (!scsi_host) {
SBP2_ERR("failed to register scsi host");
return NULL;
}
hi = (struct sbp2scsi_host_info *)&scsi_host->hostdata;
memset(hi, 0, sizeof(struct sbp2scsi_host_info));
hi = hpsb_create_hostinfo(sbp2_hl_handle, host, sizeof(*hi));
if (!hi) {
SBP2_ERR("failed to allocate hostinfo");
scsi_unregister(hi->scsi_host);
}
hpsb_set_hostinfo_key(sbp2_hl_handle, host, (unsigned long)scsi_host);
hi->scsi_host = scsi_host;
INIT_LIST_HEAD(&hi->list);
hi->host = host;
hi->sbp2_command_lock = SPIN_LOCK_UNLOCKED;
hi->scsi_host->max_id = SBP2SCSI_MAX_SCSI_IDS;
spin_lock_irqsave(&sbp2_host_info_lock, flags);
list_add_tail(&hi->list, &sbp2_host_info_list);
spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
/* XXX We need a device to pass here as the scsi-host class. Can't
* use the PCI device, since it is already bound to the ieee1394
* host. Can't use the fw-host device since it is multi-class
* enabled (scsi-host uses classdata member of the device). */
if (scsi_add_host(hi->scsi_host, NULL)) {
SBP2_ERR("failed to add scsi host");
spin_lock_irqsave(&sbp2_host_info_lock, flags);
list_del(&hi->list);
spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
scsi_unregister(hi->scsi_host);
hpsb_destroy_hostinfo(sbp2_hl_handle, host);
}
return hi;
}
/*
* This fuction returns a host info structure from the host structure, in
* case we have multiple hosts.
*/
static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host)
{
struct list_head *lh;
struct sbp2scsi_host_info *hi;
list_for_each (lh, &sbp2_host_info_list) {
hi = list_entry(lh, struct sbp2scsi_host_info, list);
if (hi->host == host)
return hi;
}
return NULL;
}
/*
* This function returns a host info structure for a given Scsi_Host
* struct.
*/
static struct sbp2scsi_host_info *sbp2_find_host_info_scsi(struct Scsi_Host *host)
{
struct list_head *lh;
struct sbp2scsi_host_info *hi;
list_for_each (lh, &sbp2_host_info_list) {
hi = list_entry(lh, struct sbp2scsi_host_info, list);
if (hi->scsi_host == host)
return hi;
}
return NULL;
}
/*
* This function is called when a host is removed.
......@@ -999,20 +954,16 @@ static struct sbp2scsi_host_info *sbp2_find_host_info_scsi(struct Scsi_Host *hos
static void sbp2_remove_host(struct hpsb_host *host)
{
struct sbp2scsi_host_info *hi;
unsigned long flags;
SBP2_DEBUG("sbp2_remove_host");
spin_lock_irqsave(&sbp2_host_info_lock, flags);
hi = sbp2_find_host_info(host);
if (hi)
list_del(&hi->list);
spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
hi = hpsb_get_hostinfo(sbp2_hl_handle, host);
if (hi) {
scsi_remove_host(hi->scsi_host);
scsi_unregister(hi->scsi_host);
}
} else
SBP2_ERR("attempt to remove unknown host %p", host);
}
/*
......@@ -2614,9 +2565,7 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
return(RCODE_ADDRESS_ERROR);
}
spin_lock_irqsave(&sbp2_host_info_lock, flags);
hi = sbp2_find_host_info(host);
spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
hi = hpsb_get_hostinfo(sbp2_hl_handle, host);
if (!hi) {
SBP2_ERR("host info is NULL - this is bad!");
......@@ -2763,7 +2712,7 @@ static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
/*
* Pull our host info and scsi id instance data from the scsi command
*/
hi = (struct sbp2scsi_host_info *) &SCpnt->device->host->hostdata;
hi = hpsb_get_hostinfo_bykey(sbp2_hl_handle, (unsigned long)SCpnt->device->host);
if (!hi) {
SBP2_ERR("sbp2scsi_host_info is NULL - this is bad!");
......@@ -2992,7 +2941,8 @@ static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
*/
static int sbp2scsi_abort (Scsi_Cmnd *SCpnt)
{
struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)&SCpnt->device->host->hostdata;
struct sbp2scsi_host_info *hi = hpsb_get_hostinfo_bykey(sbp2_hl_handle,
(unsigned long)SCpnt->device->host);
struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->device->id];
struct sbp2_command_info *command;
unsigned long flags;
......@@ -3042,7 +2992,8 @@ static int sbp2scsi_abort (Scsi_Cmnd *SCpnt)
*/
static int sbp2scsi_reset (Scsi_Cmnd *SCpnt)
{
struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)&SCpnt->device->host->hostdata;
struct sbp2scsi_host_info *hi = hpsb_get_hostinfo_bykey(sbp2_hl_handle,
(unsigned long)SCpnt->device->host);
struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->device->id];
SBP2_ERR("reset requested");
......@@ -3080,7 +3031,7 @@ static int sbp2scsi_proc_info(char *buffer, char **start, off_t offset,
if (!host) /* if we couldn't find it, we return an error */
return -ESRCH;
hi = sbp2_find_host_info_scsi(host);
hi = hpsb_get_hostinfo_bykey(sbp2_hl_handle, (unsigned long)host);
if (!hi) /* shouldn't happen, but... */
return -ESRCH;
......
......@@ -417,11 +417,6 @@ struct scsi_id_instance_data {
* Sbp2 host data structure (one per sbp2 host)
*/
struct sbp2scsi_host_info {
/*
* For use in keeping track of hosts
*/
struct list_head list;
struct hpsb_host *host;
/*
......@@ -463,7 +458,6 @@ static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_i
* IEEE-1394 core driver related prototypes
*/
static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host);
static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host);
static void sbp2_remove_host(struct hpsb_host *host);
static int sbp2_probe(struct device *dev);
......
......@@ -122,16 +122,9 @@ struct dma_iso_ctx {
struct list_head link;
};
struct video_card {
struct ti_ohci *ohci;
struct list_head list;
int id;
devfs_handle_t devfs;
};
struct file_ctx {
struct video_card *video;
struct ti_ohci *ohci;
struct list_head context_list;
struct dma_iso_ctx *current_ctx;
};
......@@ -162,10 +155,6 @@ printk(level "video1394_%d: " fmt "\n" , card , ## args)
void wakeup_dma_ir_ctx(unsigned long l);
void wakeup_dma_it_ctx(unsigned long l);
static LIST_HEAD(video1394_cards);
static spinlock_t video1394_cards_lock = SPIN_LOCK_UNLOCKED;
static devfs_handle_t devfs_handle;
static struct hpsb_highlevel *hl_handle = NULL;
......@@ -716,8 +705,7 @@ static int video1394_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct file_ctx *ctx = (struct file_ctx *)file->private_data;
struct video_card *video = ctx->video;
struct ti_ohci *ohci = video->ohci;
struct ti_ohci *ohci = ctx->ohci;
unsigned long flags;
switch(cmd)
......@@ -1162,7 +1150,7 @@ int video1394_mmap(struct file *file, struct vm_area_struct *vma)
lock_kernel();
if (ctx->current_ctx == NULL) {
PRINT(KERN_ERR, ctx->video->ohci->id, "Current iso context not set");
PRINT(KERN_ERR, ctx->ohci->id, "Current iso context not set");
} else
res = dma_region_mmap(&ctx->current_ctx->dma, file, vma);
unlock_kernel();
......@@ -1173,32 +1161,21 @@ int video1394_mmap(struct file *file, struct vm_area_struct *vma)
static int video1394_open(struct inode *inode, struct file *file)
{
int i = ieee1394_file_to_instance(file);
unsigned long flags;
struct video_card *video = NULL;
struct list_head *lh;
struct ti_ohci *ohci;
struct file_ctx *ctx;
spin_lock_irqsave(&video1394_cards_lock, flags);
list_for_each(lh, &video1394_cards) {
struct video_card *p = list_entry(lh, struct video_card, list);
if (p->id == i) {
video = p;
break;
}
}
spin_unlock_irqrestore(&video1394_cards_lock, flags);
if (video == NULL)
ohci = hpsb_get_hostinfo_bykey(hl_handle, i);
if (ohci == NULL)
return -EIO;
ctx = kmalloc(sizeof(struct file_ctx), GFP_KERNEL);
if (ctx == NULL) {
PRINT(KERN_ERR, video->ohci->id, "Cannot malloc file_ctx");
PRINT(KERN_ERR, ohci->id, "Cannot malloc file_ctx");
return -ENOMEM;
}
memset(ctx, 0, sizeof(struct file_ctx));
ctx->video = video;
ctx->ohci = ohci;
INIT_LIST_HEAD(&ctx->context_list);
ctx->current_ctx = NULL;
file->private_data = ctx;
......@@ -1209,8 +1186,7 @@ static int video1394_open(struct inode *inode, struct file *file)
static int video1394_release(struct inode *inode, struct file *file)
{
struct file_ctx *ctx = (struct file_ctx *)file->private_data;
struct video_card *video = ctx->video;
struct ti_ohci *ohci = video->ohci;
struct ti_ohci *ohci = ctx->ohci;
struct list_head *lh, *next;
u64 mask;
......@@ -1273,54 +1249,11 @@ static struct hpsb_protocol_driver video1394_driver = {
};
static int video1394_init(struct ti_ohci *ohci)
{
struct video_card *video;
unsigned long flags;
char name[24];
int minor;
video = kmalloc(sizeof(struct video_card), GFP_KERNEL);
if (video == NULL) {
PRINT(KERN_ERR, ohci->id, "Cannot allocate video_card");
return -1;
}
memset(video, 0, sizeof(struct video_card));
spin_lock_irqsave(&video1394_cards_lock, flags);
INIT_LIST_HEAD(&video->list);
list_add_tail(&video->list, &video1394_cards);
spin_unlock_irqrestore(&video1394_cards_lock, flags);
video->id = ohci->id;
video->ohci = ohci;
sprintf(name, "%s/%d", VIDEO1394_DRIVER_NAME, video->id);
minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + video->id;
video->devfs = devfs_register(NULL, name, DEVFS_FL_DEFAULT,
IEEE1394_MAJOR, minor,
S_IFCHR | S_IRUSR | S_IWUSR,
&video1394_fops, NULL);
return 0;
}
/* Must be called under spinlock */
static void remove_card(struct video_card *video)
{
devfs_unregister(video->devfs);
list_del(&video->list);
kfree(video);
}
static void video1394_remove_host (struct hpsb_host *host)
static void video1394_add_host (struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct ti_ohci *ohci;
unsigned long flags;
struct list_head *lh, *next;
struct video_card *p;
char name[16];
int minor;
/* We only work with the OHCI-1394 driver */
if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
......@@ -1328,34 +1261,34 @@ static void video1394_remove_host (struct hpsb_host *host)
ohci = (struct ti_ohci *)host->hostdata;
spin_lock_irqsave(&video1394_cards_lock, flags);
list_for_each_safe(lh, next, &video1394_cards) {
p = list_entry(lh, struct video_card, list);
if (p->ohci == ohci) {
remove_card(p);
break;
}
if (!hpsb_create_hostinfo(hl, host, 0)) {
PRINT(KERN_ERR, ohci->id, "Cannot allocate hostinfo");
return;
}
spin_unlock_irqrestore(&video1394_cards_lock, flags);
hpsb_set_hostinfo(hl, host, ohci);
hpsb_set_hostinfo_key(hl, host, ohci->id);
sprintf(name, "%s/%d", VIDEO1394_DRIVER_NAME, ohci->id);
minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->id;
devfs_register(NULL, name, 0, IEEE1394_MAJOR, minor,
S_IFCHR | S_IRUSR | S_IWUSR, &video1394_fops, NULL);
return;
}
static void video1394_add_host (struct hpsb_host *host)
{
struct ti_ohci *ohci;
/* We only work with the OHCI-1394 driver */
if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
return;
static void video1394_remove_host (struct hpsb_host *host)
{
struct ti_ohci *ohci = hpsb_get_hostinfo(hl_handle, host);
ohci = (struct ti_ohci *)host->hostdata;
if (ohci)
devfs_remove("%s/%d", VIDEO1394_DRIVER_NAME, ohci->id);
video1394_init(ohci);
return;
}
static struct hpsb_highlevel_ops hl_ops = {
.add_host = video1394_add_host,
.remove_host = video1394_remove_host,
......@@ -1497,7 +1430,7 @@ static void __exit video1394_exit_module (void)
hpsb_unregister_highlevel (hl_handle);
devfs_unregister(devfs_handle);
devfs_remove(VIDEO1394_DRIVER_NAME);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
......@@ -1514,12 +1447,12 @@ static int __init video1394_init_module (void)
return -EIO;
}
devfs_handle = devfs_mk_dir(VIDEO1394_DRIVER_NAME);
devfs_mk_dir(VIDEO1394_DRIVER_NAME);
hl_handle = hpsb_register_highlevel (VIDEO1394_DRIVER_NAME, &hl_ops);
if (hl_handle == NULL) {
PRINT_G(KERN_ERR, "No more memory for driver\n");
devfs_unregister(devfs_handle);
devfs_remove(VIDEO1394_DRIVER_NAME);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
return -ENOMEM;
}
......
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