|  | /* | 
|  | * ohci1394.c - driver for OHCI 1394 boards | 
|  | * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au> | 
|  | *                        Gord Peters <GordPeters@smarttech.com> | 
|  | *              2001      Ben Collins <bcollins@debian.org> | 
|  | * | 
|  | * 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. | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * Things known to be working: | 
|  | * . Async Request Transmit | 
|  | * . Async Response Receive | 
|  | * . Async Request Receive | 
|  | * . Async Response Transmit | 
|  | * . Iso Receive | 
|  | * . DMA mmap for iso receive | 
|  | * . Config ROM generation | 
|  | * | 
|  | * Things implemented, but still in test phase: | 
|  | * . Iso Transmit | 
|  | * . Async Stream Packets Transmit (Receive done via Iso interface) | 
|  | * | 
|  | * Things not implemented: | 
|  | * . DMA error recovery | 
|  | * | 
|  | * Known bugs: | 
|  | * . devctl BUS_RESET arg confusion (reset type or root holdoff?) | 
|  | *   added LONG_RESET_ROOT and SHORT_RESET_ROOT for root holdoff --kk | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * Acknowledgments: | 
|  | * | 
|  | * Adam J Richter <adam@yggdrasil.com> | 
|  | *  . Use of pci_class to find device | 
|  | * | 
|  | * Emilie Chung	<emilie.chung@axis.com> | 
|  | *  . Tip on Async Request Filter | 
|  | * | 
|  | * Pascal Drolet <pascal.drolet@informission.ca> | 
|  | *  . Various tips for optimization and functionnalities | 
|  | * | 
|  | * Robert Ficklin <rficklin@westengineering.com> | 
|  | *  . Loop in irq_handler | 
|  | * | 
|  | * James Goodwin <jamesg@Filanet.com> | 
|  | *  . Various tips on initialization, self-id reception, etc. | 
|  | * | 
|  | * Albrecht Dress <ad@mpifr-bonn.mpg.de> | 
|  | *  . Apple PowerBook detection | 
|  | * | 
|  | * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de> | 
|  | *  . Reset the board properly before leaving + misc cleanups | 
|  | * | 
|  | * Leon van Stuivenberg <leonvs@iae.nl> | 
|  | *  . Bug fixes | 
|  | * | 
|  | * Ben Collins <bcollins@debian.org> | 
|  | *  . Working big-endian support | 
|  | *  . Updated to 2.4.x module scheme (PCI aswell) | 
|  | *  . Config ROM generation | 
|  | * | 
|  | * Manfred Weihs <weihs@ict.tuwien.ac.at> | 
|  | *  . Reworked code for initiating bus resets | 
|  | *    (long, short, with or without hold-off) | 
|  | * | 
|  | * Nandu Santhi <contactnandu@users.sourceforge.net> | 
|  | *  . Added support for nVidia nForce2 onboard Firewire chipset | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include <linux/bitops.h> | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/list.h> | 
|  | #include <linux/slab.h> | 
|  | #include <linux/interrupt.h> | 
|  | #include <linux/wait.h> | 
|  | #include <linux/errno.h> | 
|  | #include <linux/module.h> | 
|  | #include <linux/moduleparam.h> | 
|  | #include <linux/pci.h> | 
|  | #include <linux/fs.h> | 
|  | #include <linux/poll.h> | 
|  | #include <asm/byteorder.h> | 
|  | #include <asm/atomic.h> | 
|  | #include <asm/uaccess.h> | 
|  | #include <linux/delay.h> | 
|  | #include <linux/spinlock.h> | 
|  |  | 
|  | #include <asm/pgtable.h> | 
|  | #include <asm/page.h> | 
|  | #include <asm/irq.h> | 
|  | #include <linux/types.h> | 
|  | #include <linux/vmalloc.h> | 
|  | #include <linux/init.h> | 
|  |  | 
|  | #ifdef CONFIG_PPC_PMAC | 
|  | #include <asm/machdep.h> | 
|  | #include <asm/pmac_feature.h> | 
|  | #include <asm/prom.h> | 
|  | #include <asm/pci-bridge.h> | 
|  | #endif | 
|  |  | 
|  | #include "csr1212.h" | 
|  | #include "ieee1394.h" | 
|  | #include "ieee1394_types.h" | 
|  | #include "hosts.h" | 
|  | #include "dma.h" | 
|  | #include "iso.h" | 
|  | #include "ieee1394_core.h" | 
|  | #include "highlevel.h" | 
|  | #include "ohci1394.h" | 
|  |  | 
|  | #ifdef CONFIG_IEEE1394_VERBOSEDEBUG | 
|  | #define OHCI1394_DEBUG | 
|  | #endif | 
|  |  | 
|  | #ifdef DBGMSG | 
|  | #undef DBGMSG | 
|  | #endif | 
|  |  | 
|  | #ifdef OHCI1394_DEBUG | 
|  | #define DBGMSG(fmt, args...) \ | 
|  | printk(KERN_INFO "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args) | 
|  | #else | 
|  | #define DBGMSG(fmt, args...) do {} while (0) | 
|  | #endif | 
|  |  | 
|  | /* print general (card independent) information */ | 
|  | #define PRINT_G(level, fmt, args...) \ | 
|  | printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args) | 
|  |  | 
|  | /* print card specific information */ | 
|  | #define PRINT(level, fmt, args...) \ | 
|  | printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args) | 
|  |  | 
|  | /* Module Parameters */ | 
|  | static int phys_dma = 1; | 
|  | module_param(phys_dma, int, 0444); | 
|  | MODULE_PARM_DESC(phys_dma, "Enable physical DMA (default = 1)."); | 
|  |  | 
|  | static void dma_trm_tasklet(unsigned long data); | 
|  | static void dma_trm_reset(struct dma_trm_ctx *d); | 
|  |  | 
|  | static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, | 
|  | enum context_type type, int ctx, int num_desc, | 
|  | int buf_size, int split_buf_size, int context_base); | 
|  | static void free_dma_rcv_ctx(struct dma_rcv_ctx *d); | 
|  |  | 
|  | static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, | 
|  | enum context_type type, int ctx, int num_desc, | 
|  | int context_base); | 
|  |  | 
|  | static void ohci1394_pci_remove(struct pci_dev *pdev); | 
|  |  | 
|  | #ifndef __LITTLE_ENDIAN | 
|  | static const size_t hdr_sizes[] = { | 
|  | 3,	/* TCODE_WRITEQ */ | 
|  | 4,	/* TCODE_WRITEB */ | 
|  | 3,	/* TCODE_WRITE_RESPONSE */ | 
|  | 0,	/* reserved */ | 
|  | 3,	/* TCODE_READQ */ | 
|  | 4,	/* TCODE_READB */ | 
|  | 3,	/* TCODE_READQ_RESPONSE */ | 
|  | 4,	/* TCODE_READB_RESPONSE */ | 
|  | 1,	/* TCODE_CYCLE_START */ | 
|  | 4,	/* TCODE_LOCK_REQUEST */ | 
|  | 2,	/* TCODE_ISO_DATA */ | 
|  | 4,	/* TCODE_LOCK_RESPONSE */ | 
|  | /* rest is reserved or link-internal */ | 
|  | }; | 
|  |  | 
|  | static inline void header_le32_to_cpu(quadlet_t *data, unsigned char tcode) | 
|  | { | 
|  | size_t size; | 
|  |  | 
|  | if (unlikely(tcode >= ARRAY_SIZE(hdr_sizes))) | 
|  | return; | 
|  |  | 
|  | size = hdr_sizes[tcode]; | 
|  | while (size--) | 
|  | data[size] = le32_to_cpu(data[size]); | 
|  | } | 
|  | #else | 
|  | #define header_le32_to_cpu(w,x) do {} while (0) | 
|  | #endif /* !LITTLE_ENDIAN */ | 
|  |  | 
|  | /*********************************** | 
|  | * IEEE-1394 functionality section * | 
|  | ***********************************/ | 
|  |  | 
|  | static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr) | 
|  | { | 
|  | int i; | 
|  | unsigned long flags; | 
|  | quadlet_t r; | 
|  |  | 
|  | spin_lock_irqsave (&ohci->phy_reg_lock, flags); | 
|  |  | 
|  | reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000); | 
|  |  | 
|  | for (i = 0; i < OHCI_LOOP_COUNT; i++) { | 
|  | if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000) | 
|  | break; | 
|  |  | 
|  | mdelay(1); | 
|  | } | 
|  |  | 
|  | r = reg_read(ohci, OHCI1394_PhyControl); | 
|  |  | 
|  | if (i >= OHCI_LOOP_COUNT) | 
|  | PRINT (KERN_ERR, "Get PHY Reg timeout [0x%08x/0x%08x/%d]", | 
|  | r, r & 0x80000000, i); | 
|  |  | 
|  | spin_unlock_irqrestore (&ohci->phy_reg_lock, flags); | 
|  |  | 
|  | return (r & 0x00ff0000) >> 16; | 
|  | } | 
|  |  | 
|  | static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data) | 
|  | { | 
|  | int i; | 
|  | unsigned long flags; | 
|  | u32 r = 0; | 
|  |  | 
|  | spin_lock_irqsave (&ohci->phy_reg_lock, flags); | 
|  |  | 
|  | reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000); | 
|  |  | 
|  | for (i = 0; i < OHCI_LOOP_COUNT; i++) { | 
|  | r = reg_read(ohci, OHCI1394_PhyControl); | 
|  | if (!(r & 0x00004000)) | 
|  | break; | 
|  |  | 
|  | mdelay(1); | 
|  | } | 
|  |  | 
|  | if (i == OHCI_LOOP_COUNT) | 
|  | PRINT (KERN_ERR, "Set PHY Reg timeout [0x%08x/0x%08x/%d]", | 
|  | r, r & 0x00004000, i); | 
|  |  | 
|  | spin_unlock_irqrestore (&ohci->phy_reg_lock, flags); | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Or's our value into the current value */ | 
|  | static void set_phy_reg_mask(struct ti_ohci *ohci, u8 addr, u8 data) | 
|  | { | 
|  | u8 old; | 
|  |  | 
|  | old = get_phy_reg (ohci, addr); | 
|  | old |= data; | 
|  | set_phy_reg (ohci, addr, old); | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host, | 
|  | int phyid, int isroot) | 
|  | { | 
|  | quadlet_t *q = ohci->selfid_buf_cpu; | 
|  | quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount); | 
|  | size_t size; | 
|  | quadlet_t q0, q1; | 
|  |  | 
|  | /* Check status of self-id reception */ | 
|  |  | 
|  | if (ohci->selfid_swap) | 
|  | q0 = le32_to_cpu(q[0]); | 
|  | else | 
|  | q0 = q[0]; | 
|  |  | 
|  | if ((self_id_count & 0x80000000) || | 
|  | ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) { | 
|  | PRINT(KERN_ERR, | 
|  | "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)", | 
|  | self_id_count, q0, ohci->self_id_errors); | 
|  |  | 
|  | /* Tip by James Goodwin <jamesg@Filanet.com>: | 
|  | * We had an error, generate another bus reset in response.  */ | 
|  | if (ohci->self_id_errors<OHCI1394_MAX_SELF_ID_ERRORS) { | 
|  | set_phy_reg_mask (ohci, 1, 0x40); | 
|  | ohci->self_id_errors++; | 
|  | } else { | 
|  | PRINT(KERN_ERR, | 
|  | "Too many errors on SelfID error reception, giving up!"); | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* SelfID Ok, reset error counter. */ | 
|  | ohci->self_id_errors = 0; | 
|  |  | 
|  | size = ((self_id_count & 0x00001FFC) >> 2) - 1; | 
|  | q++; | 
|  |  | 
|  | while (size > 0) { | 
|  | if (ohci->selfid_swap) { | 
|  | q0 = le32_to_cpu(q[0]); | 
|  | q1 = le32_to_cpu(q[1]); | 
|  | } else { | 
|  | q0 = q[0]; | 
|  | q1 = q[1]; | 
|  | } | 
|  |  | 
|  | if (q0 == ~q1) { | 
|  | DBGMSG ("SelfID packet 0x%x received", q0); | 
|  | hpsb_selfid_received(host, cpu_to_be32(q0)); | 
|  | if (((q0 & 0x3f000000) >> 24) == phyid) | 
|  | DBGMSG ("SelfID for this node is 0x%08x", q0); | 
|  | } else { | 
|  | PRINT(KERN_ERR, | 
|  | "SelfID is inconsistent [0x%08x/0x%08x]", q0, q1); | 
|  | } | 
|  | q += 2; | 
|  | size -= 2; | 
|  | } | 
|  |  | 
|  | DBGMSG("SelfID complete"); | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | static void ohci_soft_reset(struct ti_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)) | 
|  | break; | 
|  | mdelay(1); | 
|  | } | 
|  | DBGMSG ("Soft reset finished"); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Generate the dma receive prgs and start the context */ | 
|  | static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d, int generate_irq) | 
|  | { | 
|  | struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); | 
|  | int i; | 
|  |  | 
|  | ohci1394_stop_context(ohci, d->ctrlClear, NULL); | 
|  |  | 
|  | for (i=0; i<d->num_desc; i++) { | 
|  | u32 c; | 
|  |  | 
|  | c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH; | 
|  | if (generate_irq) | 
|  | c |= DMA_CTL_IRQ; | 
|  |  | 
|  | d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size); | 
|  |  | 
|  | /* End of descriptor list? */ | 
|  | if (i + 1 < d->num_desc) { | 
|  | d->prg_cpu[i]->branchAddress = | 
|  | cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1); | 
|  | } else { | 
|  | d->prg_cpu[i]->branchAddress = | 
|  | cpu_to_le32((d->prg_bus[0] & 0xfffffff0)); | 
|  | } | 
|  |  | 
|  | d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]); | 
|  | d->prg_cpu[i]->status = cpu_to_le32(d->buf_size); | 
|  | } | 
|  |  | 
|  | d->buf_ind = 0; | 
|  | d->buf_offset = 0; | 
|  |  | 
|  | if (d->type == DMA_CTX_ISO) { | 
|  | /* Clear contextControl */ | 
|  | reg_write(ohci, d->ctrlClear, 0xffffffff); | 
|  |  | 
|  | /* Set bufferFill, isochHeader, multichannel for IR context */ | 
|  | reg_write(ohci, d->ctrlSet, 0xd0000000); | 
|  |  | 
|  | /* Set the context match register to match on all tags */ | 
|  | reg_write(ohci, d->ctxtMatch, 0xf0000000); | 
|  |  | 
|  | /* Clear the multi channel mask high and low registers */ | 
|  | reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff); | 
|  |  | 
|  | /* Set up isoRecvIntMask to generate interrupts */ | 
|  | reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << d->ctx); | 
|  | } | 
|  |  | 
|  | /* Tell the controller where the first AR program is */ | 
|  | reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1); | 
|  |  | 
|  | /* Run context */ | 
|  | reg_write(ohci, d->ctrlSet, 0x00008000); | 
|  |  | 
|  | DBGMSG("Receive DMA ctx=%d initialized", d->ctx); | 
|  | } | 
|  |  | 
|  | /* Initialize the dma transmit context */ | 
|  | static void initialize_dma_trm_ctx(struct dma_trm_ctx *d) | 
|  | { | 
|  | struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); | 
|  |  | 
|  | /* Stop the context */ | 
|  | ohci1394_stop_context(ohci, d->ctrlClear, NULL); | 
|  |  | 
|  | d->prg_ind = 0; | 
|  | d->sent_ind = 0; | 
|  | d->free_prgs = d->num_desc; | 
|  | d->branchAddrPtr = NULL; | 
|  | INIT_LIST_HEAD(&d->fifo_list); | 
|  | INIT_LIST_HEAD(&d->pending_list); | 
|  |  | 
|  | if (d->type == DMA_CTX_ISO) { | 
|  | /* enable interrupts */ | 
|  | reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << d->ctx); | 
|  | } | 
|  |  | 
|  | DBGMSG("Transmit DMA ctx=%d initialized", d->ctx); | 
|  | } | 
|  |  | 
|  | /* Count the number of available iso contexts */ | 
|  | static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg) | 
|  | { | 
|  | u32 tmp; | 
|  |  | 
|  | reg_write(ohci, reg, 0xffffffff); | 
|  | tmp = reg_read(ohci, reg); | 
|  |  | 
|  | DBGMSG("Iso contexts reg: %08x implemented: %08x", reg, tmp); | 
|  |  | 
|  | /* Count the number of contexts */ | 
|  | return hweight32(tmp); | 
|  | } | 
|  |  | 
|  | /* Global initialization */ | 
|  | static void ohci_initialize(struct ti_ohci *ohci) | 
|  | { | 
|  | quadlet_t buf; | 
|  | int num_ports, i; | 
|  |  | 
|  | spin_lock_init(&ohci->phy_reg_lock); | 
|  |  | 
|  | /* Put some defaults to these undefined bus options */ | 
|  | buf = reg_read(ohci, OHCI1394_BusOptions); | 
|  | buf |=  0x60000000; /* Enable CMC and ISC */ | 
|  | if (hpsb_disable_irm) | 
|  | buf &= ~0x80000000; | 
|  | else | 
|  | buf |=  0x80000000; /* Enable IRMC */ | 
|  | buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */ | 
|  | buf &= ~0x18000000; /* Disable PMC and BMC */ | 
|  | reg_write(ohci, OHCI1394_BusOptions, buf); | 
|  |  | 
|  | /* Set the bus number */ | 
|  | reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); | 
|  |  | 
|  | /* Enable posted writes */ | 
|  | reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_postedWriteEnable); | 
|  |  | 
|  | /* Clear link control register */ | 
|  | reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); | 
|  |  | 
|  | /* Enable cycle timer and cycle master and set the IRM | 
|  | * contender bit in our self ID packets if appropriate. */ | 
|  | reg_write(ohci, OHCI1394_LinkControlSet, | 
|  | OHCI1394_LinkControl_CycleTimerEnable | | 
|  | OHCI1394_LinkControl_CycleMaster); | 
|  | i = get_phy_reg(ohci, 4) | PHY_04_LCTRL; | 
|  | if (hpsb_disable_irm) | 
|  | i &= ~PHY_04_CONTENDER; | 
|  | else | 
|  | i |= PHY_04_CONTENDER; | 
|  | set_phy_reg(ohci, 4, i); | 
|  |  | 
|  | /* Set up self-id dma buffer */ | 
|  | reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus); | 
|  |  | 
|  | /* enable self-id */ | 
|  | reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID); | 
|  |  | 
|  | /* Set the Config ROM mapping register */ | 
|  | reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus); | 
|  |  | 
|  | /* Now get our max packet size */ | 
|  | ohci->max_packet_size = | 
|  | 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1); | 
|  |  | 
|  | /* Clear the interrupt mask */ | 
|  | reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); | 
|  |  | 
|  | /* Clear the interrupt mask */ | 
|  | reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); | 
|  |  | 
|  | /* Initialize AR dma */ | 
|  | initialize_dma_rcv_ctx(&ohci->ar_req_context, 0); | 
|  | initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0); | 
|  |  | 
|  | /* Initialize AT dma */ | 
|  | initialize_dma_trm_ctx(&ohci->at_req_context); | 
|  | initialize_dma_trm_ctx(&ohci->at_resp_context); | 
|  |  | 
|  | /* Accept AR requests from all nodes */ | 
|  | reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000); | 
|  |  | 
|  | /* Set the address range of the physical response unit. | 
|  | * Most controllers do not implement it as a writable register though. | 
|  | * They will keep a hardwired offset of 0x00010000 and show 0x0 as | 
|  | * register content. | 
|  | * To actually enable physical responses is the job of our interrupt | 
|  | * handler which programs the physical request filter. */ | 
|  | reg_write(ohci, OHCI1394_PhyUpperBound, | 
|  | OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED >> 16); | 
|  |  | 
|  | DBGMSG("physUpperBoundOffset=%08x", | 
|  | reg_read(ohci, OHCI1394_PhyUpperBound)); | 
|  |  | 
|  | /* Specify AT retries */ | 
|  | reg_write(ohci, OHCI1394_ATRetries, | 
|  | OHCI1394_MAX_AT_REQ_RETRIES | | 
|  | (OHCI1394_MAX_AT_RESP_RETRIES<<4) | | 
|  | (OHCI1394_MAX_PHYS_RESP_RETRIES<<8)); | 
|  |  | 
|  | /* We don't want hardware swapping */ | 
|  | reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap); | 
|  |  | 
|  | /* Enable interrupts */ | 
|  | reg_write(ohci, OHCI1394_IntMaskSet, | 
|  | OHCI1394_unrecoverableError | | 
|  | OHCI1394_masterIntEnable | | 
|  | OHCI1394_busReset | | 
|  | OHCI1394_selfIDComplete | | 
|  | OHCI1394_RSPkt | | 
|  | OHCI1394_RQPkt | | 
|  | OHCI1394_respTxComplete | | 
|  | OHCI1394_reqTxComplete | | 
|  | OHCI1394_isochRx | | 
|  | OHCI1394_isochTx | | 
|  | OHCI1394_postedWriteErr | | 
|  | OHCI1394_cycleTooLong | | 
|  | OHCI1394_cycleInconsistent); | 
|  |  | 
|  | /* Enable link */ | 
|  | reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable); | 
|  |  | 
|  | buf = reg_read(ohci, OHCI1394_Version); | 
|  | PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%d]  " | 
|  | "MMIO=[%llx-%llx]  Max Packet=[%d]  IR/IT contexts=[%d/%d]", | 
|  | ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), | 
|  | ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq, | 
|  | (unsigned long long)pci_resource_start(ohci->dev, 0), | 
|  | (unsigned long long)pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1, | 
|  | ohci->max_packet_size, | 
|  | ohci->nb_iso_rcv_ctx, ohci->nb_iso_xmit_ctx); | 
|  |  | 
|  | /* Check all of our ports to make sure that if anything is | 
|  | * connected, we enable that port. */ | 
|  | num_ports = get_phy_reg(ohci, 2) & 0xf; | 
|  | for (i = 0; i < num_ports; i++) { | 
|  | unsigned int status; | 
|  |  | 
|  | set_phy_reg(ohci, 7, i); | 
|  | status = get_phy_reg(ohci, 8); | 
|  |  | 
|  | if (status & 0x20) | 
|  | set_phy_reg(ohci, 8, status & ~1); | 
|  | } | 
|  |  | 
|  | /* Serial EEPROM Sanity check. */ | 
|  | if ((ohci->max_packet_size < 512) || | 
|  | (ohci->max_packet_size > 4096)) { | 
|  | /* Serial EEPROM contents are suspect, set a sane max packet | 
|  | * size and print the raw contents for bug reports if verbose | 
|  | * debug is enabled. */ | 
|  | #ifdef CONFIG_IEEE1394_VERBOSEDEBUG | 
|  | int i; | 
|  | #endif | 
|  |  | 
|  | PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, " | 
|  | "attempting to set max_packet_size to 512 bytes"); | 
|  | reg_write(ohci, OHCI1394_BusOptions, | 
|  | (reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002); | 
|  | ohci->max_packet_size = 512; | 
|  | #ifdef CONFIG_IEEE1394_VERBOSEDEBUG | 
|  | PRINT(KERN_DEBUG, "    EEPROM Present: %d", | 
|  | (reg_read(ohci, OHCI1394_Version) >> 24) & 0x1); | 
|  | reg_write(ohci, OHCI1394_GUID_ROM, 0x80000000); | 
|  |  | 
|  | for (i = 0; | 
|  | ((i < 1000) && | 
|  | (reg_read(ohci, OHCI1394_GUID_ROM) & 0x80000000)); i++) | 
|  | udelay(10); | 
|  |  | 
|  | for (i = 0; i < 0x20; i++) { | 
|  | reg_write(ohci, OHCI1394_GUID_ROM, 0x02000000); | 
|  | PRINT(KERN_DEBUG, "    EEPROM %02x: %02x", i, | 
|  | (reg_read(ohci, OHCI1394_GUID_ROM) >> 16) & 0xff); | 
|  | } | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Insert a packet in the DMA fifo and generate the DMA prg | 
|  | * FIXME: rewrite the program in order to accept packets crossing | 
|  | *        page boundaries. | 
|  | *        check also that a single dma descriptor doesn't cross a | 
|  | *        page boundary. | 
|  | */ | 
|  | static void insert_packet(struct ti_ohci *ohci, | 
|  | struct dma_trm_ctx *d, struct hpsb_packet *packet) | 
|  | { | 
|  | u32 cycleTimer; | 
|  | int idx = d->prg_ind; | 
|  |  | 
|  | DBGMSG("Inserting packet for node " NODE_BUS_FMT | 
|  | ", tlabel=%d, tcode=0x%x, speed=%d", | 
|  | NODE_BUS_ARGS(ohci->host, packet->node_id), packet->tlabel, | 
|  | packet->tcode, packet->speed_code); | 
|  |  | 
|  | d->prg_cpu[idx]->begin.address = 0; | 
|  | d->prg_cpu[idx]->begin.branchAddress = 0; | 
|  |  | 
|  | if (d->type == DMA_CTX_ASYNC_RESP) { | 
|  | /* | 
|  | * For response packets, we need to put a timeout value in | 
|  | * the 16 lower bits of the status... let's try 1 sec timeout | 
|  | */ | 
|  | cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer); | 
|  | d->prg_cpu[idx]->begin.status = cpu_to_le32( | 
|  | (((((cycleTimer>>25)&0x7)+1)&0x7)<<13) | | 
|  | ((cycleTimer&0x01fff000)>>12)); | 
|  |  | 
|  | DBGMSG("cycleTimer: %08x timeStamp: %08x", | 
|  | cycleTimer, d->prg_cpu[idx]->begin.status); | 
|  | } else | 
|  | d->prg_cpu[idx]->begin.status = 0; | 
|  |  | 
|  | if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) { | 
|  |  | 
|  | if (packet->type == hpsb_raw) { | 
|  | d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4); | 
|  | d->prg_cpu[idx]->data[1] = cpu_to_le32(packet->header[0]); | 
|  | d->prg_cpu[idx]->data[2] = cpu_to_le32(packet->header[1]); | 
|  | } else { | 
|  | d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | | 
|  | (packet->header[0] & 0xFFFF); | 
|  |  | 
|  | if (packet->tcode == TCODE_ISO_DATA) { | 
|  | /* Sending an async stream packet */ | 
|  | d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; | 
|  | } else { | 
|  | /* Sending a normal async request or response */ | 
|  | d->prg_cpu[idx]->data[1] = | 
|  | (packet->header[1] & 0xFFFF) | | 
|  | (packet->header[0] & 0xFFFF0000); | 
|  | d->prg_cpu[idx]->data[2] = packet->header[2]; | 
|  | d->prg_cpu[idx]->data[3] = packet->header[3]; | 
|  | } | 
|  | header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode); | 
|  | } | 
|  |  | 
|  | if (packet->data_size) { /* block transmit */ | 
|  | if (packet->tcode == TCODE_STREAM_DATA){ | 
|  | d->prg_cpu[idx]->begin.control = | 
|  | cpu_to_le32(DMA_CTL_OUTPUT_MORE | | 
|  | DMA_CTL_IMMEDIATE | 0x8); | 
|  | } else { | 
|  | d->prg_cpu[idx]->begin.control = | 
|  | cpu_to_le32(DMA_CTL_OUTPUT_MORE | | 
|  | DMA_CTL_IMMEDIATE | 0x10); | 
|  | } | 
|  | d->prg_cpu[idx]->end.control = | 
|  | cpu_to_le32(DMA_CTL_OUTPUT_LAST | | 
|  | DMA_CTL_IRQ | | 
|  | DMA_CTL_BRANCH | | 
|  | packet->data_size); | 
|  | /* | 
|  | * Check that the packet data buffer | 
|  | * does not cross a page boundary. | 
|  | * | 
|  | * XXX Fix this some day. eth1394 seems to trigger | 
|  | * it, but ignoring it doesn't seem to cause a | 
|  | * problem. | 
|  | */ | 
|  | #if 0 | 
|  | if (cross_bound((unsigned long)packet->data, | 
|  | packet->data_size)>0) { | 
|  | /* FIXME: do something about it */ | 
|  | PRINT(KERN_ERR, | 
|  | "%s: packet data addr: %p size %Zd bytes " | 
|  | "cross page boundary", __func__, | 
|  | packet->data, packet->data_size); | 
|  | } | 
|  | #endif | 
|  | d->prg_cpu[idx]->end.address = cpu_to_le32( | 
|  | pci_map_single(ohci->dev, packet->data, | 
|  | packet->data_size, | 
|  | PCI_DMA_TODEVICE)); | 
|  |  | 
|  | d->prg_cpu[idx]->end.branchAddress = 0; | 
|  | d->prg_cpu[idx]->end.status = 0; | 
|  | if (d->branchAddrPtr) | 
|  | *(d->branchAddrPtr) = | 
|  | cpu_to_le32(d->prg_bus[idx] | 0x3); | 
|  | d->branchAddrPtr = | 
|  | &(d->prg_cpu[idx]->end.branchAddress); | 
|  | } else { /* quadlet transmit */ | 
|  | if (packet->type == hpsb_raw) | 
|  | d->prg_cpu[idx]->begin.control = | 
|  | cpu_to_le32(DMA_CTL_OUTPUT_LAST | | 
|  | DMA_CTL_IMMEDIATE | | 
|  | DMA_CTL_IRQ | | 
|  | DMA_CTL_BRANCH | | 
|  | (packet->header_size + 4)); | 
|  | else | 
|  | d->prg_cpu[idx]->begin.control = | 
|  | cpu_to_le32(DMA_CTL_OUTPUT_LAST | | 
|  | DMA_CTL_IMMEDIATE | | 
|  | DMA_CTL_IRQ | | 
|  | DMA_CTL_BRANCH | | 
|  | packet->header_size); | 
|  |  | 
|  | if (d->branchAddrPtr) | 
|  | *(d->branchAddrPtr) = | 
|  | cpu_to_le32(d->prg_bus[idx] | 0x2); | 
|  | d->branchAddrPtr = | 
|  | &(d->prg_cpu[idx]->begin.branchAddress); | 
|  | } | 
|  |  | 
|  | } else { /* iso packet */ | 
|  | d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | | 
|  | (packet->header[0] & 0xFFFF); | 
|  | d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; | 
|  | header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode); | 
|  |  | 
|  | d->prg_cpu[idx]->begin.control = | 
|  | cpu_to_le32(DMA_CTL_OUTPUT_MORE | | 
|  | DMA_CTL_IMMEDIATE | 0x8); | 
|  | d->prg_cpu[idx]->end.control = | 
|  | cpu_to_le32(DMA_CTL_OUTPUT_LAST | | 
|  | DMA_CTL_UPDATE | | 
|  | DMA_CTL_IRQ | | 
|  | DMA_CTL_BRANCH | | 
|  | packet->data_size); | 
|  | d->prg_cpu[idx]->end.address = cpu_to_le32( | 
|  | pci_map_single(ohci->dev, packet->data, | 
|  | packet->data_size, PCI_DMA_TODEVICE)); | 
|  |  | 
|  | d->prg_cpu[idx]->end.branchAddress = 0; | 
|  | d->prg_cpu[idx]->end.status = 0; | 
|  | DBGMSG("Iso xmit context info: header[%08x %08x]\n" | 
|  | "                       begin=%08x %08x %08x %08x\n" | 
|  | "                             %08x %08x %08x %08x\n" | 
|  | "                       end  =%08x %08x %08x %08x", | 
|  | d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1], | 
|  | d->prg_cpu[idx]->begin.control, | 
|  | d->prg_cpu[idx]->begin.address, | 
|  | d->prg_cpu[idx]->begin.branchAddress, | 
|  | d->prg_cpu[idx]->begin.status, | 
|  | d->prg_cpu[idx]->data[0], | 
|  | d->prg_cpu[idx]->data[1], | 
|  | d->prg_cpu[idx]->data[2], | 
|  | d->prg_cpu[idx]->data[3], | 
|  | d->prg_cpu[idx]->end.control, | 
|  | d->prg_cpu[idx]->end.address, | 
|  | d->prg_cpu[idx]->end.branchAddress, | 
|  | d->prg_cpu[idx]->end.status); | 
|  | if (d->branchAddrPtr) | 
|  | *(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3); | 
|  | d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress); | 
|  | } | 
|  | d->free_prgs--; | 
|  |  | 
|  | /* queue the packet in the appropriate context queue */ | 
|  | list_add_tail(&packet->driver_list, &d->fifo_list); | 
|  | d->prg_ind = (d->prg_ind + 1) % d->num_desc; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * This function fills the FIFO with the (eventual) pending packets | 
|  | * and runs or wakes up the DMA prg if necessary. | 
|  | * | 
|  | * The function MUST be called with the d->lock held. | 
|  | */ | 
|  | static void dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d) | 
|  | { | 
|  | struct hpsb_packet *packet, *ptmp; | 
|  | int idx = d->prg_ind; | 
|  | int z = 0; | 
|  |  | 
|  | /* insert the packets into the dma fifo */ | 
|  | list_for_each_entry_safe(packet, ptmp, &d->pending_list, driver_list) { | 
|  | if (!d->free_prgs) | 
|  | break; | 
|  |  | 
|  | /* For the first packet only */ | 
|  | if (!z) | 
|  | z = (packet->data_size) ? 3 : 2; | 
|  |  | 
|  | /* Insert the packet */ | 
|  | list_del_init(&packet->driver_list); | 
|  | insert_packet(ohci, d, packet); | 
|  | } | 
|  |  | 
|  | /* Nothing must have been done, either no free_prgs or no packets */ | 
|  | if (z == 0) | 
|  | return; | 
|  |  | 
|  | /* Is the context running ? (should be unless it is | 
|  | the first packet to be sent in this context) */ | 
|  | if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) { | 
|  | u32 nodeId = reg_read(ohci, OHCI1394_NodeID); | 
|  |  | 
|  | DBGMSG("Starting transmit DMA ctx=%d",d->ctx); | 
|  | reg_write(ohci, d->cmdPtr, d->prg_bus[idx] | z); | 
|  |  | 
|  | /* Check that the node id is valid, and not 63 */ | 
|  | if (!(nodeId & 0x80000000) || (nodeId & 0x3f) == 63) | 
|  | PRINT(KERN_ERR, "Running dma failed because Node ID is not valid"); | 
|  | else | 
|  | reg_write(ohci, d->ctrlSet, 0x8000); | 
|  | } else { | 
|  | /* Wake up the dma context if necessary */ | 
|  | if (!(reg_read(ohci, d->ctrlSet) & 0x400)) | 
|  | DBGMSG("Waking transmit DMA ctx=%d",d->ctx); | 
|  |  | 
|  | /* do this always, to avoid race condition */ | 
|  | reg_write(ohci, d->ctrlSet, 0x1000); | 
|  | } | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Transmission of an async or iso packet */ | 
|  | static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet) | 
|  | { | 
|  | struct ti_ohci *ohci = host->hostdata; | 
|  | struct dma_trm_ctx *d; | 
|  | unsigned long flags; | 
|  |  | 
|  | if (packet->data_size > ohci->max_packet_size) { | 
|  | PRINT(KERN_ERR, | 
|  | "Transmit packet size %Zd is too big", | 
|  | packet->data_size); | 
|  | return -EOVERFLOW; | 
|  | } | 
|  |  | 
|  | if (packet->type == hpsb_raw) | 
|  | d = &ohci->at_req_context; | 
|  | else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA)) | 
|  | d = &ohci->at_resp_context; | 
|  | else | 
|  | d = &ohci->at_req_context; | 
|  |  | 
|  | spin_lock_irqsave(&d->lock,flags); | 
|  |  | 
|  | list_add_tail(&packet->driver_list, &d->pending_list); | 
|  |  | 
|  | dma_trm_flush(ohci, d); | 
|  |  | 
|  | spin_unlock_irqrestore(&d->lock,flags); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) | 
|  | { | 
|  | struct ti_ohci *ohci = host->hostdata; | 
|  | int retval = 0, phy_reg; | 
|  |  | 
|  | switch (cmd) { | 
|  | case RESET_BUS: | 
|  | switch (arg) { | 
|  | case SHORT_RESET: | 
|  | phy_reg = get_phy_reg(ohci, 5); | 
|  | phy_reg |= 0x40; | 
|  | set_phy_reg(ohci, 5, phy_reg); /* set ISBR */ | 
|  | break; | 
|  | case LONG_RESET: | 
|  | phy_reg = get_phy_reg(ohci, 1); | 
|  | phy_reg |= 0x40; | 
|  | set_phy_reg(ohci, 1, phy_reg); /* set IBR */ | 
|  | break; | 
|  | case SHORT_RESET_NO_FORCE_ROOT: | 
|  | phy_reg = get_phy_reg(ohci, 1); | 
|  | if (phy_reg & 0x80) { | 
|  | phy_reg &= ~0x80; | 
|  | set_phy_reg(ohci, 1, phy_reg); /* clear RHB */ | 
|  | } | 
|  |  | 
|  | phy_reg = get_phy_reg(ohci, 5); | 
|  | phy_reg |= 0x40; | 
|  | set_phy_reg(ohci, 5, phy_reg); /* set ISBR */ | 
|  | break; | 
|  | case LONG_RESET_NO_FORCE_ROOT: | 
|  | phy_reg = get_phy_reg(ohci, 1); | 
|  | phy_reg &= ~0x80; | 
|  | phy_reg |= 0x40; | 
|  | set_phy_reg(ohci, 1, phy_reg); /* clear RHB, set IBR */ | 
|  | break; | 
|  | case SHORT_RESET_FORCE_ROOT: | 
|  | phy_reg = get_phy_reg(ohci, 1); | 
|  | if (!(phy_reg & 0x80)) { | 
|  | phy_reg |= 0x80; | 
|  | set_phy_reg(ohci, 1, phy_reg); /* set RHB */ | 
|  | } | 
|  |  | 
|  | phy_reg = get_phy_reg(ohci, 5); | 
|  | phy_reg |= 0x40; | 
|  | set_phy_reg(ohci, 5, phy_reg); /* set ISBR */ | 
|  | break; | 
|  | case LONG_RESET_FORCE_ROOT: | 
|  | phy_reg = get_phy_reg(ohci, 1); | 
|  | phy_reg |= 0xc0; | 
|  | set_phy_reg(ohci, 1, phy_reg); /* set RHB and IBR */ | 
|  | break; | 
|  | default: | 
|  | retval = -1; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case GET_CYCLE_COUNTER: | 
|  | retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer); | 
|  | break; | 
|  |  | 
|  | case SET_CYCLE_COUNTER: | 
|  | reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg); | 
|  | break; | 
|  |  | 
|  | case SET_BUS_ID: | 
|  | PRINT(KERN_ERR, "devctl command SET_BUS_ID err"); | 
|  | break; | 
|  |  | 
|  | case ACT_CYCLE_MASTER: | 
|  | if (arg) { | 
|  | /* check if we are root and other nodes are present */ | 
|  | u32 nodeId = reg_read(ohci, OHCI1394_NodeID); | 
|  | if ((nodeId & (1<<30)) && (nodeId & 0x3f)) { | 
|  | /* | 
|  | * enable cycleTimer, cycleMaster | 
|  | */ | 
|  | DBGMSG("Cycle master enabled"); | 
|  | reg_write(ohci, OHCI1394_LinkControlSet, | 
|  | OHCI1394_LinkControl_CycleTimerEnable | | 
|  | OHCI1394_LinkControl_CycleMaster); | 
|  | } | 
|  | } else { | 
|  | /* disable cycleTimer, cycleMaster, cycleSource */ | 
|  | reg_write(ohci, OHCI1394_LinkControlClear, | 
|  | OHCI1394_LinkControl_CycleTimerEnable | | 
|  | OHCI1394_LinkControl_CycleMaster | | 
|  | OHCI1394_LinkControl_CycleSource); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case CANCEL_REQUESTS: | 
|  | DBGMSG("Cancel request received"); | 
|  | dma_trm_reset(&ohci->at_req_context); | 
|  | dma_trm_reset(&ohci->at_resp_context); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet", | 
|  | cmd); | 
|  | break; | 
|  | } | 
|  | return retval; | 
|  | } | 
|  |  | 
|  | /*********************************** | 
|  | * rawiso ISO reception            * | 
|  | ***********************************/ | 
|  |  | 
|  | /* | 
|  | We use either buffer-fill or packet-per-buffer DMA mode. The DMA | 
|  | buffer is split into "blocks" (regions described by one DMA | 
|  | descriptor). Each block must be one page or less in size, and | 
|  | must not cross a page boundary. | 
|  |  | 
|  | There is one little wrinkle with buffer-fill mode: a packet that | 
|  | starts in the final block may wrap around into the first block. But | 
|  | the user API expects all packets to be contiguous. Our solution is | 
|  | to keep the very last page of the DMA buffer in reserve - if a | 
|  | packet spans the gap, we copy its tail into this page. | 
|  | */ | 
|  |  | 
|  | struct ohci_iso_recv { | 
|  | struct ti_ohci *ohci; | 
|  |  | 
|  | struct ohci1394_iso_tasklet task; | 
|  | int task_active; | 
|  |  | 
|  | enum { BUFFER_FILL_MODE = 0, | 
|  | PACKET_PER_BUFFER_MODE = 1 } dma_mode; | 
|  |  | 
|  | /* memory and PCI mapping for the DMA descriptors */ | 
|  | struct dma_prog_region prog; | 
|  | struct dma_cmd *block; /* = (struct dma_cmd*) prog.virt */ | 
|  |  | 
|  | /* how many DMA blocks fit in the buffer */ | 
|  | unsigned int nblocks; | 
|  |  | 
|  | /* stride of DMA blocks */ | 
|  | unsigned int buf_stride; | 
|  |  | 
|  | /* number of blocks to batch between interrupts */ | 
|  | int block_irq_interval; | 
|  |  | 
|  | /* block that DMA will finish next */ | 
|  | int block_dma; | 
|  |  | 
|  | /* (buffer-fill only) block that the reader will release next */ | 
|  | int block_reader; | 
|  |  | 
|  | /* (buffer-fill only) bytes of buffer the reader has released, | 
|  | less than one block */ | 
|  | int released_bytes; | 
|  |  | 
|  | /* (buffer-fill only) buffer offset at which the next packet will appear */ | 
|  | int dma_offset; | 
|  |  | 
|  | /* OHCI DMA context control registers */ | 
|  | u32 ContextControlSet; | 
|  | u32 ContextControlClear; | 
|  | u32 CommandPtr; | 
|  | u32 ContextMatch; | 
|  | }; | 
|  |  | 
|  | static void ohci_iso_recv_task(unsigned long data); | 
|  | static void ohci_iso_recv_stop(struct hpsb_iso *iso); | 
|  | static void ohci_iso_recv_shutdown(struct hpsb_iso *iso); | 
|  | static int  ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync); | 
|  | static void ohci_iso_recv_program(struct hpsb_iso *iso); | 
|  |  | 
|  | static int ohci_iso_recv_init(struct hpsb_iso *iso) | 
|  | { | 
|  | struct ti_ohci *ohci = iso->host->hostdata; | 
|  | struct ohci_iso_recv *recv; | 
|  | int ctx; | 
|  | int ret = -ENOMEM; | 
|  |  | 
|  | recv = kmalloc(sizeof(*recv), GFP_KERNEL); | 
|  | if (!recv) | 
|  | return -ENOMEM; | 
|  |  | 
|  | iso->hostdata = recv; | 
|  | recv->ohci = ohci; | 
|  | recv->task_active = 0; | 
|  | dma_prog_region_init(&recv->prog); | 
|  | recv->block = NULL; | 
|  |  | 
|  | /* use buffer-fill mode, unless irq_interval is 1 | 
|  | (note: multichannel requires buffer-fill) */ | 
|  |  | 
|  | if (((iso->irq_interval == 1 && iso->dma_mode == HPSB_ISO_DMA_OLD_ABI) || | 
|  | iso->dma_mode == HPSB_ISO_DMA_PACKET_PER_BUFFER) && iso->channel != -1) { | 
|  | recv->dma_mode = PACKET_PER_BUFFER_MODE; | 
|  | } else { | 
|  | recv->dma_mode = BUFFER_FILL_MODE; | 
|  | } | 
|  |  | 
|  | /* set nblocks, buf_stride, block_irq_interval */ | 
|  |  | 
|  | if (recv->dma_mode == BUFFER_FILL_MODE) { | 
|  | recv->buf_stride = PAGE_SIZE; | 
|  |  | 
|  | /* one block per page of data in the DMA buffer, minus the final guard page */ | 
|  | recv->nblocks = iso->buf_size/PAGE_SIZE - 1; | 
|  | if (recv->nblocks < 3) { | 
|  | DBGMSG("ohci_iso_recv_init: DMA buffer too small"); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | /* iso->irq_interval is in packets - translate that to blocks */ | 
|  | if (iso->irq_interval == 1) | 
|  | recv->block_irq_interval = 1; | 
|  | else | 
|  | recv->block_irq_interval = iso->irq_interval * | 
|  | ((recv->nblocks+1)/iso->buf_packets); | 
|  | if (recv->block_irq_interval*4 > recv->nblocks) | 
|  | recv->block_irq_interval = recv->nblocks/4; | 
|  | if (recv->block_irq_interval < 1) | 
|  | recv->block_irq_interval = 1; | 
|  |  | 
|  | } else { | 
|  | int max_packet_size; | 
|  |  | 
|  | recv->nblocks = iso->buf_packets; | 
|  | recv->block_irq_interval = iso->irq_interval; | 
|  | if (recv->block_irq_interval * 4 > iso->buf_packets) | 
|  | recv->block_irq_interval = iso->buf_packets / 4; | 
|  | if (recv->block_irq_interval < 1) | 
|  | recv->block_irq_interval = 1; | 
|  |  | 
|  | /* choose a buffer stride */ | 
|  | /* must be a power of 2, and <= PAGE_SIZE */ | 
|  |  | 
|  | max_packet_size = iso->buf_size / iso->buf_packets; | 
|  |  | 
|  | for (recv->buf_stride = 8; recv->buf_stride < max_packet_size; | 
|  | recv->buf_stride *= 2); | 
|  |  | 
|  | if (recv->buf_stride*iso->buf_packets > iso->buf_size || | 
|  | recv->buf_stride > PAGE_SIZE) { | 
|  | /* this shouldn't happen, but anyway... */ | 
|  | DBGMSG("ohci_iso_recv_init: problem choosing a buffer stride"); | 
|  | goto err; | 
|  | } | 
|  | } | 
|  |  | 
|  | recv->block_reader = 0; | 
|  | recv->released_bytes = 0; | 
|  | recv->block_dma = 0; | 
|  | recv->dma_offset = 0; | 
|  |  | 
|  | /* size of DMA program = one descriptor per block */ | 
|  | if (dma_prog_region_alloc(&recv->prog, | 
|  | sizeof(struct dma_cmd) * recv->nblocks, | 
|  | recv->ohci->dev)) | 
|  | goto err; | 
|  |  | 
|  | recv->block = (struct dma_cmd*) recv->prog.kvirt; | 
|  |  | 
|  | ohci1394_init_iso_tasklet(&recv->task, | 
|  | iso->channel == -1 ? OHCI_ISO_MULTICHANNEL_RECEIVE : | 
|  | OHCI_ISO_RECEIVE, | 
|  | ohci_iso_recv_task, (unsigned long) iso); | 
|  |  | 
|  | if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) { | 
|  | ret = -EBUSY; | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | recv->task_active = 1; | 
|  |  | 
|  | /* recv context registers are spaced 32 bytes apart */ | 
|  | ctx = recv->task.context; | 
|  | recv->ContextControlSet = OHCI1394_IsoRcvContextControlSet + 32 * ctx; | 
|  | recv->ContextControlClear = OHCI1394_IsoRcvContextControlClear + 32 * ctx; | 
|  | recv->CommandPtr = OHCI1394_IsoRcvCommandPtr + 32 * ctx; | 
|  | recv->ContextMatch = OHCI1394_IsoRcvContextMatch + 32 * ctx; | 
|  |  | 
|  | if (iso->channel == -1) { | 
|  | /* clear multi-channel selection mask */ | 
|  | reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, 0xFFFFFFFF); | 
|  | reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, 0xFFFFFFFF); | 
|  | } | 
|  |  | 
|  | /* write the DMA program */ | 
|  | ohci_iso_recv_program(iso); | 
|  |  | 
|  | DBGMSG("ohci_iso_recv_init: %s mode, DMA buffer is %lu pages" | 
|  | " (%u bytes), using %u blocks, buf_stride %u, block_irq_interval %d", | 
|  | recv->dma_mode == BUFFER_FILL_MODE ? | 
|  | "buffer-fill" : "packet-per-buffer", | 
|  | iso->buf_size/PAGE_SIZE, iso->buf_size, | 
|  | recv->nblocks, recv->buf_stride, recv->block_irq_interval); | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | err: | 
|  | ohci_iso_recv_shutdown(iso); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void ohci_iso_recv_stop(struct hpsb_iso *iso) | 
|  | { | 
|  | struct ohci_iso_recv *recv = iso->hostdata; | 
|  |  | 
|  | /* disable interrupts */ | 
|  | reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context); | 
|  |  | 
|  | /* halt DMA */ | 
|  | ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL); | 
|  | } | 
|  |  | 
|  | static void ohci_iso_recv_shutdown(struct hpsb_iso *iso) | 
|  | { | 
|  | struct ohci_iso_recv *recv = iso->hostdata; | 
|  |  | 
|  | if (recv->task_active) { | 
|  | ohci_iso_recv_stop(iso); | 
|  | ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task); | 
|  | recv->task_active = 0; | 
|  | } | 
|  |  | 
|  | dma_prog_region_free(&recv->prog); | 
|  | kfree(recv); | 
|  | iso->hostdata = NULL; | 
|  | } | 
|  |  | 
|  | /* set up a "gapped" ring buffer DMA program */ | 
|  | static void ohci_iso_recv_program(struct hpsb_iso *iso) | 
|  | { | 
|  | struct ohci_iso_recv *recv = iso->hostdata; | 
|  | int blk; | 
|  |  | 
|  | /* address of 'branch' field in previous DMA descriptor */ | 
|  | u32 *prev_branch = NULL; | 
|  |  | 
|  | for (blk = 0; blk < recv->nblocks; blk++) { | 
|  | u32 control; | 
|  |  | 
|  | /* the DMA descriptor */ | 
|  | struct dma_cmd *cmd = &recv->block[blk]; | 
|  |  | 
|  | /* offset of the DMA descriptor relative to the DMA prog buffer */ | 
|  | unsigned long prog_offset = blk * sizeof(struct dma_cmd); | 
|  |  | 
|  | /* offset of this packet's data within the DMA buffer */ | 
|  | unsigned long buf_offset = blk * recv->buf_stride; | 
|  |  | 
|  | if (recv->dma_mode == BUFFER_FILL_MODE) { | 
|  | control = 2 << 28; /* INPUT_MORE */ | 
|  | } else { | 
|  | control = 3 << 28; /* INPUT_LAST */ | 
|  | } | 
|  |  | 
|  | control |= 8 << 24; /* s = 1, update xferStatus and resCount */ | 
|  |  | 
|  | /* interrupt on last block, and at intervals */ | 
|  | if (blk == recv->nblocks-1 || (blk % recv->block_irq_interval) == 0) { | 
|  | control |= 3 << 20; /* want interrupt */ | 
|  | } | 
|  |  | 
|  | control |= 3 << 18; /* enable branch to address */ | 
|  | control |= recv->buf_stride; | 
|  |  | 
|  | cmd->control = cpu_to_le32(control); | 
|  | cmd->address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, buf_offset)); | 
|  | cmd->branchAddress = 0; /* filled in on next loop */ | 
|  | cmd->status = cpu_to_le32(recv->buf_stride); | 
|  |  | 
|  | /* link the previous descriptor to this one */ | 
|  | if (prev_branch) { | 
|  | *prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1); | 
|  | } | 
|  |  | 
|  | prev_branch = &cmd->branchAddress; | 
|  | } | 
|  |  | 
|  | /* the final descriptor's branch address and Z should be left at 0 */ | 
|  | } | 
|  |  | 
|  | /* listen or unlisten to a specific channel (multi-channel mode only) */ | 
|  | static void ohci_iso_recv_change_channel(struct hpsb_iso *iso, unsigned char channel, int listen) | 
|  | { | 
|  | struct ohci_iso_recv *recv = iso->hostdata; | 
|  | int reg, i; | 
|  |  | 
|  | if (channel < 32) { | 
|  | reg = listen ? OHCI1394_IRMultiChanMaskLoSet : OHCI1394_IRMultiChanMaskLoClear; | 
|  | i = channel; | 
|  | } else { | 
|  | reg = listen ? OHCI1394_IRMultiChanMaskHiSet : OHCI1394_IRMultiChanMaskHiClear; | 
|  | i = channel - 32; | 
|  | } | 
|  |  | 
|  | reg_write(recv->ohci, reg, (1 << i)); | 
|  |  | 
|  | /* issue a dummy read to force all PCI writes to be posted immediately */ | 
|  | mb(); | 
|  | reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); | 
|  | } | 
|  |  | 
|  | static void ohci_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask) | 
|  | { | 
|  | struct ohci_iso_recv *recv = iso->hostdata; | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < 64; i++) { | 
|  | if (mask & (1ULL << i)) { | 
|  | if (i < 32) | 
|  | reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoSet, (1 << i)); | 
|  | else | 
|  | reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiSet, (1 << (i-32))); | 
|  | } else { | 
|  | if (i < 32) | 
|  | reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, (1 << i)); | 
|  | else | 
|  | reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, (1 << (i-32))); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* issue a dummy read to force all PCI writes to be posted immediately */ | 
|  | mb(); | 
|  | reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); | 
|  | } | 
|  |  | 
|  | static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync) | 
|  | { | 
|  | struct ohci_iso_recv *recv = iso->hostdata; | 
|  | struct ti_ohci *ohci = recv->ohci; | 
|  | u32 command, contextMatch; | 
|  |  | 
|  | reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF); | 
|  | wmb(); | 
|  |  | 
|  | /* always keep ISO headers */ | 
|  | command = (1 << 30); | 
|  |  | 
|  | if (recv->dma_mode == BUFFER_FILL_MODE) | 
|  | command |= (1 << 31); | 
|  |  | 
|  | reg_write(recv->ohci, recv->ContextControlSet, command); | 
|  |  | 
|  | /* match on specified tags */ | 
|  | contextMatch = tag_mask << 28; | 
|  |  | 
|  | if (iso->channel == -1) { | 
|  | /* enable multichannel reception */ | 
|  | reg_write(recv->ohci, recv->ContextControlSet, (1 << 28)); | 
|  | } else { | 
|  | /* listen on channel */ | 
|  | contextMatch |= iso->channel; | 
|  | } | 
|  |  | 
|  | if (cycle != -1) { | 
|  | u32 seconds; | 
|  |  | 
|  | /* enable cycleMatch */ | 
|  | reg_write(recv->ohci, recv->ContextControlSet, (1 << 29)); | 
|  |  | 
|  | /* set starting cycle */ | 
|  | cycle &= 0x1FFF; | 
|  |  | 
|  | /* 'cycle' is only mod 8000, but we also need two 'seconds' bits - | 
|  | just snarf them from the current time */ | 
|  | seconds = reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer) >> 25; | 
|  |  | 
|  | /* advance one second to give some extra time for DMA to start */ | 
|  | seconds += 1; | 
|  |  | 
|  | cycle |= (seconds & 3) << 13; | 
|  |  | 
|  | contextMatch |= cycle << 12; | 
|  | } | 
|  |  | 
|  | if (sync != -1) { | 
|  | /* set sync flag on first DMA descriptor */ | 
|  | struct dma_cmd *cmd = &recv->block[recv->block_dma]; | 
|  | cmd->control |= cpu_to_le32(DMA_CTL_WAIT); | 
|  |  | 
|  | /* match sync field */ | 
|  | contextMatch |= (sync&0xf)<<8; | 
|  | } | 
|  |  | 
|  | reg_write(recv->ohci, recv->ContextMatch, contextMatch); | 
|  |  | 
|  | /* address of first descriptor block */ | 
|  | command = dma_prog_region_offset_to_bus(&recv->prog, | 
|  | recv->block_dma * sizeof(struct dma_cmd)); | 
|  | command |= 1; /* Z=1 */ | 
|  |  | 
|  | reg_write(recv->ohci, recv->CommandPtr, command); | 
|  |  | 
|  | /* enable interrupts */ | 
|  | reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << recv->task.context); | 
|  |  | 
|  | wmb(); | 
|  |  | 
|  | /* run */ | 
|  | reg_write(recv->ohci, recv->ContextControlSet, 0x8000); | 
|  |  | 
|  | /* issue a dummy read of the cycle timer register to force | 
|  | all PCI writes to be posted immediately */ | 
|  | mb(); | 
|  | reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); | 
|  |  | 
|  | /* check RUN */ | 
|  | if (!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) { | 
|  | PRINT(KERN_ERR, | 
|  | "Error starting IR DMA (ContextControl 0x%08x)\n", | 
|  | reg_read(recv->ohci, recv->ContextControlSet)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block) | 
|  | { | 
|  | /* re-use the DMA descriptor for the block */ | 
|  | /* by linking the previous descriptor to it */ | 
|  |  | 
|  | int next_i = block; | 
|  | int prev_i = (next_i == 0) ? (recv->nblocks - 1) : (next_i - 1); | 
|  |  | 
|  | struct dma_cmd *next = &recv->block[next_i]; | 
|  | struct dma_cmd *prev = &recv->block[prev_i]; | 
|  |  | 
|  | /* ignore out-of-range requests */ | 
|  | if ((block < 0) || (block > recv->nblocks)) | 
|  | return; | 
|  |  | 
|  | /* 'next' becomes the new end of the DMA chain, | 
|  | so disable branch and enable interrupt */ | 
|  | next->branchAddress = 0; | 
|  | next->control |= cpu_to_le32(3 << 20); | 
|  | next->status = cpu_to_le32(recv->buf_stride); | 
|  |  | 
|  | /* link prev to next */ | 
|  | prev->branchAddress = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, | 
|  | sizeof(struct dma_cmd) * next_i) | 
|  | | 1); /* Z=1 */ | 
|  |  | 
|  | /* disable interrupt on previous DMA descriptor, except at intervals */ | 
|  | if ((prev_i % recv->block_irq_interval) == 0) { | 
|  | prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */ | 
|  | } else { | 
|  | prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */ | 
|  | } | 
|  | wmb(); | 
|  |  | 
|  | /* wake up DMA in case it fell asleep */ | 
|  | reg_write(recv->ohci, recv->ContextControlSet, (1 << 12)); | 
|  | } | 
|  |  | 
|  | static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv, | 
|  | struct hpsb_iso_packet_info *info) | 
|  | { | 
|  | /* release the memory where the packet was */ | 
|  | recv->released_bytes += info->total_len; | 
|  |  | 
|  | /* have we released enough memory for one block? */ | 
|  | while (recv->released_bytes > recv->buf_stride) { | 
|  | ohci_iso_recv_release_block(recv, recv->block_reader); | 
|  | recv->block_reader = (recv->block_reader + 1) % recv->nblocks; | 
|  | recv->released_bytes -= recv->buf_stride; | 
|  | } | 
|  | } | 
|  |  | 
|  | static inline void ohci_iso_recv_release(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info) | 
|  | { | 
|  | struct ohci_iso_recv *recv = iso->hostdata; | 
|  | if (recv->dma_mode == BUFFER_FILL_MODE) { | 
|  | ohci_iso_recv_bufferfill_release(recv, info); | 
|  | } else { | 
|  | ohci_iso_recv_release_block(recv, info - iso->infos); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* parse all packets from blocks that have been fully received */ | 
|  | static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso_recv *recv) | 
|  | { | 
|  | int wake = 0; | 
|  | int runaway = 0; | 
|  | struct ti_ohci *ohci = recv->ohci; | 
|  |  | 
|  | while (1) { | 
|  | /* we expect the next parsable packet to begin at recv->dma_offset */ | 
|  | /* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */ | 
|  |  | 
|  | unsigned int offset; | 
|  | unsigned short len, cycle, total_len; | 
|  | unsigned char channel, tag, sy; | 
|  |  | 
|  | unsigned char *p = iso->data_buf.kvirt; | 
|  |  | 
|  | unsigned int this_block = recv->dma_offset/recv->buf_stride; | 
|  |  | 
|  | /* don't loop indefinitely */ | 
|  | if (runaway++ > 100000) { | 
|  | atomic_inc(&iso->overflows); | 
|  | PRINT(KERN_ERR, | 
|  | "IR DMA error - Runaway during buffer parsing!\n"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* stop parsing once we arrive at block_dma (i.e. don't get ahead of DMA) */ | 
|  | if (this_block == recv->block_dma) | 
|  | break; | 
|  |  | 
|  | wake = 1; | 
|  |  | 
|  | /* parse data length, tag, channel, and sy */ | 
|  |  | 
|  | /* note: we keep our own local copies of 'len' and 'offset' | 
|  | so the user can't mess with them by poking in the mmap area */ | 
|  |  | 
|  | len = p[recv->dma_offset+2] | (p[recv->dma_offset+3] << 8); | 
|  |  | 
|  | if (len > 4096) { | 
|  | PRINT(KERN_ERR, | 
|  | "IR DMA error - bogus 'len' value %u\n", len); | 
|  | } | 
|  |  | 
|  | channel = p[recv->dma_offset+1] & 0x3F; | 
|  | tag = p[recv->dma_offset+1] >> 6; | 
|  | sy = p[recv->dma_offset+0] & 0xF; | 
|  |  | 
|  | /* advance to data payload */ | 
|  | recv->dma_offset += 4; | 
|  |  | 
|  | /* check for wrap-around */ | 
|  | if (recv->dma_offset >= recv->buf_stride*recv->nblocks) { | 
|  | recv->dma_offset -= recv->buf_stride*recv->nblocks; | 
|  | } | 
|  |  | 
|  | /* dma_offset now points to the first byte of the data payload */ | 
|  | offset = recv->dma_offset; | 
|  |  | 
|  | /* advance to xferStatus/timeStamp */ | 
|  | recv->dma_offset += len; | 
|  |  | 
|  | total_len = len + 8; /* 8 bytes header+trailer in OHCI packet */ | 
|  | /* payload is padded to 4 bytes */ | 
|  | if (len % 4) { | 
|  | recv->dma_offset += 4 - (len%4); | 
|  | total_len += 4 - (len%4); | 
|  | } | 
|  |  | 
|  | /* check for wrap-around */ | 
|  | if (recv->dma_offset >= recv->buf_stride*recv->nblocks) { | 
|  | /* uh oh, the packet data wraps from the last | 
|  | to the first DMA block - make the packet | 
|  | contiguous by copying its "tail" into the | 
|  | guard page */ | 
|  |  | 
|  | int guard_off = recv->buf_stride*recv->nblocks; | 
|  | int tail_len = len - (guard_off - offset); | 
|  |  | 
|  | if (tail_len > 0  && tail_len < recv->buf_stride) { | 
|  | memcpy(iso->data_buf.kvirt + guard_off, | 
|  | iso->data_buf.kvirt, | 
|  | tail_len); | 
|  | } | 
|  |  | 
|  | recv->dma_offset -= recv->buf_stride*recv->nblocks; | 
|  | } | 
|  |  | 
|  | /* parse timestamp */ | 
|  | cycle = p[recv->dma_offset+0] | (p[recv->dma_offset+1]<<8); | 
|  | cycle &= 0x1FFF; | 
|  |  | 
|  | /* advance to next packet */ | 
|  | recv->dma_offset += 4; | 
|  |  | 
|  | /* check for wrap-around */ | 
|  | if (recv->dma_offset >= recv->buf_stride*recv->nblocks) { | 
|  | recv->dma_offset -= recv->buf_stride*recv->nblocks; | 
|  | } | 
|  |  | 
|  | hpsb_iso_packet_received(iso, offset, len, total_len, cycle, channel, tag, sy); | 
|  | } | 
|  |  | 
|  | if (wake) | 
|  | hpsb_iso_wake(iso); | 
|  | } | 
|  |  | 
|  | static void ohci_iso_recv_bufferfill_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv) | 
|  | { | 
|  | int loop; | 
|  | struct ti_ohci *ohci = recv->ohci; | 
|  |  | 
|  | /* loop over all blocks */ | 
|  | for (loop = 0; loop < recv->nblocks; loop++) { | 
|  |  | 
|  | /* check block_dma to see if it's done */ | 
|  | struct dma_cmd *im = &recv->block[recv->block_dma]; | 
|  |  | 
|  | /* check the DMA descriptor for new writes to xferStatus */ | 
|  | u16 xferstatus = le32_to_cpu(im->status) >> 16; | 
|  |  | 
|  | /* rescount is the number of bytes *remaining to be written* in the block */ | 
|  | u16 rescount = le32_to_cpu(im->status) & 0xFFFF; | 
|  |  | 
|  | unsigned char event = xferstatus & 0x1F; | 
|  |  | 
|  | if (!event) { | 
|  | /* nothing has happened to this block yet */ | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (event != 0x11) { | 
|  | atomic_inc(&iso->overflows); | 
|  | PRINT(KERN_ERR, | 
|  | "IR DMA error - OHCI error code 0x%02x\n", event); | 
|  | } | 
|  |  | 
|  | if (rescount != 0) { | 
|  | /* the card is still writing to this block; | 
|  | we can't touch it until it's done */ | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* OK, the block is finished... */ | 
|  |  | 
|  | /* sync our view of the block */ | 
|  | dma_region_sync_for_cpu(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride); | 
|  |  | 
|  | /* reset the DMA descriptor */ | 
|  | im->status = recv->buf_stride; | 
|  |  | 
|  | /* advance block_dma */ | 
|  | recv->block_dma = (recv->block_dma + 1) % recv->nblocks; | 
|  |  | 
|  | if ((recv->block_dma+1) % recv->nblocks == recv->block_reader) { | 
|  | atomic_inc(&iso->overflows); | 
|  | DBGMSG("ISO reception overflow - " | 
|  | "ran out of DMA blocks"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* parse any packets that have arrived */ | 
|  | ohci_iso_recv_bufferfill_parse(iso, recv); | 
|  | } | 
|  |  | 
|  | static void ohci_iso_recv_packetperbuf_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv) | 
|  | { | 
|  | int count; | 
|  | int wake = 0; | 
|  | struct ti_ohci *ohci = recv->ohci; | 
|  |  | 
|  | /* loop over the entire buffer */ | 
|  | for (count = 0; count < recv->nblocks; count++) { | 
|  | u32 packet_len = 0; | 
|  |  | 
|  | /* pointer to the DMA descriptor */ | 
|  | struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma; | 
|  |  | 
|  | /* check the DMA descriptor for new writes to xferStatus */ | 
|  | u16 xferstatus = le32_to_cpu(il->status) >> 16; | 
|  | u16 rescount = le32_to_cpu(il->status) & 0xFFFF; | 
|  |  | 
|  | unsigned char event = xferstatus & 0x1F; | 
|  |  | 
|  | if (!event) { | 
|  | /* this packet hasn't come in yet; we are done for now */ | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | if (event == 0x11) { | 
|  | /* packet received successfully! */ | 
|  |  | 
|  | /* rescount is the number of bytes *remaining* in the packet buffer, | 
|  | after the packet was written */ | 
|  | packet_len = recv->buf_stride - rescount; | 
|  |  | 
|  | } else if (event == 0x02) { | 
|  | PRINT(KERN_ERR, "IR DMA error - packet too long for buffer\n"); | 
|  | } else if (event) { | 
|  | PRINT(KERN_ERR, "IR DMA error - OHCI error code 0x%02x\n", event); | 
|  | } | 
|  |  | 
|  | /* sync our view of the buffer */ | 
|  | dma_region_sync_for_cpu(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride); | 
|  |  | 
|  | /* record the per-packet info */ | 
|  | { | 
|  | /* iso header is 8 bytes ahead of the data payload */ | 
|  | unsigned char *hdr; | 
|  |  | 
|  | unsigned int offset; | 
|  | unsigned short cycle; | 
|  | unsigned char channel, tag, sy; | 
|  |  | 
|  | offset = iso->pkt_dma * recv->buf_stride; | 
|  | hdr = iso->data_buf.kvirt + offset; | 
|  |  | 
|  | /* skip iso header */ | 
|  | offset += 8; | 
|  | packet_len -= 8; | 
|  |  | 
|  | cycle = (hdr[0] | (hdr[1] << 8)) & 0x1FFF; | 
|  | channel = hdr[5] & 0x3F; | 
|  | tag = hdr[5] >> 6; | 
|  | sy = hdr[4] & 0xF; | 
|  |  | 
|  | hpsb_iso_packet_received(iso, offset, packet_len, | 
|  | recv->buf_stride, cycle, channel, tag, sy); | 
|  | } | 
|  |  | 
|  | /* reset the DMA descriptor */ | 
|  | il->status = recv->buf_stride; | 
|  |  | 
|  | wake = 1; | 
|  | recv->block_dma = iso->pkt_dma; | 
|  | } | 
|  |  | 
|  | out: | 
|  | if (wake) | 
|  | hpsb_iso_wake(iso); | 
|  | } | 
|  |  | 
|  | static void ohci_iso_recv_task(unsigned long data) | 
|  | { | 
|  | struct hpsb_iso *iso = (struct hpsb_iso*) data; | 
|  | struct ohci_iso_recv *recv = iso->hostdata; | 
|  |  | 
|  | if (recv->dma_mode == BUFFER_FILL_MODE) | 
|  | ohci_iso_recv_bufferfill_task(iso, recv); | 
|  | else | 
|  | ohci_iso_recv_packetperbuf_task(iso, recv); | 
|  | } | 
|  |  | 
|  | /*********************************** | 
|  | * rawiso ISO transmission         * | 
|  | ***********************************/ | 
|  |  | 
|  | struct ohci_iso_xmit { | 
|  | struct ti_ohci *ohci; | 
|  | struct dma_prog_region prog; | 
|  | struct ohci1394_iso_tasklet task; | 
|  | int task_active; | 
|  | int last_cycle; | 
|  | atomic_t skips; | 
|  |  | 
|  | u32 ContextControlSet; | 
|  | u32 ContextControlClear; | 
|  | u32 CommandPtr; | 
|  | }; | 
|  |  | 
|  | /* transmission DMA program: | 
|  | one OUTPUT_MORE_IMMEDIATE for the IT header | 
|  | one OUTPUT_LAST for the buffer data */ | 
|  |  | 
|  | struct iso_xmit_cmd { | 
|  | struct dma_cmd output_more_immediate; | 
|  | u8 iso_hdr[8]; | 
|  | u32 unused[2]; | 
|  | struct dma_cmd output_last; | 
|  | }; | 
|  |  | 
|  | static int ohci_iso_xmit_init(struct hpsb_iso *iso); | 
|  | static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle); | 
|  | static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso); | 
|  | static void ohci_iso_xmit_task(unsigned long data); | 
|  |  | 
|  | static int ohci_iso_xmit_init(struct hpsb_iso *iso) | 
|  | { | 
|  | struct ohci_iso_xmit *xmit; | 
|  | unsigned int prog_size; | 
|  | int ctx; | 
|  | int ret = -ENOMEM; | 
|  |  | 
|  | xmit = kmalloc(sizeof(*xmit), GFP_KERNEL); | 
|  | if (!xmit) | 
|  | return -ENOMEM; | 
|  |  | 
|  | iso->hostdata = xmit; | 
|  | xmit->ohci = iso->host->hostdata; | 
|  | xmit->task_active = 0; | 
|  | xmit->last_cycle = -1; | 
|  | atomic_set(&iso->skips, 0); | 
|  |  | 
|  | dma_prog_region_init(&xmit->prog); | 
|  |  | 
|  | prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets; | 
|  |  | 
|  | if (dma_prog_region_alloc(&xmit->prog, prog_size, xmit->ohci->dev)) | 
|  | goto err; | 
|  |  | 
|  | ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT, | 
|  | ohci_iso_xmit_task, (unsigned long) iso); | 
|  |  | 
|  | if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) { | 
|  | ret = -EBUSY; | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | xmit->task_active = 1; | 
|  |  | 
|  | /* xmit context registers are spaced 16 bytes apart */ | 
|  | ctx = xmit->task.context; | 
|  | xmit->ContextControlSet = OHCI1394_IsoXmitContextControlSet + 16 * ctx; | 
|  | xmit->ContextControlClear = OHCI1394_IsoXmitContextControlClear + 16 * ctx; | 
|  | xmit->CommandPtr = OHCI1394_IsoXmitCommandPtr + 16 * ctx; | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | err: | 
|  | ohci_iso_xmit_shutdown(iso); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void ohci_iso_xmit_stop(struct hpsb_iso *iso) | 
|  | { | 
|  | struct ohci_iso_xmit *xmit = iso->hostdata; | 
|  | struct ti_ohci *ohci = xmit->ohci; | 
|  |  | 
|  | /* disable interrupts */ | 
|  | reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context); | 
|  |  | 
|  | /* halt DMA */ | 
|  | if (ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL)) { | 
|  | /* XXX the DMA context will lock up if you try to send too much data! */ | 
|  | PRINT(KERN_ERR, | 
|  | "you probably exceeded the OHCI card's bandwidth limit - " | 
|  | "reload the module and reduce xmit bandwidth"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso) | 
|  | { | 
|  | struct ohci_iso_xmit *xmit = iso->hostdata; | 
|  |  | 
|  | if (xmit->task_active) { | 
|  | ohci_iso_xmit_stop(iso); | 
|  | ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task); | 
|  | xmit->task_active = 0; | 
|  | } | 
|  |  | 
|  | dma_prog_region_free(&xmit->prog); | 
|  | kfree(xmit); | 
|  | iso->hostdata = NULL; | 
|  | } | 
|  |  | 
|  | static void ohci_iso_xmit_task(unsigned long data) | 
|  | { | 
|  | struct hpsb_iso *iso = (struct hpsb_iso*) data; | 
|  | struct ohci_iso_xmit *xmit = iso->hostdata; | 
|  | struct ti_ohci *ohci = xmit->ohci; | 
|  | int wake = 0; | 
|  | int count; | 
|  |  | 
|  | /* check the whole buffer if necessary, starting at pkt_dma */ | 
|  | for (count = 0; count < iso->buf_packets; count++) { | 
|  | int cycle; | 
|  |  | 
|  | /* DMA descriptor */ | 
|  | struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma); | 
|  |  | 
|  | /* check for new writes to xferStatus */ | 
|  | u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16; | 
|  | u8  event = xferstatus & 0x1F; | 
|  |  | 
|  | if (!event) { | 
|  | /* packet hasn't been sent yet; we are done for now */ | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (event != 0x11) | 
|  | PRINT(KERN_ERR, | 
|  | "IT DMA error - OHCI error code 0x%02x\n", event); | 
|  |  | 
|  | /* at least one packet went out, so wake up the writer */ | 
|  | wake = 1; | 
|  |  | 
|  | /* parse cycle */ | 
|  | cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF; | 
|  |  | 
|  | if (xmit->last_cycle > -1) { | 
|  | int cycle_diff = cycle - xmit->last_cycle; | 
|  | int skip; | 
|  |  | 
|  | /* unwrap */ | 
|  | if (cycle_diff < 0) { | 
|  | cycle_diff += 8000; | 
|  | if (cycle_diff < 0) | 
|  | PRINT(KERN_ERR, "bogus cycle diff %d\n", | 
|  | cycle_diff); | 
|  | } | 
|  |  | 
|  | skip = cycle_diff - 1; | 
|  | if (skip > 0) { | 
|  | DBGMSG("skipped %d cycles without packet loss", skip); | 
|  | atomic_add(skip, &iso->skips); | 
|  | } | 
|  | } | 
|  | xmit->last_cycle = cycle; | 
|  |  | 
|  | /* tell the subsystem the packet has gone out */ | 
|  | hpsb_iso_packet_sent(iso, cycle, event != 0x11); | 
|  |  | 
|  | /* reset the DMA descriptor for next time */ | 
|  | cmd->output_last.status = 0; | 
|  | } | 
|  |  | 
|  | if (wake) | 
|  | hpsb_iso_wake(iso); | 
|  | } | 
|  |  | 
|  | static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info) | 
|  | { | 
|  | struct ohci_iso_xmit *xmit = iso->hostdata; | 
|  | struct ti_ohci *ohci = xmit->ohci; | 
|  |  | 
|  | int next_i, prev_i; | 
|  | struct iso_xmit_cmd *next, *prev; | 
|  |  | 
|  | unsigned int offset; | 
|  | unsigned short len; | 
|  | unsigned char tag, sy; | 
|  |  | 
|  | /* check that the packet doesn't cross a page boundary | 
|  | (we could allow this if we added OUTPUT_MORE descriptor support) */ | 
|  | if (cross_bound(info->offset, info->len)) { | 
|  | PRINT(KERN_ERR, | 
|  | "rawiso xmit: packet %u crosses a page boundary", | 
|  | iso->first_packet); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | offset = info->offset; | 
|  | len = info->len; | 
|  | tag = info->tag; | 
|  | sy = info->sy; | 
|  |  | 
|  | /* sync up the card's view of the buffer */ | 
|  | dma_region_sync_for_device(&iso->data_buf, offset, len); | 
|  |  | 
|  | /* append first_packet to the DMA chain */ | 
|  | /* by linking the previous descriptor to it */ | 
|  | /* (next will become the new end of the DMA chain) */ | 
|  |  | 
|  | next_i = iso->first_packet; | 
|  | prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1); | 
|  |  | 
|  | next = dma_region_i(&xmit->prog, struct iso_xmit_cmd, next_i); | 
|  | prev = dma_region_i(&xmit->prog, struct iso_xmit_cmd, prev_i); | 
|  |  | 
|  | /* set up the OUTPUT_MORE_IMMEDIATE descriptor */ | 
|  | memset(next, 0, sizeof(struct iso_xmit_cmd)); | 
|  | next->output_more_immediate.control = cpu_to_le32(0x02000008); | 
|  |  | 
|  | /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */ | 
|  |  | 
|  | /* tcode = 0xA, and sy */ | 
|  | next->iso_hdr[0] = 0xA0 | (sy & 0xF); | 
|  |  | 
|  | /* tag and channel number */ | 
|  | next->iso_hdr[1] = (tag << 6) | (iso->channel & 0x3F); | 
|  |  | 
|  | /* transmission speed */ | 
|  | next->iso_hdr[2] = iso->speed & 0x7; | 
|  |  | 
|  | /* payload size */ | 
|  | next->iso_hdr[6] = len & 0xFF; | 
|  | next->iso_hdr[7] = len >> 8; | 
|  |  | 
|  | /* set up the OUTPUT_LAST */ | 
|  | next->output_last.control = cpu_to_le32(1 << 28); | 
|  | next->output_last.control |= cpu_to_le32(1 << 27); /* update timeStamp */ | 
|  | next->output_last.control |= cpu_to_le32(3 << 20); /* want interrupt */ | 
|  | next->output_last.control |= cpu_to_le32(3 << 18); /* enable branch */ | 
|  | next->output_last.control |= cpu_to_le32(len); | 
|  |  | 
|  | /* payload bus address */ | 
|  | next->output_last.address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, offset)); | 
|  |  | 
|  | /* leave branchAddress at zero for now */ | 
|  |  | 
|  | /* re-write the previous DMA descriptor to chain to this one */ | 
|  |  | 
|  | /* set prev branch address to point to next (Z=3) */ | 
|  | prev->output_last.branchAddress = cpu_to_le32( | 
|  | dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3); | 
|  |  | 
|  | /* | 
|  | * Link the skip address to this descriptor itself. This causes a | 
|  | * context to skip a cycle whenever lost cycles or FIFO overruns occur, | 
|  | * without dropping the data at that point the application should then | 
|  | * decide whether this is an error condition or not. Some protocols | 
|  | * can deal with this by dropping some rate-matching padding packets. | 
|  | */ | 
|  | next->output_more_immediate.branchAddress = | 
|  | prev->output_last.branchAddress; | 
|  |  | 
|  | /* disable interrupt, unless required by the IRQ interval */ | 
|  | if (prev_i % iso->irq_interval) { | 
|  | prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */ | 
|  | } else { | 
|  | prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */ | 
|  | } | 
|  |  | 
|  | wmb(); | 
|  |  | 
|  | /* wake DMA in case it is sleeping */ | 
|  | reg_write(xmit->ohci, xmit->ContextControlSet, 1 << 12); | 
|  |  | 
|  | /* issue a dummy read of the cycle timer to force all PCI | 
|  | writes to be posted immediately */ | 
|  | mb(); | 
|  | reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle) | 
|  | { | 
|  | struct ohci_iso_xmit *xmit = iso->hostdata; | 
|  | struct ti_ohci *ohci = xmit->ohci; | 
|  |  | 
|  | /* clear out the control register */ | 
|  | reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF); | 
|  | wmb(); | 
|  |  | 
|  | /* address and length of first descriptor block (Z=3) */ | 
|  | reg_write(xmit->ohci, xmit->CommandPtr, | 
|  | dma_prog_region_offset_to_bus(&xmit->prog, iso->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3); | 
|  |  | 
|  | /* cycle match */ | 
|  | if (cycle != -1) { | 
|  | u32 start = cycle & 0x1FFF; | 
|  |  | 
|  | /* 'cycle' is only mod 8000, but we also need two 'seconds' bits - | 
|  | just snarf them from the current time */ | 
|  | u32 seconds = reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer) >> 25; | 
|  |  | 
|  | /* advance one second to give some extra time for DMA to start */ | 
|  | seconds += 1; | 
|  |  | 
|  | start |= (seconds & 3) << 13; | 
|  |  | 
|  | reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16)); | 
|  | } | 
|  |  | 
|  | /* enable interrupts */ | 
|  | reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << xmit->task.context); | 
|  |  | 
|  | /* run */ | 
|  | reg_write(xmit->ohci, xmit->ContextControlSet, 0x8000); | 
|  | mb(); | 
|  |  | 
|  | /* wait 100 usec to give the card time to go active */ | 
|  | udelay(100); | 
|  |  | 
|  | /* check the RUN bit */ | 
|  | if (!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) { | 
|  | PRINT(KERN_ERR, "Error starting IT DMA (ContextControl 0x%08x)\n", | 
|  | reg_read(xmit->ohci, xmit->ContextControlSet)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, unsigned long arg) | 
|  | { | 
|  |  | 
|  | switch(cmd) { | 
|  | case XMIT_INIT: | 
|  | return ohci_iso_xmit_init(iso); | 
|  | case XMIT_START: | 
|  | return ohci_iso_xmit_start(iso, arg); | 
|  | case XMIT_STOP: | 
|  | ohci_iso_xmit_stop(iso); | 
|  | return 0; | 
|  | case XMIT_QUEUE: | 
|  | return ohci_iso_xmit_queue(iso, (struct hpsb_iso_packet_info*) arg); | 
|  | case XMIT_SHUTDOWN: | 
|  | ohci_iso_xmit_shutdown(iso); | 
|  | return 0; | 
|  |  | 
|  | case RECV_INIT: | 
|  | return ohci_iso_recv_init(iso); | 
|  | case RECV_START: { | 
|  | int *args = (int*) arg; | 
|  | return ohci_iso_recv_start(iso, args[0], args[1], args[2]); | 
|  | } | 
|  | case RECV_STOP: | 
|  | ohci_iso_recv_stop(iso); | 
|  | return 0; | 
|  | case RECV_RELEASE: | 
|  | ohci_iso_recv_release(iso, (struct hpsb_iso_packet_info*) arg); | 
|  | return 0; | 
|  | case RECV_FLUSH: | 
|  | ohci_iso_recv_task((unsigned long) iso); | 
|  | return 0; | 
|  | case RECV_SHUTDOWN: | 
|  | ohci_iso_recv_shutdown(iso); | 
|  | return 0; | 
|  | case RECV_LISTEN_CHANNEL: | 
|  | ohci_iso_recv_change_channel(iso, arg, 1); | 
|  | return 0; | 
|  | case RECV_UNLISTEN_CHANNEL: | 
|  | ohci_iso_recv_change_channel(iso, arg, 0); | 
|  | return 0; | 
|  | case RECV_SET_CHANNEL_MASK: | 
|  | ohci_iso_recv_set_channel_mask(iso, *((u64*) arg)); | 
|  | return 0; | 
|  |  | 
|  | default: | 
|  | PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet", | 
|  | cmd); | 
|  | break; | 
|  | } | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | /*************************************** | 
|  | * IEEE-1394 functionality section END * | 
|  | ***************************************/ | 
|  |  | 
|  |  | 
|  | /******************************************************** | 
|  | * Global stuff (interrupt handler, init/shutdown code) * | 
|  | ********************************************************/ | 
|  |  | 
|  | static void dma_trm_reset(struct dma_trm_ctx *d) | 
|  | { | 
|  | unsigned long flags; | 
|  | LIST_HEAD(packet_list); | 
|  | struct ti_ohci *ohci = d->ohci; | 
|  | struct hpsb_packet *packet, *ptmp; | 
|  |  | 
|  | ohci1394_stop_context(ohci, d->ctrlClear, NULL); | 
|  |  | 
|  | /* Lock the context, reset it and release it. Move the packets | 
|  | * that were pending in the context to packet_list and free | 
|  | * them after releasing the lock. */ | 
|  |  | 
|  | spin_lock_irqsave(&d->lock, flags); | 
|  |  | 
|  | list_splice_init(&d->fifo_list, &packet_list); | 
|  | list_splice_init(&d->pending_list, &packet_list); | 
|  |  | 
|  | d->branchAddrPtr = NULL; | 
|  | d->sent_ind = d->prg_ind; | 
|  | d->free_prgs = d->num_desc; | 
|  |  | 
|  | spin_unlock_irqrestore(&d->lock, flags); | 
|  |  | 
|  | if (list_empty(&packet_list)) | 
|  | return; | 
|  |  | 
|  | PRINT(KERN_INFO, "AT dma reset ctx=%d, aborting transmission", d->ctx); | 
|  |  | 
|  | /* Now process subsystem callbacks for the packets from this | 
|  | * context. */ | 
|  | list_for_each_entry_safe(packet, ptmp, &packet_list, driver_list) { | 
|  | list_del_init(&packet->driver_list); | 
|  | hpsb_packet_sent(ohci->host, packet, ACKX_ABORTED); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci, | 
|  | quadlet_t rx_event, | 
|  | quadlet_t tx_event) | 
|  | { | 
|  | struct ohci1394_iso_tasklet *t; | 
|  | unsigned long mask; | 
|  | unsigned long flags; | 
|  |  | 
|  | spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); | 
|  |  | 
|  | list_for_each_entry(t, &ohci->iso_tasklet_list, link) { | 
|  | mask = 1 << t->context; | 
|  |  | 
|  | if (t->type == OHCI_ISO_TRANSMIT) { | 
|  | if (tx_event & mask) | 
|  | tasklet_schedule(&t->tasklet); | 
|  | } else { | 
|  | /* OHCI_ISO_RECEIVE or OHCI_ISO_MULTICHANNEL_RECEIVE */ | 
|  | if (rx_event & mask) | 
|  | tasklet_schedule(&t->tasklet); | 
|  | } | 
|  | } | 
|  |  | 
|  | spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); | 
|  | } | 
|  |  | 
|  | static irqreturn_t ohci_irq_handler(int irq, void *dev_id) | 
|  | { | 
|  | quadlet_t event, node_id; | 
|  | struct ti_ohci *ohci = (struct ti_ohci *)dev_id; | 
|  | struct hpsb_host *host = ohci->host; | 
|  | int phyid = -1, isroot = 0; | 
|  | unsigned long flags; | 
|  |  | 
|  | /* Read and clear the interrupt event register.  Don't clear | 
|  | * the busReset event, though. This is done when we get the | 
|  | * selfIDComplete interrupt. */ | 
|  | spin_lock_irqsave(&ohci->event_lock, flags); | 
|  | event = reg_read(ohci, OHCI1394_IntEventClear); | 
|  | reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset); | 
|  | spin_unlock_irqrestore(&ohci->event_lock, flags); | 
|  |  | 
|  | if (!event) | 
|  | return IRQ_NONE; | 
|  |  | 
|  | /* If event is ~(u32)0 cardbus card was ejected.  In this case | 
|  | * we just return, and clean up in the ohci1394_pci_remove | 
|  | * function. */ | 
|  | if (event == ~(u32) 0) { | 
|  | DBGMSG("Device removed."); | 
|  | return IRQ_NONE; | 
|  | } | 
|  |  | 
|  | DBGMSG("IntEvent: %08x", event); | 
|  |  | 
|  | if (event & OHCI1394_unrecoverableError) { | 
|  | int ctx; | 
|  | PRINT(KERN_ERR, "Unrecoverable error!"); | 
|  |  | 
|  | if (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800) | 
|  | PRINT(KERN_ERR, "Async Req Tx Context died: " | 
|  | "ctrl[%08x] cmdptr[%08x]", | 
|  | reg_read(ohci, OHCI1394_AsReqTrContextControlSet), | 
|  | reg_read(ohci, OHCI1394_AsReqTrCommandPtr)); | 
|  |  | 
|  | if (reg_read(ohci, OHCI1394_AsRspTrContextControlSet) & 0x800) | 
|  | PRINT(KERN_ERR, "Async Rsp Tx Context died: " | 
|  | "ctrl[%08x] cmdptr[%08x]", | 
|  | reg_read(ohci, OHCI1394_AsRspTrContextControlSet), | 
|  | reg_read(ohci, OHCI1394_AsRspTrCommandPtr)); | 
|  |  | 
|  | if (reg_read(ohci, OHCI1394_AsReqRcvContextControlSet) & 0x800) | 
|  | PRINT(KERN_ERR, "Async Req Rcv Context died: " | 
|  | "ctrl[%08x] cmdptr[%08x]", | 
|  | reg_read(ohci, OHCI1394_AsReqRcvContextControlSet), | 
|  | reg_read(ohci, OHCI1394_AsReqRcvCommandPtr)); | 
|  |  | 
|  | if (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x800) | 
|  | PRINT(KERN_ERR, "Async Rsp Rcv Context died: " | 
|  | "ctrl[%08x] cmdptr[%08x]", | 
|  | reg_read(ohci, OHCI1394_AsRspRcvContextControlSet), | 
|  | reg_read(ohci, OHCI1394_AsRspRcvCommandPtr)); | 
|  |  | 
|  | for (ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) { | 
|  | if (reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800) | 
|  | PRINT(KERN_ERR, "Iso Xmit %d Context died: " | 
|  | "ctrl[%08x] cmdptr[%08x]", ctx, | 
|  | reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)), | 
|  | reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx))); | 
|  | } | 
|  |  | 
|  | for (ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) { | 
|  | if (reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800) | 
|  | PRINT(KERN_ERR, "Iso Recv %d Context died: " | 
|  | "ctrl[%08x] cmdptr[%08x] match[%08x]", ctx, | 
|  | reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)), | 
|  | reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)), | 
|  | reg_read(ohci, OHCI1394_IsoRcvContextMatch + (32 * ctx))); | 
|  | } | 
|  |  | 
|  | event &= ~OHCI1394_unrecoverableError; | 
|  | } | 
|  | if (event & OHCI1394_postedWriteErr) { | 
|  | PRINT(KERN_ERR, "physical posted write error"); | 
|  | /* no recovery strategy yet, had to involve protocol drivers */ | 
|  | event &= ~OHCI1394_postedWriteErr; | 
|  | } | 
|  | if (event & OHCI1394_cycleTooLong) { | 
|  | if(printk_ratelimit()) | 
|  | PRINT(KERN_WARNING, "isochronous cycle too long"); | 
|  | else | 
|  | DBGMSG("OHCI1394_cycleTooLong"); | 
|  | reg_write(ohci, OHCI1394_LinkControlSet, | 
|  | OHCI1394_LinkControl_CycleMaster); | 
|  | event &= ~OHCI1394_cycleTooLong; | 
|  | } | 
|  | if (event & OHCI1394_cycleInconsistent) { | 
|  | /* We subscribe to the cycleInconsistent event only to | 
|  | * clear the corresponding event bit... otherwise, | 
|  | * isochronous cycleMatch DMA won't work. */ | 
|  | DBGMSG("OHCI1394_cycleInconsistent"); | 
|  | event &= ~OHCI1394_cycleInconsistent; | 
|  | } | 
|  | if (event & OHCI1394_busReset) { | 
|  | /* The busReset event bit can't be cleared during the | 
|  | * selfID phase, so we disable busReset interrupts, to | 
|  | * avoid burying the cpu in interrupt requests. */ | 
|  | spin_lock_irqsave(&ohci->event_lock, flags); | 
|  | reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset); | 
|  |  | 
|  | if (ohci->check_busreset) { | 
|  | int loop_count = 0; | 
|  |  | 
|  | udelay(10); | 
|  |  | 
|  | while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) { | 
|  | reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); | 
|  |  | 
|  | spin_unlock_irqrestore(&ohci->event_lock, flags); | 
|  | udelay(10); | 
|  | spin_lock_irqsave(&ohci->event_lock, flags); | 
|  |  | 
|  | /* The loop counter check is to prevent the driver | 
|  | * from remaining in this state forever. For the | 
|  | * initial bus reset, the loop continues for ever | 
|  | * and the system hangs, until some device is plugged-in | 
|  | * or out manually into a port! The forced reset seems | 
|  | * to solve this problem. This mainly effects nForce2. */ | 
|  | if (loop_count > 10000) { | 
|  | ohci_devctl(host, RESET_BUS, LONG_RESET); | 
|  | DBGMSG("Detected bus-reset loop. Forced a bus reset!"); | 
|  | loop_count = 0; | 
|  | } | 
|  |  | 
|  | loop_count++; | 
|  | } | 
|  | } | 
|  | spin_unlock_irqrestore(&ohci->event_lock, flags); | 
|  | if (!host->in_bus_reset) { | 
|  | DBGMSG("irq_handler: Bus reset requested"); | 
|  |  | 
|  | /* Subsystem call */ | 
|  | hpsb_bus_reset(ohci->host); | 
|  | } | 
|  | event &= ~OHCI1394_busReset; | 
|  | } | 
|  | if (event & OHCI1394_reqTxComplete) { | 
|  | struct dma_trm_ctx *d = &ohci->at_req_context; | 
|  | DBGMSG("Got reqTxComplete interrupt " | 
|  | "status=0x%08X", reg_read(ohci, d->ctrlSet)); | 
|  | if (reg_read(ohci, d->ctrlSet) & 0x800) | 
|  | ohci1394_stop_context(ohci, d->ctrlClear, | 
|  | "reqTxComplete"); | 
|  | else | 
|  | dma_trm_tasklet((unsigned long)d); | 
|  | //tasklet_schedule(&d->task); | 
|  | event &= ~OHCI1394_reqTxComplete; | 
|  | } | 
|  | if (event & OHCI1394_respTxComplete) { | 
|  | struct dma_trm_ctx *d = &ohci->at_resp_context; | 
|  | DBGMSG("Got respTxComplete interrupt " | 
|  | "status=0x%08X", reg_read(ohci, d->ctrlSet)); | 
|  | if (reg_read(ohci, d->ctrlSet) & 0x800) | 
|  | ohci1394_stop_context(ohci, d->ctrlClear, | 
|  | "respTxComplete"); | 
|  | else | 
|  | tasklet_schedule(&d->task); | 
|  | event &= ~OHCI1394_respTxComplete; | 
|  | } | 
|  | if (event & OHCI1394_RQPkt) { | 
|  | struct dma_rcv_ctx *d = &ohci->ar_req_context; | 
|  | DBGMSG("Got RQPkt interrupt status=0x%08X", | 
|  | reg_read(ohci, d->ctrlSet)); | 
|  | if (reg_read(ohci, d->ctrlSet) & 0x800) | 
|  | ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt"); | 
|  | else | 
|  | tasklet_schedule(&d->task); | 
|  | event &= ~OHCI1394_RQPkt; | 
|  | } | 
|  | if (event & OHCI1394_RSPkt) { | 
|  | struct dma_rcv_ctx *d = &ohci->ar_resp_context; | 
|  | DBGMSG("Got RSPkt interrupt status=0x%08X", | 
|  | reg_read(ohci, d->ctrlSet)); | 
|  | if (reg_read(ohci, d->ctrlSet) & 0x800) | 
|  | ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt"); | 
|  | else | 
|  | tasklet_schedule(&d->task); | 
|  | event &= ~OHCI1394_RSPkt; | 
|  | } | 
|  | if (event & OHCI1394_isochRx) { | 
|  | quadlet_t rx_event; | 
|  |  | 
|  | rx_event = reg_read(ohci, OHCI1394_IsoRecvIntEventSet); | 
|  | reg_write(ohci, OHCI1394_IsoRecvIntEventClear, rx_event); | 
|  | ohci_schedule_iso_tasklets(ohci, rx_event, 0); | 
|  | event &= ~OHCI1394_isochRx; | 
|  | } | 
|  | if (event & OHCI1394_isochTx) { | 
|  | quadlet_t tx_event; | 
|  |  | 
|  | tx_event = reg_read(ohci, OHCI1394_IsoXmitIntEventSet); | 
|  | reg_write(ohci, OHCI1394_IsoXmitIntEventClear, tx_event); | 
|  | ohci_schedule_iso_tasklets(ohci, 0, tx_event); | 
|  | event &= ~OHCI1394_isochTx; | 
|  | } | 
|  | if (event & OHCI1394_selfIDComplete) { | 
|  | if (host->in_bus_reset) { | 
|  | node_id = reg_read(ohci, OHCI1394_NodeID); | 
|  |  | 
|  | if (!(node_id & 0x80000000)) { | 
|  | PRINT(KERN_ERR, | 
|  | "SelfID received, but NodeID invalid " | 
|  | "(probably new bus reset occurred): %08X", | 
|  | node_id); | 
|  | goto selfid_not_valid; | 
|  | } | 
|  |  | 
|  | phyid =  node_id & 0x0000003f; | 
|  | isroot = (node_id & 0x40000000) != 0; | 
|  |  | 
|  | DBGMSG("SelfID interrupt received " | 
|  | "(phyid %d, %s)", phyid, | 
|  | (isroot ? "root" : "not root")); | 
|  |  | 
|  | handle_selfid(ohci, host, phyid, isroot); | 
|  |  | 
|  | /* Clear the bus reset event and re-enable the | 
|  | * busReset interrupt.  */ | 
|  | spin_lock_irqsave(&ohci->event_lock, flags); | 
|  | reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); | 
|  | reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); | 
|  | spin_unlock_irqrestore(&ohci->event_lock, flags); | 
|  |  | 
|  | /* Turn on phys dma reception. | 
|  | * | 
|  | * TODO: Enable some sort of filtering management. | 
|  | */ | 
|  | if (phys_dma) { | 
|  | reg_write(ohci, OHCI1394_PhyReqFilterHiSet, | 
|  | 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_PhyReqFilterLoSet, | 
|  | 0xffffffff); | 
|  | } | 
|  |  | 
|  | DBGMSG("PhyReqFilter=%08x%08x", | 
|  | reg_read(ohci, OHCI1394_PhyReqFilterHiSet), | 
|  | reg_read(ohci, OHCI1394_PhyReqFilterLoSet)); | 
|  |  | 
|  | hpsb_selfid_complete(host, phyid, isroot); | 
|  | } else | 
|  | PRINT(KERN_ERR, | 
|  | "SelfID received outside of bus reset sequence"); | 
|  |  | 
|  | selfid_not_valid: | 
|  | event &= ~OHCI1394_selfIDComplete; | 
|  | } | 
|  |  | 
|  | /* Make sure we handle everything, just in case we accidentally | 
|  | * enabled an interrupt that we didn't write a handler for.  */ | 
|  | if (event) | 
|  | PRINT(KERN_ERR, "Unhandled interrupt(s) 0x%08x", | 
|  | event); | 
|  |  | 
|  | return IRQ_HANDLED; | 
|  | } | 
|  |  | 
|  | /* Put the buffer back into the dma context */ | 
|  | static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx) | 
|  | { | 
|  | struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); | 
|  | DBGMSG("Inserting dma buf ctx=%d idx=%d", d->ctx, idx); | 
|  |  | 
|  | d->prg_cpu[idx]->status = cpu_to_le32(d->buf_size); | 
|  | d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0); | 
|  | idx = (idx + d->num_desc - 1 ) % d->num_desc; | 
|  | d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001); | 
|  |  | 
|  | /* To avoid a race, ensure 1394 interface hardware sees the inserted | 
|  | * context program descriptors before it sees the wakeup bit set. */ | 
|  | wmb(); | 
|  |  | 
|  | /* wake up the dma context if necessary */ | 
|  | if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { | 
|  | PRINT(KERN_INFO, | 
|  | "Waking dma ctx=%d ... processing is probably too slow", | 
|  | d->ctx); | 
|  | } | 
|  |  | 
|  | /* do this always, to avoid race condition */ | 
|  | reg_write(ohci, d->ctrlSet, 0x1000); | 
|  | } | 
|  |  | 
|  | #define cond_le32_to_cpu(data, noswap) \ | 
|  | (noswap ? data : le32_to_cpu(data)) | 
|  |  | 
|  | static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0, | 
|  | -1, 0, -1, 0, -1, -1, 16, -1}; | 
|  |  | 
|  | /* | 
|  | * Determine the length of a packet in the buffer | 
|  | * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca> | 
|  | */ | 
|  | static inline int packet_length(struct dma_rcv_ctx *d, int idx, | 
|  | quadlet_t *buf_ptr, int offset, | 
|  | unsigned char tcode, int noswap) | 
|  | { | 
|  | int length = -1; | 
|  |  | 
|  | if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) { | 
|  | length = TCODE_SIZE[tcode]; | 
|  | if (length == 0) { | 
|  | if (offset + 12 >= d->buf_size) { | 
|  | length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc] | 
|  | [3 - ((d->buf_size - offset) >> 2)], noswap) >> 16); | 
|  | } else { | 
|  | length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16); | 
|  | } | 
|  | length += 20; | 
|  | } | 
|  | } else if (d->type == DMA_CTX_ISO) { | 
|  | /* Assumption: buffer fill mode with header/trailer */ | 
|  | length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8; | 
|  | } | 
|  |  | 
|  | if (length > 0 && length % 4) | 
|  | length += 4 - (length % 4); | 
|  |  | 
|  | return length; | 
|  | } | 
|  |  | 
|  | /* Tasklet that processes dma receive buffers */ | 
|  | static void dma_rcv_tasklet (unsigned long data) | 
|  | { | 
|  | struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data; | 
|  | struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); | 
|  | unsigned int split_left, idx, offset, rescount; | 
|  | unsigned char tcode; | 
|  | int length, bytes_left, ack; | 
|  | unsigned long flags; | 
|  | quadlet_t *buf_ptr; | 
|  | char *split_ptr; | 
|  | char msg[256]; | 
|  |  | 
|  | spin_lock_irqsave(&d->lock, flags); | 
|  |  | 
|  | idx = d->buf_ind; | 
|  | offset = d->buf_offset; | 
|  | buf_ptr = d->buf_cpu[idx] + offset/4; | 
|  |  | 
|  | rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; | 
|  | bytes_left = d->buf_size - rescount - offset; | 
|  |  | 
|  | while (bytes_left > 0) { | 
|  | tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf; | 
|  |  | 
|  | /* packet_length() will return < 4 for an error */ | 
|  | length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming); | 
|  |  | 
|  | if (length < 4) { /* something is wrong */ | 
|  | sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d", | 
|  | tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming), | 
|  | d->ctx, length); | 
|  | ohci1394_stop_context(ohci, d->ctrlClear, msg); | 
|  | spin_unlock_irqrestore(&d->lock, flags); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* The first case is where we have a packet that crosses | 
|  | * over more than one descriptor. The next case is where | 
|  | * it's all in the first descriptor.  */ | 
|  | if ((offset + length) > d->buf_size) { | 
|  | DBGMSG("Split packet rcv'd"); | 
|  | if (length > d->split_buf_size) { | 
|  | ohci1394_stop_context(ohci, d->ctrlClear, | 
|  | "Split packet size exceeded"); | 
|  | d->buf_ind = idx; | 
|  | d->buf_offset = offset; | 
|  | spin_unlock_irqrestore(&d->lock, flags); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status) | 
|  | == d->buf_size) { | 
|  | /* Other part of packet not written yet. | 
|  | * this should never happen I think | 
|  | * anyway we'll get it on the next call.  */ | 
|  | PRINT(KERN_INFO, | 
|  | "Got only half a packet!"); | 
|  | d->buf_ind = idx; | 
|  | d->buf_offset = offset; | 
|  | spin_unlock_irqrestore(&d->lock, flags); | 
|  | return; | 
|  | } | 
|  |  | 
|  | split_left = length; | 
|  | split_ptr = (char *)d->spb; | 
|  | memcpy(split_ptr,buf_ptr,d->buf_size-offset); | 
|  | split_left -= d->buf_size-offset; | 
|  | split_ptr += d->buf_size-offset; | 
|  | insert_dma_buffer(d, idx); | 
|  | idx = (idx+1) % d->num_desc; | 
|  | buf_ptr = d->buf_cpu[idx]; | 
|  | offset=0; | 
|  |  | 
|  | while (split_left >= d->buf_size) { | 
|  | memcpy(split_ptr,buf_ptr,d->buf_size); | 
|  | split_ptr += d->buf_size; | 
|  | split_left -= d->buf_size; | 
|  | insert_dma_buffer(d, idx); | 
|  | idx = (idx+1) % d->num_desc; | 
|  | buf_ptr = d->buf_cpu[idx]; | 
|  | } | 
|  |  | 
|  | if (split_left > 0) { | 
|  | memcpy(split_ptr, buf_ptr, split_left); | 
|  | offset = split_left; | 
|  | buf_ptr += offset/4; | 
|  | } | 
|  | } else { | 
|  | DBGMSG("Single packet rcv'd"); | 
|  | memcpy(d->spb, buf_ptr, length); | 
|  | offset += length; | 
|  | buf_ptr += length/4; | 
|  | if (offset==d->buf_size) { | 
|  | insert_dma_buffer(d, idx); | 
|  | idx = (idx+1) % d->num_desc; | 
|  | buf_ptr = d->buf_cpu[idx]; | 
|  | offset=0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* We get one phy packet to the async descriptor for each | 
|  | * bus reset. We always ignore it.  */ | 
|  | if (tcode != OHCI1394_TCODE_PHY) { | 
|  | if (!ohci->no_swap_incoming) | 
|  | header_le32_to_cpu(d->spb, tcode); | 
|  | DBGMSG("Packet received from node" | 
|  | " %d ack=0x%02X spd=%d tcode=0x%X" | 
|  | " length=%d ctx=%d tlabel=%d", | 
|  | (d->spb[1]>>16)&0x3f, | 
|  | (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f, | 
|  | (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3, | 
|  | tcode, length, d->ctx, | 
|  | (d->spb[0]>>10)&0x3f); | 
|  |  | 
|  | ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f) | 
|  | == 0x11) ? 1 : 0; | 
|  |  | 
|  | hpsb_packet_received(ohci->host, d->spb, | 
|  | length-4, ack); | 
|  | } | 
|  | #ifdef OHCI1394_DEBUG | 
|  | else | 
|  | PRINT (KERN_DEBUG, "Got phy packet ctx=%d ... discarded", | 
|  | d->ctx); | 
|  | #endif | 
|  |  | 
|  | rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; | 
|  |  | 
|  | bytes_left = d->buf_size - rescount - offset; | 
|  |  | 
|  | } | 
|  |  | 
|  | d->buf_ind = idx; | 
|  | d->buf_offset = offset; | 
|  |  | 
|  | spin_unlock_irqrestore(&d->lock, flags); | 
|  | } | 
|  |  | 
|  | /* Bottom half that processes sent packets */ | 
|  | static void dma_trm_tasklet (unsigned long data) | 
|  | { | 
|  | struct dma_trm_ctx *d = (struct dma_trm_ctx*)data; | 
|  | struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); | 
|  | struct hpsb_packet *packet, *ptmp; | 
|  | unsigned long flags; | 
|  | u32 status, ack; | 
|  | size_t datasize; | 
|  |  | 
|  | spin_lock_irqsave(&d->lock, flags); | 
|  |  | 
|  | list_for_each_entry_safe(packet, ptmp, &d->fifo_list, driver_list) { | 
|  | datasize = packet->data_size; | 
|  | if (datasize && packet->type != hpsb_raw) | 
|  | status = le32_to_cpu( | 
|  | d->prg_cpu[d->sent_ind]->end.status) >> 16; | 
|  | else | 
|  | status = le32_to_cpu( | 
|  | d->prg_cpu[d->sent_ind]->begin.status) >> 16; | 
|  |  | 
|  | if (status == 0) | 
|  | /* this packet hasn't been sent yet*/ | 
|  | break; | 
|  |  | 
|  | #ifdef OHCI1394_DEBUG | 
|  | if (datasize) | 
|  | if (((le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf) == 0xa) | 
|  | DBGMSG("Stream packet sent to channel %d tcode=0x%X " | 
|  | "ack=0x%X spd=%d dataLength=%d ctx=%d", | 
|  | (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>8)&0x3f, | 
|  | (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf, | 
|  | status&0x1f, (status>>5)&0x3, | 
|  | le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16, | 
|  | d->ctx); | 
|  | else | 
|  | DBGMSG("Packet sent to node %d tcode=0x%X tLabel=" | 
|  | "%d ack=0x%X spd=%d dataLength=%d ctx=%d", | 
|  | (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16)&0x3f, | 
|  | (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf, | 
|  | (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>10)&0x3f, | 
|  | status&0x1f, (status>>5)&0x3, | 
|  | le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3])>>16, | 
|  | d->ctx); | 
|  | else | 
|  | DBGMSG("Packet sent to node %d tcode=0x%X tLabel=" | 
|  | "%d ack=0x%X spd=%d data=0x%08X ctx=%d", | 
|  | (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) | 
|  | >>16)&0x3f, | 
|  | (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) | 
|  | >>4)&0xf, | 
|  | (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) | 
|  | >>10)&0x3f, | 
|  | status&0x1f, (status>>5)&0x3, | 
|  | le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]), | 
|  | d->ctx); | 
|  | #endif | 
|  |  | 
|  | if (status & 0x10) { | 
|  | ack = status & 0xf; | 
|  | } else { | 
|  | switch (status & 0x1f) { | 
|  | case EVT_NO_STATUS: /* that should never happen */ | 
|  | case EVT_RESERVED_A: /* that should never happen */ | 
|  | case EVT_LONG_PACKET: /* that should never happen */ | 
|  | PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f); | 
|  | ack = ACKX_SEND_ERROR; | 
|  | break; | 
|  | case EVT_MISSING_ACK: | 
|  | ack = ACKX_TIMEOUT; | 
|  | break; | 
|  | case EVT_UNDERRUN: | 
|  | ack = ACKX_SEND_ERROR; | 
|  | break; | 
|  | case EVT_OVERRUN: /* that should never happen */ | 
|  | PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f); | 
|  | ack = ACKX_SEND_ERROR; | 
|  | break; | 
|  | case EVT_DESCRIPTOR_READ: | 
|  | case EVT_DATA_READ: | 
|  | case EVT_DATA_WRITE: | 
|  | ack = ACKX_SEND_ERROR; | 
|  | break; | 
|  | case EVT_BUS_RESET: /* that should never happen */ | 
|  | PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f); | 
|  | ack = ACKX_SEND_ERROR; | 
|  | break; | 
|  | case EVT_TIMEOUT: | 
|  | ack = ACKX_TIMEOUT; | 
|  | break; | 
|  | case EVT_TCODE_ERR: | 
|  | ack = ACKX_SEND_ERROR; | 
|  | break; | 
|  | case EVT_RESERVED_B: /* that should never happen */ | 
|  | case EVT_RESERVED_C: /* that should never happen */ | 
|  | PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f); | 
|  | ack = ACKX_SEND_ERROR; | 
|  | break; | 
|  | case EVT_UNKNOWN: | 
|  | case EVT_FLUSHED: | 
|  | ack = ACKX_SEND_ERROR; | 
|  | break; | 
|  | default: | 
|  | PRINT(KERN_ERR, "Unhandled OHCI evt_* error 0x%x", status & 0x1f); | 
|  | ack = ACKX_SEND_ERROR; | 
|  | BUG(); | 
|  | } | 
|  | } | 
|  |  | 
|  | list_del_init(&packet->driver_list); | 
|  | hpsb_packet_sent(ohci->host, packet, ack); | 
|  |  | 
|  | if (datasize) | 
|  | pci_unmap_single(ohci->dev, | 
|  | cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address), | 
|  | datasize, PCI_DMA_TODEVICE); | 
|  |  | 
|  | d->sent_ind = (d->sent_ind+1)%d->num_desc; | 
|  | d->free_prgs++; | 
|  | } | 
|  |  | 
|  | dma_trm_flush(ohci, d); | 
|  |  | 
|  | spin_unlock_irqrestore(&d->lock, flags); | 
|  | } | 
|  |  | 
|  | static void free_dma_rcv_ctx(struct dma_rcv_ctx *d) | 
|  | { | 
|  | int i; | 
|  | struct ti_ohci *ohci = d->ohci; | 
|  |  | 
|  | if (ohci == NULL) | 
|  | return; | 
|  |  | 
|  | DBGMSG("Freeing dma_rcv_ctx %d", d->ctx); | 
|  |  | 
|  | if (d->buf_cpu) { | 
|  | for (i=0; i<d->num_desc; i++) | 
|  | if (d->buf_cpu[i] && d->buf_bus[i]) | 
|  | pci_free_consistent( | 
|  | ohci->dev, d->buf_size, | 
|  | d->buf_cpu[i], d->buf_bus[i]); | 
|  | kfree(d->buf_cpu); | 
|  | kfree(d->buf_bus); | 
|  | } | 
|  | if (d->prg_cpu) { | 
|  | for (i=0; i<d->num_desc; i++) | 
|  | if (d->prg_cpu[i] && d->prg_bus[i]) | 
|  | pci_pool_free(d->prg_pool, d->prg_cpu[i], | 
|  | d->prg_bus[i]); | 
|  | pci_pool_destroy(d->prg_pool); | 
|  | kfree(d->prg_cpu); | 
|  | kfree(d->prg_bus); | 
|  | } | 
|  | kfree(d->spb); | 
|  |  | 
|  | /* Mark this context as freed. */ | 
|  | d->ohci = NULL; | 
|  | } | 
|  |  | 
|  | static int | 
|  | alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, | 
|  | enum context_type type, int ctx, int num_desc, | 
|  | int buf_size, int split_buf_size, int context_base) | 
|  | { | 
|  | int i, len; | 
|  | static int num_allocs; | 
|  | static char pool_name[20]; | 
|  |  | 
|  | d->ohci = ohci; | 
|  | d->type = type; | 
|  | d->ctx = ctx; | 
|  |  | 
|  | d->num_desc = num_desc; | 
|  | d->buf_size = buf_size; | 
|  | d->split_buf_size = split_buf_size; | 
|  |  | 
|  | d->ctrlSet = 0; | 
|  | d->ctrlClear = 0; | 
|  | d->cmdPtr = 0; | 
|  |  | 
|  | d->buf_cpu = kzalloc(d->num_desc * sizeof(*d->buf_cpu), GFP_ATOMIC); | 
|  | d->buf_bus = kzalloc(d->num_desc * sizeof(*d->buf_bus), GFP_ATOMIC); | 
|  |  | 
|  | if (d->buf_cpu == NULL || d->buf_bus == NULL) { | 
|  | PRINT(KERN_ERR, "Failed to allocate %s", "DMA buffer"); | 
|  | free_dma_rcv_ctx(d); | 
|  | return -ENOMEM; | 
|  | } | 
|  |  | 
|  | d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_ATOMIC); | 
|  | d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_ATOMIC); | 
|  |  | 
|  | if (d->prg_cpu == NULL || d->prg_bus == NULL) { | 
|  | PRINT(KERN_ERR, "Failed to allocate %s", "DMA prg"); | 
|  | free_dma_rcv_ctx(d); | 
|  | return -ENOMEM; | 
|  | } | 
|  |  | 
|  | d->spb = kmalloc(d->split_buf_size, GFP_ATOMIC); | 
|  |  | 
|  | if (d->spb == NULL) { | 
|  | PRINT(KERN_ERR, "Failed to allocate %s", "split buffer"); | 
|  | free_dma_rcv_ctx(d); | 
|  | return -ENOMEM; | 
|  | } | 
|  |  | 
|  | len = sprintf(pool_name, "ohci1394_rcv_prg"); | 
|  | sprintf(pool_name+len, "%d", num_allocs); | 
|  | d->prg_pool = pci_pool_create(pool_name, ohci->dev, | 
|  | sizeof(struct dma_cmd), 4, 0); | 
|  | if(d->prg_pool == NULL) | 
|  | { | 
|  | PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name); | 
|  | free_dma_rcv_ctx(d); | 
|  | return -ENOMEM; | 
|  | } | 
|  | num_allocs++; | 
|  |  | 
|  | for (i=0; i<d->num_desc; i++) { | 
|  | d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, | 
|  | d->buf_size, | 
|  | d->buf_bus+i); | 
|  |  | 
|  | if (d->buf_cpu[i] != NULL) { | 
|  | memset(d->buf_cpu[i], 0, d->buf_size); | 
|  | } else { | 
|  | PRINT(KERN_ERR, | 
|  | "Failed to allocate %s", "DMA buffer"); | 
|  | free_dma_rcv_ctx(d); | 
|  | return -ENOMEM; | 
|  | } | 
|  |  | 
|  | d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i); | 
|  |  | 
|  | if (d->prg_cpu[i] != NULL) { | 
|  | memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd)); | 
|  | } else { | 
|  | PRINT(KERN_ERR, | 
|  | "Failed to allocate %s", "DMA prg"); | 
|  | free_dma_rcv_ctx(d); | 
|  | return -ENOMEM; | 
|  | } | 
|  | } | 
|  |  | 
|  | spin_lock_init(&d->lock); | 
|  |  | 
|  | d->ctrlSet = context_base + OHCI1394_ContextControlSet; | 
|  | d->ctrlClear = context_base + OHCI1394_ContextControlClear; | 
|  | d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; | 
|  |  | 
|  | tasklet_init(&d->task, dma_rcv_tasklet, (unsigned long) d); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void free_dma_trm_ctx(struct dma_trm_ctx *d) | 
|  | { | 
|  | int i; | 
|  | struct ti_ohci *ohci = d->ohci; | 
|  |  | 
|  | if (ohci == NULL) | 
|  | return; | 
|  |  | 
|  | DBGMSG("Freeing dma_trm_ctx %d", d->ctx); | 
|  |  | 
|  | if (d->prg_cpu) { | 
|  | for (i=0; i<d->num_desc; i++) | 
|  | if (d->prg_cpu[i] && d->prg_bus[i]) | 
|  | pci_pool_free(d->prg_pool, d->prg_cpu[i], | 
|  | d->prg_bus[i]); | 
|  | pci_pool_destroy(d->prg_pool); | 
|  | kfree(d->prg_cpu); | 
|  | kfree(d->prg_bus); | 
|  | } | 
|  |  | 
|  | /* Mark this context as freed. */ | 
|  | d->ohci = NULL; | 
|  | } | 
|  |  | 
|  | static int | 
|  | alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, | 
|  | enum context_type type, int ctx, int num_desc, | 
|  | int context_base) | 
|  | { | 
|  | int i, len; | 
|  | static char pool_name[20]; | 
|  | static int num_allocs=0; | 
|  |  | 
|  | d->ohci = ohci; | 
|  | d->type = type; | 
|  | d->ctx = ctx; | 
|  | d->num_desc = num_desc; | 
|  | d->ctrlSet = 0; | 
|  | d->ctrlClear = 0; | 
|  | d->cmdPtr = 0; | 
|  |  | 
|  | d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_KERNEL); | 
|  | d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_KERNEL); | 
|  |  | 
|  | if (d->prg_cpu == NULL || d->prg_bus == NULL) { | 
|  | PRINT(KERN_ERR, "Failed to allocate %s", "AT DMA prg"); | 
|  | free_dma_trm_ctx(d); | 
|  | return -ENOMEM; | 
|  | } | 
|  |  | 
|  | len = sprintf(pool_name, "ohci1394_trm_prg"); | 
|  | sprintf(pool_name+len, "%d", num_allocs); | 
|  | d->prg_pool = pci_pool_create(pool_name, ohci->dev, | 
|  | sizeof(struct at_dma_prg), 4, 0); | 
|  | if (d->prg_pool == NULL) { | 
|  | PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name); | 
|  | free_dma_trm_ctx(d); | 
|  | return -ENOMEM; | 
|  | } | 
|  | num_allocs++; | 
|  |  | 
|  | for (i = 0; i < d->num_desc; i++) { | 
|  | d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i); | 
|  |  | 
|  | if (d->prg_cpu[i] != NULL) { | 
|  | memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg)); | 
|  | } else { | 
|  | PRINT(KERN_ERR, | 
|  | "Failed to allocate %s", "AT DMA prg"); | 
|  | free_dma_trm_ctx(d); | 
|  | return -ENOMEM; | 
|  | } | 
|  | } | 
|  |  | 
|  | spin_lock_init(&d->lock); | 
|  |  | 
|  | /* initialize tasklet */ | 
|  | d->ctrlSet = context_base + OHCI1394_ContextControlSet; | 
|  | d->ctrlClear = context_base + OHCI1394_ContextControlClear; | 
|  | d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; | 
|  | tasklet_init(&d->task, dma_trm_tasklet, (unsigned long)d); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void ohci_set_hw_config_rom(struct hpsb_host *host, __be32 *config_rom) | 
|  | { | 
|  | struct ti_ohci *ohci = host->hostdata; | 
|  |  | 
|  | reg_write(ohci, OHCI1394_ConfigROMhdr, be32_to_cpu(config_rom[0])); | 
|  | reg_write(ohci, OHCI1394_BusOptions, be32_to_cpu(config_rom[2])); | 
|  |  | 
|  | memcpy(ohci->csr_config_rom_cpu, config_rom, OHCI_CONFIG_ROM_LEN); | 
|  | } | 
|  |  | 
|  |  | 
|  | static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg, | 
|  | quadlet_t data, quadlet_t compare) | 
|  | { | 
|  | struct ti_ohci *ohci = host->hostdata; | 
|  | int i; | 
|  |  | 
|  | reg_write(ohci, OHCI1394_CSRData, data); | 
|  | reg_write(ohci, OHCI1394_CSRCompareData, compare); | 
|  | reg_write(ohci, OHCI1394_CSRControl, reg & 0x3); | 
|  |  | 
|  | for (i = 0; i < OHCI_LOOP_COUNT; i++) { | 
|  | if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) | 
|  | break; | 
|  |  | 
|  | mdelay(1); | 
|  | } | 
|  |  | 
|  | return reg_read(ohci, OHCI1394_CSRData); | 
|  | } | 
|  |  | 
|  | static struct hpsb_host_driver ohci1394_driver = { | 
|  | .owner =		THIS_MODULE, | 
|  | .name =			OHCI1394_DRIVER_NAME, | 
|  | .set_hw_config_rom =	ohci_set_hw_config_rom, | 
|  | .transmit_packet =	ohci_transmit, | 
|  | .devctl =		ohci_devctl, | 
|  | .isoctl =               ohci_isoctl, | 
|  | .hw_csr_reg =		ohci_hw_csr_reg, | 
|  | }; | 
|  |  | 
|  | /*********************************** | 
|  | * PCI Driver Interface functions  * | 
|  | ***********************************/ | 
|  |  | 
|  | #ifdef CONFIG_PPC_PMAC | 
|  | static void ohci1394_pmac_on(struct pci_dev *dev) | 
|  | { | 
|  | if (machine_is(powermac)) { | 
|  | struct device_node *ofn = pci_device_to_OF_node(dev); | 
|  |  | 
|  | if (ofn) { | 
|  | pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1); | 
|  | pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void ohci1394_pmac_off(struct pci_dev *dev) | 
|  | { | 
|  | if (machine_is(powermac)) { | 
|  | struct device_node *ofn = pci_device_to_OF_node(dev); | 
|  |  | 
|  | if (ofn) { | 
|  | pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); | 
|  | pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); | 
|  | } | 
|  | } | 
|  | } | 
|  | #else | 
|  | #define ohci1394_pmac_on(dev) | 
|  | #define ohci1394_pmac_off(dev) | 
|  | #endif /* CONFIG_PPC_PMAC */ | 
|  |  | 
|  | static int __devinit ohci1394_pci_probe(struct pci_dev *dev, | 
|  | const struct pci_device_id *ent) | 
|  | { | 
|  | struct hpsb_host *host; | 
|  | struct ti_ohci *ohci;	/* shortcut to currently handled device */ | 
|  | resource_size_t ohci_base; | 
|  | int err = -ENOMEM; | 
|  |  | 
|  | ohci1394_pmac_on(dev); | 
|  | if (pci_enable_device(dev)) { | 
|  | PRINT_G(KERN_ERR, "Failed to enable OHCI hardware"); | 
|  | err = -ENXIO; | 
|  | goto err; | 
|  | } | 
|  | pci_set_master(dev); | 
|  |  | 
|  | host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci), &dev->dev); | 
|  | if (!host) { | 
|  | PRINT_G(KERN_ERR, "Failed to allocate %s", "host structure"); | 
|  | goto err; | 
|  | } | 
|  | ohci = host->hostdata; | 
|  | ohci->dev = dev; | 
|  | ohci->host = host; | 
|  | ohci->init_state = OHCI_INIT_ALLOC_HOST; | 
|  | host->pdev = dev; | 
|  | pci_set_drvdata(dev, ohci); | 
|  |  | 
|  | /* We don't want hardware swapping */ | 
|  | pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0); | 
|  |  | 
|  | /* Some oddball Apple controllers do not order the selfid | 
|  | * properly, so we make up for it here.  */ | 
|  | #ifndef __LITTLE_ENDIAN | 
|  | /* XXX: Need a better way to check this. I'm wondering if we can | 
|  | * read the values of the OHCI1394_PCI_HCI_Control and the | 
|  | * noByteSwapData registers to see if they were not cleared to | 
|  | * zero. Should this work? Obviously it's not defined what these | 
|  | * registers will read when they aren't supported. Bleh! */ | 
|  | if (dev->vendor == PCI_VENDOR_ID_APPLE && | 
|  | dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { | 
|  | ohci->no_swap_incoming = 1; | 
|  | ohci->selfid_swap = 0; | 
|  | } else | 
|  | ohci->selfid_swap = 1; | 
|  | #endif | 
|  |  | 
|  |  | 
|  | #ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_FW | 
|  | #define PCI_DEVICE_ID_NVIDIA_NFORCE2_FW 0x006e | 
|  | #endif | 
|  |  | 
|  | /* These chipsets require a bit of extra care when checking after | 
|  | * a busreset.  */ | 
|  | if ((dev->vendor == PCI_VENDOR_ID_APPLE && | 
|  | dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) || | 
|  | (dev->vendor ==  PCI_VENDOR_ID_NVIDIA && | 
|  | dev->device == PCI_DEVICE_ID_NVIDIA_NFORCE2_FW)) | 
|  | ohci->check_busreset = 1; | 
|  |  | 
|  | /* We hardwire the MMIO length, since some CardBus adaptors | 
|  | * fail to report the right length.  Anyway, the ohci spec | 
|  | * clearly says it's 2kb, so this shouldn't be a problem. */ | 
|  | ohci_base = pci_resource_start(dev, 0); | 
|  | if (pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE) | 
|  | PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!", | 
|  | (unsigned long long)pci_resource_len(dev, 0)); | 
|  |  | 
|  | if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE, | 
|  | OHCI1394_DRIVER_NAME)) { | 
|  | PRINT_G(KERN_ERR, "MMIO resource (0x%llx - 0x%llx) unavailable", | 
|  | (unsigned long long)ohci_base, | 
|  | (unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE); | 
|  | goto err; | 
|  | } | 
|  | ohci->init_state = OHCI_INIT_HAVE_MEM_REGION; | 
|  |  | 
|  | ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE); | 
|  | if (ohci->registers == NULL) { | 
|  | PRINT_G(KERN_ERR, "Failed to remap registers"); | 
|  | err = -ENXIO; | 
|  | goto err; | 
|  | } | 
|  | ohci->init_state = OHCI_INIT_HAVE_IOMAPPING; | 
|  | DBGMSG("Remapped memory spaces reg 0x%p", ohci->registers); | 
|  |  | 
|  | /* csr_config rom allocation */ | 
|  | ohci->csr_config_rom_cpu = | 
|  | pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, | 
|  | &ohci->csr_config_rom_bus); | 
|  | if (ohci->csr_config_rom_cpu == NULL) { | 
|  | PRINT_G(KERN_ERR, "Failed to allocate %s", "buffer config rom"); | 
|  | goto err; | 
|  | } | 
|  | ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER; | 
|  |  | 
|  | /* self-id dma buffer allocation */ | 
|  | ohci->selfid_buf_cpu = | 
|  | pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, | 
|  | &ohci->selfid_buf_bus); | 
|  | if (ohci->selfid_buf_cpu == NULL) { | 
|  | PRINT_G(KERN_ERR, "Failed to allocate %s", "self-ID buffer"); | 
|  | goto err; | 
|  | } | 
|  | ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER; | 
|  |  | 
|  | if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff) | 
|  | PRINT(KERN_INFO, "SelfID buffer %p is not aligned on " | 
|  | "8Kb boundary... may cause problems on some CXD3222 chip", | 
|  | ohci->selfid_buf_cpu); | 
|  |  | 
|  | /* No self-id errors at startup */ | 
|  | ohci->self_id_errors = 0; | 
|  |  | 
|  | ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE; | 
|  | /* AR DMA request context allocation */ | 
|  | if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context, | 
|  | DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC, | 
|  | AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE, | 
|  | OHCI1394_AsReqRcvContextBase) < 0) { | 
|  | PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Req context"); | 
|  | goto err; | 
|  | } | 
|  | /* AR DMA response context allocation */ | 
|  | if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context, | 
|  | DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC, | 
|  | AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE, | 
|  | OHCI1394_AsRspRcvContextBase) < 0) { | 
|  | PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Resp context"); | 
|  | goto err; | 
|  | } | 
|  | /* AT DMA request context */ | 
|  | if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context, | 
|  | DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC, | 
|  | OHCI1394_AsReqTrContextBase) < 0) { | 
|  | PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Req context"); | 
|  | goto err; | 
|  | } | 
|  | /* AT DMA response context */ | 
|  | if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context, | 
|  | DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC, | 
|  | OHCI1394_AsRspTrContextBase) < 0) { | 
|  | PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Resp context"); | 
|  | goto err; | 
|  | } | 
|  | /* Start off with a soft reset, to clear everything to a sane | 
|  | * state. */ | 
|  | ohci_soft_reset(ohci); | 
|  |  | 
|  | /* Now enable LPS, which we need in order to start accessing | 
|  | * most of the registers.  In fact, on some cards (ALI M5251), | 
|  | * accessing registers in the SClk domain without LPS enabled | 
|  | * will lock up the machine. */ | 
|  | reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS); | 
|  |  | 
|  | /* Disable and clear interrupts */ | 
|  | reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); | 
|  |  | 
|  | /* Flush MMIO writes and wait to make sure we have full link enabled. */ | 
|  | reg_read(ohci, OHCI1394_Version); | 
|  | msleep(50); | 
|  |  | 
|  | /* Determine the number of available IR and IT contexts. */ | 
|  | ohci->nb_iso_rcv_ctx = | 
|  | get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); | 
|  | ohci->nb_iso_xmit_ctx = | 
|  | get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); | 
|  |  | 
|  | /* Set the usage bits for non-existent contexts so they can't | 
|  | * be allocated */ | 
|  | ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx; | 
|  | ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx; | 
|  |  | 
|  | INIT_LIST_HEAD(&ohci->iso_tasklet_list); | 
|  | spin_lock_init(&ohci->iso_tasklet_list_lock); | 
|  | ohci->ISO_channel_usage = 0; | 
|  | spin_lock_init(&ohci->IR_channel_lock); | 
|  |  | 
|  | spin_lock_init(&ohci->event_lock); | 
|  |  | 
|  | /* | 
|  | * interrupts are disabled, all right, but... due to IRQF_SHARED we | 
|  | * might get called anyway.  We'll see no event, of course, but | 
|  | * we need to get to that "no event", so enough should be initialized | 
|  | * by that point. | 
|  | */ | 
|  | err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED, | 
|  | OHCI1394_DRIVER_NAME, ohci); | 
|  | if (err) { | 
|  | PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq); | 
|  | goto err; | 
|  | } | 
|  | ohci->init_state = OHCI_INIT_HAVE_IRQ; | 
|  | ohci_initialize(ohci); | 
|  |  | 
|  | /* Set certain csr values */ | 
|  | host->csr.guid_hi = reg_read(ohci, OHCI1394_GUIDHi); | 
|  | host->csr.guid_lo = reg_read(ohci, OHCI1394_GUIDLo); | 
|  | host->csr.cyc_clk_acc = 100;  /* how do we determine clk accuracy? */ | 
|  | host->csr.max_rec = (reg_read(ohci, OHCI1394_BusOptions) >> 12) & 0xf; | 
|  | host->csr.lnk_spd = reg_read(ohci, OHCI1394_BusOptions) & 0x7; | 
|  |  | 
|  | if (phys_dma) { | 
|  | host->low_addr_space = | 
|  | (u64) reg_read(ohci, OHCI1394_PhyUpperBound) << 16; | 
|  | if (!host->low_addr_space) | 
|  | host->low_addr_space = OHCI1394_PHYS_UPPER_BOUND_FIXED; | 
|  | } | 
|  | host->middle_addr_space = OHCI1394_MIDDLE_ADDRESS_SPACE; | 
|  |  | 
|  | /* Tell the highlevel this host is ready */ | 
|  | if (hpsb_add_host(host)) { | 
|  | PRINT_G(KERN_ERR, "Failed to register host with highlevel"); | 
|  | goto err; | 
|  | } | 
|  | ohci->init_state = OHCI_INIT_DONE; | 
|  |  | 
|  | return 0; | 
|  | err: | 
|  | ohci1394_pci_remove(dev); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | static void ohci1394_pci_remove(struct pci_dev *dev) | 
|  | { | 
|  | struct ti_ohci *ohci; | 
|  | struct device *device; | 
|  |  | 
|  | ohci = pci_get_drvdata(dev); | 
|  | if (!ohci) | 
|  | goto out; | 
|  |  | 
|  | device = get_device(&ohci->host->device); | 
|  |  | 
|  | switch (ohci->init_state) { | 
|  | case OHCI_INIT_DONE: | 
|  | hpsb_remove_host(ohci->host); | 
|  |  | 
|  | /* Clear out BUS Options */ | 
|  | reg_write(ohci, OHCI1394_ConfigROMhdr, 0); | 
|  | reg_write(ohci, OHCI1394_BusOptions, | 
|  | (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) | | 
|  | 0x00ff0000); | 
|  | memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN); | 
|  |  | 
|  | case OHCI_INIT_HAVE_IRQ: | 
|  | /* Clear interrupt registers */ | 
|  | reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); | 
|  |  | 
|  | /* Disable IRM Contender */ | 
|  | set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4)); | 
|  |  | 
|  | /* Clear link control register */ | 
|  | reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); | 
|  |  | 
|  | /* Let all other nodes know to ignore us */ | 
|  | ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT); | 
|  |  | 
|  | /* Soft reset before we start - this disables | 
|  | * interrupts and clears linkEnable and LPS. */ | 
|  | ohci_soft_reset(ohci); | 
|  | free_irq(dev->irq, ohci); | 
|  |  | 
|  | case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE: | 
|  | /* The ohci_soft_reset() stops all DMA contexts, so we | 
|  | * dont need to do this.  */ | 
|  | free_dma_rcv_ctx(&ohci->ar_req_context); | 
|  | free_dma_rcv_ctx(&ohci->ar_resp_context); | 
|  | free_dma_trm_ctx(&ohci->at_req_context); | 
|  | free_dma_trm_ctx(&ohci->at_resp_context); | 
|  |  | 
|  | case OHCI_INIT_HAVE_SELFID_BUFFER: | 
|  | pci_free_consistent(dev, OHCI1394_SI_DMA_BUF_SIZE, | 
|  | ohci->selfid_buf_cpu, | 
|  | ohci->selfid_buf_bus); | 
|  |  | 
|  | case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER: | 
|  | pci_free_consistent(dev, OHCI_CONFIG_ROM_LEN, | 
|  | ohci->csr_config_rom_cpu, | 
|  | ohci->csr_config_rom_bus); | 
|  |  | 
|  | case OHCI_INIT_HAVE_IOMAPPING: | 
|  | iounmap(ohci->registers); | 
|  |  | 
|  | case OHCI_INIT_HAVE_MEM_REGION: | 
|  | release_mem_region(pci_resource_start(dev, 0), | 
|  | OHCI1394_REGISTER_SIZE); | 
|  |  | 
|  | case OHCI_INIT_ALLOC_HOST: | 
|  | pci_set_drvdata(dev, NULL); | 
|  | } | 
|  |  | 
|  | if (device) | 
|  | put_device(device); | 
|  | out: | 
|  | ohci1394_pmac_off(dev); | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_PM | 
|  | static int ohci1394_pci_suspend(struct pci_dev *dev, pm_message_t state) | 
|  | { | 
|  | int err; | 
|  | struct ti_ohci *ohci = pci_get_drvdata(dev); | 
|  |  | 
|  | if (!ohci) { | 
|  | printk(KERN_ERR "%s: tried to suspend nonexisting host\n", | 
|  | OHCI1394_DRIVER_NAME); | 
|  | return -ENXIO; | 
|  | } | 
|  | DBGMSG("suspend called"); | 
|  |  | 
|  | /* Clear the async DMA contexts and stop using the controller */ | 
|  | hpsb_bus_reset(ohci->host); | 
|  |  | 
|  | /* See ohci1394_pci_remove() for comments on this sequence */ | 
|  | reg_write(ohci, OHCI1394_ConfigROMhdr, 0); | 
|  | reg_write(ohci, OHCI1394_BusOptions, | 
|  | (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) | | 
|  | 0x00ff0000); | 
|  | reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); | 
|  | set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4)); | 
|  | reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); | 
|  | ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT); | 
|  | ohci_soft_reset(ohci); | 
|  |  | 
|  | free_irq(dev->irq, ohci); | 
|  | err = pci_save_state(dev); | 
|  | if (err) { | 
|  | PRINT(KERN_ERR, "pci_save_state failed with %d", err); | 
|  | return err; | 
|  | } | 
|  | err = pci_set_power_state(dev, pci_choose_state(dev, state)); | 
|  | if (err) | 
|  | DBGMSG("pci_set_power_state failed with %d", err); | 
|  | ohci1394_pmac_off(dev); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int ohci1394_pci_resume(struct pci_dev *dev) | 
|  | { | 
|  | int err; | 
|  | struct ti_ohci *ohci = pci_get_drvdata(dev); | 
|  |  | 
|  | if (!ohci) { | 
|  | printk(KERN_ERR "%s: tried to resume nonexisting host\n", | 
|  | OHCI1394_DRIVER_NAME); | 
|  | return -ENXIO; | 
|  | } | 
|  | DBGMSG("resume called"); | 
|  |  | 
|  | ohci1394_pmac_on(dev); | 
|  | pci_set_power_state(dev, PCI_D0); | 
|  | pci_restore_state(dev); | 
|  | err = pci_enable_device(dev); | 
|  | if (err) { | 
|  | PRINT(KERN_ERR, "pci_enable_device failed with %d", err); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | /* See ohci1394_pci_probe() for comments on this sequence */ | 
|  | ohci_soft_reset(ohci); | 
|  | reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS); | 
|  | reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); | 
|  | reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); | 
|  | reg_read(ohci, OHCI1394_Version); | 
|  | msleep(50); | 
|  |  | 
|  | err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED, | 
|  | OHCI1394_DRIVER_NAME, ohci); | 
|  | if (err) { | 
|  | PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | ohci_initialize(ohci); | 
|  |  | 
|  | hpsb_resume_host(ohci->host); | 
|  | return 0; | 
|  | } | 
|  | #endif /* CONFIG_PM */ | 
|  |  | 
|  | static struct pci_device_id ohci1394_pci_tbl[] = { | 
|  | { | 
|  | .class = 	PCI_CLASS_SERIAL_FIREWIRE_OHCI, | 
|  | .class_mask = 	PCI_ANY_ID, | 
|  | .vendor =	PCI_ANY_ID, | 
|  | .device =	PCI_ANY_ID, | 
|  | .subvendor =	PCI_ANY_ID, | 
|  | .subdevice =	PCI_ANY_ID, | 
|  | }, | 
|  | { 0, }, | 
|  | }; | 
|  |  | 
|  | MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl); | 
|  |  | 
|  | static struct pci_driver ohci1394_pci_driver = { | 
|  | .name =		OHCI1394_DRIVER_NAME, | 
|  | .id_table =	ohci1394_pci_tbl, | 
|  | .probe =	ohci1394_pci_probe, | 
|  | .remove =	ohci1394_pci_remove, | 
|  | #ifdef CONFIG_PM | 
|  | .resume =	ohci1394_pci_resume, | 
|  | .suspend =	ohci1394_pci_suspend, | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | /*********************************** | 
|  | * OHCI1394 Video Interface        * | 
|  | ***********************************/ | 
|  |  | 
|  | /* essentially the only purpose of this code is to allow another | 
|  | module to hook into ohci's interrupt handler */ | 
|  |  | 
|  | /* returns zero if successful, one if DMA context is locked up */ | 
|  | int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg) | 
|  | { | 
|  | int i=0; | 
|  |  | 
|  | /* stop the channel program if it's still running */ | 
|  | reg_write(ohci, reg, 0x8000); | 
|  |  | 
|  | /* Wait until it effectively stops */ | 
|  | while (reg_read(ohci, reg) & 0x400) { | 
|  | i++; | 
|  | if (i>5000) { | 
|  | PRINT(KERN_ERR, | 
|  | "Runaway loop while stopping context: %s...", msg ? msg : ""); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | mb(); | 
|  | udelay(10); | 
|  | } | 
|  | if (msg) PRINT(KERN_ERR, "%s: dma prg stopped", msg); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type, | 
|  | void (*func)(unsigned long), unsigned long data) | 
|  | { | 
|  | tasklet_init(&tasklet->tasklet, func, data); | 
|  | tasklet->type = type; | 
|  | /* We init the tasklet->link field, so we can list_del() it | 
|  | * without worrying whether it was added to the list or not. */ | 
|  | INIT_LIST_HEAD(&tasklet->link); | 
|  | } | 
|  |  | 
|  | int ohci1394_register_iso_tasklet(struct ti_ohci *ohci, | 
|  | struct ohci1394_iso_tasklet *tasklet) | 
|  | { | 
|  | unsigned long flags, *usage; | 
|  | int n, i, r = -EBUSY; | 
|  |  | 
|  | if (tasklet->type == OHCI_ISO_TRANSMIT) { | 
|  | n = ohci->nb_iso_xmit_ctx; | 
|  | usage = &ohci->it_ctx_usage; | 
|  | } | 
|  | else { | 
|  | n = ohci->nb_iso_rcv_ctx; | 
|  | usage = &ohci->ir_ctx_usage; | 
|  |  | 
|  | /* only one receive context can be multichannel (OHCI sec 10.4.1) */ | 
|  | if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) { | 
|  | if (test_and_set_bit(0, &ohci->ir_multichannel_used)) { | 
|  | return r; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); | 
|  |  | 
|  | for (i = 0; i < n; i++) | 
|  | if (!test_and_set_bit(i, usage)) { | 
|  | tasklet->context = i; | 
|  | list_add_tail(&tasklet->link, &ohci->iso_tasklet_list); | 
|  | r = 0; | 
|  | break; | 
|  | } | 
|  |  | 
|  | spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); | 
|  |  | 
|  | return r; | 
|  | } | 
|  |  | 
|  | void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci, | 
|  | struct ohci1394_iso_tasklet *tasklet) | 
|  | { | 
|  | unsigned long flags; | 
|  |  | 
|  | tasklet_kill(&tasklet->tasklet); | 
|  |  | 
|  | spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); | 
|  |  | 
|  | if (tasklet->type == OHCI_ISO_TRANSMIT) | 
|  | clear_bit(tasklet->context, &ohci->it_ctx_usage); | 
|  | else { | 
|  | clear_bit(tasklet->context, &ohci->ir_ctx_usage); | 
|  |  | 
|  | if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) { | 
|  | clear_bit(0, &ohci->ir_multichannel_used); | 
|  | } | 
|  | } | 
|  |  | 
|  | list_del(&tasklet->link); | 
|  |  | 
|  | spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); | 
|  | } | 
|  |  | 
|  | EXPORT_SYMBOL(ohci1394_stop_context); | 
|  | EXPORT_SYMBOL(ohci1394_init_iso_tasklet); | 
|  | EXPORT_SYMBOL(ohci1394_register_iso_tasklet); | 
|  | EXPORT_SYMBOL(ohci1394_unregister_iso_tasklet); | 
|  |  | 
|  | /*********************************** | 
|  | * General module initialization   * | 
|  | ***********************************/ | 
|  |  | 
|  | MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>"); | 
|  | MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers"); | 
|  | MODULE_LICENSE("GPL"); | 
|  |  | 
|  | static void __exit ohci1394_cleanup (void) | 
|  | { | 
|  | pci_unregister_driver(&ohci1394_pci_driver); | 
|  | } | 
|  |  | 
|  | static int __init ohci1394_init(void) | 
|  | { | 
|  | return pci_register_driver(&ohci1394_pci_driver); | 
|  | } | 
|  |  | 
|  | module_init(ohci1394_init); | 
|  | module_exit(ohci1394_cleanup); |