diff options
| -rw-r--r-- | drivers/ieee1394/Config.in | 21 | ||||
| -rw-r--r-- | drivers/ieee1394/Makefile | 6 | ||||
| -rw-r--r-- | drivers/ieee1394/amdtp.c | 6 | ||||
| -rw-r--r-- | drivers/ieee1394/dv1394-private.h | 2 | ||||
| -rw-r--r-- | drivers/ieee1394/dv1394.c | 199 | ||||
| -rw-r--r-- | drivers/ieee1394/dv1394.h | 73 | ||||
| -rw-r--r-- | drivers/ieee1394/hosts.c | 2 | ||||
| -rw-r--r-- | drivers/ieee1394/hosts.h | 1 | ||||
| -rw-r--r-- | drivers/ieee1394/ieee1394_core.c | 20 | ||||
| -rw-r--r-- | drivers/ieee1394/ieee1394_core.h | 1 | ||||
| -rw-r--r-- | drivers/ieee1394/ieee1394_transactions.c | 22 | ||||
| -rw-r--r-- | drivers/ieee1394/ieee1394_types.h | 1 | ||||
| -rw-r--r-- | drivers/ieee1394/nodemgr.c | 43 | ||||
| -rw-r--r-- | drivers/ieee1394/ohci1394.c | 287 | ||||
| -rw-r--r-- | drivers/ieee1394/ohci1394.h | 13 | ||||
| -rw-r--r-- | drivers/ieee1394/pcilynx.c | 177 | ||||
| -rw-r--r-- | drivers/ieee1394/pcilynx.h | 8 | ||||
| -rw-r--r-- | drivers/ieee1394/raw1394.c | 4 | ||||
| -rw-r--r-- | drivers/ieee1394/sbp2.c | 433 | ||||
| -rw-r--r-- | drivers/ieee1394/sbp2.h | 16 | ||||
| -rw-r--r-- | drivers/ieee1394/video1394.c | 201 |
21 files changed, 1023 insertions, 513 deletions
diff --git a/drivers/ieee1394/Config.in b/drivers/ieee1394/Config.in index 02c6ccb388af..f6d555d0080d 100644 --- a/drivers/ieee1394/Config.in +++ b/drivers/ieee1394/Config.in @@ -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 diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile index 59d51d5e518e..9237b30b450a 100644 --- a/drivers/ieee1394/Makefile +++ b/drivers/ieee1394/Makefile @@ -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) diff --git a/drivers/ieee1394/amdtp.c b/drivers/ieee1394/amdtp.c index 1f4a8eaef372..4b86e7f2e311 100644 --- a/drivers/ieee1394/amdtp.c +++ b/drivers/ieee1394/amdtp.c @@ -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"); } diff --git a/drivers/ieee1394/dv1394-private.h b/drivers/ieee1394/dv1394-private.h index fb30b90a46dc..3e6fff77c5cb 100644 --- a/drivers/ieee1394/dv1394-private.h +++ b/drivers/ieee1394/dv1394-private.h @@ -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 diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c index 355f274b46e0..35ae739c81a4 100644 --- a/drivers/ieee1394/dv1394.c +++ b/drivers/ieee1394/dv1394.c @@ -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, }; diff --git a/drivers/ieee1394/dv1394.h b/drivers/ieee1394/dv1394.h index d427cfde6eb7..089851076c2e 100644 --- a/drivers/ieee1394/dv1394.h +++ b/drivers/ieee1394/dv1394.h @@ -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 diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c index 5701f53f32a6..0bd840be7df9 100644 --- a/drivers/ieee1394/hosts.c +++ b/drivers/ieee1394/hosts.c @@ -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; diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h index 5488e8ecba43..58cf427609db 100644 --- a/drivers/ieee1394/hosts.h +++ b/drivers/ieee1394/hosts.h @@ -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]; diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index f72a0b9641af..347346599671 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -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 @@ out_fail: function returns. */ file->f_op = &ieee1394_chardev_ops; - unlock_kernel(); return retval; #undef INCREF diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index e3d1975d977d..693c4d3b816b 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h @@ -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 */ diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c index 5a63fe3571d1..c153cb724463 100644 --- a/drivers/ieee1394/ieee1394_transactions.c +++ b/drivers/ieee1394/ieee1394_transactions.c @@ -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; diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h index 9f348d0cbf2b..d5ce71d9dcfa 100644 --- a/drivers/ieee1394/ieee1394_types.h +++ b/drivers/ieee1394/ieee1394_types.h @@ -7,7 +7,6 @@ #include <linux/version.h> #include <linux/list.h> #include <linux/init.h> -#include <linux/string.h> #include <asm/byteorder.h> diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 5f769564f33c..9960ca86c266 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -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 diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index e0d1172fc3e4..e25f4ecdcf8a 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -37,7 +37,7 @@ * . DMA error recovery * * Known bugs: - * . Apple PowerBook detected but not working yet (still true?) + * . devctl BUS_RESET arg confusion (reset type or root holdoff?) */ /* @@ -77,12 +77,6 @@ * . Config ROM generation */ -/* Issues: - * - * - devctl BUS_RESET should treat arg as reset type - * - */ - #include <linux/config.h> #include <linux/kernel.h> #include <linux/list.h> @@ -160,17 +154,21 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args) printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args) static char version[] __devinitdata = - "$Revision: 1.101 $ Ben Collins <bcollins@debian.org>"; + "$Rev: 504 $ Ben Collins <bcollins@debian.org>"; /* Module Parameters */ MODULE_PARM(attempt_root,"i"); -MODULE_PARM_DESC(attempt_root, "Attempt to make the host root."); +MODULE_PARM_DESC(attempt_root, "Attempt to make the host root (default = 0)."); static int attempt_root = 0; +MODULE_PARM(phys_dma,"i"); +MODULE_PARM_DESC(phys_dma, "Enable physical dma (default = 1)."); +static int phys_dma = 1; + static void dma_trm_tasklet(unsigned long data); static void dma_trm_reset(struct dma_trm_ctx *d); -static void __devexit ohci1394_pci_remove(struct pci_dev *pdev); +static void ohci1394_pci_remove(struct pci_dev *pdev); static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci, quadlet_t isoRecvEvent, @@ -224,7 +222,7 @@ static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr) spin_lock_irqsave (&ohci->phy_reg_lock, flags); - reg_write(ohci, OHCI1394_PhyControl, (((u16)addr << 8) & 0x00000f00) | 0x00008000); + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000); for (i = 0; i < OHCI_LOOP_COUNT; i++) { if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000) @@ -252,7 +250,7 @@ static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data) spin_lock_irqsave (&ohci->phy_reg_lock, flags); - reg_write(ohci, OHCI1394_PhyControl, 0x00004000 | (((u16)addr << 8) & 0x00000f00) | data); + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000); for (i = 0; i < OHCI_LOOP_COUNT; i++) { r = reg_read(ohci, OHCI1394_PhyControl); @@ -291,8 +289,6 @@ static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host, size_t size; quadlet_t q0, q1; - mdelay(10); - /* Check status of self-id reception */ if (ohci->selfid_swap) @@ -363,13 +359,6 @@ static void ohci_soft_reset(struct ti_ohci *ohci) { break; mdelay(1); } - - /* Now reenable LPS, since that's usually what we want after a - * softreset anyway. Wait 50msec to make sure we have full link - * enabled. */ - reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); - mdelay(50); - DBGMSG (ohci->id, "Soft reset finished"); } @@ -488,14 +477,42 @@ static void ohci_initialize(struct ti_ohci *ohci) { quadlet_t buf; + /* Start off with a soft reset, to clear everything to a sane + * state. */ + ohci_soft_reset(ohci); + + /* Now enable LPS, which we need in order to start accessing + * most of the registers. In fact, on some cards (ALI M5251), + * accessing registers in the SClk domain without LPS enabled + * will lock up the machine. Wait 50msec to make sure we have + * full link enabled. */ + reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); + mdelay(50); + + /* Determine the number of available IR and IT contexts. */ + ohci->nb_iso_rcv_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); + DBGMSG(ohci->id, "%d iso receive contexts available", + ohci->nb_iso_rcv_ctx); + + ohci->nb_iso_xmit_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); + DBGMSG(ohci->id, "%d iso transmit contexts available", + ohci->nb_iso_xmit_ctx); + + /* Set the usage bits for non-existent contexts so they can't + * be allocated */ + ohci->ir_ctx_usage |= ~0 << ohci->nb_iso_rcv_ctx; + ohci->it_ctx_usage |= ~0 << ohci->nb_iso_xmit_ctx; + spin_lock_init(&ohci->phy_reg_lock); spin_lock_init(&ohci->event_lock); /* Put some defaults to these undefined bus options */ buf = reg_read(ohci, OHCI1394_BusOptions); - buf |= 0x60000000; /* Enable CMC and ISC */ + buf |= 0xE0000000; /* Enable IRMC, CMC and ISC */ buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */ - buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */ + buf &= ~0x18000000; /* Disable PMC and BMC */ reg_write(ohci, OHCI1394_BusOptions, buf); /* Set the bus number */ @@ -507,8 +524,10 @@ static void ohci_initialize(struct ti_ohci *ohci) /* Clear link control register */ reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); - /* Enable cycle timer and cycle master */ + /* Enable cycle timer and cycle master and set the IRM + * contender bit in our self ID packets. */ reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000); + set_phy_reg_mask(ohci, 4, 0xc0); /* Clear interrupt registers */ reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); @@ -610,7 +629,7 @@ static void ohci_initialize(struct ti_ohci *ohci) ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq, pci_resource_start(ohci->dev, 0), - pci_resource_start(ohci->dev, 0) + pci_resource_len(ohci->dev, 0), + pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE, ohci->max_packet_size); } @@ -1242,15 +1261,6 @@ static void ohci_irq_handler(int irq, void *dev_id, 0xffffffff); reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff); - /* Turn on phys dma reception. We should - * probably manage the filtering somehow, - * instead of blindly turning it on. */ - reg_write(ohci,OHCI1394_PhyReqFilterHiSet, - 0xffffffff); - reg_write(ohci,OHCI1394_PhyReqFilterLoSet, - 0xffffffff); - reg_write(ohci,OHCI1394_PhyUpperBound, - 0xffff0000); } else PRINT(KERN_ERR, ohci->id, "SelfID received outside of bus reset sequence"); @@ -1262,6 +1272,31 @@ static void ohci_irq_handler(int irq, void *dev_id, reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); spin_unlock_irqrestore(&ohci->event_lock, flags); event &= ~OHCI1394_selfIDComplete; + + /* Turn on phys dma reception. We should + * probably manage the filtering somehow, + * instead of blindly turning it on. */ + + /* + * CAUTION! + * Some chips (TI TSB43AB22) won't take a value in + * the PhyReqFilter register until after the IntEvent + * is cleared for bus reset, and even then a short + * delay is required. + */ + if (phys_dma) { + mdelay(1); + reg_write(ohci,OHCI1394_PhyReqFilterHiSet, + 0xffffffff); + reg_write(ohci,OHCI1394_PhyReqFilterLoSet, + 0xffffffff); + reg_write(ohci,OHCI1394_PhyUpperBound, + 0xffff0000); + } + + DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n", + reg_read(ohci,OHCI1394_PhyReqFilterHiSet), + reg_read(ohci,OHCI1394_PhyReqFilterLoSet)); } /* Make sure we handle everything, just in case we accidentally @@ -1831,7 +1866,7 @@ static u16 ohci_crc16 (u32 *ptr, int length) crc = 0; for (; length > 0; length--) { - data = *ptr++; + data = be32_to_cpu(*ptr++); for (shift = 28; shift >= 0; shift -= 4) { sum = ((crc >> 12) ^ (data >> shift)) & 0x000f; crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; @@ -2023,7 +2058,7 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, struct hpsb_host *host; struct ti_ohci *ohci; /* shortcut to currently handled device */ - unsigned long ohci_base, ohci_len; + unsigned long ohci_base; int i; if (version_printed++ == 0) @@ -2041,6 +2076,7 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, ohci->id = card_id_counter++; ohci->dev = dev; ohci->host = host; + ohci->init_state = OHCI_INIT_ALLOC_HOST; host->pdev = dev; pci_set_drvdata(dev, ohci); @@ -2056,76 +2092,54 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, * zero. Should this work? Obviously it's not defined what these * registers will read when they aren't supported. Bleh! */ if (dev->vendor == PCI_VENDOR_ID_APPLE && - dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { - ohci->no_swap_incoming = 1; - ohci->selfid_swap = 0; + dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { + ohci->no_swap_incoming = 1; + ohci->selfid_swap = 0; } else ohci->selfid_swap = 1; #endif - /* csr_config rom allocation */ - ohci->csr_config_rom_cpu = - pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, - &ohci->csr_config_rom_bus); - OHCI_DMA_ALLOC("consistent csr_config_rom"); - if (ohci->csr_config_rom_cpu == NULL) - FAIL(-ENOMEM, "Failed to allocate buffer config rom"); - - + /* We hardwire the MMIO length, since some CardBus adaptors + * fail to report the right length. Anyway, the ohci spec + * clearly says it's 2kb, so this shouldn't be a problem. */ ohci_base = pci_resource_start(dev, 0); - ohci_len = pci_resource_len(dev, 0); - - if (!request_mem_region (ohci_base, ohci_len, OHCI1394_DRIVER_NAME)) - FAIL(-ENOMEM, "MMIO resource (0x%lx@0x%lx) unavailable, aborting.", - ohci_base, ohci_len); - - ohci->registers = ioremap(ohci_base, ohci_len); + if (pci_resource_len(dev, 0) != OHCI1394_REGISTER_SIZE) + PRINT(KERN_WARNING, ohci->id, "Unexpected PCI resource length of %lx!", + pci_resource_len(dev, 0)); + + /* Seems PCMCIA handles this internally. Not sure why. Seems + * pretty bogus to force a driver to special case this. */ +#ifndef PCMCIA + if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME)) + FAIL(-ENOMEM, "MMIO resource (0x%lx - 0x%lx) unavailable", + ohci_base, ohci_base + OHCI1394_REGISTER_SIZE); +#endif + ohci->init_state = OHCI_INIT_HAVE_MEM_REGION; + ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE); if (ohci->registers == NULL) FAIL(-ENXIO, "Failed to remap registers - card not accessible"); - + ohci->init_state = OHCI_INIT_HAVE_IOMAPPING; DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", ohci->registers); + /* csr_config rom allocation */ + ohci->csr_config_rom_cpu = + pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, + &ohci->csr_config_rom_bus); + OHCI_DMA_ALLOC("consistent csr_config_rom"); + if (ohci->csr_config_rom_cpu == NULL) + FAIL(-ENOMEM, "Failed to allocate buffer config rom"); + ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER; - /* Start off with a softreset, to clear everything to a sane - * state. This will also set Link Power State (LPS), which we - * need in order to start accessing most of the registers. */ - ohci_soft_reset(ohci); - - /* determinte the number of available IR and IT contexts right away, - because they need to be known for alloc_dma_*_ctx() */ - ohci->nb_iso_rcv_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); - DBGMSG(ohci->id, "%d iso receive contexts available", - ohci->nb_iso_rcv_ctx); - - ohci->ir_ctx_usage = 0; - - /* set the usage bits for non-existent contexts so they can't be allocated */ - for(i = ohci->nb_iso_rcv_ctx; i < sizeof(ohci->ir_ctx_usage)*8; i++) - __set_bit(i, &ohci->ir_ctx_usage); - - ohci->nb_iso_xmit_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); - DBGMSG(ohci->id, "%d iso transmit contexts available", - ohci->nb_iso_xmit_ctx); - - ohci->it_ctx_usage = 0; - - /* set the usage bits for non-existent contexts so they can't be allocated */ - for(i = ohci->nb_iso_xmit_ctx; i < sizeof(ohci->it_ctx_usage)*8; i++) - __set_bit(i, &ohci->it_ctx_usage); - - - /* - * self-id dma buffer allocation - */ + /* self-id dma buffer allocation */ ohci->selfid_buf_cpu = pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, &ohci->selfid_buf_bus); OHCI_DMA_ALLOC("consistent selfid_buf"); + if (ohci->selfid_buf_cpu == NULL) FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets"); + ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER; if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff) PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on " @@ -2135,6 +2149,7 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, /* No self-id errors at startup */ ohci->self_id_errors = 0; + ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE; /* AR DMA request context allocation */ ohci->ar_req_context = alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC, @@ -2169,6 +2184,9 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, if (ohci->at_resp_context == NULL) FAIL(-ENOMEM, "Failed to allocate AT Resp context"); + ohci->ir_ctx_usage = 0; + ohci->it_ctx_usage = 0; + /* IR DMA context */ ohci->ir_context = alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, 0, IR_NUM_DESC, @@ -2199,85 +2217,76 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, OHCI1394_DRIVER_NAME, ohci)) FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq); + ohci->init_state = OHCI_INIT_HAVE_IRQ; ohci_initialize(ohci); /* Tell the highlevel this host is ready */ hpsb_add_host(host); + ohci->init_state = OHCI_INIT_DONE; return 0; #undef FAIL } -static void __devexit ohci1394_pci_remove(struct pci_dev *pdev) +static void ohci1394_pci_remove(struct pci_dev *pdev) { struct ti_ohci *ohci; - quadlet_t buf; ohci = pci_get_drvdata(pdev); if (!ohci) return; - if (ohci->host) + switch (ohci->init_state) { + case OHCI_INIT_DONE: hpsb_remove_host(ohci->host); - /* Soft reset before we start */ - ohci_soft_reset(ohci); - - /* Free AR dma */ - free_dma_rcv_ctx(&ohci->ar_req_context); - free_dma_rcv_ctx(&ohci->ar_resp_context); + case OHCI_INIT_HAVE_IRQ: + /* Soft reset before we start - this disables + * interrupts and clears linkEnable and LPS. */ + ohci_soft_reset(ohci); + free_irq(ohci->dev->irq, ohci); - /* Free AT dma */ - free_dma_trm_ctx(&ohci->at_req_context); - free_dma_trm_ctx(&ohci->at_resp_context); + case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE: + /* Free AR dma */ + free_dma_rcv_ctx(&ohci->ar_req_context); + free_dma_rcv_ctx(&ohci->ar_resp_context); - /* Free IR dma */ - free_dma_rcv_ctx(&ohci->ir_context); + /* Free AT dma */ + free_dma_trm_ctx(&ohci->at_req_context); + free_dma_trm_ctx(&ohci->at_resp_context); - /* Free IT dma */ - free_dma_trm_ctx(&ohci->it_context); - - /* Disable all interrupts */ - reg_write(ohci, OHCI1394_IntMaskClear, 0x80000000); - free_irq(ohci->dev->irq, ohci); - - /* Free self-id buffer */ - if (ohci->selfid_buf_cpu) { + /* Free IR dma */ + free_dma_rcv_ctx(&ohci->ir_context); + + /* Free IT dma */ + free_dma_trm_ctx(&ohci->it_context); + + case OHCI_INIT_HAVE_SELFID_BUFFER: pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, ohci->selfid_buf_cpu, ohci->selfid_buf_bus); OHCI_DMA_FREE("consistent selfid_buf"); - } - - /* Free config rom */ - if (ohci->csr_config_rom_cpu) { + + case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER: pci_free_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, - ohci->csr_config_rom_cpu, + ohci->csr_config_rom_cpu, ohci->csr_config_rom_bus); OHCI_DMA_FREE("consistent csr_config_rom"); - } - - /* Disable our bus options */ - buf = reg_read(ohci, OHCI1394_BusOptions); - buf &= ~0xf8000000; - buf |= 0x00ff0000; - reg_write(ohci, OHCI1394_BusOptions, buf); - - /* Clear LinkEnable and LPS */ - reg_write(ohci, OHCI1394_HCControlClear, 0x000a0000); - if (ohci->registers) + case OHCI_INIT_HAVE_IOMAPPING: iounmap(ohci->registers); - release_mem_region (pci_resource_start(ohci->dev, 0), - pci_resource_len(ohci->dev, 0)); + case OHCI_INIT_HAVE_MEM_REGION: +#ifndef PCMCIA + release_mem_region(pci_resource_start(ohci->dev, 0), + OHCI1394_REGISTER_SIZE); +#endif #ifdef CONFIG_ALL_PPC - /* On UniNorth, power down the cable and turn off the - * chip clock when the module is removed to save power - * on laptops. Turning it back ON is done by the arch - * code when pci_enable_device() is called - */ + /* On UniNorth, power down the cable and turn off the chip + * clock when the module is removed to save power on + * laptops. Turning it back ON is done by the arch code when + * pci_enable_device() is called */ { struct device_node* of_node; @@ -2289,8 +2298,10 @@ static void __devexit ohci1394_pci_remove(struct pci_dev *pdev) } #endif /* CONFIG_ALL_PPC */ - pci_set_drvdata(ohci->dev, NULL); - hpsb_unref_host(ohci->host); + case OHCI_INIT_ALLOC_HOST: + pci_set_drvdata(ohci->dev, NULL); + hpsb_unref_host(ohci->host); + } } #define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) @@ -2313,7 +2324,7 @@ static struct pci_driver ohci1394_pci_driver = { name: OHCI1394_DRIVER_NAME, id_table: ohci1394_pci_tbl, probe: ohci1394_pci_probe, - remove: __devexit_p(ohci1394_pci_remove), + remove: ohci1394_pci_remove, }; diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h index 7d2bb3396bef..61e4988055b6 100644 --- a/drivers/ieee1394/ohci1394.h +++ b/drivers/ieee1394/ohci1394.h @@ -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; diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index f04d4ba13c25..17d105d443e7 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -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); } diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h index 879774645348..d1cc73c2b14b 100644 --- a/drivers/ieee1394/pcilynx.h +++ b/drivers/ieee1394/pcilynx.h @@ -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 */ diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 4a0f83221049..ee52d81f5264 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -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, diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index fe14a1e573c2..3338ed620e69 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -86,6 +86,9 @@ * sbp2_max_sectors, - Change max sectors per I/O supported (default = 255) * sbp2_max_outstanding_cmds - Change max outstanding concurrent commands (default = 8) * sbp2_max_cmds_per_lun - Change max concurrent commands per sbp2 device (default = 1) + * sbp2_exclusive_login - Set to zero if you'd like to allow multiple hosts the ability + * to log in at the same time. Sbp2 device must support this, + * and you must know what you're doing (default = 1) * * (e.g. insmod sbp2 sbp2_serialize_io = 1) * @@ -135,11 +138,14 @@ * - Error Handling: SCSI aborts and bus reset requests are handled somewhat * but the code needs additional debugging. * - * - The SBP-2 driver is currently only supported as a module. It would not take + * - Module: The SBP-2 driver is currently only supported as a module. It would not take * much work to allow it to be compiled into the kernel, but you'd have to * add some init code to the kernel to support this... and modules are much * more flexible anyway. ;-) * + * - Hot-plugging: Interaction with the SCSI stack and support for hot-plugging could + * stand some improvement. + * * * History: * @@ -265,7 +271,7 @@ * which do not support requests of 128KB or greater. Now use * max_sectors scsi host entry to limit transfer sizes. * * Change status fifo address from a single address to a set of addresses, - * with each sbp2 device having it's own status fifo address. This makes + * with each sbp2 device having its own status fifo address. This makes * it easier to match the status write to the sbp2 device instance. * * Minor change to use lun when logging into sbp2 devices. First step in * supporting multi-lun devices such as CD/DVD changer devices. @@ -278,7 +284,20 @@ * 02/20/02 - Added a couple additional module load options. * Needed to bump down max commands per lun because of the !%@&*^# QPS CDRW * drive I have, which doesn't seem to get along with other sbp2 devices - * (or handle linked commands well). + * (or handle linked commands well). + * 04/21/02 - Added some additional debug capabilities: + * * Able to handle phys dma requests directly, if host controller has phys + * dma disabled (e.g. insmod ohci1394 phys_dma=0). Undefine CONFIG_IEEE1394_SBP2_PHYS_DMA + * if you'd like to disable sbp2 driver from registering for phys address range. + * * New packet dump debug define (CONFIG_IEEE1394_SBP2_PACKET_DUMP) which allows + * dumping of all sbp2 related packets sent and received. Especially effective + * when phys dma is disabled on ohci controller (e.g. insmod ohci1394 phys_dma=0). + * * Added new sbp2 module load option (sbp2_exclusive_login) for allowing + * non-exclusive login to sbp2 device, for special multi-host applications. + * 04/23/02 - Fix for Sony CD-ROM drives. Only send fetch agent reset to sbp2 device if it + * returns the dead bit in status. Thanks to Chandan (chandan@toad.net) for this one. + * 04/27/02 - Fix sbp2 login problem on SMP systems, enable real spinlocks by default. (JSG) + * 06/09/02 - Don't force 36-bute SCSI inquiry, but leave in a define for badly behaved devices. (JSG) */ @@ -305,6 +324,7 @@ #include <asm/uaccess.h> #include <asm/io.h> #include <asm/byteorder.h> +#include <asm/atomic.h> #include <asm/system.h> #include <asm/io.h> #include <asm/scatterlist.h> @@ -329,6 +349,9 @@ #include "ieee1394_hotplug.h" #include "sbp2.h" +static char version[] __devinitdata = + "$Rev: 507 $ James Goodwin <jamesg@filanet.com>"; + /* * Module load parameter definitions */ @@ -387,6 +410,18 @@ MODULE_PARM(sbp2_max_cmds_per_lun,"i"); MODULE_PARM_DESC(sbp2_max_cmds_per_lun, "Change max concurrent commands per sbp2 device (default = 1)"); static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN; +/* + * Exclusive login to sbp2 device? In most cases, the sbp2 driver should do an exclusive login, as it's + * generally unsafe to have two hosts talking to a single sbp2 device at the same time (filesystem + * coherency, etc.). If you're running an sbp2 device that supports multiple logins, and you're either + * running read-only filesystems or some sort of special filesystem supporting multiple hosts, 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"); +MODULE_PARM_DESC(sbp2_exclusive_login, "Exclusive login to sbp2 device (default = 1)"); +static int sbp2_exclusive_login = 1; + /* * Export information about protocols/devices supported by this driver. @@ -411,6 +446,7 @@ MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table); /* #define CONFIG_IEEE1394_SBP2_DEBUG_DMA */ /* #define CONFIG_IEEE1394_SBP2_DEBUG 1 */ /* #define CONFIG_IEEE1394_SBP2_DEBUG 2 */ +/* #define CONFIG_IEEE1394_SBP2_PACKET_DUMP */ #ifdef CONFIG_IEEE1394_SBP2_DEBUG_ORBS #define SBP2_ORB_DEBUG(fmt, args...) HPSB_ERR("sbp2(%s): "fmt, __FUNCTION__, ## args) @@ -456,10 +492,10 @@ static u32 global_outstanding_dmas = 0; #define SBP2_ERR(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args) /* - * Spinlock debugging stuff. I'm playing it safe until the driver has been - * debugged on SMP. (JSG) + * Spinlock debugging stuff. */ -/* #define SBP2_USE_REAL_SPINLOCKS */ +#define SBP2_USE_REAL_SPINLOCKS + #ifdef SBP2_USE_REAL_SPINLOCKS #define sbp2_spin_lock(lock, flags) spin_lock_irqsave(lock, flags) #define sbp2_spin_unlock(lock, flags) spin_unlock_irqrestore(lock, flags); @@ -470,6 +506,14 @@ static spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED; #endif /* + * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on if your sbp2 device + * is not properly handling the SCSI inquiry command. This hack makes the inquiry look more + * like a typical MS Windows inquiry. + */ + +/* #define SBP2_FORCE_36_BYTE_INQUIRY */ + +/* * Globals */ @@ -490,6 +534,13 @@ static struct hpsb_address_ops sbp2_ops = { write: sbp2_handle_status_write }; +#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA +static struct hpsb_address_ops sbp2_physdma_ops = { + read: sbp2_handle_physdma_read, + write: sbp2_handle_physdma_write, +}; +#endif + static struct hpsb_protocol_driver sbp2_driver = { name: "SBP2 Driver", id_table: sbp2_id_table, @@ -498,7 +549,6 @@ static struct hpsb_protocol_driver sbp2_driver = { update: sbp2_update }; - /************************************** * General utility functions @@ -537,6 +587,56 @@ static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length) #define sbp2util_cpu_to_be32_buffer(x,y) #endif +#ifdef CONFIG_IEEE1394_SBP2_PACKET_DUMP +/* + * Debug packet dump routine. Length is in bytes. + */ +static void sbp2util_packet_dump(void *buffer, int length, char *dump_name, u32 dump_phys_addr) +{ + int i; + unsigned char *dump = buffer; + + if (!dump || !length || !dump_name) + return; + + if (dump_phys_addr) + printk("[%s, 0x%x]", dump_name, dump_phys_addr); + else + printk("[%s]", dump_name); + for (i = 0; i < length; i++) { + if (i > 0x3f) { + printk("\n ..."); + break; + } + if ((i & 0x3) == 0) + printk(" "); + if ((i & 0xf) == 0) + printk("\n "); + printk("%02x ", (int) dump[i]); + } + printk("\n"); + + return; +} +#else +#define sbp2util_packet_dump(w,x,y,z) +#endif + +/* + * Goofy routine that basically does a down_timeout function. + */ +static int sbp2util_down_timeout(atomic_t *done, int timeout) +{ + int i; + + for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) { + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout(HZ/10)) /* 100ms */ + return(1); + } + return ((i > 0) ? 0:1); +} + /* * This function is called to initially create a packet pool for use in * sbp2 I/O requests. This packet pool is used when sending out sbp2 @@ -665,7 +765,7 @@ sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi, hpsb_node_fill_packet(ne, packet); - packet->tlabel = get_tlabel(hi->host, packet->node_id, 1); + packet->tlabel = get_tlabel(hi->host, packet->node_id, 0); if (!data_size) { fill_async_writequad(packet, addr, data); @@ -950,6 +1050,13 @@ int sbp2_init(void) SBP2_STATUS_FIFO_ADDRESS + SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1)); + /* + * Handle data movement if physical dma is not enabled/supported on host controller + */ +#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA + hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL); +#endif + hpsb_register_protocol(&sbp2_driver); return 0; @@ -1241,7 +1348,7 @@ alloc_fail_first: scsi_id->max_payload_size = sbp2_speedto_maxrec[SPEED_100]; ud->driver_data = scsi_id; - init_waitqueue_head(&scsi_id->sbp2_login_wait); + atomic_set(&scsi_id->sbp2_login_complete, 0); /* * Initialize structures needed for the command orb pool. @@ -1379,20 +1486,62 @@ static void sbp2_remove_device(struct sbp2scsi_host_info *hi, kfree(scsi_id); } - +#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA +/* + * This function deals with physical dma write requests (for adapters that do not support + * physical dma in hardware). Mostly just here for debugging... + */ +static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data, + u64 addr, unsigned int length) +{ + + /* + * Manually put the data in the right place. + */ + memcpy(bus_to_virt((u32)addr), data, length); + sbp2util_packet_dump(data, length, "sbp2 phys dma write by device", (u32)addr); + return(RCODE_COMPLETE); +} + +/* + * This function deals with physical dma read requests (for adapters that do not support + * physical dma in hardware). Mostly just here for debugging... + */ +static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length) +{ + + /* + * Grab data from memory and send a read response. + */ + memcpy(data, bus_to_virt((u32)addr), length); + sbp2util_packet_dump(data, length, "sbp2 phys dma read by device", (u32)addr); + return(RCODE_COMPLETE); +} +#endif + /************************************** * SBP-2 protocol related section **************************************/ /* + * This function determines if we should convert scsi commands for a particular sbp2 device type + */ +static __inline__ int sbp2_command_conversion_device_type(u8 device_type) +{ + return (((device_type == TYPE_DISK) || + (device_type == TYPE_SDAD) || + (device_type == TYPE_ROM)) ? 1:0); +} + +/* * This function is called in order to login to a particular SBP-2 device, * after a bus reset. */ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { quadlet_t data[2]; - unsigned long flags; SBP2_DEBUG("sbp2_login_device"); @@ -1412,7 +1561,7 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_insta scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST); scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0); /* One second reconnect time */ - scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(1); /* Exclusive access to device */ + scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(sbp2_exclusive_login); /* Exclusive access to device */ scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1); /* Notify us of login complete */ /* Set the lun if we were able to pull it from the device's unit directory */ if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) { @@ -1437,6 +1586,9 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_insta SBP2_DEBUG("sbp2_login_device: orb byte-swapped"); + sbp2util_packet_dump(scsi_id->login_orb, sizeof(struct sbp2_login_orb), + "sbp2 login orb", scsi_id->login_orb_dma); + /* * Initialize login response and status fifo */ @@ -1452,35 +1604,28 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_insta data[1] = scsi_id->login_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); + atomic_set(&scsi_id->sbp2_login_complete, 0); + SBP2_DEBUG("sbp2_login_device: prepared to write"); hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8); SBP2_DEBUG("sbp2_login_device: written"); /* - * Wait for login status... but, only if the device has not - * already logged-in (some devices are fast) + * Wait for login status (up to 20 seconds)... */ - - save_flags(flags); - cli(); - /* 20 second timeout */ - if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) - sleep_on_timeout(&scsi_id->sbp2_login_wait, 20*HZ); - restore_flags(flags); - - SBP2_DEBUG("sbp2_login_device: initial check"); + if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 20*HZ)) { + SBP2_ERR("Error logging into SBP-2 device - login timed-out"); + return(-EIO); + } /* - * Match status to the login orb. If they do not match, it's - * probably because the login timed-out. + * Sanity. Make sure status returned matches login orb. */ if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) { SBP2_ERR("Error logging into SBP-2 device - login timed-out"); return(-EIO); } - SBP2_DEBUG("sbp2_login_device: second check"); - /* * Check status */ @@ -1552,6 +1697,9 @@ static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_inst */ sbp2util_cpu_to_be32_buffer(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb)); + sbp2util_packet_dump(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb), + "sbp2 logout orb", scsi_id->logout_orb_dma); + /* * Ok, let's write to the target's management agent register */ @@ -1559,10 +1707,12 @@ static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_inst data[1] = scsi_id->logout_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); + atomic_set(&scsi_id->sbp2_login_complete, 0); + hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8); /* Wait for device to logout...1 second. */ - sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); + sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ); SBP2_INFO("Logged out of SBP-2 device"); @@ -1577,7 +1727,6 @@ static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_inst static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { quadlet_t data[2]; - unsigned long flags; SBP2_DEBUG("sbp2_reconnect_device"); @@ -1607,6 +1756,9 @@ static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_i */ sbp2util_cpu_to_be32_buffer(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb)); + sbp2util_packet_dump(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb), + "sbp2 reconnect orb", scsi_id->reconnect_orb_dma); + /* * Initialize status fifo */ @@ -1619,22 +1771,20 @@ static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_i data[1] = scsi_id->reconnect_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); + atomic_set(&scsi_id->sbp2_login_complete, 0); + hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8); /* - * Wait for reconnect status... but, only if the device has not - * already reconnected (some devices are fast). + * Wait for reconnect status (up to 1 second)... */ - save_flags(flags); - cli(); - /* One second timout */ - if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) - sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); - restore_flags(flags); + if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ)) { + SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out"); + return(-EIO); + } /* - * Match status to the reconnect orb. If they do not match, it's - * probably because the reconnect timed-out. + * Sanity. Make sure status returned matches reconnect orb. */ if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) { SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out"); @@ -2002,6 +2152,10 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, /* Number of page table (s/g) elements */ command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); + sbp2util_packet_dump(scatter_gather_element, + (sizeof(struct sbp2_unrestricted_page_table)) * sg_count, + "sbp2 s/g list", command->sge_dma); + /* * Byte swap page tables if necessary */ @@ -2081,6 +2235,10 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, /* Number of page table (s/g) elements */ command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); + sbp2util_packet_dump(scatter_gather_element, + (sizeof(struct sbp2_unrestricted_page_table)) * sg_count, + "sbp2 s/g list", command->sge_dma); + /* * Byte swap page tables if necessary */ @@ -2219,13 +2377,11 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta { unchar *cmd = (unchar *) SCpnt->cmnd; unsigned int request_bufflen = SCpnt->request_bufflen; - u8 device_type - = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun); struct sbp2_command_info *command; SBP2_DEBUG("sbp2_send_command"); - SBP2_DEBUG("SCSI command:"); -#if CONFIG_IEEE1394_SBP2_DEBUG >= 2 +#if (CONFIG_IEEE1394_SBP2_DEBUG >= 2) || defined(CONFIG_IEEE1394_SBP2_PACKET_DUMP) + printk("[scsi command]\n "); print_command (cmd); #endif SBP2_DEBUG("SCSI transfer size = %x", request_bufflen); @@ -2242,11 +2398,14 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta /* * The scsi stack sends down a request_bufflen which does not match the * length field in the scsi cdb. This causes some sbp2 devices to - * reject this inquiry command. Hack fix is to set both buff length and - * length field in cdb to 36. This gives best compatibility. + * reject this inquiry command. Fix the request_bufflen. */ if (*cmd == INQUIRY) { +#ifdef SBP2_FORCE_36_BYTE_INQUIRY request_bufflen = cmd[4] = 0x24; +#else + request_bufflen = cmd[4]; +#endif } /* @@ -2259,11 +2418,10 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta * Update our cdb if necessary (to handle sbp2 RBC command set * differences). This is where the command set hacks go! =) */ - if ((device_type == TYPE_DISK) || - (device_type == TYPE_SDAD) || - (device_type == TYPE_ROM)) { - sbp2_check_sbp2_command(command->command_orb.cdb); - } + sbp2_check_sbp2_command(scsi_id, command->command_orb.cdb); + + sbp2util_packet_dump(&command->command_orb, sizeof(struct sbp2_command_orb), + "sbp2 command orb", command->command_orb_dma); /* * Initialize status fifo @@ -2283,9 +2441,10 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta * This function deals with command set differences between Linux scsi * command set and sbp2 RBC command set. */ -static void sbp2_check_sbp2_command(unchar *cmd) +static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd) { unchar new_cmd[16]; + u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun); SBP2_DEBUG("sbp2_check_sbp2_command"); @@ -2293,67 +2452,79 @@ static void sbp2_check_sbp2_command(unchar *cmd) case READ_6: - SBP2_DEBUG("Convert READ_6 to READ_10"); + if (sbp2_command_conversion_device_type(device_type)) { - /* - * Need to turn read_6 into read_10 - */ - new_cmd[0] = 0x28; - new_cmd[1] = (cmd[1] & 0xe0); - new_cmd[2] = 0x0; - new_cmd[3] = (cmd[1] & 0x1f); - new_cmd[4] = cmd[2]; - new_cmd[5] = cmd[3]; - new_cmd[6] = 0x0; - new_cmd[7] = 0x0; - new_cmd[8] = cmd[4]; - new_cmd[9] = cmd[5]; - - memcpy(cmd, new_cmd, 10); + SBP2_DEBUG("Convert READ_6 to READ_10"); + + /* + * Need to turn read_6 into read_10 + */ + new_cmd[0] = 0x28; + new_cmd[1] = (cmd[1] & 0xe0); + new_cmd[2] = 0x0; + new_cmd[3] = (cmd[1] & 0x1f); + new_cmd[4] = cmd[2]; + new_cmd[5] = cmd[3]; + new_cmd[6] = 0x0; + new_cmd[7] = 0x0; + new_cmd[8] = cmd[4]; + new_cmd[9] = cmd[5]; + + memcpy(cmd, new_cmd, 10); + + } break; case WRITE_6: - SBP2_DEBUG("Convert WRITE_6 to WRITE_10"); + if (sbp2_command_conversion_device_type(device_type)) { - /* - * Need to turn write_6 into write_10 - */ - new_cmd[0] = 0x2a; - new_cmd[1] = (cmd[1] & 0xe0); - new_cmd[2] = 0x0; - new_cmd[3] = (cmd[1] & 0x1f); - new_cmd[4] = cmd[2]; - new_cmd[5] = cmd[3]; - new_cmd[6] = 0x0; - new_cmd[7] = 0x0; - new_cmd[8] = cmd[4]; - new_cmd[9] = cmd[5]; - - memcpy(cmd, new_cmd, 10); + SBP2_DEBUG("Convert WRITE_6 to WRITE_10"); + + /* + * Need to turn write_6 into write_10 + */ + new_cmd[0] = 0x2a; + new_cmd[1] = (cmd[1] & 0xe0); + new_cmd[2] = 0x0; + new_cmd[3] = (cmd[1] & 0x1f); + new_cmd[4] = cmd[2]; + new_cmd[5] = cmd[3]; + new_cmd[6] = 0x0; + new_cmd[7] = 0x0; + new_cmd[8] = cmd[4]; + new_cmd[9] = cmd[5]; + + memcpy(cmd, new_cmd, 10); + + } break; case MODE_SENSE: - SBP2_DEBUG("Convert MODE_SENSE_6 to MOSE_SENSE_10"); + if (sbp2_command_conversion_device_type(device_type)) { - /* - * Need to turn mode_sense_6 into mode_sense_10 - */ - new_cmd[0] = 0x5a; - new_cmd[1] = cmd[1]; - new_cmd[2] = cmd[2]; - new_cmd[3] = 0x0; - new_cmd[4] = 0x0; - new_cmd[5] = 0x0; - new_cmd[6] = 0x0; - new_cmd[7] = 0x0; - new_cmd[8] = cmd[4]; - new_cmd[9] = cmd[5]; - - memcpy(cmd, new_cmd, 10); + SBP2_DEBUG("Convert MODE_SENSE_6 to MODE_SENSE_10"); + + /* + * Need to turn mode_sense_6 into mode_sense_10 + */ + new_cmd[0] = 0x5a; + new_cmd[1] = cmd[1]; + new_cmd[2] = cmd[2]; + new_cmd[3] = 0x0; + new_cmd[4] = 0x0; + new_cmd[5] = 0x0; + new_cmd[6] = 0x0; + new_cmd[7] = 0x0; + new_cmd[8] = cmd[4]; + new_cmd[9] = cmd[5]; + + memcpy(cmd, new_cmd, 10); + + } break; @@ -2404,8 +2575,7 @@ static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense * This function is called after a command is completed, in order to do any necessary SBP-2 * response data translations for the SCSI stack */ -static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi, - struct scsi_id_instance_data *scsi_id, +static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, Scsi_Cmnd *SCpnt) { u8 *scsi_buf = SCpnt->request_buffer; @@ -2451,18 +2621,16 @@ static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi, case MODE_SENSE: - if ((device_type == TYPE_DISK) || - (device_type == TYPE_SDAD) || - (device_type == TYPE_ROM)) { - + if (sbp2_command_conversion_device_type(device_type)) { + SBP2_DEBUG("Modify mode sense response (10 byte version)"); - + scsi_buf[0] = scsi_buf[1]; /* Mode data length */ scsi_buf[1] = scsi_buf[2]; /* Medium type */ scsi_buf[2] = scsi_buf[3]; /* Device specific parameter */ scsi_buf[3] = scsi_buf[7]; /* Block descriptor length */ memcpy(scsi_buf + 4, scsi_buf + 8, scsi_buf[0]); - + } break; @@ -2495,6 +2663,8 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest SBP2_DEBUG("sbp2_handle_status_write"); + sbp2util_packet_dump(data, length, "sbp2 status write by device", (u32)addr); + if (!host) { SBP2_ERR("host is NULL - this is bad!"); return(RCODE_ADDRESS_ERROR); @@ -2566,21 +2736,21 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest /* * Translate SBP-2 status to SCSI sense data */ + SBP2_DEBUG("CHECK CONDITION"); scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer); } /* - * Handle check conditions. If there is either SBP status or SCSI status - * then we'll do a fetch agent reset and note that a check condition - * occured. + * Check to see if the dead bit is set. If so, we'll have to initiate + * a fetch agent reset. */ - if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc) || - scsi_status) { + if (STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc)) { + /* * Initiate a fetch agent reset. */ - SBP2_DEBUG("CHECK CONDITION"); - sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT); + SBP2_DEBUG("Dead bit set - initiating fetch agent reset"); + sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT); } SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb); @@ -2602,10 +2772,19 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest scsi_id->last_orb = NULL; } + } else { + + /* + * It's probably a login/logout/reconnect status. + */ + if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) || + (scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) || + (scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) { + atomic_set(&scsi_id->sbp2_login_complete, 1); + } } sbp2_spin_unlock(&hi->sbp2_command_lock, flags); - wake_up(&scsi_id->sbp2_login_wait); return(RCODE_COMPLETE); } @@ -2805,7 +2984,7 @@ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi * Take care of any sbp2 response data mucking here (RBC stuff, etc.) */ if (SCpnt->result == DID_OK) { - sbp2_check_sbp2_response(hi, scsi_id, SCpnt); + sbp2_check_sbp2_response(scsi_id, SCpnt); } /* @@ -2822,10 +3001,13 @@ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi * retried... it could have happened because of a 1394 bus reset * or hot-plug... */ - if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) { +#if 0 + if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && + (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) { SBP2_DEBUG("UNIT ATTENTION - return busy"); SCpnt->result = DID_BUS_BUSY << 16; } +#endif /* * Tell scsi stack that we're done with this command @@ -2835,9 +3017,9 @@ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi done (SCpnt); spin_unlock_irq(&io_request_lock); #else - spin_lock_irq(&hi->scsi_host->host_lock); + spin_lock_irq(hi->scsi_host->host_lock); done (SCpnt); - spin_unlock_irq(&hi->scsi_host->host_lock); + spin_unlock_irq(hi->scsi_host->host_lock); #endif return; @@ -2905,7 +3087,7 @@ static int sbp2scsi_reset (Scsi_Cmnd *SCpnt) SBP2_ERR("reset requested"); if (scsi_id) { - SBP2_ERR("Generating IEEE-1394 bus reset"); + SBP2_ERR("Generating sbp2 fetch agent reset"); sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT); } @@ -2969,19 +3151,22 @@ static const char *sbp2scsi_info (struct Scsi_Host *host) if (!hi) /* shouldn't happen, but... */ return "IEEE-1394 SBP-2 protocol driver"; - sprintf(info, "IEEE-1394 SBP-2 protocol driver (host: %s)\n" + sprintf(info, "IEEE-1394 SBP-2 protocol driver (host: %s)\n%s\n" "SBP-2 module load options:\n" "- Max speed supported: %s\n" "- Max sectors per I/O supported: %d\n" "- Max outstanding commands supported: %d\n" "- Max outstanding commands per lun supported: %d\n" - "- Serialized I/O (debug): %s", - hi->host->driver->name, + "- Serialized I/O (debug): %s\n" + "- Exclusive login: %s", + hi->host->driver->name, + version, hpsb_speedto_str[sbp2_max_speed], sbp2_max_sectors, sbp2_max_outstanding_cmds, sbp2_max_cmds_per_lun, - sbp2_serialize_io ? "yes" : "no"); + sbp2_serialize_io ? "yes" : "no", + sbp2_exclusive_login ? "yes" : "no"); return info; } diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h index 4ebe8c34a61b..7d6da4a61dd5 100644 --- a/drivers/ieee1394/sbp2.h +++ b/drivers/ieee1394/sbp2.h @@ -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); diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index 730878ecab79..edab382285e3 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -168,86 +168,35 @@ static struct hpsb_highlevel *hl_handle = NULL; /* 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 guaranteed. 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 unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - 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 = (unsigned long) - page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); - return ret; -} - -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); - return ret; -} - static inline unsigned long kvirt_to_bus(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = virt_to_bus((void *)kva); - MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); - return ret; + 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. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + 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) { @@ -256,8 +205,7 @@ static void * rvmalloc(unsigned long size) 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; } @@ -267,15 +215,14 @@ 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) + while ((long) 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; } @@ -520,11 +467,11 @@ alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc, static void reset_ir_status(struct dma_iso_ctx *d, int n) { int i; - d->ir_prg[n][0].status = 4; - d->ir_prg[n][1].status = PAGE_SIZE-4; + d->ir_prg[n][0].status = cpu_to_le32(4); + d->ir_prg[n][1].status = cpu_to_le32(PAGE_SIZE-4); for (i=2;i<d->nb_cmd-1;i++) - d->ir_prg[n][i].status = PAGE_SIZE; - d->ir_prg[n][i].status = d->left_size; + d->ir_prg[n][i].status = cpu_to_le32(PAGE_SIZE); + d->ir_prg[n][i].status = cpu_to_le32(d->left_size); } static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags) @@ -534,38 +481,38 @@ static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags) int i; /* the first descriptor will read only 4 bytes */ - ir_prg[0].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_BRANCH | 4; + ir_prg[0].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_BRANCH | 4); /* set the sync flag */ if (flags & VIDEO1394_SYNC_FRAMES) - ir_prg[0].control |= DMA_CTL_WAIT; + ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT); - ir_prg[0].address = kvirt_to_bus(buf); - ir_prg[0].branchAddress = (virt_to_bus(&(ir_prg[1].control)) - & 0xfffffff0) | 0x1; + ir_prg[0].address = cpu_to_le32(kvirt_to_bus(buf)); + ir_prg[0].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[1].control)) + & 0xfffffff0) | 0x1); /* the second descriptor will read PAGE_SIZE-4 bytes */ - ir_prg[1].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_BRANCH | (PAGE_SIZE-4); - ir_prg[1].address = kvirt_to_bus(buf+4); - ir_prg[1].branchAddress = (virt_to_bus(&(ir_prg[2].control)) - & 0xfffffff0) | 0x1; + ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_BRANCH | (PAGE_SIZE-4)); + ir_prg[1].address = cpu_to_le32(kvirt_to_bus(buf+4)); + ir_prg[1].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[2].control)) + & 0xfffffff0) | 0x1); for (i=2;i<d->nb_cmd-1;i++) { - ir_prg[i].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_BRANCH | PAGE_SIZE; - ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE); + ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_BRANCH | PAGE_SIZE); + ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE)); ir_prg[i].branchAddress = - (virt_to_bus(&(ir_prg[i+1].control)) - & 0xfffffff0) | 0x1; + cpu_to_le32((virt_to_bus(&(ir_prg[i+1].control)) + & 0xfffffff0) | 0x1); } /* the last descriptor will generate an interrupt */ - ir_prg[i].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size; - ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE); + ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size); + ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE)); } static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags) @@ -628,7 +575,7 @@ int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) spin_lock(&d->lock); for (i=0;i<d->num_desc;i++) { - if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) { + if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) { reset_ir_status(d, i); d->buffer_status[i] = VIDEO1394_BUFFER_READY; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) @@ -664,7 +611,7 @@ static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d, buf[7] = timeStamp & 0xff; /* if first packet is empty packet, then put timestamp into the next full one too */ - if ( (d->it_prg[n][0].data[1] >>16) == 0x008) { + if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) { buf += d->packet_size; buf[6] = timeStamp >> 8; buf[7] = timeStamp & 0xff; @@ -683,7 +630,7 @@ static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d, buf[7] = timeStamp & 0xff; /* if first packet is empty packet, then put timestamp into the next full one too */ - if ( (d->it_prg[n][0].data[1] >>16) == 0x008) { + if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) { buf += d->packet_size; buf[6] = timeStamp >> 8; buf[7] = timeStamp & 0xff; @@ -707,7 +654,8 @@ int wakeup_dma_it_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) spin_lock(&d->lock); for (i=0;i<d->num_desc;i++) { - if (d->it_prg[i][d->last_used_cmd[i]].end.status& 0xFFFF0000) { + if (d->it_prg[i][d->last_used_cmd[i]].end.status& + cpu_to_le32(0xFFFF0000)) { int next = d->next_buffer[i]; put_timestamp(ohci, d, next); d->it_prg[i][d->last_used_cmd[i]].end.status = 0; @@ -727,39 +675,40 @@ static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag) d->last_used_cmd[n] = d->nb_cmd - 1; for (i=0;i<d->nb_cmd;i++) { - it_prg[i].begin.control = DMA_CTL_OUTPUT_MORE | - DMA_CTL_IMMEDIATE | 8 ; + it_prg[i].begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE | + DMA_CTL_IMMEDIATE | 8) ; it_prg[i].begin.address = 0; it_prg[i].begin.status = 0; - it_prg[i].data[0] = + it_prg[i].data[0] = cpu_to_le32( (SPEED_100 << 16) | (/* tag */ 1 << 14) | (d->channel << 8) - | (TCODE_ISO_DATA << 4); - if (i==0) it_prg[i].data[0] |= sync_tag; - it_prg[i].data[1] = d->packet_size << 16; + | (TCODE_ISO_DATA << 4)); + if (i==0) it_prg[i].data[0] |= cpu_to_le32(sync_tag); + it_prg[i].data[1] = cpu_to_le32(d->packet_size << 16); it_prg[i].data[2] = 0; it_prg[i].data[3] = 0; - it_prg[i].end.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH; + it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | + DMA_CTL_BRANCH); it_prg[i].end.address = - kvirt_to_bus(buf+i*d->packet_size); + cpu_to_le32(kvirt_to_bus(buf+i*d->packet_size)); if (i<d->nb_cmd-1) { - it_prg[i].end.control |= d->packet_size; + it_prg[i].end.control |= cpu_to_le32(d->packet_size); it_prg[i].begin.branchAddress = - (virt_to_bus(&(it_prg[i+1].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) + & 0xfffffff0) | 0x3); it_prg[i].end.branchAddress = - (virt_to_bus(&(it_prg[i+1].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) + & 0xfffffff0) | 0x3); } else { /* the last prg generates an interrupt */ - it_prg[i].end.control |= DMA_CTL_UPDATE | - DMA_CTL_IRQ | d->left_size; + it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | + DMA_CTL_IRQ | d->left_size); /* the last prg doesn't branch */ it_prg[i].begin.branchAddress = 0; it_prg[i].end.branchAddress = 0; @@ -798,21 +747,21 @@ static void initialize_dma_it_prg_var_packet_queue( } else { size = packet_sizes[i]; } - it_prg[i].data[1] = size << 16; - it_prg[i].end.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH; + it_prg[i].data[1] = cpu_to_le32(size << 16); + it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH); if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) { - it_prg[i].end.control |= size; + it_prg[i].end.control |= cpu_to_le32(size); it_prg[i].begin.branchAddress = - (virt_to_bus(&(it_prg[i+1].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) + & 0xfffffff0) | 0x3); it_prg[i].end.branchAddress = - (virt_to_bus(&(it_prg[i+1].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) + & 0xfffffff0) | 0x3); } else { /* the last prg generates an interrupt */ - it_prg[i].end.control |= DMA_CTL_UPDATE | - DMA_CTL_IRQ | size; + it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | + DMA_CTL_IRQ | size); /* the last prg doesn't branch */ it_prg[i].begin.branchAddress = 0; it_prg[i].end.branchAddress = 0; @@ -1057,8 +1006,8 @@ static int video1394_ioctl(struct inode *inode, struct file *file, if (d->last_buffer>=0) d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = - (virt_to_bus(&(d->ir_prg[v.buffer][0].control)) - & 0xfffffff0) | 0x1; + cpu_to_le32((virt_to_bus(&(d->ir_prg[v.buffer][0].control)) + & 0xfffffff0) | 0x1); d->last_buffer = v.buffer; @@ -1217,14 +1166,14 @@ static int video1394_ioctl(struct inode *inode, struct file *file, d->it_prg[d->last_buffer] [ d->last_used_cmd[d->last_buffer] ].end.branchAddress = - (virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) + & 0xfffffff0) | 0x3); d->it_prg[d->last_buffer] [d->last_used_cmd[d->last_buffer] ].begin.branchAddress = - (virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) + & 0xfffffff0) | 0x3); d->next_buffer[d->last_buffer] = v.buffer; } d->last_buffer = v.buffer; |
