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

[PATCH] IEEE1394 updates

This is against 2.5.25. Lots of fixes. Brings things inline with 2.5.25.
Probably makes the subsystem actually work now (well, it will work, but
I bet without it, it doesn't). Merged in changes from the current 2.5.x
source.
parent 3617d270
......@@ -9,22 +9,33 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
if [ "$CONFIG_IEEE1394" != "n" ]; then
comment "Device Drivers"
dep_tristate ' Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394
if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM
bool ' Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS
if [ "$CONFIG_I2C" = "n" -o "$CONFIG_I2C_ALGOBIT" = "n" ]; then
comment ' Texas Instruments PCILynx requires I2C bit-banging'
else
dep_tristate ' Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394 $CONFIG_I2C $CONFIG_I2C_ALGOBIT
fi
# Non-maintained pcilynx options
# if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
# bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM
# bool ' Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS
# fi
dep_tristate ' OHCI-1394 support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394
comment "Protocol Drivers"
dep_tristate ' OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394
dep_tristate ' SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394
if [ "$CONFIG_IEEE1394_SBP2" != "n" ]; then
bool ' Enable Phys DMA support for SBP2 (Debug)' CONFIG_IEEE1394_SBP2_PHYS_DMA
fi
dep_tristate ' Ethernet over 1394' CONFIG_IEEE1394_ETH1394 $CONFIG_IEEE1394
dep_tristate ' OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394
dep_tristate ' Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
dep_tristate ' IEC61883-1 Plug support' CONFIG_IEEE1394_CMP $CONFIG_IEEE1394
if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
if [ "$CONFIG_IEEE1394_CMP" != "n" ]; then
dep_tristate ' IEC61883-6 (Audio transmission) support' CONFIG_IEEE1394_AMDTP $CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394_CMP
fi
......
......@@ -2,8 +2,11 @@
# Makefile for the Linux IEEE 1394 implementation
#
O_TARGET := ieee1394drv.o
export-objs := ieee1394_core.o ohci1394.o cmp.o
list-multi := ieee1394.o
ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
highlevel.o csr.o nodemgr.o
......@@ -19,3 +22,6 @@ obj-$(CONFIG_IEEE1394_AMDTP) += amdtp.o
obj-$(CONFIG_IEEE1394_CMP) += cmp.o
include $(TOPDIR)/Rules.make
ieee1394.o: $(ieee1394-objs)
$(LD) -r -o $@ $(ieee1394-objs)
......@@ -1110,7 +1110,7 @@ MODULE_LICENSE("GPL");
static int __init amdtp_init_module (void)
{
if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL,
if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_AMDTP,
THIS_MODULE, &amdtp_fops)) {
HPSB_ERR("amdtp: unable to get minor device block");
return -EIO;
......@@ -1120,7 +1120,7 @@ static int __init amdtp_init_module (void)
&amdtp_highlevel_ops);
if (amdtp_highlevel == NULL) {
HPSB_ERR("amdtp: unable to register highlevel ops");
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
return -EIO;
}
......@@ -1132,7 +1132,7 @@ static int __init amdtp_init_module (void)
static void __exit amdtp_exit_module (void)
{
hpsb_unregister_highlevel(amdtp_highlevel);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
HPSB_INFO("Unloaded AMDTP driver");
}
......
......@@ -460,7 +460,7 @@ struct video_card {
This is a regular int, but use test_and_set_bit() (on bit zero)
for atomicity.
*/
int open;
unsigned long open;
/*
2) the spinlock - this provides mutual exclusion between the interrupt
......
......@@ -53,6 +53,7 @@
via pci_alloc_consistent()
DONE:
- restart IT DMA after a bus reset
- safely obtain and release ISO Tx channels in cooperation with OHCI driver
- map received DIF blocks to their proper location in DV frame (ensure
recovery if dropped packet)
......@@ -192,71 +193,19 @@ static inline struct video_card* file_to_video_card(struct file *file)
/* Memory management functions */
/*******************************/
#define MDEBUG(x) do { } while(0) /* Debug memory management */
/* [DaveM] I've recoded most of this so that:
* 1) It's easier to tell what is happening
* 2) It's more portable, especially for translating things
* out of vmalloc mapped areas in the kernel.
* 3) Less unnecessary translations happen.
*
* The code used to assume that the kernel vmalloc mappings
* existed in the page tables of every process, this is simply
* not guarenteed. We now use pgd_offset_k which is the
* defined way to get at the kernel page tables.
*/
/* Given PGD from the address space's page table, return the kernel
* virtual mapping of the physical memory mapped at ADR.
*/
static inline struct page *uvirt_to_page(pgd_t *pgd, unsigned long adr)
{
pmd_t *pmd;
pte_t *ptep, pte;
struct page *ret = NULL;
if (!pgd_none(*pgd)) {
pmd = pmd_offset(pgd, adr);
if (!pmd_none(*pmd)) {
ptep = pte_offset_kernel(pmd, adr);
pte = *ptep;
if(pte_present(pte))
ret = pte_page(pte);
}
}
return ret;
}
/* Here we want the physical address of the memory.
* This is used when initializing the contents of the
* area and marking the pages as reserved, and for
* handling page faults on the rvmalloc()ed buffer
*/
static inline unsigned long kvirt_to_pa(unsigned long adr)
{
unsigned long va, kva, ret;
va = VMALLOC_VMADDR(adr);
kva = (unsigned long) page_address(uvirt_to_page(pgd_offset_k(va), va));
kva |= adr & (PAGE_SIZE-1); /* restore the offset */
ret = __pa(kva);
MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
return ret;
}
static void * rvmalloc(unsigned long size)
{
void * mem;
unsigned long adr, page;
unsigned long adr;
size = PAGE_ALIGN(size);
mem=vmalloc_32(size);
if (mem) {
memset(mem, 0, size); /* Clear the ram out,
no junk to the user */
adr=(unsigned long) mem;
while (size > 0) {
page = kvirt_to_pa(adr);
mem_map_reserve(virt_to_page(__va(page)));
mem_map_reserve(vmalloc_to_page((void *)adr));
adr+=PAGE_SIZE;
size-=PAGE_SIZE;
}
......@@ -266,13 +215,12 @@ static void * rvmalloc(unsigned long size)
static void rvfree(void * mem, unsigned long size)
{
unsigned long adr, page;
unsigned long adr;
if (mem) {
adr=(unsigned long) mem;
while (size > 0) {
page = kvirt_to_pa(adr);
mem_map_unreserve(virt_to_page(__va(page)));
mem_map_unreserve(vmalloc_to_page((void *)adr));
adr+=PAGE_SIZE;
size-=PAGE_SIZE;
}
......@@ -1166,9 +1114,9 @@ static int do_dv1394_init(struct video_card *video, struct dv1394_init *init)
/* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */
for(i = 0; i < video->user_dma.n_pages; i++) {
unsigned long va = VMALLOC_VMADDR( (unsigned long) video->user_buf + i * PAGE_SIZE );
unsigned long va = (unsigned long) video->user_buf + i * PAGE_SIZE;
video->user_dma.sglist[i].page = uvirt_to_page(pgd_offset_k(va), va);
video->user_dma.sglist[i].page = vmalloc_to_page((void *)va);
video->user_dma.sglist[i].length = PAGE_SIZE;
}
......@@ -1492,7 +1440,7 @@ static int do_dv1394_shutdown(struct video_card *video, int free_user_buf)
static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access)
{
unsigned long offset;
unsigned long page, kernel_virt_addr;
unsigned long kernel_virt_addr;
struct page *ret = NOPAGE_SIGBUS;
struct video_card *video = (struct video_card*) area->vm_private_data;
......@@ -1510,10 +1458,7 @@ static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long a
offset = address - area->vm_start;
kernel_virt_addr = (unsigned long) video->user_buf + offset;
page = kvirt_to_pa(kernel_virt_addr);
ret = virt_to_page(__va(page));
ret = vmalloc_to_page((void *)kernel_virt_addr);
get_page(ret);
out:
......@@ -2936,9 +2881,129 @@ static void dv1394_add_host (struct hpsb_host *host)
dv1394_init(ohci, DV1394_PAL, MODE_TRANSMIT);
}
/* Bus reset handler. In the event of a bus reset, we may need to
re-start the DMA contexts - otherwise the user program would
end up waiting forever.
*/
static void dv1394_host_reset(struct hpsb_host *host)
{
struct ti_ohci *ohci;
struct video_card *video = NULL;
unsigned long flags;
struct list_head *lh;
/* We only work with the OHCI-1394 driver */
if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
return;
ohci = (struct ti_ohci *)host->hostdata;
/* find the corresponding video_cards */
spin_lock_irqsave(&dv1394_cards_lock, flags);
if(!list_empty(&dv1394_cards)) {
list_for_each(lh, &dv1394_cards) {
video = list_entry(lh, struct video_card, list);
if((video->id >> 2) == ohci->id)
break;
}
}
spin_unlock_irqrestore(&dv1394_cards_lock, flags);
if(!video)
return;
/* check IT context */
if(video->ohci_it_ctx != -1) {
u32 ctx;
spin_lock_irqsave(&video->spinlock, flags);
ctx = reg_read(video->ohci, video->ohci_IsoXmitContextControlSet);
/* if(RUN but not ACTIVE) */
if( (ctx & (1<<15)) &&
!(ctx & (1<<10)) ) {
debug_printk("dv1394: IT context stopped due to bus reset; waking it up\n");
/* to be safe, assume a frame has been dropped. User-space programs
should handle this condition like an underflow. */
video->dropped_frames++;
/* for some reason you must clear, then re-set the RUN bit to restart DMA */
/* clear RUN */
reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
flush_pci_write(video->ohci);
/* set RUN */
reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 15));
flush_pci_write(video->ohci);
/* set the WAKE bit (just in case; this isn't strictly necessary) */
reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 12));
flush_pci_write(video->ohci);
irq_printk("dv1394: AFTER IT restart ctx 0x%08x ptr 0x%08x\n",
reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
}
spin_unlock_irqrestore(&video->spinlock, flags);
}
/* check IR context */
if(video->ohci_ir_ctx != -1) {
u32 ctx;
spin_lock_irqsave(&video->spinlock, flags);
ctx = reg_read(video->ohci, video->ohci_IsoRcvContextControlSet);
/* if(RUN but not ACTIVE) */
if( (ctx & (1<<15)) &&
!(ctx & (1<<10)) ) {
debug_printk("dv1394: IR context stopped due to bus reset; waking it up\n");
/* to be safe, assume a frame has been dropped. User-space programs
should handle this condition like an overflow. */
video->dropped_frames++;
/* for some reason you must clear, then re-set the RUN bit to restart DMA */
/* XXX this doesn't work for me, I can't get IR DMA to restart :[ */
/* clear RUN */
reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
flush_pci_write(video->ohci);
/* set RUN */
reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 15));
flush_pci_write(video->ohci);
/* set the WAKE bit (just in case; this isn't strictly necessary) */
reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
flush_pci_write(video->ohci);
irq_printk("dv1394: AFTER IR restart ctx 0x%08x ptr 0x%08x\n",
reg_read(video->ohci, video->ohci_IsoRcvContextControlSet),
reg_read(video->ohci, video->ohci_IsoRcvCommandPtr));
}
spin_unlock_irqrestore(&video->spinlock, flags);
}
/* wake readers/writers/ioctl'ers */
wake_up_interruptible(&video->waitq);
}
static struct hpsb_highlevel_ops hl_ops = {
add_host: dv1394_add_host,
remove_host: dv1394_remove_host,
host_reset: dv1394_host_reset,
};
......
......@@ -123,6 +123,67 @@
frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
it may transmit the new frames.
ERROR HANDLING
An error (buffer underflow/overflow or a break in the DV stream due
to a 1394 bus reset) can be detected by checking the dropped_frames
field of struct dv1394_status (obtained through the
DV1394_GET_STATUS ioctl).
The best way to recover from such an error is to re-initialize
dv1394, either by using the DV1394_INIT ioctl call, or closing the
file descriptor and opening it again. (note that you must unmap all
ringbuffer mappings when closing the file descriptor, or else
dv1394 will still be considered 'in use').
MAIN LOOP
For maximum efficiency and robustness against bus errors, you are
advised to model the main loop of your application after the
following pseudo-code example:
(checks of system call return values omitted for brevity; always
check return values in your code!)
while( frames left ) {
struct pollfd *pfd = ...;
pfd->fd = dv1394_fd;
pfd->revents = 0;
pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive)
(add other sources of I/O here)
poll(pfd, 1, -1); (or select(); add a timeout if you want)
if(pfd->revents) {
struct dv1394_status status;
ioctl(dv1394_fd, DV1394_GET_STATUS, &status);
if(status.dropped_frames > 0) {
reset_dv1394();
} else {
for(int i = 0; i < status.n_clear_frames; i++) {
copy_DV_frame();
}
}
}
}
where copy_DV_frame() reads or writes on the dv1394 file descriptor
(read/write mode) or copies data to/from the mmap ringbuffer and
then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new
frames are availble (mmap mode).
reset_dv1394() is called in the event of a buffer
underflow/overflow or a halt in the DV stream (e.g. due to a 1394
bus reset). To guarantee recovery from the error, this function
should close the dv1394 file descriptor (and munmap() all
ringbuffer mappings, if you are using them), then re-open the
dv1394 device (and re-map the ringbuffer).
*/
......@@ -218,6 +279,13 @@ struct dv1394_init {
unsigned int syt_offset;
};
/* NOTE: you may only allocate the DV frame ringbuffer once each time
you open the dv1394 device. DV1394_INIT will fail if you call it a
second time with different 'n_frames' or 'format' arguments (which
would imply a different size for the ringbuffer). If you need a
different buffer size, simply close and re-open the device, then
initialize it with your new settings. */
/* Q: What are cip_n and cip_d? */
/*
......@@ -262,8 +330,9 @@ struct dv1394_status {
ready to be filled with data */
unsigned int n_clear_frames;
/* how many times the DV output has underflowed
since the last call to DV1394_GET_STATUS */
/* how many times the DV stream has underflowed, overflowed,
or otherwise encountered an error, since the previous call
to DV1394_GET_STATUS */
unsigned int dropped_frames;
/* N.B. The dropped_frames counter is only a lower bound on the actual
......
......@@ -124,7 +124,7 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra)
h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL);
if (!h) return NULL;
memset(h, 0, sizeof(struct hpsb_host));
memset(h, 0, sizeof(struct hpsb_host) + extra);
h->hostdata = h + 1;
h->driver = drv;
......
......@@ -31,6 +31,7 @@ struct hpsb_host {
u32 tlabel_pool[2];
struct semaphore tlabel_count;
spinlock_t tlabel_lock;
u32 tlabel_current;
unsigned char iso_listen_count[64];
......
......@@ -740,7 +740,8 @@ void abort_requests(struct hpsb_host *host)
host->ops->devctl(host, CANCEL_REQUESTS, 0);
spin_lock_irqsave(&host->pending_pkt_lock, flags);
list_splice_init(&host->pending_packets, &llist);
list_splice(&host->pending_packets, &llist);
INIT_LIST_HEAD(&host->pending_packets);
spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
list_for_each(lh, &llist) {
......@@ -905,17 +906,16 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
/* printk("ieee1394_dispatch_open(%d)", blocknum); */
/* lock the whole kernel here, to prevent a driver from
being unloaded between the file_ops lookup and the open */
lock_kernel();
read_lock(&ieee1394_chardevs_lock);
file_ops = ieee1394_chardevs[blocknum].file_ops;
module = ieee1394_chardevs[blocknum].module;
/* bump the reference count of the driver that
will receive the open() */
INCREF(module);
file_ops = ieee1394_chardevs[blocknum].file_ops;
read_unlock(&ieee1394_chardevs_lock);
if(file_ops == NULL) {
DECREF(module);
goto out_fail;
}
......@@ -923,10 +923,6 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
own file_operations */
file->f_op = file_ops;
/* bump the reference count of the driver that
will receive the open() */
INCREF(module);
/* at this point BOTH ieee1394 and the task-specific driver have
an extra reference */
......@@ -955,7 +951,6 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
and will be dropped by the VFS when the file is
released. */
unlock_kernel();
return 0;
}
......@@ -965,7 +960,6 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
function returns. */
file->f_op = &ieee1394_chardev_ops;
unlock_kernel();
return retval;
#undef INCREF
......
......@@ -182,6 +182,7 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
#define IEEE1394_MINOR_BLOCK_RAW1394 0
#define IEEE1394_MINOR_BLOCK_VIDEO1394 1
#define IEEE1394_MINOR_BLOCK_DV1394 2
#define IEEE1394_MINOR_BLOCK_AMDTP 3
#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
/* return the index (within a minor number block) of a file */
......
......@@ -169,8 +169,9 @@ void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data)
*/
int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait)
{
int tlabel;
int tlabel = 0;
unsigned long flags;
int found_tlabel = 0;
if (wait) {
down(&host->tlabel_count);
......@@ -180,15 +181,18 @@ int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait)
spin_lock_irqsave(&host->tlabel_lock, flags);
if (host->tlabel_pool[0] != ~0) {
tlabel = ffz(host->tlabel_pool[0]);
host->tlabel_pool[0] |= 1 << tlabel;
} else {
tlabel = ffz(host->tlabel_pool[1]);
host->tlabel_pool[1] |= 1 << tlabel;
tlabel += 32;
while (!found_tlabel) {
tlabel = host->tlabel_current;
if (tlabel < 32 && !(host->tlabel_pool[0] & 1 << tlabel)) {
host->tlabel_pool[0] |= 1 << tlabel;
found_tlabel = 1;
} else if (!(host->tlabel_pool[1] & 1 << (tlabel - 32))) {
host->tlabel_pool[1] |= 1 << (tlabel - 32);
found_tlabel = 1;
}
host->tlabel_current = (host->tlabel_current + 1) % 64;
}
spin_unlock_irqrestore(&host->tlabel_lock, flags);
return tlabel;
......
......@@ -7,7 +7,6 @@
#include <linux/version.h>
#include <linux/list.h>
#include <linux/init.h>
#include <linux/string.h>
#include <asm/byteorder.h>
......
......@@ -177,7 +177,7 @@ static int nodemgr_read_quadlet(struct hpsb_host *host,
for (i = 0; i < 3; i++) {
ret = hpsb_read(host, nodeid, generation, address, quad, 4);
if (ret != -EAGAIN)
if (!ret)
break;
}
*quad = be32_to_cpu(*quad);
......@@ -985,12 +985,26 @@ static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, unsigned
HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT,
NODE_BUS_ARGS(nodeid));
#endif
/*
* Must retry a few times if config rom read returns zero (how long?). Will
* not normally occur, but we should do the right thing. For example, with
* some sbp2 devices, the bridge chipset cannot return valid config rom reads
* immediately after power-on, since they need to detect the type of
* device attached (disk or CD-ROM).
*/
for (i = 0; i < 4; i++) {
if (nodemgr_read_quadlet(host, nodeid, generation,
addr, &buffer[0]) < 0) {
HPSB_ERR("ConfigROM quadlet transaction error for node "
NODE_BUS_FMT, NODE_BUS_ARGS(nodeid));
return -1;
}
if (buffer[0])
break;
if (nodemgr_read_quadlet(host, nodeid, generation,
addr, &buffer[0]) < 0) {
HPSB_ERR("ConfigROM quadlet transaction error for node "
NODE_BUS_FMT, NODE_BUS_ARGS(nodeid));
return -1;
set_current_state(TASK_INTERRUPTIBLE);
if (schedule_timeout (HZ/4))
return -1;
}
header_size = buffer[0] >> 24;
......@@ -1051,10 +1065,15 @@ static void nodemgr_node_probe_one(struct hpsb_host *host,
return;
if (buffer[1] != IEEE1394_BUSID_MAGIC) {
/* This isn't a 1394 device */
HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device",
NODE_BUS_ARGS(nodeid));
return;
/* This isn't a 1394 device, but we let it slide. There
* was a report of a device with broken firmware which
* reported '2394' instead of '1394', which is obviously a
* mistake. One would hope that a non-1394 device never
* gets connected to Firewire bus. If someone does, we
* shouldn't be held responsible, so we'll allow it with a
* warning. */
HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]",
NODE_BUS_ARGS(nodeid), buffer[1]);
}
guid = ((u64)buffer[3] << 32) | buffer[4];
......@@ -1103,11 +1122,11 @@ static void nodemgr_node_probe(struct hpsb_host *host)
nodeid_t nodeid = LOCAL_BUS;
unsigned int generation;
/* Pause for 1 second, to make sure things settle down. If
/* Pause for 1/4 second, to make sure things settle down. If
* schedule_timeout returns non-zero, it means we caught a signal
* and need to return. */
set_current_state(TASK_INTERRUPTIBLE);
if (schedule_timeout (HZ))
if (schedule_timeout (HZ/4))
return;
/* Now get the generation in which the node ID's we collect
......
This diff is collapsed.
......@@ -21,6 +21,8 @@
#ifndef _OHCI1394_H
#define _OHCI1394_H
#include <asm/io.h>
#include "ieee1394_types.h"
#include <asm/io.h>
......@@ -144,7 +146,16 @@ struct ti_ohci {
struct pci_dev *dev;
u32 state;
enum {
OHCI_INIT_ALLOC_HOST,
OHCI_INIT_HAVE_MEM_REGION,
OHCI_INIT_HAVE_IOMAPPING,
OHCI_INIT_HAVE_CONFIG_ROM_BUFFER,
OHCI_INIT_HAVE_SELFID_BUFFER,
OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE,
OHCI_INIT_HAVE_IRQ,
OHCI_INIT_DONE,
} init_state;
/* remapped memory spaces */
void *registers;
......
......@@ -2,6 +2,7 @@
* ti_pcilynx.c - Texas Instruments PCILynx driver
* Copyright (C) 1999,2000 Andreas Bombe <andreas.bombe@munich.netsurf.de>,
* Stephan Linz <linz@mazet.de>
* Manfred Weihs <weihs@ict.tuwien.ac.at>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -41,6 +42,8 @@
#include "highlevel.h"
#include "pcilynx.h"
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
/* print general (card independent) information */
#define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
......@@ -56,9 +59,85 @@
#endif
/* Module Parameters */
MODULE_PARM(skip_eeprom,"i");
MODULE_PARM_DESC(skip_eeprom, "Do not try to read bus info block from serial eeprom, but user generic one (default = 0).");
static int skip_eeprom = 0;
static struct hpsb_host_driver *lynx_driver;
static unsigned int card_id;
/*
* I2C stuff
*/
/* the i2c stuff was inspired by i2c-philips-par.c */
static void bit_setscl(void *data, int state)
{
if (state) {
((struct ti_lynx *) data)->i2c_driven_state |= 0x00000040;
} else {
((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000040;
}
reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
}
static void bit_setsda(void *data, int state)
{
if (state) {
((struct ti_lynx *) data)->i2c_driven_state |= 0x00000010;
} else {
((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000010;
}
reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
}
static int bit_getscl(void *data)
{
return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000040;
}
static int bit_getsda(void *data)
{
return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000010;
}
static int bit_reg(struct i2c_client *client)
{
return 0;
}
static int bit_unreg(struct i2c_client *client)
{
return 0;
}
static struct i2c_algo_bit_data bit_data = {
NULL,
bit_setsda,
bit_setscl,
bit_getsda,
bit_getscl,
5, 5, 100, /* waits, timeout */
};
static struct i2c_adapter bit_ops = {
"PCILynx I2C adapter",
0xAA, //FIXME: probably we should get an id in i2c-id.h
NULL,
NULL,
NULL,
NULL,
bit_reg,
bit_unreg,
};
/*
* PCL handling functions.
*/
......@@ -880,7 +959,7 @@ static ssize_t mem_read(struct file *file, char *buffer, size_t count,
retval = copy_to_user(buffer, md->lynx->mem_dma_buffer, count);
up(&md->lynx->mem_dma_mutex);
if (retval) return -EFAULT;
if (retval < 0) return retval;
*offset += count;
return count;
}
......@@ -1232,6 +1311,11 @@ static int __devinit add_card(struct pci_dev *dev,
int i;
int error;
/* needed for i2c communication with serial eeprom */
struct i2c_adapter i2c_adapter;
struct i2c_algo_bit_data i2c_adapter_data;
int got_valid_bus_info_block = 0; /* set to 1, if we were able to get a valid bus info block from serial eeprom */
error = -ENXIO;
......@@ -1492,6 +1576,94 @@ static int __devinit add_card(struct pci_dev *dev,
if (i != -1) set_phy_reg(lynx, 4, i | 0x40);
}
if (!skip_eeprom)
{
i2c_adapter = bit_ops;
i2c_adapter_data = bit_data;
i2c_adapter.algo_data = &i2c_adapter_data;
i2c_adapter_data.data = lynx;
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
PRINT(KERN_DEBUG, lynx->id,"original eeprom control: %d",reg_read(lynx,SERIAL_EEPROM_CONTROL));
#endif
/* reset hardware to sane state */
lynx->i2c_driven_state = 0x00000070;
reg_write(lynx, SERIAL_EEPROM_CONTROL, lynx->i2c_driven_state);
if (i2c_bit_add_bus(&i2c_adapter) < 0)
{
PRINT(KERN_ERR, lynx->id, "unable to register i2c");
}
else
{
/* do i2c stuff */
unsigned char i2c_cmd = 0x10;
struct i2c_msg msg[2] = { { 0x50, 0, 1, &i2c_cmd },
{ 0x50, I2C_M_RD, 20, (unsigned char*) lynx->config_rom }
};
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
union i2c_smbus_data data;
if (i2c_smbus_xfer(&i2c_adapter, 80, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE,NULL))
PRINT(KERN_ERR, lynx->id,"eeprom read start has failed");
else
{
u16 addr;
for (addr=0x00; addr < 0x100; addr++) {
if (i2c_smbus_xfer(&i2c_adapter, 80, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE,& data)) {
PRINT(KERN_ERR, lynx->id, "unable to read i2c %x", addr);
break;
}
else
PRINT(KERN_DEBUG, lynx->id,"got serial eeprom data at %x: %x",addr, data.byte);
}
}
#endif
/* we use i2c_transfer, because i2c_smbus_read_block_data does not work properly and we
do it more efficiently in one transaction rather then using several reads */
if (i2c_transfer(&i2c_adapter, msg, 2) < 0) {
PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c");
} else {
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
int i;
#endif
PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom");
/* FIXME: probably we shoud rewrite the max_rec, max_ROM(1394a), generation(1394a) and link_spd(1394a) field
and recalculate the CRC */
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
for (i=0; i < 5 ; i++)
PRINT(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x",i, be32_to_cpu(lynx->config_rom[i]));
#endif
/* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */
if (((be32_to_cpu(lynx->config_rom[0]) & 0xffff0000) == 0x04040000) &&
(lynx->config_rom[1] == __constant_cpu_to_be32(0x31333934)))
{
PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from");
got_valid_bus_info_block = 1;
} else {
PRINT(KERN_WARNING, lynx->id, "read something from serial eeprom, but it does not seem to be a valid bus info block");
}
}
i2c_bit_del_bus(&i2c_adapter);
}
}
if (got_valid_bus_info_block) {
memcpy(lynx->config_rom+5,lynx_csr_rom+5,sizeof(lynx_csr_rom)-20);
} else {
PRINT(KERN_INFO, lynx->id, "since we did not get a bus info block from serial eeprom, we use a generic one with a hard coded GUID");
memcpy(lynx->config_rom,lynx_csr_rom,sizeof(lynx_csr_rom));
}
hpsb_add_host(host);
lynx->state = is_host;
......@@ -1503,7 +1675,8 @@ static int __devinit add_card(struct pci_dev *dev,
static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
{
*ptr = lynx_csr_rom;
struct ti_lynx *lynx = host->hostdata;
*ptr = lynx->config_rom;
return sizeof(lynx_csr_rom);
}
......
......@@ -25,6 +25,8 @@
#define CHANNEL_ASYNC_SEND 3
#define CHANNEL_ISO_SEND 4
#define PCILYNX_CONFIG_ROM_LENGTH 1024
typedef int pcl_t;
struct ti_lynx {
......@@ -48,7 +50,7 @@ struct ti_lynx {
void *local_rom;
void *local_ram;
void *aux_port;
quadlet_t config_rom[PCILYNX_CONFIG_ROM_LENGTH/4];
#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
atomic_t aux_intr_seen;
......@@ -109,6 +111,8 @@ struct ti_lynx {
struct tasklet_struct tq;
spinlock_t lock;
} iso_rcv;
u32 i2c_driven_state; /* the state we currently drive the Serial EEPROM Control register */
};
/* the per-file data structure for mem space access */
......@@ -156,6 +160,8 @@ static inline void reg_clear_bits(const struct ti_lynx *lynx, int offset,
#define MISC_CONTROL 0x40
#define MISC_CONTROL_SWRESET (1<<0)
#define SERIAL_EEPROM_CONTROL 0x44
#define PCI_INT_STATUS 0x48
#define PCI_INT_ENABLE 0x4c
/* status and enable have identical bit numbers */
......
......@@ -189,6 +189,8 @@ static void remove_host(struct hpsb_host *host)
}
kfree(hi);
atomic_inc(&internal_generation);
}
static void host_reset(struct hpsb_host *host)
......@@ -223,8 +225,6 @@ static void host_reset(struct hpsb_host *host)
}
}
spin_unlock_irqrestore(&host_info_lock, flags);
atomic_inc(&internal_generation);
}
static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
......
This diff is collapsed.
......@@ -398,9 +398,9 @@ struct scsi_id_instance_data {
u32 sbp2_firmware_revision;
/*
* Wait queue used for logins, reconnects, logouts
* Variable used for logins, reconnects, logouts
*/
wait_queue_head_t sbp2_login_wait;
atomic_t sbp2_login_complete;
/*
* Pool of command orbs, so we can have more than overlapped command per id
......@@ -501,6 +501,13 @@ static int sbp2_start_device(struct sbp2scsi_host_info *hi,
static void sbp2_remove_device(struct sbp2scsi_host_info *hi,
struct scsi_id_instance_data *scsi_id);
#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);
static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
u64 addr, unsigned int length);
#endif
/*
* SBP-2 protocol related prototypes
*/
......@@ -523,9 +530,8 @@ static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_i
static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data);
static void sbp2_check_sbp2_command(unchar *cmd);
static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
Scsi_Cmnd *SCpnt);
static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd);
static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, Scsi_Cmnd *SCpnt);
static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id);
static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
......
This diff is collapsed.
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