2007-05-08 04:33:32 +04:00
/*
* Driver for OHCI 1394 controllers
2006-12-20 03:58:35 +03:00
*
* Copyright ( C ) 2003 - 2006 Kristian Hoegsberg < krh @ bitplanet . net >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
2007-08-20 23:58:30 +04:00
# include <linux/compiler.h>
2006-12-20 03:58:35 +03:00
# include <linux/delay.h>
2006-12-28 01:36:37 +03:00
# include <linux/dma-mapping.h>
2007-08-20 23:40:30 +04:00
# include <linux/gfp.h>
2007-08-20 23:41:22 +04:00
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/kernel.h>
2007-05-15 23:36:10 +04:00
# include <linux/mm.h>
2007-08-20 23:41:22 +04:00
# include <linux/module.h>
# include <linux/pci.h>
2007-08-20 23:40:30 +04:00
# include <linux/spinlock.h>
2006-12-28 01:36:37 +03:00
2007-08-20 23:40:30 +04:00
# include <asm/page.h>
2007-08-25 16:08:19 +04:00
# include <asm/system.h>
2006-12-20 03:58:35 +03:00
# include "fw-ohci.h"
2007-08-20 23:41:22 +04:00
# include "fw-transaction.h"
2006-12-20 03:58:35 +03:00
2007-05-08 04:33:35 +04:00
# define DESCRIPTOR_OUTPUT_MORE 0
# define DESCRIPTOR_OUTPUT_LAST (1 << 12)
# define DESCRIPTOR_INPUT_MORE (2 << 12)
# define DESCRIPTOR_INPUT_LAST (3 << 12)
# define DESCRIPTOR_STATUS (1 << 11)
# define DESCRIPTOR_KEY_IMMEDIATE (2 << 8)
# define DESCRIPTOR_PING (1 << 7)
# define DESCRIPTOR_YY (1 << 6)
# define DESCRIPTOR_NO_IRQ (0 << 4)
# define DESCRIPTOR_IRQ_ERROR (1 << 4)
# define DESCRIPTOR_IRQ_ALWAYS (3 << 4)
# define DESCRIPTOR_BRANCH_ALWAYS (3 << 2)
# define DESCRIPTOR_WAIT (3 << 0)
2006-12-20 03:58:35 +03:00
struct descriptor {
__le16 req_count ;
__le16 control ;
__le32 data_address ;
__le32 branch_address ;
__le16 res_count ;
__le16 transfer_status ;
} __attribute__ ( ( aligned ( 16 ) ) ) ;
2007-02-17 01:34:40 +03:00
struct db_descriptor {
__le16 first_size ;
__le16 control ;
__le16 second_req_count ;
__le16 first_req_count ;
__le32 branch_address ;
__le16 second_res_count ;
__le16 first_res_count ;
__le32 reserved0 ;
__le32 first_buffer ;
__le32 second_buffer ;
__le32 reserved1 ;
} __attribute__ ( ( aligned ( 16 ) ) ) ;
2007-05-08 04:33:35 +04:00
# define CONTROL_SET(regs) (regs)
# define CONTROL_CLEAR(regs) ((regs) + 4)
# define COMMAND_PTR(regs) ((regs) + 12)
# define CONTEXT_MATCH(regs) ((regs) + 16)
2007-02-06 22:49:31 +03:00
2007-02-06 22:49:30 +03:00
struct ar_buffer {
2006-12-20 03:58:35 +03:00
struct descriptor descriptor ;
2007-02-06 22:49:30 +03:00
struct ar_buffer * next ;
__le32 data [ 0 ] ;
} ;
2006-12-20 03:58:35 +03:00
2007-02-06 22:49:30 +03:00
struct ar_context {
struct fw_ohci * ohci ;
struct ar_buffer * current_buffer ;
struct ar_buffer * last_buffer ;
void * pointer ;
2007-02-06 22:49:31 +03:00
u32 regs ;
2006-12-20 03:58:35 +03:00
struct tasklet_struct tasklet ;
} ;
2007-02-17 01:34:39 +03:00
struct context ;
typedef int ( * descriptor_callback_t ) ( struct context * ctx ,
struct descriptor * d ,
struct descriptor * last ) ;
struct context {
2007-03-04 16:45:18 +03:00
struct fw_ohci * ohci ;
2007-02-17 01:34:39 +03:00
u32 regs ;
2007-03-04 16:45:18 +03:00
2007-02-17 01:34:39 +03:00
struct descriptor * buffer ;
dma_addr_t buffer_bus ;
size_t buffer_size ;
struct descriptor * head_descriptor ;
struct descriptor * tail_descriptor ;
struct descriptor * tail_descriptor_last ;
struct descriptor * prev_descriptor ;
descriptor_callback_t callback ;
2007-03-04 16:45:18 +03:00
struct tasklet_struct tasklet ;
2007-02-17 01:34:39 +03:00
} ;
2007-05-08 04:33:35 +04:00
# define IT_HEADER_SY(v) ((v) << 0)
# define IT_HEADER_TCODE(v) ((v) << 4)
# define IT_HEADER_CHANNEL(v) ((v) << 8)
# define IT_HEADER_TAG(v) ((v) << 14)
# define IT_HEADER_SPEED(v) ((v) << 16)
# define IT_HEADER_DATA_LENGTH(v) ((v) << 16)
2006-12-20 03:58:35 +03:00
struct iso_context {
struct fw_iso_context base ;
2007-02-17 01:34:39 +03:00
struct context context ;
2007-12-19 11:09:18 +03:00
int excess_bytes ;
2007-02-17 01:34:44 +03:00
void * header ;
size_t header_length ;
2006-12-20 03:58:35 +03:00
} ;
# define CONFIG_ROM_SIZE 1024
struct fw_ohci {
struct fw_card card ;
2007-02-17 01:34:49 +03:00
u32 version ;
2006-12-20 03:58:35 +03:00
__iomem char * registers ;
dma_addr_t self_id_bus ;
__le32 * self_id_cpu ;
struct tasklet_struct bus_reset_tasklet ;
2007-01-26 08:38:04 +03:00
int node_id ;
2006-12-20 03:58:35 +03:00
int generation ;
int request_generation ;
2007-03-07 20:12:56 +03:00
u32 bus_seconds ;
2006-12-20 03:58:35 +03:00
2007-05-08 04:33:32 +04:00
/*
* Spinlock for accessing fw_ohci data . Never call out of
* this driver with this lock held .
*/
2006-12-20 03:58:35 +03:00
spinlock_t lock ;
u32 self_id_buffer [ 512 ] ;
/* Config rom buffers */
__be32 * config_rom ;
dma_addr_t config_rom_bus ;
__be32 * next_config_rom ;
dma_addr_t next_config_rom_bus ;
u32 next_header ;
struct ar_context ar_request_ctx ;
struct ar_context ar_response_ctx ;
2007-03-07 20:12:49 +03:00
struct context at_request_ctx ;
struct context at_response_ctx ;
2006-12-20 03:58:35 +03:00
u32 it_context_mask ;
struct iso_context * it_context_list ;
u32 ir_context_mask ;
struct iso_context * ir_context_list ;
} ;
2007-01-22 21:17:37 +03:00
static inline struct fw_ohci * fw_ohci ( struct fw_card * card )
2006-12-20 03:58:35 +03:00
{
return container_of ( card , struct fw_ohci , card ) ;
}
2007-02-17 01:34:40 +03:00
# define IT_CONTEXT_CYCLE_MATCH_ENABLE 0x80000000
# define IR_CONTEXT_BUFFER_FILL 0x80000000
# define IR_CONTEXT_ISOCH_HEADER 0x40000000
# define IR_CONTEXT_CYCLE_MATCH_ENABLE 0x20000000
# define IR_CONTEXT_MULTI_CHANNEL_MODE 0x10000000
# define IR_CONTEXT_DUAL_BUFFER_MODE 0x08000000
2006-12-20 03:58:35 +03:00
# define CONTEXT_RUN 0x8000
# define CONTEXT_WAKE 0x1000
# define CONTEXT_DEAD 0x0800
# define CONTEXT_ACTIVE 0x0400
# define OHCI1394_MAX_AT_REQ_RETRIES 0x2
# define OHCI1394_MAX_AT_RESP_RETRIES 0x2
# define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
# define FW_OHCI_MAJOR 240
# define OHCI1394_REGISTER_SIZE 0x800
# define OHCI_LOOP_COUNT 500
# define OHCI1394_PCI_HCI_Control 0x40
# define SELF_ID_BUF_SIZE 0x800
2007-02-06 22:49:30 +03:00
# define OHCI_TCODE_PHY_PACKET 0x0e
2007-02-17 01:34:49 +03:00
# define OHCI_VERSION_1_1 0x010010
2007-03-07 20:12:49 +03:00
# define ISO_BUFFER_SIZE (64 * 1024)
# define AT_BUFFER_SIZE 4096
2007-01-26 08:38:49 +03:00
2006-12-20 03:58:35 +03:00
static char ohci_driver_name [ ] = KBUILD_MODNAME ;
2007-01-22 21:17:37 +03:00
static inline void reg_write ( const struct fw_ohci * ohci , int offset , u32 data )
2006-12-20 03:58:35 +03:00
{
writel ( data , ohci - > registers + offset ) ;
}
2007-01-22 21:17:37 +03:00
static inline u32 reg_read ( const struct fw_ohci * ohci , int offset )
2006-12-20 03:58:35 +03:00
{
return readl ( ohci - > registers + offset ) ;
}
2007-01-22 21:17:37 +03:00
static inline void flush_writes ( const struct fw_ohci * ohci )
2006-12-20 03:58:35 +03:00
{
/* Do a dummy read to flush writes. */
reg_read ( ohci , OHCI1394_Version ) ;
}
static int
ohci_update_phy_reg ( struct fw_card * card , int addr ,
int clear_bits , int set_bits )
{
struct fw_ohci * ohci = fw_ohci ( card ) ;
u32 val , old ;
reg_write ( ohci , OHCI1394_PhyControl , OHCI1394_PhyControl_Read ( addr ) ) ;
2007-07-13 00:24:19 +04:00
flush_writes ( ohci ) ;
2006-12-20 03:58:35 +03:00
msleep ( 2 ) ;
val = reg_read ( ohci , OHCI1394_PhyControl ) ;
if ( ( val & OHCI1394_PhyControl_ReadDone ) = = 0 ) {
fw_error ( " failed to set phy reg bits. \n " ) ;
return - EBUSY ;
}
old = OHCI1394_PhyControl_ReadData ( val ) ;
old = ( old & ~ clear_bits ) | set_bits ;
reg_write ( ohci , OHCI1394_PhyControl ,
OHCI1394_PhyControl_Write ( addr , old ) ) ;
return 0 ;
}
2007-02-06 22:49:30 +03:00
static int ar_context_add_page ( struct ar_context * ctx )
2006-12-20 03:58:35 +03:00
{
2007-02-06 22:49:30 +03:00
struct device * dev = ctx - > ohci - > card . device ;
struct ar_buffer * ab ;
dma_addr_t ab_bus ;
size_t offset ;
ab = ( struct ar_buffer * ) __get_free_page ( GFP_ATOMIC ) ;
if ( ab = = NULL )
return - ENOMEM ;
ab_bus = dma_map_single ( dev , ab , PAGE_SIZE , DMA_BIDIRECTIONAL ) ;
if ( dma_mapping_error ( ab_bus ) ) {
free_page ( ( unsigned long ) ab ) ;
return - ENOMEM ;
}
2007-05-10 03:23:14 +04:00
memset ( & ab - > descriptor , 0 , sizeof ( ab - > descriptor ) ) ;
2007-05-08 04:33:35 +04:00
ab - > descriptor . control = cpu_to_le16 ( DESCRIPTOR_INPUT_MORE |
DESCRIPTOR_STATUS |
DESCRIPTOR_BRANCH_ALWAYS ) ;
2007-02-06 22:49:30 +03:00
offset = offsetof ( struct ar_buffer , data ) ;
ab - > descriptor . req_count = cpu_to_le16 ( PAGE_SIZE - offset ) ;
ab - > descriptor . data_address = cpu_to_le32 ( ab_bus + offset ) ;
ab - > descriptor . res_count = cpu_to_le16 ( PAGE_SIZE - offset ) ;
ab - > descriptor . branch_address = 0 ;
dma_sync_single_for_device ( dev , ab_bus , PAGE_SIZE , DMA_BIDIRECTIONAL ) ;
2007-05-23 02:55:48 +04:00
ctx - > last_buffer - > descriptor . branch_address = cpu_to_le32 ( ab_bus | 1 ) ;
2007-02-06 22:49:30 +03:00
ctx - > last_buffer - > next = ab ;
ctx - > last_buffer = ab ;
2007-05-08 04:33:35 +04:00
reg_write ( ctx - > ohci , CONTROL_SET ( ctx - > regs ) , CONTEXT_WAKE ) ;
2006-12-20 03:58:35 +03:00
flush_writes ( ctx - > ohci ) ;
2007-02-06 22:49:30 +03:00
return 0 ;
2006-12-20 03:58:35 +03:00
}
2007-02-06 22:49:30 +03:00
static __le32 * handle_ar_packet ( struct ar_context * ctx , __le32 * buffer )
2006-12-20 03:58:35 +03:00
{
struct fw_ohci * ohci = ctx - > ohci ;
2007-01-26 08:37:57 +03:00
struct fw_packet p ;
u32 status , length , tcode ;
2007-02-06 22:49:30 +03:00
p . header [ 0 ] = le32_to_cpu ( buffer [ 0 ] ) ;
p . header [ 1 ] = le32_to_cpu ( buffer [ 1 ] ) ;
p . header [ 2 ] = le32_to_cpu ( buffer [ 2 ] ) ;
2007-01-26 08:37:57 +03:00
tcode = ( p . header [ 0 ] > > 4 ) & 0x0f ;
switch ( tcode ) {
case TCODE_WRITE_QUADLET_REQUEST :
case TCODE_READ_QUADLET_RESPONSE :
2007-02-06 22:49:30 +03:00
p . header [ 3 ] = ( __force __u32 ) buffer [ 3 ] ;
2007-01-26 08:37:57 +03:00
p . header_length = 16 ;
2007-02-06 22:49:30 +03:00
p . payload_length = 0 ;
2007-01-26 08:37:57 +03:00
break ;
case TCODE_READ_BLOCK_REQUEST :
2007-02-06 22:49:30 +03:00
p . header [ 3 ] = le32_to_cpu ( buffer [ 3 ] ) ;
p . header_length = 16 ;
p . payload_length = 0 ;
break ;
case TCODE_WRITE_BLOCK_REQUEST :
2007-01-26 08:37:57 +03:00
case TCODE_READ_BLOCK_RESPONSE :
case TCODE_LOCK_REQUEST :
case TCODE_LOCK_RESPONSE :
2007-02-06 22:49:30 +03:00
p . header [ 3 ] = le32_to_cpu ( buffer [ 3 ] ) ;
2007-01-26 08:37:57 +03:00
p . header_length = 16 ;
2007-02-06 22:49:30 +03:00
p . payload_length = p . header [ 3 ] > > 16 ;
2007-01-26 08:37:57 +03:00
break ;
case TCODE_WRITE_RESPONSE :
case TCODE_READ_QUADLET_REQUEST :
2007-02-06 22:49:30 +03:00
case OHCI_TCODE_PHY_PACKET :
2007-01-26 08:37:57 +03:00
p . header_length = 12 ;
2007-02-06 22:49:30 +03:00
p . payload_length = 0 ;
2007-01-26 08:37:57 +03:00
break ;
}
2006-12-20 03:58:35 +03:00
2007-02-06 22:49:30 +03:00
p . payload = ( void * ) buffer + p . header_length ;
/* FIXME: What to do about evt_* errors? */
length = ( p . header_length + p . payload_length + 3 ) / 4 ;
status = le32_to_cpu ( buffer [ length ] ) ;
p . ack = ( ( status > > 16 ) & 0x1f ) - 16 ;
p . speed = ( status > > 21 ) & 0x7 ;
p . timestamp = status & 0xffff ;
p . generation = ohci - > request_generation ;
2006-12-20 03:58:35 +03:00
2007-05-08 04:33:32 +04:00
/*
* The OHCI bus reset handler synthesizes a phy packet with
2006-12-20 03:58:35 +03:00
* the new generation number when a bus reset happens ( see
* section 8.4 .2 .3 ) . This helps us determine when a request
* was received and make sure we send the response in the same
* generation . We only need this for requests ; for responses
* we use the unique tlabel for finding the matching
2007-05-08 04:33:32 +04:00
* request .
*/
2006-12-20 03:58:35 +03:00
2007-01-26 08:37:57 +03:00
if ( p . ack + 16 = = 0x09 )
2007-02-06 22:49:30 +03:00
ohci - > request_generation = ( buffer [ 2 ] > > 16 ) & 0xff ;
2006-12-20 03:58:35 +03:00
else if ( ctx = = & ohci - > ar_request_ctx )
2007-01-26 08:37:57 +03:00
fw_core_handle_request ( & ohci - > card , & p ) ;
2006-12-20 03:58:35 +03:00
else
2007-01-26 08:37:57 +03:00
fw_core_handle_response ( & ohci - > card , & p ) ;
2006-12-20 03:58:35 +03:00
2007-02-06 22:49:30 +03:00
return buffer + length + 1 ;
}
2006-12-20 03:58:35 +03:00
2007-02-06 22:49:30 +03:00
static void ar_context_tasklet ( unsigned long data )
{
struct ar_context * ctx = ( struct ar_context * ) data ;
struct fw_ohci * ohci = ctx - > ohci ;
struct ar_buffer * ab ;
struct descriptor * d ;
void * buffer , * end ;
ab = ctx - > current_buffer ;
d = & ab - > descriptor ;
if ( d - > res_count = = 0 ) {
size_t size , rest , offset ;
2007-05-08 04:33:32 +04:00
/*
* This descriptor is finished and we may have a
2007-02-06 22:49:30 +03:00
* packet split across this and the next buffer . We
2007-05-08 04:33:32 +04:00
* reuse the page for reassembling the split packet .
*/
2007-02-06 22:49:30 +03:00
offset = offsetof ( struct ar_buffer , data ) ;
dma_unmap_single ( ohci - > card . device ,
2007-06-23 22:28:17 +04:00
le32_to_cpu ( ab - > descriptor . data_address ) - offset ,
PAGE_SIZE , DMA_BIDIRECTIONAL ) ;
2007-02-06 22:49:30 +03:00
buffer = ab ;
ab = ab - > next ;
d = & ab - > descriptor ;
size = buffer + PAGE_SIZE - ctx - > pointer ;
rest = le16_to_cpu ( d - > req_count ) - le16_to_cpu ( d - > res_count ) ;
memmove ( buffer , ctx - > pointer , size ) ;
memcpy ( buffer + size , ab - > data , rest ) ;
ctx - > current_buffer = ab ;
ctx - > pointer = ( void * ) ab - > data + rest ;
end = buffer + size + rest ;
while ( buffer < end )
buffer = handle_ar_packet ( ctx , buffer ) ;
free_page ( ( unsigned long ) buffer ) ;
ar_context_add_page ( ctx ) ;
} else {
buffer = ctx - > pointer ;
ctx - > pointer = end =
( void * ) ab + PAGE_SIZE - le16_to_cpu ( d - > res_count ) ;
while ( buffer < end )
buffer = handle_ar_packet ( ctx , buffer ) ;
}
2006-12-20 03:58:35 +03:00
}
static int
2007-02-06 22:49:31 +03:00
ar_context_init ( struct ar_context * ctx , struct fw_ohci * ohci , u32 regs )
2006-12-20 03:58:35 +03:00
{
2007-02-06 22:49:30 +03:00
struct ar_buffer ab ;
2006-12-20 03:58:35 +03:00
2007-02-06 22:49:31 +03:00
ctx - > regs = regs ;
ctx - > ohci = ohci ;
ctx - > last_buffer = & ab ;
2006-12-20 03:58:35 +03:00
tasklet_init ( & ctx - > tasklet , ar_context_tasklet , ( unsigned long ) ctx ) ;
2007-02-06 22:49:30 +03:00
ar_context_add_page ( ctx ) ;
ar_context_add_page ( ctx ) ;
ctx - > current_buffer = ab . next ;
ctx - > pointer = ctx - > current_buffer - > data ;
2007-05-31 03:06:35 +04:00
return 0 ;
}
static void ar_context_run ( struct ar_context * ctx )
{
struct ar_buffer * ab = ctx - > current_buffer ;
dma_addr_t ab_bus ;
size_t offset ;
offset = offsetof ( struct ar_buffer , data ) ;
2007-06-23 22:28:17 +04:00
ab_bus = le32_to_cpu ( ab - > descriptor . data_address ) - offset ;
2007-05-31 03:06:35 +04:00
reg_write ( ctx - > ohci , COMMAND_PTR ( ctx - > regs ) , ab_bus | 1 ) ;
2007-05-08 04:33:35 +04:00
reg_write ( ctx - > ohci , CONTROL_SET ( ctx - > regs ) , CONTEXT_RUN ) ;
2007-02-06 22:49:30 +03:00
flush_writes ( ctx - > ohci ) ;
2006-12-20 03:58:35 +03:00
}
2007-03-04 16:45:18 +03:00
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
static struct descriptor *
find_branch_descriptor ( struct descriptor * d , int z )
{
int b , key ;
b = ( le16_to_cpu ( d - > control ) & DESCRIPTOR_BRANCH_ALWAYS ) > > 2 ;
key = ( le16_to_cpu ( d - > control ) & DESCRIPTOR_KEY_IMMEDIATE ) > > 8 ;
/* figure out which descriptor the branch address goes in */
if ( z = = 2 & & ( b = = 3 | | key = = 2 ) )
return d ;
else
return d + z - 1 ;
}
2007-02-17 01:34:39 +03:00
static void context_tasklet ( unsigned long data )
{
struct context * ctx = ( struct context * ) data ;
struct fw_ohci * ohci = ctx - > ohci ;
struct descriptor * d , * last ;
u32 address ;
int z ;
dma_sync_single_for_cpu ( ohci - > card . device , ctx - > buffer_bus ,
ctx - > buffer_size , DMA_TO_DEVICE ) ;
d = ctx - > tail_descriptor ;
last = ctx - > tail_descriptor_last ;
while ( last - > branch_address ! = 0 ) {
address = le32_to_cpu ( last - > branch_address ) ;
z = address & 0xf ;
2007-05-10 03:23:14 +04:00
d = ctx - > buffer + ( address - ctx - > buffer_bus ) / sizeof ( * d ) ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
last = find_branch_descriptor ( d , z ) ;
2007-02-17 01:34:39 +03:00
if ( ! ctx - > callback ( ctx , d , last ) )
break ;
ctx - > tail_descriptor = d ;
ctx - > tail_descriptor_last = last ;
}
}
static int
context_init ( struct context * ctx , struct fw_ohci * ohci ,
size_t buffer_size , u32 regs ,
descriptor_callback_t callback )
{
ctx - > ohci = ohci ;
ctx - > regs = regs ;
ctx - > buffer_size = buffer_size ;
ctx - > buffer = kmalloc ( buffer_size , GFP_KERNEL ) ;
if ( ctx - > buffer = = NULL )
return - ENOMEM ;
tasklet_init ( & ctx - > tasklet , context_tasklet , ( unsigned long ) ctx ) ;
ctx - > callback = callback ;
ctx - > buffer_bus =
dma_map_single ( ohci - > card . device , ctx - > buffer ,
buffer_size , DMA_TO_DEVICE ) ;
if ( dma_mapping_error ( ctx - > buffer_bus ) ) {
kfree ( ctx - > buffer ) ;
return - ENOMEM ;
}
ctx - > head_descriptor = ctx - > buffer ;
ctx - > prev_descriptor = ctx - > buffer ;
ctx - > tail_descriptor = ctx - > buffer ;
ctx - > tail_descriptor_last = ctx - > buffer ;
2007-05-08 04:33:32 +04:00
/*
* We put a dummy descriptor in the buffer that has a NULL
2007-02-17 01:34:39 +03:00
* branch address and looks like it ' s been sent . That way we
* have a descriptor to append DMA programs to . Also , the
* ring buffer invariant is that it always has at least one
2007-05-08 04:33:32 +04:00
* element so that head = = tail means buffer full .
*/
2007-02-17 01:34:39 +03:00
2007-05-10 03:23:14 +04:00
memset ( ctx - > head_descriptor , 0 , sizeof ( * ctx - > head_descriptor ) ) ;
2007-05-08 04:33:35 +04:00
ctx - > head_descriptor - > control = cpu_to_le16 ( DESCRIPTOR_OUTPUT_LAST ) ;
2007-02-17 01:34:39 +03:00
ctx - > head_descriptor - > transfer_status = cpu_to_le16 ( 0x8011 ) ;
ctx - > head_descriptor + + ;
return 0 ;
}
2007-02-17 01:34:44 +03:00
static void
2007-02-17 01:34:39 +03:00
context_release ( struct context * ctx )
{
struct fw_card * card = & ctx - > ohci - > card ;
dma_unmap_single ( card - > device , ctx - > buffer_bus ,
ctx - > buffer_size , DMA_TO_DEVICE ) ;
kfree ( ctx - > buffer ) ;
}
static struct descriptor *
context_get_descriptors ( struct context * ctx , int z , dma_addr_t * d_bus )
{
struct descriptor * d , * tail , * end ;
d = ctx - > head_descriptor ;
tail = ctx - > tail_descriptor ;
2007-05-10 03:23:14 +04:00
end = ctx - > buffer + ctx - > buffer_size / sizeof ( * d ) ;
2007-02-17 01:34:39 +03:00
if ( d + z < = tail ) {
goto has_space ;
} else if ( d > tail & & d + z < = end ) {
goto has_space ;
} else if ( d > tail & & ctx - > buffer + z < = tail ) {
d = ctx - > buffer ;
goto has_space ;
}
return NULL ;
has_space :
2007-05-10 03:23:14 +04:00
memset ( d , 0 , z * sizeof ( * d ) ) ;
* d_bus = ctx - > buffer_bus + ( d - ctx - > buffer ) * sizeof ( * d ) ;
2007-02-17 01:34:39 +03:00
return d ;
}
2007-02-17 01:34:40 +03:00
static void context_run ( struct context * ctx , u32 extra )
2007-02-17 01:34:39 +03:00
{
struct fw_ohci * ohci = ctx - > ohci ;
2007-05-08 04:33:35 +04:00
reg_write ( ohci , COMMAND_PTR ( ctx - > regs ) ,
2007-02-17 01:34:39 +03:00
le32_to_cpu ( ctx - > tail_descriptor_last - > branch_address ) ) ;
2007-05-08 04:33:35 +04:00
reg_write ( ohci , CONTROL_CLEAR ( ctx - > regs ) , ~ 0 ) ;
reg_write ( ohci , CONTROL_SET ( ctx - > regs ) , CONTEXT_RUN | extra ) ;
2007-02-17 01:34:39 +03:00
flush_writes ( ohci ) ;
}
static void context_append ( struct context * ctx ,
struct descriptor * d , int z , int extra )
{
dma_addr_t d_bus ;
2007-05-10 03:23:14 +04:00
d_bus = ctx - > buffer_bus + ( d - ctx - > buffer ) * sizeof ( * d ) ;
2007-02-17 01:34:39 +03:00
ctx - > head_descriptor = d + z + extra ;
ctx - > prev_descriptor - > branch_address = cpu_to_le32 ( d_bus | z ) ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
ctx - > prev_descriptor = find_branch_descriptor ( d , z ) ;
2007-02-17 01:34:39 +03:00
dma_sync_single_for_device ( ctx - > ohci - > card . device , ctx - > buffer_bus ,
ctx - > buffer_size , DMA_TO_DEVICE ) ;
2007-05-08 04:33:35 +04:00
reg_write ( ctx - > ohci , CONTROL_SET ( ctx - > regs ) , CONTEXT_WAKE ) ;
2007-02-17 01:34:39 +03:00
flush_writes ( ctx - > ohci ) ;
}
static void context_stop ( struct context * ctx )
{
u32 reg ;
2007-02-17 01:34:42 +03:00
int i ;
2007-02-17 01:34:39 +03:00
2007-05-08 04:33:35 +04:00
reg_write ( ctx - > ohci , CONTROL_CLEAR ( ctx - > regs ) , CONTEXT_RUN ) ;
2007-02-17 01:34:42 +03:00
flush_writes ( ctx - > ohci ) ;
2007-02-17 01:34:39 +03:00
2007-02-17 01:34:42 +03:00
for ( i = 0 ; i < 10 ; i + + ) {
2007-05-08 04:33:35 +04:00
reg = reg_read ( ctx - > ohci , CONTROL_SET ( ctx - > regs ) ) ;
2007-02-17 01:34:42 +03:00
if ( ( reg & CONTEXT_ACTIVE ) = = 0 )
break ;
fw_notify ( " context_stop: still active (0x%08x) \n " , reg ) ;
2007-07-13 00:25:14 +04:00
mdelay ( 1 ) ;
2007-02-17 01:34:42 +03:00
}
2007-02-17 01:34:39 +03:00
}
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
struct driver_data {
struct fw_packet * packet ;
} ;
2006-12-20 03:58:35 +03:00
2007-05-08 04:33:32 +04:00
/*
* This function apppends a packet to the DMA queue for transmission .
2007-03-07 20:12:49 +03:00
* Must always be called with the ochi - > lock held to ensure proper
2007-05-08 04:33:32 +04:00
* generation handling and locking around packet queue manipulation .
*/
2007-03-07 20:12:49 +03:00
static int
at_context_queue_packet ( struct context * ctx , struct fw_packet * packet )
2006-12-20 03:58:35 +03:00
{
struct fw_ohci * ohci = ctx - > ohci ;
2007-10-21 13:20:07 +04:00
dma_addr_t d_bus , uninitialized_var ( payload_bus ) ;
2007-03-07 20:12:49 +03:00
struct driver_data * driver_data ;
struct descriptor * d , * last ;
__le32 * header ;
2006-12-20 03:58:35 +03:00
int z , tcode ;
2007-03-07 20:12:49 +03:00
u32 reg ;
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
d = context_get_descriptors ( ctx , 4 , & d_bus ) ;
if ( d = = NULL ) {
packet - > ack = RCODE_SEND_ERROR ;
return - 1 ;
2006-12-20 03:58:35 +03:00
}
2007-05-08 04:33:35 +04:00
d [ 0 ] . control = cpu_to_le16 ( DESCRIPTOR_KEY_IMMEDIATE ) ;
2007-03-07 20:12:49 +03:00
d [ 0 ] . res_count = cpu_to_le16 ( packet - > timestamp ) ;
2007-05-08 04:33:32 +04:00
/*
* The DMA format for asyncronous link packets is different
2006-12-20 03:58:35 +03:00
* from the IEEE1394 layout , so shift the fields around
* accordingly . If header_length is 8 , it ' s a PHY packet , to
2007-05-08 04:33:32 +04:00
* which we need to prepend an extra quadlet .
*/
2007-03-07 20:12:49 +03:00
header = ( __le32 * ) & d [ 1 ] ;
2006-12-20 03:58:35 +03:00
if ( packet - > header_length > 8 ) {
2007-03-07 20:12:49 +03:00
header [ 0 ] = cpu_to_le32 ( ( packet - > header [ 0 ] & 0xffff ) |
( packet - > speed < < 16 ) ) ;
header [ 1 ] = cpu_to_le32 ( ( packet - > header [ 1 ] & 0xffff ) |
( packet - > header [ 0 ] & 0xffff0000 ) ) ;
header [ 2 ] = cpu_to_le32 ( packet - > header [ 2 ] ) ;
2006-12-20 03:58:35 +03:00
tcode = ( packet - > header [ 0 ] > > 4 ) & 0x0f ;
if ( TCODE_IS_BLOCK_PACKET ( tcode ) )
2007-03-07 20:12:49 +03:00
header [ 3 ] = cpu_to_le32 ( packet - > header [ 3 ] ) ;
2006-12-20 03:58:35 +03:00
else
2007-03-07 20:12:49 +03:00
header [ 3 ] = ( __force __le32 ) packet - > header [ 3 ] ;
d [ 0 ] . req_count = cpu_to_le16 ( packet - > header_length ) ;
2006-12-20 03:58:35 +03:00
} else {
2007-03-07 20:12:49 +03:00
header [ 0 ] = cpu_to_le32 ( ( OHCI1394_phy_tcode < < 4 ) |
( packet - > speed < < 16 ) ) ;
header [ 1 ] = cpu_to_le32 ( packet - > header [ 0 ] ) ;
header [ 2 ] = cpu_to_le32 ( packet - > header [ 1 ] ) ;
d [ 0 ] . req_count = cpu_to_le16 ( 12 ) ;
2006-12-20 03:58:35 +03:00
}
2007-03-07 20:12:49 +03:00
driver_data = ( struct driver_data * ) & d [ 3 ] ;
driver_data - > packet = packet ;
2007-03-27 03:18:19 +04:00
packet - > driver_data = driver_data ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
2007-03-07 20:12:49 +03:00
if ( packet - > payload_length > 0 ) {
payload_bus =
dma_map_single ( ohci - > card . device , packet - > payload ,
packet - > payload_length , DMA_TO_DEVICE ) ;
if ( dma_mapping_error ( payload_bus ) ) {
packet - > ack = RCODE_SEND_ERROR ;
return - 1 ;
}
d [ 2 ] . req_count = cpu_to_le16 ( packet - > payload_length ) ;
d [ 2 ] . data_address = cpu_to_le32 ( payload_bus ) ;
last = & d [ 2 ] ;
z = 3 ;
2006-12-20 03:58:35 +03:00
} else {
2007-03-07 20:12:49 +03:00
last = & d [ 0 ] ;
z = 2 ;
2006-12-20 03:58:35 +03:00
}
2007-05-08 04:33:35 +04:00
last - > control | = cpu_to_le16 ( DESCRIPTOR_OUTPUT_LAST |
DESCRIPTOR_IRQ_ALWAYS |
DESCRIPTOR_BRANCH_ALWAYS ) ;
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
/* FIXME: Document how the locking works. */
if ( ohci - > generation ! = packet - > generation ) {
2007-08-29 21:40:28 +04:00
if ( packet - > payload_length > 0 )
dma_unmap_single ( ohci - > card . device , payload_bus ,
packet - > payload_length , DMA_TO_DEVICE ) ;
2007-03-07 20:12:49 +03:00
packet - > ack = RCODE_GENERATION ;
return - 1 ;
}
context_append ( ctx , d , z , 4 - z ) ;
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
/* If the context isn't already running, start it up. */
2007-05-08 04:33:35 +04:00
reg = reg_read ( ctx - > ohci , CONTROL_SET ( ctx - > regs ) ) ;
2007-04-11 02:11:17 +04:00
if ( ( reg & CONTEXT_RUN ) = = 0 )
2007-03-07 20:12:49 +03:00
context_run ( ctx , 0 ) ;
return 0 ;
2006-12-20 03:58:35 +03:00
}
2007-03-07 20:12:49 +03:00
static int handle_at_packet ( struct context * context ,
struct descriptor * d ,
struct descriptor * last )
2006-12-20 03:58:35 +03:00
{
2007-03-07 20:12:49 +03:00
struct driver_data * driver_data ;
2006-12-20 03:58:35 +03:00
struct fw_packet * packet ;
2007-03-07 20:12:49 +03:00
struct fw_ohci * ohci = context - > ohci ;
dma_addr_t payload_bus ;
2006-12-20 03:58:35 +03:00
int evt ;
2007-03-07 20:12:49 +03:00
if ( last - > transfer_status = = 0 )
/* This descriptor isn't done yet, stop iteration. */
return 0 ;
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
driver_data = ( struct driver_data * ) & d [ 3 ] ;
packet = driver_data - > packet ;
if ( packet = = NULL )
/* This packet was cancelled, just continue. */
return 1 ;
2007-02-06 22:49:32 +03:00
2007-03-07 20:12:49 +03:00
payload_bus = le32_to_cpu ( last - > data_address ) ;
if ( payload_bus ! = 0 )
dma_unmap_single ( ohci - > card . device , payload_bus ,
2006-12-20 03:58:35 +03:00
packet - > payload_length , DMA_TO_DEVICE ) ;
2007-03-07 20:12:49 +03:00
evt = le16_to_cpu ( last - > transfer_status ) & 0x1f ;
packet - > timestamp = le16_to_cpu ( last - > res_count ) ;
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
switch ( evt ) {
case OHCI1394_evt_timeout :
/* Async response transmit timed out. */
packet - > ack = RCODE_CANCELLED ;
break ;
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
case OHCI1394_evt_flushed :
2007-05-08 04:33:32 +04:00
/*
* The packet was flushed should give same error as
* when we try to use a stale generation count .
*/
2007-03-07 20:12:49 +03:00
packet - > ack = RCODE_GENERATION ;
break ;
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
case OHCI1394_evt_missing_ack :
2007-05-08 04:33:32 +04:00
/*
* Using a valid ( current ) generation count , but the
* node is not on the bus or not sending acks .
*/
2007-03-07 20:12:49 +03:00
packet - > ack = RCODE_NO_ACK ;
break ;
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
case ACK_COMPLETE + 0x10 :
case ACK_PENDING + 0x10 :
case ACK_BUSY_X + 0x10 :
case ACK_BUSY_A + 0x10 :
case ACK_BUSY_B + 0x10 :
case ACK_DATA_ERROR + 0x10 :
case ACK_TYPE_ERROR + 0x10 :
packet - > ack = evt - 0x10 ;
break ;
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
default :
packet - > ack = RCODE_SEND_ERROR ;
break ;
}
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
packet - > callback ( packet , & ohci - > card , packet - > ack ) ;
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
return 1 ;
2006-12-20 03:58:35 +03:00
}
2007-05-08 04:33:35 +04:00
# define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff)
# define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f)
# define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff)
# define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff)
# define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff)
2007-01-26 08:38:26 +03:00
static void
handle_local_rom ( struct fw_ohci * ohci , struct fw_packet * packet , u32 csr )
{
struct fw_packet response ;
int tcode , length , i ;
2007-05-08 04:33:35 +04:00
tcode = HEADER_GET_TCODE ( packet - > header [ 0 ] ) ;
2007-01-26 08:38:26 +03:00
if ( TCODE_IS_BLOCK_PACKET ( tcode ) )
2007-05-08 04:33:35 +04:00
length = HEADER_GET_DATA_LENGTH ( packet - > header [ 3 ] ) ;
2007-01-26 08:38:26 +03:00
else
length = 4 ;
i = csr - CSR_CONFIG_ROM ;
if ( i + length > CONFIG_ROM_SIZE ) {
fw_fill_response ( & response , packet - > header ,
RCODE_ADDRESS_ERROR , NULL , 0 ) ;
} else if ( ! TCODE_IS_READ_REQUEST ( tcode ) ) {
fw_fill_response ( & response , packet - > header ,
RCODE_TYPE_ERROR , NULL , 0 ) ;
} else {
fw_fill_response ( & response , packet - > header , RCODE_COMPLETE ,
( void * ) ohci - > config_rom + i , length ) ;
}
fw_core_handle_response ( & ohci - > card , & response ) ;
}
static void
handle_local_lock ( struct fw_ohci * ohci , struct fw_packet * packet , u32 csr )
{
struct fw_packet response ;
int tcode , length , ext_tcode , sel ;
__be32 * payload , lock_old ;
u32 lock_arg , lock_data ;
2007-05-08 04:33:35 +04:00
tcode = HEADER_GET_TCODE ( packet - > header [ 0 ] ) ;
length = HEADER_GET_DATA_LENGTH ( packet - > header [ 3 ] ) ;
2007-01-26 08:38:26 +03:00
payload = packet - > payload ;
2007-05-08 04:33:35 +04:00
ext_tcode = HEADER_GET_EXTENDED_TCODE ( packet - > header [ 3 ] ) ;
2007-01-26 08:38:26 +03:00
if ( tcode = = TCODE_LOCK_REQUEST & &
ext_tcode = = EXTCODE_COMPARE_SWAP & & length = = 8 ) {
lock_arg = be32_to_cpu ( payload [ 0 ] ) ;
lock_data = be32_to_cpu ( payload [ 1 ] ) ;
} else if ( tcode = = TCODE_READ_QUADLET_REQUEST ) {
lock_arg = 0 ;
lock_data = 0 ;
} else {
fw_fill_response ( & response , packet - > header ,
RCODE_TYPE_ERROR , NULL , 0 ) ;
goto out ;
}
sel = ( csr - CSR_BUS_MANAGER_ID ) / 4 ;
reg_write ( ohci , OHCI1394_CSRData , lock_data ) ;
reg_write ( ohci , OHCI1394_CSRCompareData , lock_arg ) ;
reg_write ( ohci , OHCI1394_CSRControl , sel ) ;
if ( reg_read ( ohci , OHCI1394_CSRControl ) & 0x80000000 )
lock_old = cpu_to_be32 ( reg_read ( ohci , OHCI1394_CSRData ) ) ;
else
fw_notify ( " swap not done yet \n " ) ;
fw_fill_response ( & response , packet - > header ,
2007-05-10 03:23:14 +04:00
RCODE_COMPLETE , & lock_old , sizeof ( lock_old ) ) ;
2007-01-26 08:38:26 +03:00
out :
fw_core_handle_response ( & ohci - > card , & response ) ;
}
static void
2007-03-07 20:12:49 +03:00
handle_local_request ( struct context * ctx , struct fw_packet * packet )
2007-01-26 08:38:26 +03:00
{
u64 offset ;
u32 csr ;
2007-03-07 20:12:55 +03:00
if ( ctx = = & ctx - > ohci - > at_request_ctx ) {
packet - > ack = ACK_PENDING ;
packet - > callback ( packet , & ctx - > ohci - > card , packet - > ack ) ;
}
2007-01-26 08:38:26 +03:00
offset =
( ( unsigned long long )
2007-05-08 04:33:35 +04:00
HEADER_GET_OFFSET_HIGH ( packet - > header [ 1 ] ) < < 32 ) |
2007-01-26 08:38:26 +03:00
packet - > header [ 2 ] ;
csr = offset - CSR_REGISTER_BASE ;
/* Handle config rom reads. */
if ( csr > = CSR_CONFIG_ROM & & csr < CSR_CONFIG_ROM_END )
handle_local_rom ( ctx - > ohci , packet , csr ) ;
else switch ( csr ) {
case CSR_BUS_MANAGER_ID :
case CSR_BANDWIDTH_AVAILABLE :
case CSR_CHANNELS_AVAILABLE_HI :
case CSR_CHANNELS_AVAILABLE_LO :
handle_local_lock ( ctx - > ohci , packet , csr ) ;
break ;
default :
if ( ctx = = & ctx - > ohci - > at_request_ctx )
fw_core_handle_request ( & ctx - > ohci - > card , packet ) ;
else
fw_core_handle_response ( & ctx - > ohci - > card , packet ) ;
break ;
}
2007-03-07 20:12:55 +03:00
if ( ctx = = & ctx - > ohci - > at_response_ctx ) {
packet - > ack = ACK_COMPLETE ;
packet - > callback ( packet , & ctx - > ohci - > card , packet - > ack ) ;
}
2007-01-26 08:38:26 +03:00
}
2007-01-26 08:38:04 +03:00
2006-12-20 03:58:35 +03:00
static void
2007-03-07 20:12:49 +03:00
at_context_transmit ( struct context * ctx , struct fw_packet * packet )
2006-12-20 03:58:35 +03:00
{
unsigned long flags ;
2007-03-07 20:12:49 +03:00
int retval ;
2006-12-20 03:58:35 +03:00
spin_lock_irqsave ( & ctx - > ohci - > lock , flags ) ;
2007-05-08 04:33:35 +04:00
if ( HEADER_GET_DESTINATION ( packet - > header [ 0 ] ) = = ctx - > ohci - > node_id & &
2007-01-26 08:38:04 +03:00
ctx - > ohci - > generation = = packet - > generation ) {
2007-01-26 08:38:26 +03:00
spin_unlock_irqrestore ( & ctx - > ohci - > lock , flags ) ;
handle_local_request ( ctx , packet ) ;
return ;
2007-01-26 08:38:04 +03:00
}
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
retval = at_context_queue_packet ( ctx , packet ) ;
2006-12-20 03:58:35 +03:00
spin_unlock_irqrestore ( & ctx - > ohci - > lock , flags ) ;
2007-03-07 20:12:49 +03:00
if ( retval < 0 )
packet - > callback ( packet , & ctx - > ohci - > card , packet - > ack ) ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
2006-12-20 03:58:35 +03:00
}
static void bus_reset_tasklet ( unsigned long data )
{
struct fw_ohci * ohci = ( struct fw_ohci * ) data ;
2007-01-26 08:38:04 +03:00
int self_id_count , i , j , reg ;
2006-12-20 03:58:35 +03:00
int generation , new_generation ;
unsigned long flags ;
2007-07-25 21:18:08 +04:00
void * free_rom = NULL ;
dma_addr_t free_rom_bus = 0 ;
2006-12-20 03:58:35 +03:00
reg = reg_read ( ohci , OHCI1394_NodeID ) ;
if ( ! ( reg & OHCI1394_NodeID_idValid ) ) {
2007-08-30 02:11:40 +04:00
fw_notify ( " node ID not valid, new bus reset in progress \n " ) ;
2006-12-20 03:58:35 +03:00
return ;
}
2007-08-30 02:11:40 +04:00
if ( ( reg & OHCI1394_NodeID_nodeNumber ) = = 63 ) {
fw_notify ( " malconfigured bus \n " ) ;
return ;
}
ohci - > node_id = reg & ( OHCI1394_NodeID_busNumber |
OHCI1394_NodeID_nodeNumber ) ;
2006-12-20 03:58:35 +03:00
2007-05-08 04:33:32 +04:00
/*
* The count in the SelfIDCount register is the number of
2006-12-20 03:58:35 +03:00
* bytes in the self ID receive buffer . Since we also receive
* the inverted quadlets and a header quadlet , we shift one
2007-05-08 04:33:32 +04:00
* bit extra to get the actual number of self IDs .
*/
2006-12-20 03:58:35 +03:00
self_id_count = ( reg_read ( ohci , OHCI1394_SelfIDCount ) > > 3 ) & 0x3ff ;
generation = ( le32_to_cpu ( ohci - > self_id_cpu [ 0 ] ) > > 16 ) & 0xff ;
2007-08-25 16:08:19 +04:00
rmb ( ) ;
2006-12-20 03:58:35 +03:00
for ( i = 1 , j = 0 ; j < self_id_count ; i + = 2 , j + + ) {
if ( ohci - > self_id_cpu [ i ] ! = ~ ohci - > self_id_cpu [ i + 1 ] )
fw_error ( " inconsistent self IDs \n " ) ;
ohci - > self_id_buffer [ j ] = le32_to_cpu ( ohci - > self_id_cpu [ i ] ) ;
}
2007-08-25 16:08:19 +04:00
rmb ( ) ;
2006-12-20 03:58:35 +03:00
2007-05-08 04:33:32 +04:00
/*
* Check the consistency of the self IDs we just read . The
2006-12-20 03:58:35 +03:00
* problem we face is that a new bus reset can start while we
* read out the self IDs from the DMA buffer . If this happens ,
* the DMA buffer will be overwritten with new self IDs and we
* will read out inconsistent data . The OHCI specification
* ( section 11.2 ) recommends a technique similar to
* linux / seqlock . h , where we remember the generation of the
* self IDs in the buffer before reading them out and compare
* it to the current generation after reading them out . If
* the two generations match we know we have a consistent set
2007-05-08 04:33:32 +04:00
* of self IDs .
*/
2006-12-20 03:58:35 +03:00
new_generation = ( reg_read ( ohci , OHCI1394_SelfIDCount ) > > 16 ) & 0xff ;
if ( new_generation ! = generation ) {
fw_notify ( " recursive bus reset detected, "
" discarding self ids \n " ) ;
return ;
}
/* FIXME: Document how the locking works. */
spin_lock_irqsave ( & ohci - > lock , flags ) ;
ohci - > generation = generation ;
2007-03-07 20:12:49 +03:00
context_stop ( & ohci - > at_request_ctx ) ;
context_stop ( & ohci - > at_response_ctx ) ;
2006-12-20 03:58:35 +03:00
reg_write ( ohci , OHCI1394_IntEventClear , OHCI1394_busReset ) ;
2007-05-08 04:33:32 +04:00
/*
* This next bit is unrelated to the AT context stuff but we
2006-12-20 03:58:35 +03:00
* have to do it under the spinlock also . If a new config rom
* was set up before this reset , the old one is now no longer
* in use and we can free it . Update the config rom pointers
* to point to the current config rom and clear the
2007-05-08 04:33:32 +04:00
* next_config_rom pointer so a new udpate can take place .
*/
2006-12-20 03:58:35 +03:00
if ( ohci - > next_config_rom ! = NULL ) {
2007-06-06 03:27:05 +04:00
if ( ohci - > next_config_rom ! = ohci - > config_rom ) {
free_rom = ohci - > config_rom ;
free_rom_bus = ohci - > config_rom_bus ;
}
2006-12-20 03:58:35 +03:00
ohci - > config_rom = ohci - > next_config_rom ;
ohci - > config_rom_bus = ohci - > next_config_rom_bus ;
ohci - > next_config_rom = NULL ;
2007-05-08 04:33:32 +04:00
/*
* Restore config_rom image and manually update
2006-12-20 03:58:35 +03:00
* config_rom registers . Writing the header quadlet
* will indicate that the config rom is ready , so we
2007-05-08 04:33:32 +04:00
* do that last .
*/
2006-12-20 03:58:35 +03:00
reg_write ( ohci , OHCI1394_BusOptions ,
be32_to_cpu ( ohci - > config_rom [ 2 ] ) ) ;
ohci - > config_rom [ 0 ] = cpu_to_be32 ( ohci - > next_header ) ;
reg_write ( ohci , OHCI1394_ConfigROMhdr , ohci - > next_header ) ;
}
spin_unlock_irqrestore ( & ohci - > lock , flags ) ;
2007-07-25 21:18:08 +04:00
if ( free_rom )
dma_free_coherent ( ohci - > card . device , CONFIG_ROM_SIZE ,
free_rom , free_rom_bus ) ;
2007-01-26 08:38:04 +03:00
fw_core_handle_bus_reset ( & ohci - > card , ohci - > node_id , generation ,
2006-12-20 03:58:35 +03:00
self_id_count , ohci - > self_id_buffer ) ;
}
static irqreturn_t irq_handler ( int irq , void * data )
{
struct fw_ohci * ohci = data ;
2007-03-07 20:12:56 +03:00
u32 event , iso_event , cycle_time ;
2006-12-20 03:58:35 +03:00
int i ;
event = reg_read ( ohci , OHCI1394_IntEventClear ) ;
2007-06-09 21:31:14 +04:00
if ( ! event | | ! ~ event )
2006-12-20 03:58:35 +03:00
return IRQ_NONE ;
reg_write ( ohci , OHCI1394_IntEventClear , event ) ;
if ( event & OHCI1394_selfIDComplete )
tasklet_schedule ( & ohci - > bus_reset_tasklet ) ;
if ( event & OHCI1394_RQPkt )
tasklet_schedule ( & ohci - > ar_request_ctx . tasklet ) ;
if ( event & OHCI1394_RSPkt )
tasklet_schedule ( & ohci - > ar_response_ctx . tasklet ) ;
if ( event & OHCI1394_reqTxComplete )
tasklet_schedule ( & ohci - > at_request_ctx . tasklet ) ;
if ( event & OHCI1394_respTxComplete )
tasklet_schedule ( & ohci - > at_response_ctx . tasklet ) ;
2007-02-17 01:34:36 +03:00
iso_event = reg_read ( ohci , OHCI1394_IsoRecvIntEventClear ) ;
2006-12-20 03:58:35 +03:00
reg_write ( ohci , OHCI1394_IsoRecvIntEventClear , iso_event ) ;
while ( iso_event ) {
i = ffs ( iso_event ) - 1 ;
2007-02-17 01:34:39 +03:00
tasklet_schedule ( & ohci - > ir_context_list [ i ] . context . tasklet ) ;
2006-12-20 03:58:35 +03:00
iso_event & = ~ ( 1 < < i ) ;
}
2007-02-17 01:34:36 +03:00
iso_event = reg_read ( ohci , OHCI1394_IsoXmitIntEventClear ) ;
2006-12-20 03:58:35 +03:00
reg_write ( ohci , OHCI1394_IsoXmitIntEventClear , iso_event ) ;
while ( iso_event ) {
i = ffs ( iso_event ) - 1 ;
2007-02-17 01:34:39 +03:00
tasklet_schedule ( & ohci - > it_context_list [ i ] . context . tasklet ) ;
2006-12-20 03:58:35 +03:00
iso_event & = ~ ( 1 < < i ) ;
}
2007-08-20 23:58:30 +04:00
if ( unlikely ( event & OHCI1394_postedWriteErr ) )
fw_error ( " PCI posted write error \n " ) ;
2007-12-23 00:14:52 +03:00
if ( unlikely ( event & OHCI1394_cycleTooLong ) ) {
if ( printk_ratelimit ( ) )
fw_notify ( " isochronous cycle too long \n " ) ;
reg_write ( ohci , OHCI1394_LinkControlSet ,
OHCI1394_LinkControl_cycleMaster ) ;
}
2007-03-07 20:12:56 +03:00
if ( event & OHCI1394_cycle64Seconds ) {
cycle_time = reg_read ( ohci , OHCI1394_IsochronousCycleTimer ) ;
if ( ( cycle_time & 0x80000000 ) = = 0 )
ohci - > bus_seconds + + ;
}
2006-12-20 03:58:35 +03:00
return IRQ_HANDLED ;
}
2007-05-31 03:06:35 +04:00
static int software_reset ( struct fw_ohci * ohci )
{
int i ;
reg_write ( ohci , OHCI1394_HCControlSet , OHCI1394_HCControl_softReset ) ;
for ( i = 0 ; i < OHCI_LOOP_COUNT ; i + + ) {
if ( ( reg_read ( ohci , OHCI1394_HCControlSet ) &
OHCI1394_HCControl_softReset ) = = 0 )
return 0 ;
msleep ( 1 ) ;
}
return - EBUSY ;
}
2006-12-20 03:58:35 +03:00
static int ohci_enable ( struct fw_card * card , u32 * config_rom , size_t length )
{
struct fw_ohci * ohci = fw_ohci ( card ) ;
struct pci_dev * dev = to_pci_dev ( card - > device ) ;
2007-05-31 03:06:35 +04:00
if ( software_reset ( ohci ) ) {
fw_error ( " Failed to reset ohci card. \n " ) ;
return - EBUSY ;
}
/*
* 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 50 msec to make sure we have
* full link enabled .
*/
reg_write ( ohci , OHCI1394_HCControlSet ,
OHCI1394_HCControl_LPS |
OHCI1394_HCControl_postedWriteEnable ) ;
flush_writes ( ohci ) ;
msleep ( 50 ) ;
reg_write ( ohci , OHCI1394_HCControlClear ,
OHCI1394_HCControl_noByteSwapData ) ;
reg_write ( ohci , OHCI1394_LinkControlSet ,
OHCI1394_LinkControl_rcvSelfID |
OHCI1394_LinkControl_cycleTimerEnable |
OHCI1394_LinkControl_cycleMaster ) ;
reg_write ( ohci , OHCI1394_ATRetries ,
OHCI1394_MAX_AT_REQ_RETRIES |
( OHCI1394_MAX_AT_RESP_RETRIES < < 4 ) |
( OHCI1394_MAX_PHYS_RESP_RETRIES < < 8 ) ) ;
ar_context_run ( & ohci - > ar_request_ctx ) ;
ar_context_run ( & ohci - > ar_response_ctx ) ;
reg_write ( ohci , OHCI1394_SelfIDBuffer , ohci - > self_id_bus ) ;
reg_write ( ohci , OHCI1394_PhyUpperBound , 0x00010000 ) ;
reg_write ( ohci , OHCI1394_IntEventClear , ~ 0 ) ;
reg_write ( ohci , OHCI1394_IntMaskClear , ~ 0 ) ;
reg_write ( ohci , OHCI1394_IntMaskSet ,
OHCI1394_selfIDComplete |
OHCI1394_RQPkt | OHCI1394_RSPkt |
OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
OHCI1394_isochRx | OHCI1394_isochTx |
2007-12-23 00:14:52 +03:00
OHCI1394_postedWriteErr | OHCI1394_cycleTooLong |
OHCI1394_cycle64Seconds | OHCI1394_masterIntEnable ) ;
2007-05-31 03:06:35 +04:00
/* Activate link_on bit and contender bit in our self ID packets.*/
if ( ohci_update_phy_reg ( card , 4 , 0 ,
PHY_LINK_ACTIVE | PHY_CONTENDER ) < 0 )
return - EIO ;
2007-05-08 04:33:32 +04:00
/*
* When the link is not yet enabled , the atomic config rom
2006-12-20 03:58:35 +03:00
* update mechanism described below in ohci_set_config_rom ( )
* is not active . We have to update ConfigRomHeader and
* BusOptions manually , and the write to ConfigROMmap takes
* effect immediately . We tie this to the enabling of the
* link , so we have a valid config rom before enabling - the
* OHCI requires that ConfigROMhdr and BusOptions have valid
* values before enabling .
*
* However , when the ConfigROMmap is written , some controllers
* always read back quadlets 0 and 2 from the config rom to
* the ConfigRomHeader and BusOptions registers on bus reset .
* They shouldn ' t do that in this initial case where the link
* isn ' t enabled . This means we have to use the same
* workaround here , setting the bus header to 0 and then write
* the right values in the bus reset tasklet .
*/
2007-06-06 03:27:05 +04:00
if ( config_rom ) {
ohci - > next_config_rom =
dma_alloc_coherent ( ohci - > card . device , CONFIG_ROM_SIZE ,
& ohci - > next_config_rom_bus ,
GFP_KERNEL ) ;
if ( ohci - > next_config_rom = = NULL )
return - ENOMEM ;
2006-12-20 03:58:35 +03:00
2007-06-06 03:27:05 +04:00
memset ( ohci - > next_config_rom , 0 , CONFIG_ROM_SIZE ) ;
fw_memcpy_to_be32 ( ohci - > next_config_rom , config_rom , length * 4 ) ;
} else {
/*
* In the suspend case , config_rom is NULL , which
* means that we just reuse the old config rom .
*/
ohci - > next_config_rom = ohci - > config_rom ;
ohci - > next_config_rom_bus = ohci - > config_rom_bus ;
}
2006-12-20 03:58:35 +03:00
2007-06-06 03:27:05 +04:00
ohci - > next_header = be32_to_cpu ( ohci - > next_config_rom [ 0 ] ) ;
2006-12-20 03:58:35 +03:00
ohci - > next_config_rom [ 0 ] = 0 ;
reg_write ( ohci , OHCI1394_ConfigROMhdr , 0 ) ;
2007-06-06 03:27:05 +04:00
reg_write ( ohci , OHCI1394_BusOptions ,
be32_to_cpu ( ohci - > next_config_rom [ 2 ] ) ) ;
2006-12-20 03:58:35 +03:00
reg_write ( ohci , OHCI1394_ConfigROMmap , ohci - > next_config_rom_bus ) ;
reg_write ( ohci , OHCI1394_AsReqFilterHiSet , 0x80000000 ) ;
if ( request_irq ( dev - > irq , irq_handler ,
2007-03-06 05:19:51 +03:00
IRQF_SHARED , ohci_driver_name , ohci ) ) {
2006-12-20 03:58:35 +03:00
fw_error ( " Failed to allocate shared interrupt %d. \n " ,
dev - > irq ) ;
dma_free_coherent ( ohci - > card . device , CONFIG_ROM_SIZE ,
ohci - > config_rom , ohci - > config_rom_bus ) ;
return - EIO ;
}
reg_write ( ohci , OHCI1394_HCControlSet ,
OHCI1394_HCControl_linkEnable |
OHCI1394_HCControl_BIBimageValid ) ;
flush_writes ( ohci ) ;
2007-05-08 04:33:32 +04:00
/*
* We are ready to go , initiate bus reset to finish the
* initialization .
*/
2006-12-20 03:58:35 +03:00
fw_core_initiate_bus_reset ( & ohci - > card , 1 ) ;
return 0 ;
}
static int
ohci_set_config_rom ( struct fw_card * card , u32 * config_rom , size_t length )
{
struct fw_ohci * ohci ;
unsigned long flags ;
2007-07-25 21:18:08 +04:00
int retval = - EBUSY ;
2006-12-20 03:58:35 +03:00
__be32 * next_config_rom ;
dma_addr_t next_config_rom_bus ;
ohci = fw_ohci ( card ) ;
2007-05-08 04:33:32 +04:00
/*
* When the OHCI controller is enabled , the config rom update
2006-12-20 03:58:35 +03:00
* mechanism is a bit tricky , but easy enough to use . See
* section 5.5 .6 in the OHCI specification .
*
* The OHCI controller caches the new config rom address in a
* shadow register ( ConfigROMmapNext ) and needs a bus reset
* for the changes to take place . When the bus reset is
* detected , the controller loads the new values for the
* ConfigRomHeader and BusOptions registers from the specified
* config rom and loads ConfigROMmap from the ConfigROMmapNext
* shadow register . All automatically and atomically .
*
* Now , there ' s a twist to this story . The automatic load of
* ConfigRomHeader and BusOptions doesn ' t honor the
* noByteSwapData bit , so with a be32 config rom , the
* controller will load be32 values in to these registers
* during the atomic update , even on litte endian
* architectures . The workaround we use is to put a 0 in the
* header quadlet ; 0 is endian agnostic and means that the
* config rom isn ' t ready yet . In the bus reset tasklet we
* then set up the real values for the two registers .
*
* We use ohci - > lock to avoid racing with the code that sets
* ohci - > next_config_rom to NULL ( see bus_reset_tasklet ) .
*/
next_config_rom =
dma_alloc_coherent ( ohci - > card . device , CONFIG_ROM_SIZE ,
& next_config_rom_bus , GFP_KERNEL ) ;
if ( next_config_rom = = NULL )
return - ENOMEM ;
spin_lock_irqsave ( & ohci - > lock , flags ) ;
if ( ohci - > next_config_rom = = NULL ) {
ohci - > next_config_rom = next_config_rom ;
ohci - > next_config_rom_bus = next_config_rom_bus ;
memset ( ohci - > next_config_rom , 0 , CONFIG_ROM_SIZE ) ;
fw_memcpy_to_be32 ( ohci - > next_config_rom , config_rom ,
length * 4 ) ;
ohci - > next_header = config_rom [ 0 ] ;
ohci - > next_config_rom [ 0 ] = 0 ;
reg_write ( ohci , OHCI1394_ConfigROMmap ,
ohci - > next_config_rom_bus ) ;
2007-07-25 21:18:08 +04:00
retval = 0 ;
2006-12-20 03:58:35 +03:00
}
spin_unlock_irqrestore ( & ohci - > lock , flags ) ;
2007-05-08 04:33:32 +04:00
/*
* Now initiate a bus reset to have the changes take
2006-12-20 03:58:35 +03:00
* effect . We clean up the old config rom memory and DMA
* mappings in the bus reset tasklet , since the OHCI
* controller could need to access it before the bus reset
2007-05-08 04:33:32 +04:00
* takes effect .
*/
2006-12-20 03:58:35 +03:00
if ( retval = = 0 )
fw_core_initiate_bus_reset ( & ohci - > card , 1 ) ;
2007-07-25 21:18:08 +04:00
else
dma_free_coherent ( ohci - > card . device , CONFIG_ROM_SIZE ,
next_config_rom , next_config_rom_bus ) ;
2006-12-20 03:58:35 +03:00
return retval ;
}
static void ohci_send_request ( struct fw_card * card , struct fw_packet * packet )
{
struct fw_ohci * ohci = fw_ohci ( card ) ;
at_context_transmit ( & ohci - > at_request_ctx , packet ) ;
}
static void ohci_send_response ( struct fw_card * card , struct fw_packet * packet )
{
struct fw_ohci * ohci = fw_ohci ( card ) ;
at_context_transmit ( & ohci - > at_response_ctx , packet ) ;
}
2007-02-06 22:49:32 +03:00
static int ohci_cancel_packet ( struct fw_card * card , struct fw_packet * packet )
{
struct fw_ohci * ohci = fw_ohci ( card ) ;
2007-03-07 20:12:49 +03:00
struct context * ctx = & ohci - > at_request_ctx ;
struct driver_data * driver_data = packet - > driver_data ;
int retval = - ENOENT ;
2007-02-06 22:49:32 +03:00
2007-03-07 20:12:49 +03:00
tasklet_disable ( & ctx - > tasklet ) ;
2007-02-06 22:49:32 +03:00
2007-03-07 20:12:49 +03:00
if ( packet - > ack ! = 0 )
goto out ;
2007-02-06 22:49:32 +03:00
2007-03-07 20:12:49 +03:00
driver_data - > packet = NULL ;
packet - > ack = RCODE_CANCELLED ;
packet - > callback ( packet , & ohci - > card , packet - > ack ) ;
retval = 0 ;
2007-02-06 22:49:32 +03:00
2007-03-07 20:12:49 +03:00
out :
tasklet_enable ( & ctx - > tasklet ) ;
2007-02-06 22:49:32 +03:00
2007-03-07 20:12:49 +03:00
return retval ;
2007-02-06 22:49:32 +03:00
}
2006-12-20 03:58:35 +03:00
static int
ohci_enable_phys_dma ( struct fw_card * card , int node_id , int generation )
{
struct fw_ohci * ohci = fw_ohci ( card ) ;
unsigned long flags ;
2007-01-23 23:11:43 +03:00
int n , retval = 0 ;
2006-12-20 03:58:35 +03:00
2007-05-08 04:33:32 +04:00
/*
* FIXME : Make sure this bitmask is cleared when we clear the busReset
* interrupt bit . Clear physReqResourceAllBuses on bus reset .
*/
2006-12-20 03:58:35 +03:00
spin_lock_irqsave ( & ohci - > lock , flags ) ;
if ( ohci - > generation ! = generation ) {
retval = - ESTALE ;
goto out ;
}
2007-05-08 04:33:32 +04:00
/*
* Note , if the node ID contains a non - local bus ID , physical DMA is
* enabled for _all_ nodes on remote buses .
*/
2007-01-23 23:11:43 +03:00
n = ( node_id & 0xffc0 ) = = LOCAL_BUS ? node_id & 0x3f : 63 ;
if ( n < 32 )
reg_write ( ohci , OHCI1394_PhyReqFilterLoSet , 1 < < n ) ;
else
reg_write ( ohci , OHCI1394_PhyReqFilterHiSet , 1 < < ( n - 32 ) ) ;
2006-12-20 03:58:35 +03:00
flush_writes ( ohci ) ;
out :
2007-01-21 22:46:45 +03:00
spin_unlock_irqrestore ( & ohci - > lock , flags ) ;
2006-12-20 03:58:35 +03:00
return retval ;
}
2007-03-04 16:45:18 +03:00
2007-03-07 20:12:56 +03:00
static u64
ohci_get_bus_time ( struct fw_card * card )
{
struct fw_ohci * ohci = fw_ohci ( card ) ;
u32 cycle_time ;
u64 bus_time ;
cycle_time = reg_read ( ohci , OHCI1394_IsochronousCycleTimer ) ;
bus_time = ( ( u64 ) ohci - > bus_seconds < < 32 ) | cycle_time ;
return bus_time ;
}
2007-02-17 01:34:46 +03:00
static int handle_ir_dualbuffer_packet ( struct context * context ,
struct descriptor * d ,
struct descriptor * last )
2006-12-20 03:58:35 +03:00
{
2007-02-17 01:34:40 +03:00
struct iso_context * ctx =
container_of ( context , struct iso_context , context ) ;
struct db_descriptor * db = ( struct db_descriptor * ) d ;
2007-03-15 00:34:53 +03:00
__le32 * ir_header ;
2007-02-17 01:34:44 +03:00
size_t header_length ;
2007-03-15 00:34:53 +03:00
void * p , * end ;
int i ;
2007-02-17 01:34:46 +03:00
2007-12-19 11:09:18 +03:00
if ( db - > first_res_count > 0 & & db - > second_res_count > 0 ) {
if ( ctx - > excess_bytes < = le16_to_cpu ( db - > second_req_count ) ) {
/* This descriptor isn't done yet, stop iteration. */
return 0 ;
}
ctx - > excess_bytes - = le16_to_cpu ( db - > second_req_count ) ;
}
2007-02-17 01:34:40 +03:00
2007-03-15 00:34:53 +03:00
header_length = le16_to_cpu ( db - > first_req_count ) -
le16_to_cpu ( db - > first_res_count ) ;
i = ctx - > header_length ;
p = db + 1 ;
end = p + header_length ;
while ( p < end & & i + ctx - > base . header_size < = PAGE_SIZE ) {
2007-05-08 04:33:32 +04:00
/*
* The iso header is byteswapped to little endian by
2007-04-11 02:11:16 +04:00
* the controller , but the remaining header quadlets
* are big endian . We want to present all the headers
* as big endian , so we have to swap the first
2007-05-08 04:33:32 +04:00
* quadlet .
*/
2007-04-11 02:11:16 +04:00
* ( u32 * ) ( ctx - > header + i ) = __swab32 ( * ( u32 * ) ( p + 4 ) ) ;
memcpy ( ctx - > header + i + 4 , p + 8 , ctx - > base . header_size - 4 ) ;
2007-03-15 00:34:53 +03:00
i + = ctx - > base . header_size ;
2007-12-19 11:09:18 +03:00
ctx - > excess_bytes + =
( le32_to_cpu ( * ( u32 * ) ( p + 4 ) ) > > 16 ) & 0xffff ;
2007-03-15 00:34:53 +03:00
p + = ctx - > base . header_size + 4 ;
}
ctx - > header_length = i ;
2007-02-17 01:34:44 +03:00
2007-12-19 11:09:18 +03:00
ctx - > excess_bytes - = le16_to_cpu ( db - > second_req_count ) -
le16_to_cpu ( db - > second_res_count ) ;
2007-05-08 04:33:35 +04:00
if ( le16_to_cpu ( db - > control ) & DESCRIPTOR_IRQ_ALWAYS ) {
2007-03-15 00:34:53 +03:00
ir_header = ( __le32 * ) ( db + 1 ) ;
ctx - > base . callback ( & ctx - > base ,
le32_to_cpu ( ir_header [ 0 ] ) & 0xffff ,
2007-02-17 01:34:44 +03:00
ctx - > header_length , ctx - > header ,
2007-02-17 01:34:40 +03:00
ctx - > base . callback_data ) ;
2007-02-17 01:34:44 +03:00
ctx - > header_length = 0 ;
}
2006-12-20 03:58:35 +03:00
2007-02-17 01:34:40 +03:00
return 1 ;
2006-12-20 03:58:35 +03:00
}
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
static int handle_ir_packet_per_buffer ( struct context * context ,
struct descriptor * d ,
struct descriptor * last )
{
struct iso_context * ctx =
container_of ( context , struct iso_context , context ) ;
2007-12-19 23:26:38 +03:00
struct descriptor * pd ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
__le32 * ir_header ;
2007-12-19 23:26:38 +03:00
void * p ;
int i ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
2007-12-19 23:26:38 +03:00
for ( pd = d ; pd < = last ; pd + + ) {
if ( pd - > transfer_status )
break ;
}
if ( pd > last )
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
/* Descriptor(s) not done yet, stop iteration */
return 0 ;
i = ctx - > header_length ;
2007-12-19 23:26:38 +03:00
p = last + 1 ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
2007-12-19 23:26:38 +03:00
if ( ctx - > base . header_size > 0 & &
i + ctx - > base . header_size < = PAGE_SIZE ) {
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
/*
* The iso header is byteswapped to little endian by
* the controller , but the remaining header quadlets
* are big endian . We want to present all the headers
* as big endian , so we have to swap the first quadlet .
*/
* ( u32 * ) ( ctx - > header + i ) = __swab32 ( * ( u32 * ) ( p + 4 ) ) ;
memcpy ( ctx - > header + i + 4 , p + 8 , ctx - > base . header_size - 4 ) ;
2007-12-19 23:26:38 +03:00
ctx - > header_length + = ctx - > base . header_size ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
}
2007-12-19 23:26:38 +03:00
if ( le16_to_cpu ( last - > control ) & DESCRIPTOR_IRQ_ALWAYS ) {
ir_header = ( __le32 * ) p ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
ctx - > base . callback ( & ctx - > base ,
le32_to_cpu ( ir_header [ 0 ] ) & 0xffff ,
ctx - > header_length , ctx - > header ,
ctx - > base . callback_data ) ;
ctx - > header_length = 0 ;
}
return 1 ;
}
2007-02-17 01:34:39 +03:00
static int handle_it_packet ( struct context * context ,
struct descriptor * d ,
struct descriptor * last )
2006-12-20 03:58:35 +03:00
{
2007-02-17 01:34:39 +03:00
struct iso_context * ctx =
container_of ( context , struct iso_context , context ) ;
2007-03-04 16:45:18 +03:00
2007-02-17 01:34:39 +03:00
if ( last - > transfer_status = = 0 )
/* This descriptor isn't done yet, stop iteration. */
return 0 ;
2007-05-08 04:33:35 +04:00
if ( le16_to_cpu ( last - > control ) & DESCRIPTOR_IRQ_ALWAYS )
2007-02-17 01:34:44 +03:00
ctx - > base . callback ( & ctx - > base , le16_to_cpu ( last - > res_count ) ,
0 , NULL , ctx - > base . callback_data ) ;
2007-02-17 01:34:39 +03:00
return 1 ;
2006-12-20 03:58:35 +03:00
}
2007-02-17 01:34:39 +03:00
static struct fw_iso_context *
2007-03-15 00:34:54 +03:00
ohci_allocate_iso_context ( struct fw_card * card , int type , size_t header_size )
2006-12-20 03:58:35 +03:00
{
struct fw_ohci * ohci = fw_ohci ( card ) ;
struct iso_context * ctx , * list ;
2007-02-17 01:34:39 +03:00
descriptor_callback_t callback ;
2007-02-17 01:34:40 +03:00
u32 * mask , regs ;
2006-12-20 03:58:35 +03:00
unsigned long flags ;
2007-02-17 01:34:44 +03:00
int index , retval = - ENOMEM ;
2006-12-20 03:58:35 +03:00
if ( type = = FW_ISO_CONTEXT_TRANSMIT ) {
mask = & ohci - > it_context_mask ;
list = ohci - > it_context_list ;
2007-02-17 01:34:39 +03:00
callback = handle_it_packet ;
2006-12-20 03:58:35 +03:00
} else {
2007-03-04 16:45:18 +03:00
mask = & ohci - > ir_context_mask ;
list = ohci - > ir_context_list ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
if ( ohci - > version > = OHCI_VERSION_1_1 )
callback = handle_ir_dualbuffer_packet ;
else
callback = handle_ir_packet_per_buffer ;
2006-12-20 03:58:35 +03:00
}
spin_lock_irqsave ( & ohci - > lock , flags ) ;
index = ffs ( * mask ) - 1 ;
if ( index > = 0 )
* mask & = ~ ( 1 < < index ) ;
spin_unlock_irqrestore ( & ohci - > lock , flags ) ;
if ( index < 0 )
return ERR_PTR ( - EBUSY ) ;
2007-03-04 16:45:18 +03:00
if ( type = = FW_ISO_CONTEXT_TRANSMIT )
regs = OHCI1394_IsoXmitContextBase ( index ) ;
else
regs = OHCI1394_IsoRcvContextBase ( index ) ;
2006-12-20 03:58:35 +03:00
ctx = & list [ index ] ;
2007-05-10 03:23:14 +04:00
memset ( ctx , 0 , sizeof ( * ctx ) ) ;
2007-02-17 01:34:44 +03:00
ctx - > header_length = 0 ;
ctx - > header = ( void * ) __get_free_page ( GFP_KERNEL ) ;
if ( ctx - > header = = NULL )
goto out ;
2007-02-17 01:34:39 +03:00
retval = context_init ( & ctx - > context , ohci , ISO_BUFFER_SIZE ,
2007-02-17 01:34:40 +03:00
regs , callback ) ;
2007-02-17 01:34:44 +03:00
if ( retval < 0 )
goto out_with_header ;
2006-12-20 03:58:35 +03:00
return & ctx - > base ;
2007-02-17 01:34:44 +03:00
out_with_header :
free_page ( ( unsigned long ) ctx - > header ) ;
out :
spin_lock_irqsave ( & ohci - > lock , flags ) ;
* mask | = 1 < < index ;
spin_unlock_irqrestore ( & ohci - > lock , flags ) ;
return ERR_PTR ( retval ) ;
2006-12-20 03:58:35 +03:00
}
2007-03-15 00:34:54 +03:00
static int ohci_start_iso ( struct fw_iso_context * base ,
s32 cycle , u32 sync , u32 tags )
2006-12-20 03:58:35 +03:00
{
2007-03-04 16:45:18 +03:00
struct iso_context * ctx = container_of ( base , struct iso_context , base ) ;
2007-02-17 01:34:39 +03:00
struct fw_ohci * ohci = ctx - > context . ohci ;
2007-03-28 22:26:10 +04:00
u32 control , match ;
2006-12-20 03:58:35 +03:00
int index ;
2007-02-17 01:34:40 +03:00
if ( ctx - > base . type = = FW_ISO_CONTEXT_TRANSMIT ) {
index = ctx - ohci - > it_context_list ;
2007-03-28 22:26:10 +04:00
match = 0 ;
if ( cycle > = 0 )
match = IT_CONTEXT_CYCLE_MATCH_ENABLE |
2007-02-17 01:34:40 +03:00
( cycle & 0x7fff ) < < 16 ;
2007-02-17 01:34:50 +03:00
2007-02-17 01:34:40 +03:00
reg_write ( ohci , OHCI1394_IsoXmitIntEventClear , 1 < < index ) ;
reg_write ( ohci , OHCI1394_IsoXmitIntMaskSet , 1 < < index ) ;
2007-03-28 22:26:10 +04:00
context_run ( & ctx - > context , match ) ;
2007-02-17 01:34:40 +03:00
} else {
index = ctx - ohci - > ir_context_list ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
control = IR_CONTEXT_ISOCH_HEADER ;
if ( ohci - > version > = OHCI_VERSION_1_1 )
control | = IR_CONTEXT_DUAL_BUFFER_MODE ;
2007-03-28 22:26:10 +04:00
match = ( tags < < 28 ) | ( sync < < 8 ) | ctx - > base . channel ;
if ( cycle > = 0 ) {
match | = ( cycle & 0x07fff ) < < 12 ;
control | = IR_CONTEXT_CYCLE_MATCH_ENABLE ;
}
2006-12-20 03:58:35 +03:00
2007-02-17 01:34:40 +03:00
reg_write ( ohci , OHCI1394_IsoRecvIntEventClear , 1 < < index ) ;
reg_write ( ohci , OHCI1394_IsoRecvIntMaskSet , 1 < < index ) ;
2007-05-08 04:33:35 +04:00
reg_write ( ohci , CONTEXT_MATCH ( ctx - > context . regs ) , match ) ;
2007-03-28 22:26:10 +04:00
context_run ( & ctx - > context , control ) ;
2007-02-17 01:34:40 +03:00
}
2006-12-20 03:58:35 +03:00
return 0 ;
}
2007-02-17 01:34:42 +03:00
static int ohci_stop_iso ( struct fw_iso_context * base )
{
struct fw_ohci * ohci = fw_ohci ( base - > card ) ;
2007-03-04 16:45:18 +03:00
struct iso_context * ctx = container_of ( base , struct iso_context , base ) ;
2007-02-17 01:34:42 +03:00
int index ;
if ( ctx - > base . type = = FW_ISO_CONTEXT_TRANSMIT ) {
index = ctx - ohci - > it_context_list ;
reg_write ( ohci , OHCI1394_IsoXmitIntMaskClear , 1 < < index ) ;
} else {
index = ctx - ohci - > ir_context_list ;
reg_write ( ohci , OHCI1394_IsoRecvIntMaskClear , 1 < < index ) ;
}
flush_writes ( ohci ) ;
context_stop ( & ctx - > context ) ;
return 0 ;
}
2006-12-20 03:58:35 +03:00
static void ohci_free_iso_context ( struct fw_iso_context * base )
{
struct fw_ohci * ohci = fw_ohci ( base - > card ) ;
2007-03-04 16:45:18 +03:00
struct iso_context * ctx = container_of ( base , struct iso_context , base ) ;
2006-12-20 03:58:35 +03:00
unsigned long flags ;
int index ;
2007-02-17 01:34:42 +03:00
ohci_stop_iso ( base ) ;
context_release ( & ctx - > context ) ;
2007-02-17 01:34:44 +03:00
free_page ( ( unsigned long ) ctx - > header ) ;
2007-02-17 01:34:42 +03:00
2006-12-20 03:58:35 +03:00
spin_lock_irqsave ( & ohci - > lock , flags ) ;
if ( ctx - > base . type = = FW_ISO_CONTEXT_TRANSMIT ) {
index = ctx - ohci - > it_context_list ;
ohci - > it_context_mask | = 1 < < index ;
} else {
index = ctx - ohci - > ir_context_list ;
ohci - > ir_context_mask | = 1 < < index ;
}
spin_unlock_irqrestore ( & ohci - > lock , flags ) ;
}
static int
2007-02-17 01:34:40 +03:00
ohci_queue_iso_transmit ( struct fw_iso_context * base ,
struct fw_iso_packet * packet ,
struct fw_iso_buffer * buffer ,
unsigned long payload )
2006-12-20 03:58:35 +03:00
{
2007-03-04 16:45:18 +03:00
struct iso_context * ctx = container_of ( base , struct iso_context , base ) ;
2007-02-17 01:34:39 +03:00
struct descriptor * d , * last , * pd ;
2006-12-20 03:58:35 +03:00
struct fw_iso_packet * p ;
__le32 * header ;
2007-02-17 01:34:38 +03:00
dma_addr_t d_bus , page_bus ;
2006-12-20 03:58:35 +03:00
u32 z , header_z , payload_z , irq ;
u32 payload_index , payload_end_index , next_page_index ;
2007-02-17 01:34:39 +03:00
int page , end_page , i , length , offset ;
2006-12-20 03:58:35 +03:00
2007-05-08 04:33:32 +04:00
/*
* FIXME : Cycle lost behavior should be configurable : lose
* packet , retransmit or terminate . .
*/
2006-12-20 03:58:35 +03:00
p = packet ;
2007-02-17 01:34:38 +03:00
payload_index = payload ;
2006-12-20 03:58:35 +03:00
if ( p - > skip )
z = 1 ;
else
z = 2 ;
if ( p - > header_length > 0 )
z + + ;
/* Determine the first page the payload isn't contained in. */
end_page = PAGE_ALIGN ( payload_index + p - > payload_length ) > > PAGE_SHIFT ;
if ( p - > payload_length > 0 )
payload_z = end_page - ( payload_index > > PAGE_SHIFT ) ;
else
payload_z = 0 ;
z + = payload_z ;
/* Get header size in number of descriptors. */
2007-05-10 03:23:14 +04:00
header_z = DIV_ROUND_UP ( p - > header_length , sizeof ( * d ) ) ;
2006-12-20 03:58:35 +03:00
2007-02-17 01:34:39 +03:00
d = context_get_descriptors ( & ctx - > context , z + header_z , & d_bus ) ;
if ( d = = NULL )
return - ENOMEM ;
2006-12-20 03:58:35 +03:00
if ( ! p - > skip ) {
2007-05-08 04:33:35 +04:00
d [ 0 ] . control = cpu_to_le16 ( DESCRIPTOR_KEY_IMMEDIATE ) ;
2006-12-20 03:58:35 +03:00
d [ 0 ] . req_count = cpu_to_le16 ( 8 ) ;
header = ( __le32 * ) & d [ 1 ] ;
2007-05-08 04:33:35 +04:00
header [ 0 ] = cpu_to_le32 ( IT_HEADER_SY ( p - > sy ) |
IT_HEADER_TAG ( p - > tag ) |
IT_HEADER_TCODE ( TCODE_STREAM_DATA ) |
IT_HEADER_CHANNEL ( ctx - > base . channel ) |
IT_HEADER_SPEED ( ctx - > base . speed ) ) ;
2006-12-20 03:58:35 +03:00
header [ 1 ] =
2007-05-08 04:33:35 +04:00
cpu_to_le32 ( IT_HEADER_DATA_LENGTH ( p - > header_length +
2006-12-20 03:58:35 +03:00
p - > payload_length ) ) ;
}
if ( p - > header_length > 0 ) {
d [ 2 ] . req_count = cpu_to_le16 ( p - > header_length ) ;
2007-05-10 03:23:14 +04:00
d [ 2 ] . data_address = cpu_to_le32 ( d_bus + z * sizeof ( * d ) ) ;
2006-12-20 03:58:35 +03:00
memcpy ( & d [ z ] , p - > header , p - > header_length ) ;
}
pd = d + z - payload_z ;
payload_end_index = payload_index + p - > payload_length ;
for ( i = 0 ; i < payload_z ; i + + ) {
page = payload_index > > PAGE_SHIFT ;
offset = payload_index & ~ PAGE_MASK ;
next_page_index = ( page + 1 ) < < PAGE_SHIFT ;
length =
min ( next_page_index , payload_end_index ) - payload_index ;
pd [ i ] . req_count = cpu_to_le16 ( length ) ;
2007-02-17 01:34:38 +03:00
page_bus = page_private ( buffer - > pages [ page ] ) ;
pd [ i ] . data_address = cpu_to_le32 ( page_bus + offset ) ;
2006-12-20 03:58:35 +03:00
payload_index + = length ;
}
if ( p - > interrupt )
2007-05-08 04:33:35 +04:00
irq = DESCRIPTOR_IRQ_ALWAYS ;
2006-12-20 03:58:35 +03:00
else
2007-05-08 04:33:35 +04:00
irq = DESCRIPTOR_NO_IRQ ;
2006-12-20 03:58:35 +03:00
2007-02-17 01:34:39 +03:00
last = z = = 2 ? d : d + z - 1 ;
2007-05-08 04:33:35 +04:00
last - > control | = cpu_to_le16 ( DESCRIPTOR_OUTPUT_LAST |
DESCRIPTOR_STATUS |
DESCRIPTOR_BRANCH_ALWAYS |
2007-02-17 01:34:35 +03:00
irq ) ;
2006-12-20 03:58:35 +03:00
2007-02-17 01:34:39 +03:00
context_append ( & ctx - > context , d , z , header_z ) ;
2006-12-20 03:58:35 +03:00
return 0 ;
}
2007-03-04 16:45:18 +03:00
2007-02-17 01:34:40 +03:00
static int
2007-02-17 01:34:46 +03:00
ohci_queue_iso_receive_dualbuffer ( struct fw_iso_context * base ,
struct fw_iso_packet * packet ,
struct fw_iso_buffer * buffer ,
unsigned long payload )
2007-02-17 01:34:40 +03:00
{
struct iso_context * ctx = container_of ( base , struct iso_context , base ) ;
struct db_descriptor * db = NULL ;
struct descriptor * d ;
struct fw_iso_packet * p ;
dma_addr_t d_bus , page_bus ;
u32 z , header_z , length , rest ;
2007-03-15 00:34:53 +03:00
int page , offset , packet_count , header_size ;
2007-03-04 16:45:18 +03:00
2007-05-08 04:33:32 +04:00
/*
* FIXME : Cycle lost behavior should be configurable : lose
* packet , retransmit or terminate . .
*/
2007-02-17 01:34:40 +03:00
p = packet ;
z = 2 ;
2007-05-08 04:33:32 +04:00
/*
* The OHCI controller puts the status word in the header
* buffer too , so we need 4 extra bytes per packet .
*/
2007-03-15 00:34:53 +03:00
packet_count = p - > header_length / ctx - > base . header_size ;
header_size = packet_count * ( ctx - > base . header_size + 4 ) ;
2007-02-17 01:34:40 +03:00
/* Get header size in number of descriptors. */
2007-05-10 03:23:14 +04:00
header_z = DIV_ROUND_UP ( header_size , sizeof ( * d ) ) ;
2007-02-17 01:34:40 +03:00
page = payload > > PAGE_SHIFT ;
offset = payload & ~ PAGE_MASK ;
rest = p - > payload_length ;
/* FIXME: make packet-per-buffer/dual-buffer a context option */
while ( rest > 0 ) {
d = context_get_descriptors ( & ctx - > context ,
z + header_z , & d_bus ) ;
if ( d = = NULL )
return - ENOMEM ;
db = ( struct db_descriptor * ) d ;
2007-05-08 04:33:35 +04:00
db - > control = cpu_to_le16 ( DESCRIPTOR_STATUS |
DESCRIPTOR_BRANCH_ALWAYS ) ;
2007-03-15 00:34:53 +03:00
db - > first_size = cpu_to_le16 ( ctx - > base . header_size + 4 ) ;
2007-12-19 11:09:18 +03:00
if ( p - > skip & & rest = = p - > payload_length ) {
db - > control | = cpu_to_le16 ( DESCRIPTOR_WAIT ) ;
db - > first_req_count = db - > first_size ;
} else {
db - > first_req_count = cpu_to_le16 ( header_size ) ;
}
2007-02-17 01:34:45 +03:00
db - > first_res_count = db - > first_req_count ;
2007-05-10 03:23:14 +04:00
db - > first_buffer = cpu_to_le32 ( d_bus + sizeof ( * db ) ) ;
2007-03-04 16:45:18 +03:00
2007-12-19 11:09:18 +03:00
if ( p - > skip & & rest = = p - > payload_length )
length = 4 ;
else if ( offset + rest < PAGE_SIZE )
2007-02-17 01:34:40 +03:00
length = rest ;
else
length = PAGE_SIZE - offset ;
2007-02-17 01:34:45 +03:00
db - > second_req_count = cpu_to_le16 ( length ) ;
db - > second_res_count = db - > second_req_count ;
2007-02-17 01:34:40 +03:00
page_bus = page_private ( buffer - > pages [ page ] ) ;
db - > second_buffer = cpu_to_le32 ( page_bus + offset ) ;
2007-02-17 01:34:47 +03:00
if ( p - > interrupt & & length = = rest )
2007-05-08 04:33:35 +04:00
db - > control | = cpu_to_le16 ( DESCRIPTOR_IRQ_ALWAYS ) ;
2007-02-17 01:34:47 +03:00
2007-02-17 01:34:40 +03:00
context_append ( & ctx - > context , d , z , header_z ) ;
offset = ( offset + length ) & ~ PAGE_MASK ;
rest - = length ;
2007-12-19 11:09:18 +03:00
if ( offset = = 0 )
page + + ;
2007-02-17 01:34:40 +03:00
}
2007-02-17 01:34:46 +03:00
return 0 ;
}
2007-02-17 01:34:50 +03:00
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
static int
ohci_queue_iso_receive_packet_per_buffer ( struct fw_iso_context * base ,
struct fw_iso_packet * packet ,
struct fw_iso_buffer * buffer ,
unsigned long payload )
{
struct iso_context * ctx = container_of ( base , struct iso_context , base ) ;
struct descriptor * d = NULL , * pd = NULL ;
2007-12-19 23:26:38 +03:00
struct fw_iso_packet * p = packet ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
dma_addr_t d_bus , page_bus ;
u32 z , header_z , rest ;
2007-12-19 23:26:38 +03:00
int i , j , length ;
int page , offset , packet_count , header_size , payload_per_buffer ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
/*
* The OHCI controller puts the status word in the
* buffer too , so we need 4 extra bytes per packet .
*/
packet_count = p - > header_length / ctx - > base . header_size ;
2007-12-19 23:26:38 +03:00
header_size = ctx - > base . header_size + 4 ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
/* Get header size in number of descriptors. */
header_z = DIV_ROUND_UP ( header_size , sizeof ( * d ) ) ;
page = payload > > PAGE_SHIFT ;
offset = payload & ~ PAGE_MASK ;
2007-12-19 23:26:38 +03:00
payload_per_buffer = p - > payload_length / packet_count ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
for ( i = 0 ; i < packet_count ; i + + ) {
/* d points to the header descriptor */
2007-12-19 23:26:38 +03:00
z = DIV_ROUND_UP ( payload_per_buffer + offset , PAGE_SIZE ) + 1 ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
d = context_get_descriptors ( & ctx - > context ,
2007-12-19 23:26:38 +03:00
z + header_z , & d_bus ) ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
if ( d = = NULL )
return - ENOMEM ;
2007-12-19 23:26:38 +03:00
d - > control = cpu_to_le16 ( DESCRIPTOR_STATUS |
DESCRIPTOR_INPUT_MORE ) ;
if ( p - > skip & & i = = 0 )
d - > control | = cpu_to_le16 ( DESCRIPTOR_WAIT ) ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
d - > req_count = cpu_to_le16 ( header_size ) ;
d - > res_count = d - > req_count ;
2007-12-19 23:26:38 +03:00
d - > transfer_status = 0 ;
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
d - > data_address = cpu_to_le32 ( d_bus + ( z * sizeof ( * d ) ) ) ;
2007-12-19 23:26:38 +03:00
rest = payload_per_buffer ;
for ( j = 1 ; j < z ; j + + ) {
pd = d + j ;
pd - > control = cpu_to_le16 ( DESCRIPTOR_STATUS |
DESCRIPTOR_INPUT_MORE ) ;
if ( offset + rest < PAGE_SIZE )
length = rest ;
else
length = PAGE_SIZE - offset ;
pd - > req_count = cpu_to_le16 ( length ) ;
pd - > res_count = pd - > req_count ;
pd - > transfer_status = 0 ;
page_bus = page_private ( buffer - > pages [ page ] ) ;
pd - > data_address = cpu_to_le32 ( page_bus + offset ) ;
offset = ( offset + length ) & ~ PAGE_MASK ;
rest - = length ;
if ( offset = = 0 )
page + + ;
}
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
pd - > control = cpu_to_le16 ( DESCRIPTOR_STATUS |
DESCRIPTOR_INPUT_LAST |
DESCRIPTOR_BRANCH_ALWAYS ) ;
2007-12-19 23:26:38 +03:00
if ( p - > interrupt & & i = = packet_count - 1 )
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
pd - > control | = cpu_to_le16 ( DESCRIPTOR_IRQ_ALWAYS ) ;
context_append ( & ctx - > context , d , z , header_z ) ;
}
return 0 ;
}
2007-02-17 01:34:40 +03:00
static int
ohci_queue_iso ( struct fw_iso_context * base ,
struct fw_iso_packet * packet ,
struct fw_iso_buffer * buffer ,
unsigned long payload )
{
2007-02-17 01:34:49 +03:00
struct iso_context * ctx = container_of ( base , struct iso_context , base ) ;
2007-02-17 01:34:40 +03:00
if ( base - > type = = FW_ISO_CONTEXT_TRANSMIT )
return ohci_queue_iso_transmit ( base , packet , buffer , payload ) ;
2007-02-17 01:34:49 +03:00
else if ( ctx - > context . ohci - > version > = OHCI_VERSION_1_1 )
2007-02-17 01:34:46 +03:00
return ohci_queue_iso_receive_dualbuffer ( base , packet ,
buffer , payload ) ;
2007-02-17 01:34:49 +03:00
else
firewire: OHCI 1.0 Isochronous Receive support
Third rendition of FireWire OHCI 1.0 Isochronous Receive support, using a
zer-copy method similar to OHCI 1.1 which puts the IR data payload directly
into the userspace buffer. The zero-copy implementation eliminates the
video artifacts, audio popping, and buffer underrun problems seen with
version 1 of this patch, as well as fixing a regression in OHCI 1.1 support
introduced by version 2 of this patch.
Successfully tested in OHCI 1.1 mode on the following chipsets:
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
- Ti TSB41AB2 (rev 01), OHCI 1.1 (PCI on SB Audigy)
- Apple UniNorth 2 (rev 81), OHCI 1.1 (PowerBook G4 onboard)
Successfully tested in OHCI 1.0 mode on the following chipsets:
- Agere FW323 (rev 06), OHCI 1.0 (Mac Mini onboard)
- Agere FW323 (rev 06), OHCI 1.0 (PCI)
- Via VT6306 (rev 46), OHCI 1.0 (PCI)
- NEC OrangeLink (rev 01), OHCI 1.0 (PCI)
- NEC uPD72847 (rev 01), OHCI 1.1 (PCI)
- Ti XIO2200(A) (rev 01), OHCI 1.1 (PCIe)
The bulk of testing was done in an x86_64 system, but was also successfully
sanity-tested on other systems, including a PPC(32) PowerBook G4 and an i686
EPIA M10k. Crude benchmarking (watching top during capture) puts the cpu
utilization during capture on the EPIA's 1GHz Via C3 processor around 13%,
which is down from 30% with the v1 code.
Some implementation details:
To maintain the same userspace API as dual-buffer mode, we set up two
descriptors for every incoming packet. The first is an INPUT_MORE descriptor,
pointing to a buffer large enough to hold just the packet's iso headers,
immediately followed by an INPUT_LAST descriptor, pointing to a chunk of the
userspace buffer big enough for the packet's data payload. With this setup,
each incoming packet fills in these two descriptors in a manner that very
closely emulates dual-buffer receive, to the point where the bulk of the
handle_ir_* code is now identical between the two (and probably primed for
some restructuring to share code between them).
The only caveat I have at the moment is that neither of my OHCI 1.0 Via
VT6307-based FireWire controllers work particularly well with this code
for reasons I have yet to figure out.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
2007-12-03 21:43:12 +03:00
return ohci_queue_iso_receive_packet_per_buffer ( base , packet ,
buffer ,
payload ) ;
2007-02-17 01:34:40 +03:00
}
2007-01-14 17:29:07 +03:00
static const struct fw_card_driver ohci_driver = {
2006-12-20 03:58:35 +03:00
. name = ohci_driver_name ,
. enable = ohci_enable ,
. update_phy_reg = ohci_update_phy_reg ,
. set_config_rom = ohci_set_config_rom ,
. send_request = ohci_send_request ,
. send_response = ohci_send_response ,
2007-02-06 22:49:32 +03:00
. cancel_packet = ohci_cancel_packet ,
2006-12-20 03:58:35 +03:00
. enable_phys_dma = ohci_enable_phys_dma ,
2007-03-07 20:12:56 +03:00
. get_bus_time = ohci_get_bus_time ,
2006-12-20 03:58:35 +03:00
. allocate_iso_context = ohci_allocate_iso_context ,
. free_iso_context = ohci_free_iso_context ,
. queue_iso = ohci_queue_iso ,
2007-02-17 01:34:41 +03:00
. start_iso = ohci_start_iso ,
2007-02-17 01:34:42 +03:00
. stop_iso = ohci_stop_iso ,
2006-12-20 03:58:35 +03:00
} ;
static int __devinit
pci_probe ( struct pci_dev * dev , const struct pci_device_id * ent )
{
struct fw_ohci * ohci ;
2007-02-17 01:34:49 +03:00
u32 bus_options , max_receive , link_speed ;
2006-12-20 03:58:35 +03:00
u64 guid ;
2007-05-10 03:23:15 +04:00
int err ;
2006-12-20 03:58:35 +03:00
size_t size ;
2007-05-10 03:23:14 +04:00
ohci = kzalloc ( sizeof ( * ohci ) , GFP_KERNEL ) ;
2006-12-20 03:58:35 +03:00
if ( ohci = = NULL ) {
fw_error ( " Could not malloc fw_ohci data. \n " ) ;
return - ENOMEM ;
}
fw_card_initialize ( & ohci - > card , & ohci_driver , & dev - > dev ) ;
2007-05-10 03:23:15 +04:00
err = pci_enable_device ( dev ) ;
if ( err ) {
2006-12-20 03:58:35 +03:00
fw_error ( " Failed to enable OHCI hardware. \n " ) ;
2007-05-10 03:23:15 +04:00
goto fail_put_card ;
2006-12-20 03:58:35 +03:00
}
pci_set_master ( dev ) ;
pci_write_config_dword ( dev , OHCI1394_PCI_HCI_Control , 0 ) ;
pci_set_drvdata ( dev , ohci ) ;
spin_lock_init ( & ohci - > lock ) ;
tasklet_init ( & ohci - > bus_reset_tasklet ,
bus_reset_tasklet , ( unsigned long ) ohci ) ;
2007-05-10 03:23:15 +04:00
err = pci_request_region ( dev , 0 , ohci_driver_name ) ;
if ( err ) {
2006-12-20 03:58:35 +03:00
fw_error ( " MMIO resource unavailable \n " ) ;
2007-05-10 03:23:15 +04:00
goto fail_disable ;
2006-12-20 03:58:35 +03:00
}
ohci - > registers = pci_iomap ( dev , 0 , OHCI1394_REGISTER_SIZE ) ;
if ( ohci - > registers = = NULL ) {
fw_error ( " Failed to remap registers \n " ) ;
2007-05-10 03:23:15 +04:00
err = - ENXIO ;
goto fail_iomem ;
2006-12-20 03:58:35 +03:00
}
ar_context_init ( & ohci - > ar_request_ctx , ohci ,
OHCI1394_AsReqRcvContextControlSet ) ;
ar_context_init ( & ohci - > ar_response_ctx , ohci ,
OHCI1394_AsRspRcvContextControlSet ) ;
2007-03-07 20:12:49 +03:00
context_init ( & ohci - > at_request_ctx , ohci , AT_BUFFER_SIZE ,
OHCI1394_AsReqTrContextControlSet , handle_at_packet ) ;
2006-12-20 03:58:35 +03:00
2007-03-07 20:12:49 +03:00
context_init ( & ohci - > at_response_ctx , ohci , AT_BUFFER_SIZE ,
OHCI1394_AsRspTrContextControlSet , handle_at_packet ) ;
2006-12-20 03:58:35 +03:00
reg_write ( ohci , OHCI1394_IsoRecvIntMaskSet , ~ 0 ) ;
ohci - > it_context_mask = reg_read ( ohci , OHCI1394_IsoRecvIntMaskSet ) ;
reg_write ( ohci , OHCI1394_IsoRecvIntMaskClear , ~ 0 ) ;
size = sizeof ( struct iso_context ) * hweight32 ( ohci - > it_context_mask ) ;
ohci - > it_context_list = kzalloc ( size , GFP_KERNEL ) ;
reg_write ( ohci , OHCI1394_IsoXmitIntMaskSet , ~ 0 ) ;
ohci - > ir_context_mask = reg_read ( ohci , OHCI1394_IsoXmitIntMaskSet ) ;
reg_write ( ohci , OHCI1394_IsoXmitIntMaskClear , ~ 0 ) ;
size = sizeof ( struct iso_context ) * hweight32 ( ohci - > ir_context_mask ) ;
ohci - > ir_context_list = kzalloc ( size , GFP_KERNEL ) ;
if ( ohci - > it_context_list = = NULL | | ohci - > ir_context_list = = NULL ) {
fw_error ( " Out of memory for it/ir contexts. \n " ) ;
2007-05-10 03:23:15 +04:00
err = - ENOMEM ;
goto fail_registers ;
2006-12-20 03:58:35 +03:00
}
/* self-id dma buffer allocation */
ohci - > self_id_cpu = dma_alloc_coherent ( ohci - > card . device ,
SELF_ID_BUF_SIZE ,
& ohci - > self_id_bus ,
GFP_KERNEL ) ;
if ( ohci - > self_id_cpu = = NULL ) {
fw_error ( " Out of memory for self ID buffer. \n " ) ;
2007-05-10 03:23:15 +04:00
err = - ENOMEM ;
goto fail_registers ;
2006-12-20 03:58:35 +03:00
}
bus_options = reg_read ( ohci , OHCI1394_BusOptions ) ;
max_receive = ( bus_options > > 12 ) & 0xf ;
link_speed = bus_options & 0x7 ;
guid = ( ( u64 ) reg_read ( ohci , OHCI1394_GUIDHi ) < < 32 ) |
reg_read ( ohci , OHCI1394_GUIDLo ) ;
2007-05-10 03:23:15 +04:00
err = fw_card_add ( & ohci - > card , max_receive , link_speed , guid ) ;
if ( err < 0 )
goto fail_self_id ;
2006-12-20 03:58:35 +03:00
2007-02-17 01:34:49 +03:00
ohci - > version = reg_read ( ohci , OHCI1394_Version ) & 0x00ff00ff ;
2007-02-17 01:34:43 +03:00
fw_notify ( " Added fw-ohci device %s, OHCI version %x.%x \n " ,
2007-02-17 01:34:49 +03:00
dev - > dev . bus_id , ohci - > version > > 16 , ohci - > version & 0xff ) ;
2006-12-20 03:58:35 +03:00
return 0 ;
2007-05-10 03:23:15 +04:00
fail_self_id :
dma_free_coherent ( ohci - > card . device , SELF_ID_BUF_SIZE ,
ohci - > self_id_cpu , ohci - > self_id_bus ) ;
fail_registers :
kfree ( ohci - > it_context_list ) ;
kfree ( ohci - > ir_context_list ) ;
pci_iounmap ( dev , ohci - > registers ) ;
fail_iomem :
pci_release_region ( dev , 0 ) ;
fail_disable :
pci_disable_device ( dev ) ;
fail_put_card :
fw_card_put ( & ohci - > card ) ;
return err ;
2006-12-20 03:58:35 +03:00
}
static void pci_remove ( struct pci_dev * dev )
{
struct fw_ohci * ohci ;
ohci = pci_get_drvdata ( dev ) ;
2007-03-07 20:12:38 +03:00
reg_write ( ohci , OHCI1394_IntMaskClear , ~ 0 ) ;
flush_writes ( ohci ) ;
2006-12-20 03:58:35 +03:00
fw_core_remove_card ( & ohci - > card ) ;
2007-05-08 04:33:32 +04:00
/*
* FIXME : Fail all pending packets here , now that the upper
* layers can ' t queue any more .
*/
2006-12-20 03:58:35 +03:00
software_reset ( ohci ) ;
free_irq ( dev - > irq , ohci ) ;
2007-05-10 03:23:15 +04:00
dma_free_coherent ( ohci - > card . device , SELF_ID_BUF_SIZE ,
ohci - > self_id_cpu , ohci - > self_id_bus ) ;
kfree ( ohci - > it_context_list ) ;
kfree ( ohci - > ir_context_list ) ;
pci_iounmap ( dev , ohci - > registers ) ;
pci_release_region ( dev , 0 ) ;
pci_disable_device ( dev ) ;
fw_card_put ( & ohci - > card ) ;
2006-12-20 03:58:35 +03:00
fw_notify ( " Removed fw-ohci device. \n " ) ;
}
2007-05-31 03:06:35 +04:00
# ifdef CONFIG_PM
static int pci_suspend ( struct pci_dev * pdev , pm_message_t state )
{
struct fw_ohci * ohci = pci_get_drvdata ( pdev ) ;
int err ;
software_reset ( ohci ) ;
free_irq ( pdev - > irq , ohci ) ;
err = pci_save_state ( pdev ) ;
if ( err ) {
2007-06-09 21:26:22 +04:00
fw_error ( " pci_save_state failed \n " ) ;
2007-05-31 03:06:35 +04:00
return err ;
}
err = pci_set_power_state ( pdev , pci_choose_state ( pdev , state ) ) ;
2007-09-06 11:50:30 +04:00
if ( err )
fw_error ( " pci_set_power_state failed with %d \n " , err ) ;
2007-05-31 03:06:35 +04:00
return 0 ;
}
static int pci_resume ( struct pci_dev * pdev )
{
struct fw_ohci * ohci = pci_get_drvdata ( pdev ) ;
int err ;
pci_set_power_state ( pdev , PCI_D0 ) ;
pci_restore_state ( pdev ) ;
err = pci_enable_device ( pdev ) ;
if ( err ) {
2007-06-09 21:26:22 +04:00
fw_error ( " pci_enable_device failed \n " ) ;
2007-05-31 03:06:35 +04:00
return err ;
}
2007-06-06 03:27:05 +04:00
return ohci_enable ( & ohci - > card , NULL , 0 ) ;
2007-05-31 03:06:35 +04:00
}
# endif
2006-12-20 03:58:35 +03:00
static struct pci_device_id pci_table [ ] = {
{ PCI_DEVICE_CLASS ( PCI_CLASS_SERIAL_FIREWIRE_OHCI , ~ 0 ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( pci , pci_table ) ;
static struct pci_driver fw_ohci_pci_driver = {
. name = ohci_driver_name ,
. id_table = pci_table ,
. probe = pci_probe ,
. remove = pci_remove ,
2007-05-31 03:06:35 +04:00
# ifdef CONFIG_PM
. resume = pci_resume ,
. suspend = pci_suspend ,
# endif
2006-12-20 03:58:35 +03:00
} ;
MODULE_AUTHOR ( " Kristian Hoegsberg <krh@bitplanet.net> " ) ;
MODULE_DESCRIPTION ( " Driver for PCI OHCI IEEE1394 controllers " ) ;
MODULE_LICENSE ( " GPL " ) ;
2007-05-06 01:17:13 +04:00
/* Provide a module alias so root-on-sbp2 initrds don't break. */
# ifndef CONFIG_IEEE1394_OHCI1394_MODULE
MODULE_ALIAS ( " ohci1394 " ) ;
# endif
2006-12-20 03:58:35 +03:00
static int __init fw_ohci_init ( void )
{
return pci_register_driver ( & fw_ohci_pci_driver ) ;
}
static void __exit fw_ohci_cleanup ( void )
{
pci_unregister_driver ( & fw_ohci_pci_driver ) ;
}
module_init ( fw_ohci_init ) ;
module_exit ( fw_ohci_cleanup ) ;