X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fieee1394%2Fohci1394.c;h=36e25ac823dc73c2f69c58e391dd4382af59de55;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=7c3f6e7bcdf70ff5400d64102cac7ebe1af7d2cc;hpb=e3f6fb6212a7102bdb56ba38fa1e98fe72950475;p=linux-2.6.git diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 7c3f6e7bc..36e25ac82 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -162,7 +162,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args) printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args) static char version[] __devinitdata = - "$Rev: 1223 $ Ben Collins "; + "$Rev: 1250 $ Ben Collins "; /* Module Parameters */ static int phys_dma = 1; @@ -482,7 +482,9 @@ static void ohci_initialize(struct ti_ohci *ohci) /* Put some defaults to these undefined bus options */ buf = reg_read(ohci, OHCI1394_BusOptions); - buf |= 0xE0000000; /* Enable IRMC, CMC and ISC */ + buf |= 0x60000000; /* Enable CMC and ISC */ + if (!hpsb_disable_irm) + 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); @@ -497,10 +499,12 @@ static void ohci_initialize(struct ti_ohci *ohci) reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); /* Enable cycle timer and cycle master and set the IRM - * contender bit in our self ID packets. */ - reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_CycleTimerEnable | + * contender bit in our self ID packets if appropriate. */ + reg_write(ohci, OHCI1394_LinkControlSet, + OHCI1394_LinkControl_CycleTimerEnable | OHCI1394_LinkControl_CycleMaster); - set_phy_reg_mask(ohci, 4, 0xc0); + set_phy_reg_mask(ohci, 4, PHY_04_LCTRL | + (hpsb_disable_irm ? 0 : PHY_04_CONTENDER)); /* Set up self-id dma buffer */ reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus); @@ -515,12 +519,6 @@ static void ohci_initialize(struct ti_ohci *ohci) /* Now get our max packet size */ ohci->max_packet_size = 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1); - - if (ohci->max_packet_size < 512) { - HPSB_ERR("warning: Invalid max packet size of %d, setting to 512", - ohci->max_packet_size); - ohci->max_packet_size = 512; - } /* Don't accept phy packets into AR request context */ reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); @@ -540,6 +538,9 @@ static void ohci_initialize(struct ti_ohci *ohci) /* Initialize AT dma */ initialize_dma_trm_ctx(&ohci->at_req_context); initialize_dma_trm_ctx(&ohci->at_resp_context); + + /* Initialize IR Legacy DMA channel mask */ + ohci->ir_legacy_channels = 0; /* * Accept AT requests from all nodes. This probably @@ -1029,6 +1030,8 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) case ISO_LISTEN_CHANNEL: { u64 mask; + struct dma_rcv_ctx *d = &ohci->ir_legacy_context; + int ir_legacy_active; if (arg<0 || arg>63) { PRINT(KERN_ERR, @@ -1037,22 +1040,6 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) return -EFAULT; } - /* activate the legacy IR context */ - if (ohci->ir_legacy_context.ohci == NULL) { - if (alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context, - DMA_CTX_ISO, 0, IR_NUM_DESC, - IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, - OHCI1394_IsoRcvContextBase) < 0) { - PRINT(KERN_ERR, "%s: failed to allocate an IR context", - __FUNCTION__); - return -ENOMEM; - } - ohci->ir_legacy_channels = 0; - initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1); - - DBGMSG("ISO receive legacy context activated"); - } - mask = (u64)0x1<IR_channel_lock, flags); @@ -1065,9 +1052,37 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) return -EFAULT; } + ir_legacy_active = ohci->ir_legacy_channels; + ohci->ISO_channel_usage |= mask; ohci->ir_legacy_channels |= mask; + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + + if (!ir_legacy_active) { + if (ohci1394_register_iso_tasklet(ohci, + &ohci->ir_legacy_tasklet) < 0) { + PRINT(KERN_ERR, "No IR DMA context available"); + return -EBUSY; + } + + /* the IR context can be assigned to any DMA context + * by ohci1394_register_iso_tasklet */ + d->ctx = ohci->ir_legacy_tasklet.context; + d->ctrlSet = OHCI1394_IsoRcvContextControlSet + + 32*d->ctx; + d->ctrlClear = OHCI1394_IsoRcvContextControlClear + + 32*d->ctx; + d->cmdPtr = OHCI1394_IsoRcvCommandPtr + 32*d->ctx; + d->ctxtMatch = OHCI1394_IsoRcvContextMatch + 32*d->ctx; + + initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1); + + PRINT(KERN_ERR, "IR legacy activated"); + } + + spin_lock_irqsave(&ohci->IR_channel_lock, flags); + if (arg>31) reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, 1<<(arg-32)); @@ -1117,9 +1132,9 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) if (ohci->ir_legacy_channels == 0) { stop_dma_rcv_ctx(&ohci->ir_legacy_context); - free_dma_rcv_ctx(&ohci->ir_legacy_context); - DBGMSG("ISO receive legacy context deactivated"); + DBGMSG("ISO legacy receive context stopped"); } + break; } default: @@ -1289,8 +1304,10 @@ static int ohci_iso_recv_init(struct hpsb_iso *iso) OHCI_ISO_RECEIVE, ohci_iso_recv_task, (unsigned long) iso); - if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) + if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) { + ret = -EBUSY; goto err; + } recv->task_active = 1; @@ -1915,8 +1932,10 @@ static int ohci_iso_xmit_init(struct hpsb_iso *iso) 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) + if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) { + ret = -EBUSY; goto err; + } xmit->task_active = 1; @@ -2545,6 +2564,10 @@ static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx) 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, @@ -2706,7 +2729,7 @@ static void dma_rcv_tasklet (unsigned long data) (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, - (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>10)&0x3f); + (cond_le32_to_cpu(d->spb[0], ohci->no_swap_incoming)>>10)&0x3f); ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f) == 0x11) ? 1 : 0; @@ -2769,7 +2792,7 @@ static void dma_trm_tasklet (unsigned long data) d->ctx); else DBGMSG("Packet sent to node %d tcode=0x%X tLabel=" - "0x%02X ack=0x%X spd=%d dataLength=%d ctx=%d", + "%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, @@ -2778,7 +2801,7 @@ static void dma_trm_tasklet (unsigned long data) d->ctx); else DBGMSG("Packet sent to node %d tcode=0x%X tLabel=" - "0x%02X ack=0x%X spd=%d data=0x%08X ctx=%d", + "%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]) @@ -2908,7 +2931,7 @@ static void free_dma_rcv_ctx(struct dma_rcv_ctx *d) kfree(d->prg_cpu); kfree(d->prg_bus); } - if (d->spb) kfree(d->spb); + kfree(d->spb); /* Mark this context as freed. */ d->ohci = NULL; @@ -2919,7 +2942,9 @@ 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; + int i, len; + static int num_allocs; + static char pool_name[20]; d->ohci = ohci; d->type = type; @@ -2963,9 +2988,19 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, free_dma_rcv_ctx(d); return -ENOMEM; } - - d->prg_pool = pci_pool_create("ohci1394 rcv prg", ohci->dev, + + 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++; + OHCI_DMA_ALLOC("dma_rcv prg pool"); for (i=0; inum_desc; i++) { @@ -3002,20 +3037,6 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, ohci1394_init_iso_tasklet(&ohci->ir_legacy_tasklet, OHCI_ISO_MULTICHANNEL_RECEIVE, dma_rcv_tasklet, (unsigned long) d); - if (ohci1394_register_iso_tasklet(ohci, - &ohci->ir_legacy_tasklet) < 0) { - PRINT(KERN_ERR, "No IR DMA context available"); - free_dma_rcv_ctx(d); - return -EBUSY; - } - - /* the IR context can be assigned to any DMA context - * by ohci1394_register_iso_tasklet */ - d->ctx = ohci->ir_legacy_tasklet.context; - d->ctrlSet = OHCI1394_IsoRcvContextControlSet + 32*d->ctx; - d->ctrlClear = OHCI1394_IsoRcvContextControlClear + 32*d->ctx; - d->cmdPtr = OHCI1394_IsoRcvCommandPtr + 32*d->ctx; - d->ctxtMatch = OHCI1394_IsoRcvContextMatch + 32*d->ctx; } else { d->ctrlSet = context_base + OHCI1394_ContextControlSet; d->ctrlClear = context_base + OHCI1394_ContextControlClear; @@ -3058,7 +3079,9 @@ 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; + int i, len; + static char pool_name[20]; + static int num_allocs=0; d->ohci = ohci; d->type = type; @@ -3080,8 +3103,17 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*)); memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t)); - d->prg_pool = pci_pool_create("ohci1394 trm prg", ohci->dev, + 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++; + OHCI_DMA_ALLOC("dma_rcv prg pool"); for (i = 0; i < d->num_desc; i++) { @@ -3353,10 +3385,19 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, ohci->ISO_channel_usage = 0; spin_lock_init(&ohci->IR_channel_lock); - /* the IR DMA context is allocated on-demand; mark it inactive */ - ohci->ir_legacy_context.ohci = NULL; + /* Allocate the IR DMA context right here so we don't have + * to do it in interrupt path - note that this doesn't + * waste much memory and avoids the jugglery required to + * allocate it in IRQ path. */ + if (alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context, + DMA_CTX_ISO, 0, IR_NUM_DESC, + IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, + OHCI1394_IsoRcvContextBase) < 0) { + FAIL(-ENOMEM, "Cannot allocate IR Legacy DMA context"); + } - /* same for the IT DMA context */ + /* We hopefully don't have to pre-allocate IT DMA like we did + * for IR DMA above. Allocate it on-demand and mark inactive. */ ohci->it_legacy_context.ohci = NULL; if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, @@ -3445,6 +3486,10 @@ static void ohci1394_pci_remove(struct pci_dev *pdev) /* Free IT dma */ free_dma_trm_ctx(&ohci->it_legacy_context); + /* Free IR legacy dma */ + free_dma_rcv_ctx(&ohci->ir_legacy_context); + + case OHCI_INIT_HAVE_SELFID_BUFFER: pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, ohci->selfid_buf_cpu, @@ -3510,7 +3555,7 @@ static int ohci1394_pci_resume (struct pci_dev *pdev) } -static int ohci1394_pci_suspend (struct pci_dev *pdev, u32 state) +static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state) { #ifdef CONFIG_PMAC_PBOOK { @@ -3676,7 +3721,7 @@ static void __exit ohci1394_cleanup (void) static int __init ohci1394_init(void) { - return pci_module_init(&ohci1394_pci_driver); + return pci_register_driver(&ohci1394_pci_driver); } module_init(ohci1394_init);