linux1394-cvslog Mailing List for IEEE 1394 for Linux (Page 3)
Brought to you by:
aeb,
bencollins
You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(10) |
Jul
(12) |
Aug
(8) |
Sep
(9) |
Oct
(4) |
Nov
(5) |
Dec
(5) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(7) |
Feb
(3) |
Mar
(15) |
Apr
(12) |
May
(5) |
Jun
(9) |
Jul
(32) |
Aug
(39) |
Sep
(42) |
Oct
(22) |
Nov
(28) |
Dec
(8) |
2002 |
Jan
(37) |
Feb
(47) |
Mar
(6) |
Apr
(29) |
May
(33) |
Jun
(9) |
Jul
(28) |
Aug
(30) |
Sep
(15) |
Oct
(75) |
Nov
(37) |
Dec
(31) |
2003 |
Jan
|
Feb
(89) |
Mar
(41) |
Apr
(13) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: SVN U. <ben...@li...> - 2003-03-05 00:14:16
|
Author: bencollins Date: 2003-03-04 19:13:26 -0500 (Tue, 04 Mar 2003) New Revision: 811 Removed: trunk/Config.help trunk/Config.in Modified: trunk/Makefile Log: Remove obsolete files. Remove unused portions of makefile. Modified: trunk/Makefile ============================================================================== --- trunk/Makefile (original) +++ trunk/Makefile 2003-03-04 19:13:27.000000000 -0500 @@ -18,13 +18,6 @@ clean-files := oui.c -ieee1394.o: $(ieee1394-objs) - $(LD) $(LDFLAGS) -r -o $@ $(ieee1394-objs) - -ifeq ($(obj),) -obj = . -endif - $(obj)/oui.o: $(obj)/oui.c $(obj)/oui.c: $(obj)/oui.db $(obj)/oui2c.sh $(CONFIG_SHELL) $(obj)/oui2c.sh < $(obj)/oui.db > $(obj)/oui.c Deleted: trunk/Config.help ============================================================================== --- trunk/Config.help (original) +++ trunk/Config.help 2003-03-04 19:13:27.000000000 -0500 @@ -1,136 +0,0 @@ -CONFIG_IEEE1394 - IEEE 1394 describes a high performance serial bus, which is also - known as FireWire(tm) or i.Link(tm) and is used for connecting all - sorts of devices (most notably digital video cameras) to your - computer. - - If you have FireWire hardware and want to use it, say Y here. This - is the core support only, you will also need to select a driver for - your IEEE 1394 adapter. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/modules.txt>. The module - will be called ieee1394.o. - -CONFIG_IEEE1394_PCILYNX - Say Y here if you have an IEEE-1394 controller with the Texas - Instruments PCILynx chip. Note: this driver is written for revision - 2 of this chip and may not work with revision 0. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/modules.txt>. The module - will be called pcilynx.o. - -CONFIG_IEEE1394_PCILYNX_LOCALRAM - This option makes the PCILynx driver use local RAM available on some - PCILynx setups for Packet Control Lists. Local RAM is random access - memory which resides on the PCILynx board as opposed to on your - computer's motherboard. Local RAM may speed up command processing - because no PCI transfers are necessary during use of the Packet - Control Lists. - - Note that there are no known PCILynx systems providing local RAM - except for the evaluation boards by Texas Instruments and that the - PCILynx does not reliably report missing RAM. This means that it is - dangerous to say Y here if you are not absolutely sure that your - board provides 64KB of local RAM. - - If unsure, say N. - -CONFIG_IEEE1394_PCILYNX_PORTS - This option enables driver code to access the RAM, ROM and AUX ports - of the PCILynx through character devices in /dev. If you don't know - what this is about then you won't need it. - - If unsure, say N. - -CONFIG_IEEE1394_OHCI1394 - Enable this driver if you have an IEEE 1394 controller based on the - OHCI-1394 specification. The current driver is only tested with OHCI - chipsets made by Texas Instruments and NEC. Most third-party vendors - use one of these chipsets. It should work with any OHCI-1394 - compliant card, however. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/modules.txt>. The module - will be called ohci1394.o. - -CONFIG_IEEE1394_VIDEO1394 - This option enables video device usage for OHCI-1394 cards. Enable - this option only if you have an IEEE 1394 video device connected to - an OHCI-1394 card. - -CONFIG_IEEE1394_DV1394 - This driver allows you to transmit and receive DV (digital video) - streams on an OHCI-1394 card using a simple frame-oriented - interface. - - The user-space API for dv1394 is documented in dv1394.h. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/modules.txt>. The module - will be called dv1394.o. - -CONFIG_IEEE1394_SBP2 - This option enables you to use SBP-2 devices connected to your IEEE - 1394 bus. SBP-2 devices include harddrives and DVD devices. - -CONFIG_IEEE1394_RAWIO - Say Y here if you want support for the raw device. This is generally - a good idea, so you should say Y here. The raw device enables - direct communication of user programs with the IEEE 1394 bus and - thus with the attached peripherals. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/modules.txt>. The module - will be called raw1394.o. - -CONFIG_IEEE1394_ETH1394 - Extremely Experimental! This driver is a Linux specific way to use your - IEEE1394 Host as an Ethernet type device. This is _NOT_ IP1394. - -CONFIG_IEEE1394_AMDTP - This option enables the Audio & Music Data Transmission Protocol - (IEC61883-6) driver, which implements audio transmission over - IEEE1394. - - The userspace interface is documented in amdtp.h. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/modules.txt>. The module - will be called amdtp.o. - -CONFIG_IEEE1394_CMP - This option enables the Connection Management Procedures - (IEC61883-1) driver, which implements input and output plugs. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/modules.txt>. The module - will be called amdtp.o. - -CONFIG_IEEE1394_VERBOSEDEBUG - If you say Y here, you will get very verbose debugging logs from the - subsystem which includes a dump of the header of every sent and - received packet. This can amount to a high amount of data collected - in a very short time which is usually also saved to disk by the - system logging daemons. - - Say Y if you really want or need the debugging output, everyone else - says N. - -CONFIG_IEEE1394_OUI_DB - If you say Y here, then an OUI list (vendor unique ID's) will be - compiled into the ieee1394 module. This doesn't really do much accept - being able to display the vendor of a hardware node. The downside is - that it adds about 300k to the size of the module, or kernel (depending - on whether you compile ieee1394 as a module, or static in the kernel). - - This option is not needed for userspace programs like gscanbus to show - this information. Deleted: trunk/Config.in ============================================================================== --- trunk/Config.in (original) +++ trunk/Config.in 2003-03-04 19:13:27.000000000 -0500 @@ -1,48 +0,0 @@ -# -*- shell-script -*- - -if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - mainmenu_option next_comment - comment 'IEEE 1394 (FireWire) support (EXPERIMENTAL)' - - dep_tristate 'IEEE 1394 (FireWire) support (EXPERIMENTAL)' CONFIG_IEEE1394 $CONFIG_PCI - - if [ "$CONFIG_IEEE1394" != "n" ]; then - comment "Subsystem Options" - bool ' Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG - bool ' OUI Database built-in' CONFIG_IEEE1394_OUI_DB - - comment "Host Controller Drivers" - - if [ "$CONFIG_I2C" != "" -a "$CONFIG_I2C_ALGOBIT" != "" ]; then - if [ "$CONFIG_I2C" != "n" -a "$CONFIG_I2C_ALGOBIT" != "n" ]; then - dep_tristate ' Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394 $CONFIG_I2C $CONFIG_I2C_ALGOBIT - else - comment ' Texas Instruments PCILynx requires I2C bit-banging' - fi - fi - - # Non-maintained pcilynx options - # if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then - # bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM - # bool ' Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS - # fi - - dep_tristate ' OHCI-1394 support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394 - - comment "Protocol Drivers" - dep_tristate ' OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394 - dep_tristate ' SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394 - if [ "$CONFIG_IEEE1394_SBP2" != "n" ]; then - bool ' Enable Phys DMA support for SBP2 (Debug)' CONFIG_IEEE1394_SBP2_PHYS_DMA - fi - dep_tristate ' Ethernet over 1394' CONFIG_IEEE1394_ETH1394 $CONFIG_IEEE1394 - dep_tristate ' OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394 - dep_tristate ' Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394 - dep_tristate ' IEC61883-1 Plug support' CONFIG_IEEE1394_CMP $CONFIG_IEEE1394 - - if [ "$CONFIG_IEEE1394_CMP" != "n" ]; then - dep_tristate ' IEC61883-6 (Audio transmission) support' CONFIG_IEEE1394_AMDTP $CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394_CMP - fi - fi - endmenu -fi |
From: SVN U. <dm...@li...> - 2003-03-01 01:48:16
|
Author: dmaas Date: 2003-02-28 20:47:27 -0500 (Fri, 28 Feb 2003) New Revision: 810 Modified: branches/linux-2.4/ieee1394.h branches/linux-2.4/ohci1394.c branches/linux-2.4/ohci1394.h Log: sync ohci1394 as much as possible with trunk Modified: branches/linux-2.4/ohci1394.c ============================================================================== --- branches/linux-2.4/ohci1394.c (original) +++ branches/linux-2.4/ohci1394.c 2003-02-28 20:47:29.000000000 -0500 @@ -182,12 +182,6 @@ static void ohci1394_pci_remove(struct pci_dev *pdev); #ifndef __LITTLE_ENDIAN -/* Swap a series of quads inplace. */ -static __inline__ void block_swab32(quadlet_t *data, size_t size) { - while (size--) - data[size] = swab32(data[size]); -} - static unsigned hdr_sizes[] = { 3, /* TCODE_WRITEQ */ @@ -205,16 +199,19 @@ }; /* Swap headers */ -static inline void packet_swab(quadlet_t *data, int tcode, int len) +static inline void packet_swab(quadlet_t *data, int tcode) { + size_t size = hdr_sizes[tcode]; + if (tcode > TCODE_LOCK_RESPONSE || hdr_sizes[tcode] == 0) return; - block_swab32(data, hdr_sizes[tcode]); + + while (size--) + data[size] = swab32(data[size]); } #else /* Don't waste cycles on same sex byte swaps */ -#define packet_swab(w,x,y) -#define block_swab32(x,y) +#define packet_swab(w,x) #endif /* !LITTLE_ENDIAN */ /*********************************** @@ -323,7 +320,7 @@ /* SelfID Ok, reset error counter. */ ohci->self_id_errors = 0; - + size = ((self_id_count & 0x00001FFC) >> 2) - 1; q++; @@ -387,12 +384,12 @@ "Running dma failed because Node ID == 63"); return -1; } - + /* Run the dma context */ reg_write(ohci, reg, 0x8000); - + if (msg) PRINT(KERN_DEBUG, ohci->id, "%s", msg); - + return 0; } @@ -406,11 +403,11 @@ 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? */ @@ -487,7 +484,7 @@ reg_write(ohci, reg, 0xffffffff); tmp = reg_read(ohci, reg); - + DBGMSG(ohci->id,"Iso contexts reg: %08x implemented: %08x", reg, tmp); /* Count the number of contexts */ @@ -585,7 +582,8 @@ reg_write(ohci, OHCI1394_HCControlClear, 0x40000000); /* Enable interrupts */ - reg_write(ohci, OHCI1394_IntMaskSet, + reg_write(ohci, OHCI1394_IntMaskSet, + OHCI1394_unrecoverableError | OHCI1394_masterIntEnable | OHCI1394_busReset | OHCI1394_selfIDComplete | @@ -653,19 +651,31 @@ } else { d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | (packet->header[0] & 0xFFFF); - 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]; - packet_swab(d->prg_cpu[idx]->data, packet->tcode, - packet->header_size>>2); + + 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]; + } + packet_swab(d->prg_cpu[idx]->data, packet->tcode); } if (packet->data_size) { /* block transmit */ - d->prg_cpu[idx]->begin.control = - cpu_to_le32(DMA_CTL_OUTPUT_MORE | - DMA_CTL_IMMEDIATE | 0x10); + 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 | @@ -724,7 +734,7 @@ d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | (packet->header[0] & 0xFFFF); d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; - packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2); + packet_swab(d->prg_cpu[idx]->data, packet->tcode); d->prg_cpu[idx]->begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE | @@ -869,7 +879,7 @@ 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); @@ -893,11 +903,11 @@ 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, ohci->id, "devctl command SET_BUS_ID err"); break; @@ -974,7 +984,7 @@ DBGMSG(ohci->id, "ISO receive legacy context activated"); } - + ohci->ISO_channel_usage |= mask; ohci->ir_legacy_channels |= mask; @@ -2186,10 +2196,52 @@ DBGMSG(ohci->id, "IntEvent: %08x", event); - /* Die right here an now */ if (event & OHCI1394_unrecoverableError) { - PRINT(KERN_ERR, ohci->id, "Unrecoverable error, shutting down card!"); - return; + int ctx; + PRINT(KERN_ERR, ohci->id, "Unrecoverable error!"); + + if (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800) + PRINT(KERN_ERR, ohci->id, "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, ohci->id, "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, ohci->id, "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, ohci->id, "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, ohci->id, "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, ohci->id, "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_cycleInconsistent) { @@ -2306,9 +2358,9 @@ isroot = (node_id & 0x40000000) != 0; DBGMSG(ohci->id, - "SelfID interrupt received " - "(phyid %d, %s)", phyid, - (isroot ? "root" : "not root")); + "SelfID interrupt received " + "(phyid %d, %s)", phyid, + (isroot ? "root" : "not root")); handle_selfid(ohci, host, phyid, isroot); @@ -2342,7 +2394,7 @@ hpsb_selfid_complete(host, phyid, isroot); } else - PRINT(KERN_ERR, ohci->id, + PRINT(KERN_ERR, ohci->id, "SelfID received outside of bus reset sequence"); selfid_not_valid: @@ -2520,7 +2572,7 @@ * bus reset. We always ignore it. */ if (tcode != OHCI1394_TCODE_PHY) { if (!ohci->no_swap_incoming) - packet_swab(d->spb, tcode, (length - 4) >> 2); + packet_swab(d->spb, tcode); DBGMSG(ohci->id, "Packet received from node" " %d ack=0x%02X spd=%d tcode=0x%X" " length=%d ctx=%d tlabel=%d", @@ -2715,11 +2767,11 @@ if (d->prg_cpu) { for (i=0; i<d->num_desc; i++) if (d->prg_cpu[i] && d->prg_bus[i]) { - pci_free_consistent( - d->ohci->dev, sizeof(struct dma_cmd), - d->prg_cpu[i], d->prg_bus[i]); + pci_pool_free(d->prg_pool, d->prg_cpu[i], d->prg_bus[i]); OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i); } + pci_pool_destroy(d->prg_pool); + OHCI_DMA_FREE("dma_rcv prg pool"); kfree(d->prg_cpu); kfree(d->prg_bus); } @@ -2779,6 +2831,10 @@ return -ENOMEM; } + d->prg_pool = pci_pool_create("ohci1394 rcv prg", ohci->dev, + sizeof(struct dma_cmd), 4, 0, SLAB_KERNEL); + OHCI_DMA_ALLOC("dma_rcv prg pool"); + for (i=0; i<d->num_desc; i++) { d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, d->buf_size, @@ -2794,11 +2850,8 @@ return -ENOMEM; } - - d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, - sizeof(struct dma_cmd), - d->prg_bus+i); - OHCI_DMA_ALLOC("consistent dma_rcv prg[%d]", i); + d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, SLAB_KERNEL, d->prg_bus+i); + OHCI_DMA_ALLOC("pool dma_rcv prg[%d]", i); if (d->prg_cpu[i] != NULL) { memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd)); @@ -2866,11 +2919,11 @@ if (d->prg_cpu) { for (i=0; i<d->num_desc; i++) if (d->prg_cpu[i] && d->prg_bus[i]) { - pci_free_consistent( - d->ohci->dev, sizeof(struct at_dma_prg), - d->prg_cpu[i], d->prg_bus[i]); - OHCI_DMA_FREE("consistent dma_trm prg[%d]", i); + pci_pool_free(d->prg_pool, d->prg_cpu[i], d->prg_bus[i]); + OHCI_DMA_FREE("pool dma_trm prg[%d]", i); } + pci_pool_destroy(d->prg_pool); + OHCI_DMA_FREE("dma_trm prg pool"); kfree(d->prg_cpu); kfree(d->prg_bus); } @@ -2906,11 +2959,13 @@ 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, + sizeof(struct at_dma_prg), 4, 0, SLAB_KERNEL); + OHCI_DMA_ALLOC("dma_rcv prg pool"); + for (i = 0; i < d->num_desc; i++) { - d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, - sizeof(struct at_dma_prg), - d->prg_bus+i); - OHCI_DMA_ALLOC("consistent dma_trm prg[%d]", i); + d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, SLAB_KERNEL, d->prg_bus+i); + OHCI_DMA_ALLOC("pool dma_trm prg[%d]", i); if (d->prg_cpu[i] != NULL) { memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg)); @@ -3150,7 +3205,7 @@ struct hpsb_host *host; struct ti_ohci *ohci; /* shortcut to currently handled device */ unsigned long ohci_base; - + if (version_printed++ == 0) PRINT_G(KERN_INFO, "%s", version); @@ -3226,7 +3281,7 @@ pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, &ohci->selfid_buf_bus); OHCI_DMA_ALLOC("consistent selfid_buf"); - + if (ohci->selfid_buf_cpu == NULL) FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets"); ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER; @@ -3349,10 +3404,10 @@ /* Free IR dma */ free_dma_rcv_ctx(&ohci->ir_legacy_context); - + /* Free IT dma */ free_dma_trm_ctx(&ohci->it_legacy_context); - + case OHCI_INIT_HAVE_SELFID_BUFFER: pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, ohci->selfid_buf_cpu, Modified: branches/linux-2.4/ohci1394.h ============================================================================== --- branches/linux-2.4/ohci1394.h (original) +++ branches/linux-2.4/ohci1394.h 2003-02-28 20:47:29.000000000 -0500 @@ -95,6 +95,7 @@ /* dma block descriptors */ struct dma_cmd **prg_cpu; dma_addr_t *prg_bus; + struct pci_pool *prg_pool; /* dma buffers */ quadlet_t **buf_cpu; @@ -121,6 +122,7 @@ /* dma block descriptors */ struct at_dma_prg **prg_cpu; dma_addr_t *prg_bus; + struct pci_pool *prg_pool; unsigned int prg_ind; unsigned int sent_ind; @@ -186,7 +188,7 @@ struct dma_trm_ctx at_resp_context; struct dma_trm_ctx at_req_context; - /* iso receive */ + /* iso receive */ int nb_iso_rcv_ctx; unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ unsigned long ir_multichannel_used; /* ditto */ Modified: branches/linux-2.4/ieee1394.h ============================================================================== --- branches/linux-2.4/ieee1394.h (original) +++ branches/linux-2.4/ieee1394.h 2003-02-28 20:47:29.000000000 -0500 @@ -15,6 +15,7 @@ #define TCODE_CYCLE_START 0x8 #define TCODE_LOCK_REQUEST 0x9 #define TCODE_ISO_DATA 0xa +#define TCODE_STREAM_DATA 0xa #define TCODE_LOCK_RESPONSE 0xb #define RCODE_COMPLETE 0x0 |
From: SVN U. <dm...@li...> - 2003-03-01 01:23:56
|
Author: dmaas Date: 2003-02-28 20:23:15 -0500 (Fri, 28 Feb 2003) New Revision: 809 Modified: branches/linux-2.4/ohci1394.c branches/linux-2.4/ohci1394.h Log: merge the rawiso implementation from trunk ohci1394.c Modified: branches/linux-2.4/ohci1394.c ============================================================================== --- branches/linux-2.4/ohci1394.c (original) +++ branches/linux-2.4/ohci1394.c 2003-02-28 20:23:16.000000000 -0500 @@ -26,12 +26,10 @@ * . Async Request Receive * . Async Response Transmit * . Iso Receive + * . Iso Transmit * . DMA mmap for iso receive * . Config ROM generation * - * Things implemented, but still in test phase: - * . Iso Transmit - * * Things not implemented: * . Async Stream Packets * . DMA error recovery @@ -75,6 +73,9 @@ * . Updated to 2.4.x module scheme (PCI aswell) * . Removed procfs support since it trashes random mem * . Config ROM generation + * + * Dan Maas <dm...@ma...> + * . New isochronous API (rawiso) */ #include <linux/config.h> @@ -112,6 +113,8 @@ #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" @@ -167,6 +170,15 @@ 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 @@ -417,10 +429,28 @@ 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 AR context */ + /* Run context */ reg_write(ohci, d->ctrlSet, 0x00008000); DBGMSG(ohci->id, "Receive DMA ctx=%d initialized", d->ctx); @@ -441,6 +471,11 @@ 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(ohci->id, "Transmit DMA ctx=%d initialized", d->ctx); } @@ -517,12 +552,6 @@ /* Don't accept phy packets into AR request context */ reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); - /* Set bufferFill, isochHeader, multichannel for IR context */ - reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000); - - /* Set the context match register to match on all tags */ - reg_write(ohci, OHCI1394_IsoRcvContextMatch, 0xf0000000); - /* Clear the interrupt mask */ reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); @@ -531,10 +560,6 @@ reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); - /* Clear the multi channel mask high and low registers */ - reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff); - reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff); - /* Initialize AR dma */ initialize_dma_rcv_ctx(&ohci->ar_req_context, 0); initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0); @@ -543,19 +568,6 @@ initialize_dma_trm_ctx(&ohci->at_req_context); initialize_dma_trm_ctx(&ohci->at_resp_context); - /* Initialize IR dma */ - initialize_dma_rcv_ctx(&ohci->ir_context, 1); - - /* Initialize IT dma */ - initialize_dma_trm_ctx(&ohci->it_context); - - /* Set up isoRecvIntMask to generate interrupts for context 0 - (thanks to Michael Greger for seeing that I forgot this) */ - reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001); - - /* Set up isoXmitIntMask to generate interrupts for context 0 */ - reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 0x00000001); - /* * Accept AT requests from all nodes. This probably * will have to be controlled from the subsystem @@ -599,7 +611,7 @@ } /* - * Insert a packet in the AT DMA fifo and generate the DMA prg + * 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 @@ -759,8 +771,8 @@ } /* - * This function fills the AT FIFO with the (eventual) pending packets - * and runs or wakes up the AT DMA prg if necessary. + * 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. */ @@ -776,7 +788,7 @@ idx = d->prg_ind; z = (p->data_size) ? 3 : 2; - /* insert the packets into the at dma fifo */ + /* insert the packets into the dma fifo */ while (d->free_prgs > 0 && !list_empty(&d->pending_list)) { struct hpsb_packet *p = driver_packet(d->pending_list.next); list_del(&p->driver_list); @@ -798,13 +810,15 @@ /* Wake up the dma context if necessary */ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { DBGMSG(ohci->id,"Waking transmit DMA ctx=%d",d->ctx); - reg_write(ohci, d->ctrlSet, 0x1000); } + + /* do this always, to avoid race condition */ + reg_write(ohci, d->ctrlSet, 0x1000); } return 1; } -/* Transmission of an async packet */ +/* 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; @@ -818,12 +832,36 @@ return 0; } - /* Decide wether we have an iso, a request, or a response packet */ + /* Decide whether we have an iso, a request, or a response packet */ if (packet->type == hpsb_raw) d = &ohci->at_req_context; - else if (packet->tcode == TCODE_ISO_DATA) - d = &ohci->it_context; - else if (packet->tcode & 0x02) + else if ((packet->tcode == TCODE_ISO_DATA) && (packet->type == hpsb_iso)) { + /* The legacy IT DMA context is initialized on first + * use. However, the alloc cannot be run from + * interrupt context, so we bail out if that is the + * case. I don't see anyone sending ISO packets from + * interrupt context anyway... */ + + if(ohci->it_legacy_context.ohci == NULL) { + if(in_interrupt()) { + PRINT(KERN_ERR, ohci->id, + "legacy IT context cannot be initialized during interrupt"); + return 0; + } + + if (alloc_dma_trm_ctx(ohci, &ohci->it_legacy_context, + DMA_CTX_ISO, 0, IT_NUM_DESC, + OHCI1394_IsoXmitContextBase) < 0) { + PRINT(KERN_ERR, ohci->id, + "error initializing legacy IT context"); + return 0; + } + + initialize_dma_trm_ctx(&ohci->it_legacy_context); + } + + d = &ohci->it_legacy_context; + } else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA)) d = &ohci->at_resp_context; else d = &ohci->at_req_context; @@ -919,8 +957,26 @@ spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); 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, ohci->id, + "%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(ohci->id, "ISO receive legacy context activated"); + } ohci->ISO_channel_usage |= mask; + ohci->ir_legacy_channels |= mask; if (arg>31) reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, @@ -957,6 +1013,7 @@ } ohci->ISO_channel_usage &= ~mask; + ohci->ir_legacy_channels &= ~mask; if (arg>31) reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, @@ -967,6 +1024,11 @@ spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); DBGMSG(ohci->id, "Listening disabled on channel %d", arg); + + if(ohci->ir_legacy_channels == 0) { + free_dma_rcv_ctx(&ohci->ir_legacy_context); + DBGMSG(ohci->id, "ISO receive legacy context deactivated"); + } break; } default: @@ -977,6 +1039,1063 @@ 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, + PACKET_PER_BUFFER_MODE } 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_bufferfill_task(unsigned long data); +static void ohci_iso_recv_packetperbuf_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), SLAB_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->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->id, "ohci_iso_recv_init: DMA buffer too small"); + goto err; + } + + /* iso->irq_interval is in packets - translate that to blocks */ + /* (err, sort of... 1 is always the safest value) */ + recv->block_irq_interval = iso->irq_interval / recv->nblocks; + if(recv->block_irq_interval < 1) + recv->block_irq_interval = 1; + else if(recv->block_irq_interval*4 > recv->nblocks) + recv->block_irq_interval = recv->nblocks/4; + } else { + int max_packet_size; + + recv->nblocks = iso->buf_packets; + 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->id, "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, + recv->dma_mode == BUFFER_FILL_MODE ? + ohci_iso_recv_bufferfill_task : + ohci_iso_recv_packetperbuf_task, + (unsigned long) iso); + + if(ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) + 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->id, "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; + 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 |= 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, recv->ohci->id, + "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]; + + /* '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); + + /* 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) +{ + int len; + + /* release the memory where the packet was */ + len = info->len; + + /* add the wasted space for padding to 4 bytes */ + if(len % 4) + len += 4 - (len % 4); + + /* add 8 bytes for the OHCI DMA data format overhead */ + len += 8; + + recv->released_bytes += 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; + + 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; + 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, recv->ohci->id, + "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, recv->ohci->id, + "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; + + /* payload is padded to 4 bytes */ + if(len % 4) { + recv->dma_offset += 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, cycle, channel, tag, sy); + } + + if(wake) + hpsb_iso_wake(iso); +} + +static void ohci_iso_recv_bufferfill_task(unsigned long data) +{ + struct hpsb_iso *iso = (struct hpsb_iso*) data; + struct ohci_iso_recv *recv = iso->hostdata; + + int loop; + + /* 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 = im->status >> 16; + + /* rescount is the number of bytes *remaining to be written* in the block */ + u16 rescount = 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, recv->ohci->id, + "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(&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(recv->ohci->id, "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(unsigned long data) +{ + struct hpsb_iso *iso = (struct hpsb_iso*) data; + struct ohci_iso_recv *recv = iso->hostdata; + int count; + int wake = 0; + + /* 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, recv->ohci->id, "IR DMA error - packet too long for buffer\n"); + } else if(event) { + PRINT(KERN_ERR, recv->ohci->id, "IR DMA error - OHCI error code 0x%02x\n", event); + } + + /* sync our view of the buffer */ + dma_region_sync(&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, 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); +} + + +/*********************************** + * rawiso ISO transmission * + ***********************************/ + +struct ohci_iso_xmit { + struct ti_ohci *ohci; + struct dma_prog_region prog; + struct ohci1394_iso_tasklet task; + int task_active; + + 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), SLAB_KERNEL); + if(!xmit) + return -ENOMEM; + + iso->hostdata = xmit; + xmit->ohci = iso->host->hostdata; + xmit->task_active = 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) + 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; + + /* 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, xmit->ohci->id, + "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; + 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, xmit->ohci->id, + "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; + + /* 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; + + 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, xmit->ohci->id, + "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(&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); + + /* 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; + + /* 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, xmit->ohci->id, "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_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 * ***************************************/ @@ -1038,7 +2157,7 @@ if (t->type == OHCI_ISO_TRANSMIT && tx_event & mask) tasklet_schedule(&t->tasklet); - if (t->type == OHCI_ISO_RECEIVE && rx_event & mask) + else if (rx_event & mask) tasklet_schedule(&t->tasklet); } @@ -1056,7 +2175,7 @@ unsigned long flags; /* Read and clear the interrupt event register. Don't clear - * the busReset event, though, this is done when we get the + * 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); @@ -1076,7 +2195,7 @@ if (event & OHCI1394_cycleInconsistent) { /* We subscribe to the cycleInconsistent event only to * clear the corresponding event bit... otherwise, - * isochronous cycleMatch DMA wont work. */ + * isochronous cycleMatch DMA won't work. */ DBGMSG(ohci->id, "OHCI1394_cycleInconsistent"); event &= ~OHCI1394_cycleInconsistent; } @@ -1178,7 +2297,7 @@ if (!(node_id & 0x80000000)) { PRINT(KERN_ERR, ohci->id, "SelfID received, but NodeID invalid " - "(probably new bus reset occured): %08X", + "(probably new bus reset occurred): %08X", node_id); goto selfid_not_valid; } @@ -1216,6 +2335,7 @@ reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0x00000000); reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0x00000000); } + DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n", reg_read(ohci,OHCI1394_PhyReqFilterHiSet), reg_read(ohci,OHCI1394_PhyReqFilterLoSet)); @@ -1252,8 +2372,10 @@ PRINT(KERN_INFO, ohci->id, "Waking dma ctx=%d ... processing is probably too slow", d->ctx); - reg_write(ohci, d->ctrlSet, 0x1000); } + + /* do this always, to avoid race condition */ + reg_write(ohci, d->ctrlSet, 0x1000); } #define cond_le32_to_cpu(data, noswap) \ @@ -1566,13 +2688,18 @@ return; DBGMSG(d->ohci->id, "Freeing dma_rcv_ctx %d", d->ctx); - - ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - if (d->type == DMA_CTX_ISO) - ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_tasklet); - else - tasklet_kill(&d->task); + if(d->ctrlClear) { + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); + + if (d->type == DMA_CTX_ISO) { + /* disable interrupts */ + reg_write(d->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << d->ctx); + ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_legacy_tasklet); + } else { + tasklet_kill(&d->task); + } + } if (d->buf_cpu) { for (i=0; i<d->num_desc; i++) @@ -1617,9 +2744,9 @@ d->buf_size = buf_size; d->split_buf_size = split_buf_size; - d->ctrlSet = context_base + OHCI1394_ContextControlSet; - d->ctrlClear = context_base + OHCI1394_ContextControlClear; - d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; + d->ctrlSet = 0; + d->ctrlClear = 0; + d->cmdPtr = 0; d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL); d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); @@ -1686,17 +2813,30 @@ spin_lock_init(&d->lock); if (type == DMA_CTX_ISO) { - ohci1394_init_iso_tasklet(&ohci->ir_tasklet, OHCI_ISO_RECEIVE, + 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_tasklet) < 0) { + &ohci->ir_legacy_tasklet) < 0) { PRINT(KERN_ERR, ohci->id, "No IR DMA context available"); free_dma_rcv_ctx(d); return -EBUSY; } - } - else + + /* 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; + d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; + tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long) d); + } return 0; } @@ -1710,12 +2850,18 @@ DBGMSG(d->ohci->id, "Freeing dma_trm_ctx %d", d->ctx); - ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); + if(d->ctrlClear) { + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); - if (d->type == DMA_CTX_ISO) - ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->it_tasklet); - else - tasklet_kill(&d->task); + if (d->type == DMA_CTX_ISO) { + /* disable interrupts */ + reg_write(d->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << d->ctx); + ohci1394_unregister_iso_tasklet(d->ohci, + &d->ohci->it_legacy_tasklet); + } else { + tasklet_kill(&d->task); + } + } if (d->prg_cpu) { for (i=0; i<d->num_desc; i++) @@ -1744,9 +2890,9 @@ d->type = type; d->ctx = ctx; d->num_desc = num_desc; - d->ctrlSet = context_base + OHCI1394_ContextControlSet; - d->ctrlClear = context_base + OHCI1394_ContextControlClear; - d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; + d->ctrlSet = 0; + d->ctrlClear = 0; + d->cmdPtr = 0; d->prg_cpu = kmalloc(d->num_desc * sizeof(struct at_dma_prg*), GFP_KERNEL); @@ -1780,17 +2926,26 @@ /* initialize tasklet */ if (type == DMA_CTX_ISO) { - ohci1394_init_iso_tasklet(&ohci->it_tasklet, OHCI_ISO_TRANSMIT, + ohci1394_init_iso_tasklet(&ohci->it_legacy_tasklet, OHCI_ISO_TRANSMIT, dma_trm_tasklet, (unsigned long) d); if (ohci1394_register_iso_tasklet(ohci, - &ohci->it_tasklet) < 0) { + &ohci->it_legacy_tasklet) < 0) { PRINT(KERN_ERR, ohci->id, "No IT DMA context available"); free_dma_trm_ctx(d); return -EBUSY; } - } - else + + /* IT can be assigned to any context by register_iso_tasklet */ + d->ctx = ohci->it_legacy_tasklet.context; + d->ctrlSet = OHCI1394_IsoXmitContextControlSet + 16 * d->ctx; + d->ctrlClear = OHCI1394_IsoXmitContextControlClear + 16 * d->ctx; + d->cmdPtr = OHCI1394_IsoXmitCommandPtr + 16 * d->ctx; + } else { + 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; } @@ -1969,7 +3124,7 @@ .get_rom = ohci_get_rom, .transmit_packet = ohci_transmit, .devctl = ohci_devctl, - .isoctl = NULL, /* temporary */ + .isoctl = ohci_isoctl, .hw_csr_reg = ohci_hw_csr_reg, }; @@ -2144,19 +3299,11 @@ ohci->ISO_channel_usage = 0; spin_lock_init(&ohci->IR_channel_lock); - /* IR DMA context */ - if (alloc_dma_rcv_ctx(ohci, &ohci->ir_context, - DMA_CTX_ISO, 0, IR_NUM_DESC, - IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, - OHCI1394_IsoRcvContextBase) < 0) - FAIL(-ENOMEM, "Failed to allocate IR context"); + /* the IR DMA context is allocated on-demand; mark it inactive */ + ohci->ir_legacy_context.ohci = NULL; - - /* IT DMA context allocation */ - if (alloc_dma_trm_ctx(ohci, &ohci->it_context, - DMA_CTX_ISO, 0, IT_NUM_DESC, - OHCI1394_IsoXmitContextBase) < 0) - FAIL(-ENOMEM, "Failed to allocate IT context"); + /* same for the IT DMA context */ + ohci->it_legacy_context.ohci = NULL; if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, OHCI1394_DRIVER_NAME, ohci)) @@ -2201,10 +3348,10 @@ free_dma_trm_ctx(&ohci->at_resp_context); /* Free IR dma */ - free_dma_rcv_ctx(&ohci->ir_context); + free_dma_rcv_ctx(&ohci->ir_legacy_context); /* Free IT dma */ - free_dma_trm_ctx(&ohci->it_context); + free_dma_trm_ctx(&ohci->it_legacy_context); case OHCI_INIT_HAVE_SELFID_BUFFER: pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, @@ -2253,10 +3400,10 @@ static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = { { - .class = PCI_CLASS_FIREWIRE_OHCI, - .class_mask = 0x00ffffff, - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, + .class = PCI_CLASS_FIREWIRE_OHCI, + .class_mask = ~0, + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, @@ -2281,7 +3428,7 @@ /* essentially the only purpose of this code is to allow another module to hook into ohci's interrupt handler */ -void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg) +int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg) { int i=0; @@ -2293,11 +3440,15 @@ i++; if (i>5000) { PRINT(KERN_ERR, ohci->id, - "Runaway loop while stopping context..."); - break; + "Runaway loop while stopping context: %s...", msg ? msg : ""); + return 1; } + + mb(); + udelay(10); } if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg); + return 0; } void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type, @@ -2306,7 +3457,7 @@ tasklet_init(&tasklet->tasklet, func, data); tasklet->type = type; /* We init the tasklet->link field, so we can list_del() it - * without worrying wether it was added to the list or not. */ + * without worrying whether it was added to the list or not. */ INIT_LIST_HEAD(&tasklet->link); } @@ -2323,6 +3474,13 @@ 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); @@ -2336,7 +3494,7 @@ } spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); - + return r; } @@ -2351,9 +3509,14 @@ if (tasklet->type == OHCI_ISO_TRANSMIT) clear_bit(tasklet->context, &ohci->it_ctx_usage); - else + 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); Modified: branches/linux-2.4/ohci1394.h ============================================================================== --- branches/linux-2.4/ohci1394.h (original) +++ branches/linux-2.4/ohci1394.h 2003-02-28 20:23:16.000000000 -0500 @@ -108,6 +108,7 @@ int ctrlClear; int ctrlSet; int cmdPtr; + int ctxtMatch; }; /* DMA transmit context */ @@ -143,7 +144,8 @@ struct tasklet_struct tasklet; struct list_head link; int context; - enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE } type; + enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE, + OHCI_ISO_MULTICHANNEL_RECEIVE } type; }; struct ti_ohci { @@ -168,7 +170,7 @@ /* dma buffer for self-id packets */ quadlet_t *selfid_buf_cpu; dma_addr_t selfid_buf_bus; - + /* buffer for csr config rom */ quadlet_t *csr_config_rom_cpu; dma_addr_t csr_config_rom_bus; @@ -184,19 +186,29 @@ struct dma_trm_ctx at_resp_context; struct dma_trm_ctx at_req_context; - /* iso receive */ - struct dma_rcv_ctx ir_context; - struct ohci1394_iso_tasklet ir_tasklet; - spinlock_t IR_channel_lock; + /* iso receive */ int nb_iso_rcv_ctx; unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ + unsigned long ir_multichannel_used; /* ditto */ + spinlock_t IR_channel_lock; + + /* iso receive (legacy API) */ + u64 ir_legacy_channels; /* note: this differs from ISO_channel_usage; + it only accounts for channels listened to + by the legacy API, so that we can know when + it is safe to free the legacy API context */ + + struct dma_rcv_ctx ir_legacy_context; + struct ohci1394_iso_tasklet ir_legacy_tasklet; /* iso transmit */ - struct dma_trm_ctx it_context; - struct ohci1394_iso_tasklet it_tasklet; int nb_iso_xmit_ctx; unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */ - + + /* iso transmit (legacy API) */ + struct dma_trm_ctx it_legacy_context; + struct ohci1394_iso_tasklet it_legacy_tasklet; + u64 ISO_channel_usage; /* IEEE-1394 part follows */ @@ -211,10 +223,10 @@ /* Tasklets for iso receive and transmit, used by video1394, * amdtp and dv1394 */ - + struct list_head iso_tasklet_list; spinlock_t iso_tasklet_list_lock; - + /* Swap the selfid buffer? */ unsigned int selfid_swap:1; /* Some Apple chipset seem to swap incoming headers for us */ @@ -292,6 +304,9 @@ #define OHCI1394_IsoRecvIntEventClear 0x0A4 #define OHCI1394_IsoRecvIntMaskSet 0x0A8 #define OHCI1394_IsoRecvIntMaskClear 0x0AC +#define OHCI1394_InitialBandwidthAvailable 0x0B0 +#define OHCI1394_InitialChannelsAvailableHi 0x0B4 +#define OHCI1394_InitialChannelsAvailableLo 0x0B8 #define OHCI1394_FairnessControl 0x0DC #define OHCI1394_LinkControlSet 0x0E0 #define OHCI1394_LinkControlClear 0x0E4 @@ -388,12 +403,12 @@ truncated */ #define EVT_OVERRUN 0x5 /* A recv FIFO overflowed on reception of ISO packet */ -#define EVT_DESCRIPTOR_READ 0x6 /* An unrecoverable error occured while host was +#define EVT_DESCRIPTOR_READ 0x6 /* An unrecoverable error occurred while host was reading a descriptor block */ -#define EVT_DATA_READ 0x7 /* An error occured while host controller was +#define EVT_DATA_READ 0x7 /* An error occurred while host controller was attempting to read from host memory in the data stage of descriptor processing */ -#define EVT_DATA_WRITE 0x8 /* An error occured while host controller was +#define EVT_DATA_WRITE 0x8 /* An error occurred while host controller was attempting to write either during the data stage of descriptor processing, or when processing a single 16-bit host memory write */ @@ -422,8 +437,8 @@ void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci, struct ohci1394_iso_tasklet *tasklet); -void ohci1394_stop_context (struct ti_ohci *ohci, int reg, char *msg); +/* returns zero if successful, one if DMA context is locked up */ +int ohci1394_stop_context (struct ti_ohci *ohci, int reg, char *msg); struct ti_ohci *ohci1394_get_struct(int card_num); #endif - |
From: SVN U. <dm...@li...> - 2003-03-01 00:25:53
|
Author: dmaas Date: 2003-02-28 19:24:50 -0500 (Fri, 28 Feb 2003) New Revision: 808 Added: branches/linux-2.4/iso.c branches/linux-2.4/iso.h branches/linux-2.4/raw1394-private.h Modified: branches/linux-2.4/Makefile branches/linux-2.4/dv1394.c branches/linux-2.4/hosts.h branches/linux-2.4/ieee1394-ioctl.h branches/linux-2.4/ieee1394_core.c branches/linux-2.4/ohci1394.c branches/linux-2.4/raw1394.c branches/linux-2.4/raw1394.h Log: sync raw1394 and iso with trunk (rawiso merge part 1) Added: branches/linux-2.4/iso.h ============================================================================== --- branches/linux-2.4/iso.h (original) +++ branches/linux-2.4/iso.h 2003-02-28 19:24:52.000000000 -0500 @@ -0,0 +1,184 @@ +/* + * IEEE 1394 for Linux + * + * kernel ISO transmission/reception + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#ifndef IEEE1394_ISO_H +#define IEEE1394_ISO_H + +#include "hosts.h" +#include "dma.h" + +/* high-level ISO interface */ + +/* This API sends and receives isochronous packets on a large, + virtually-contiguous kernel memory buffer. The buffer may be mapped + into a user-space process for zero-copy transmission and reception. + + There are no explicit boundaries between packets in the buffer. A + packet may be transmitted or received at any location. However, + low-level drivers may impose certain restrictions on alignment or + size of packets. (e.g. in OHCI no packet may cross a page boundary, + and packets should be quadlet-aligned) +*/ + +/* Packet descriptor - the API maintains a ring buffer of these packet + descriptors in kernel memory (hpsb_iso.infos[]). */ + +struct hpsb_iso_packet_info { + /* offset of data payload relative to the first byte of the buffer */ + __u32 offset; + + /* length of the data payload, in bytes (not including the isochronous header) */ + __u16 len; + + /* (recv only) the cycle number (mod 8000) on which the packet was received */ + __u16 cycle; + + /* (recv only) channel on which the packet was received */ + __u8 channel; + + /* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */ + __u8 tag; + __u8 sy; +}; + +enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 }; + +struct hpsb_iso { + enum hpsb_iso_type type; + + /* pointer to low-level driver and its private data */ + struct hpsb_host *host; + void *hostdata; + + /* a function to be called (from interrupt context) after + outgoing packets have been sent, or incoming packets have + arrived */ + void (*callback)(struct hpsb_iso*); + + /* wait for buffer space */ + wait_queue_head_t waitq; + + int speed; /* SPEED_100, 200, or 400 */ + int channel; /* -1 if multichannel */ + + /* greatest # of packets between interrupts - controls + the maximum latency of the buffer */ + int irq_interval; + + /* the buffer for packet data payloads */ + struct dma_region data_buf; + + /* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */ + unsigned int buf_size; + + /* ringbuffer of packet descriptors in regular kernel memory */ + struct hpsb_iso_packet_info *infos; + + /* # of packets in the ringbuffer */ + unsigned int buf_packets; + + /* protects packet cursors */ + spinlock_t lock; + + /* the index of the next packet that will be produced + or consumed by the user */ + int first_packet; + + /* the index of the next packet that will be transmitted + or received by the 1394 hardware */ + int pkt_dma; + + /* how many packets, starting at first_packet: + (transmit) are ready to be filled with data + (receive) contain received data */ + int n_ready_packets; + + /* how many times the buffer has overflowed or underflowed */ + atomic_t overflows; + + /* private flags to track initialization progress */ +#define HPSB_ISO_DRIVER_INIT (1<<0) +#define HPSB_ISO_DRIVER_STARTED (1<<1) + unsigned int flags; + + /* # of packets left to prebuffer (xmit only) */ + int prebuffer; + + /* starting cycle for DMA (xmit only) */ + int start_cycle; + + /* cycle at which next packet will be transmitted, + -1 if not known */ + int xmit_cycle; +}; + +/* functions available to high-level drivers (e.g. raw1394) */ + +/* allocate the buffer and DMA context */ + +struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int speed, + int irq_interval, + void (*callback)(struct hpsb_iso*)); + +/* note: if channel = -1, multi-channel receive is enabled */ +struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int irq_interval, + void (*callback)(struct hpsb_iso*)); + +/* multi-channel only */ +int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel); +int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel); +int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask); + +/* start/stop DMA */ +int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle, int prebuffer); +int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle, int tag_mask, int sync); +void hpsb_iso_stop(struct hpsb_iso *iso); + +/* deallocate buffer and DMA context */ +void hpsb_iso_shutdown(struct hpsb_iso *iso); + +/* queue a packet for transmission. 'offset' is relative to the beginning of the + DMA buffer, where the packet's data payload should already have been placed */ +int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy); + +/* wait until all queued packets have been transmitted to the bus */ +int hpsb_iso_xmit_sync(struct hpsb_iso *iso); + +/* N packets have been read out of the buffer, re-use the buffer space */ +int hpsb_iso_recv_release_packets(struct hpsb_iso *recv, unsigned int n_packets); + +/* returns # of packets ready to send or receive */ +int hpsb_iso_n_ready(struct hpsb_iso *iso); + +/* the following are callbacks available to low-level drivers */ + +/* call after a packet has been transmitted to the bus (interrupt context is OK) + 'cycle' is the _exact_ cycle the packet was sent on + 'error' should be non-zero if some sort of error occurred when sending the packet +*/ +void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error); + +/* call after a packet has been received (interrupt context OK) */ +void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, + u16 cycle, u8 channel, u8 tag, u8 sy); + +/* call to wake waiting processes after buffer space has opened up. */ +void hpsb_iso_wake(struct hpsb_iso *iso); + +#endif /* IEEE1394_ISO_H */ Modified: branches/linux-2.4/ieee1394_core.c ============================================================================== --- branches/linux-2.4/ieee1394_core.c (original) +++ branches/linux-2.4/ieee1394_core.c 2003-02-28 19:24:52.000000000 -0500 @@ -43,6 +43,7 @@ #include "nodemgr.h" #include "ieee1394_hotplug.h" #include "dma.h" +#include "iso.h" /* * Disable the nodemgr detection and config rom reading functionality. @@ -1144,14 +1145,17 @@ module_exit(ieee1394_cleanup); /* Exported symbols */ + +/** hosts.c **/ EXPORT_SYMBOL(hpsb_alloc_host); EXPORT_SYMBOL(hpsb_add_host); EXPORT_SYMBOL(hpsb_remove_host); EXPORT_SYMBOL(hpsb_ref_host); EXPORT_SYMBOL(hpsb_unref_host); + +/** ieee1394_core.c **/ EXPORT_SYMBOL(hpsb_speedto_str); EXPORT_SYMBOL(hpsb_add_packet_complete_task); - EXPORT_SYMBOL(alloc_hpsb_packet); EXPORT_SYMBOL(free_hpsb_packet); EXPORT_SYMBOL(hpsb_send_packet); @@ -1161,7 +1165,12 @@ EXPORT_SYMBOL(hpsb_selfid_complete); EXPORT_SYMBOL(hpsb_packet_sent); EXPORT_SYMBOL(hpsb_packet_received); +EXPORT_SYMBOL(ieee1394_register_chardev); +EXPORT_SYMBOL(ieee1394_unregister_chardev); +EXPORT_SYMBOL(ieee1394_devfs_handle); +EXPORT_SYMBOL(ieee1394_procfs_entry); +/** ieee1394_transactions.c **/ EXPORT_SYMBOL(get_tlabel); EXPORT_SYMBOL(free_tlabel); EXPORT_SYMBOL(fill_async_readquad); @@ -1188,6 +1197,7 @@ EXPORT_SYMBOL(hpsb_write); EXPORT_SYMBOL(hpsb_lock); +/** highlevel.c **/ EXPORT_SYMBOL(hpsb_register_highlevel); EXPORT_SYMBOL(hpsb_unregister_highlevel); EXPORT_SYMBOL(hpsb_register_addrspace); @@ -1202,6 +1212,7 @@ EXPORT_SYMBOL(highlevel_remove_host); EXPORT_SYMBOL(highlevel_host_reset); +/** nodemgr.c **/ EXPORT_SYMBOL(hpsb_guid_get_entry); EXPORT_SYMBOL(hpsb_nodeid_get_entry); EXPORT_SYMBOL(hpsb_node_fill_packet); @@ -1214,12 +1225,6 @@ EXPORT_SYMBOL(hpsb_unregister_protocol); EXPORT_SYMBOL(hpsb_release_unit_directory); -EXPORT_SYMBOL(ieee1394_register_chardev); -EXPORT_SYMBOL(ieee1394_unregister_chardev); -EXPORT_SYMBOL(ieee1394_devfs_handle); - -EXPORT_SYMBOL(ieee1394_procfs_entry); - /** dma.c **/ EXPORT_SYMBOL(dma_prog_region_init); EXPORT_SYMBOL(dma_prog_region_alloc); @@ -1231,3 +1236,21 @@ EXPORT_SYMBOL(dma_region_mmap); EXPORT_SYMBOL(dma_region_offset_to_bus); +/** iso.c **/ +EXPORT_SYMBOL(hpsb_iso_xmit_init); +EXPORT_SYMBOL(hpsb_iso_recv_init); +EXPORT_SYMBOL(hpsb_iso_xmit_start); +EXPORT_SYMBOL(hpsb_iso_recv_start); +EXPORT_SYMBOL(hpsb_iso_recv_listen_channel); +EXPORT_SYMBOL(hpsb_iso_recv_unlisten_channel); +EXPORT_SYMBOL(hpsb_iso_recv_set_channel_mask); +EXPORT_SYMBOL(hpsb_iso_stop); +EXPORT_SYMBOL(hpsb_iso_shutdown); +EXPORT_SYMBOL(hpsb_iso_xmit_queue_packet); +EXPORT_SYMBOL(hpsb_iso_xmit_sync); +EXPORT_SYMBOL(hpsb_iso_recv_release_packets); +EXPORT_SYMBOL(hpsb_iso_n_ready); +EXPORT_SYMBOL(hpsb_iso_packet_sent); +EXPORT_SYMBOL(hpsb_iso_packet_received); +EXPORT_SYMBOL(hpsb_iso_wake); + Modified: branches/linux-2.4/ohci1394.c ============================================================================== --- branches/linux-2.4/ohci1394.c (original) +++ branches/linux-2.4/ohci1394.c 2003-02-28 19:24:52.000000000 -0500 @@ -1969,6 +1969,7 @@ .get_rom = ohci_get_rom, .transmit_packet = ohci_transmit, .devctl = ohci_devctl, + .isoctl = NULL, /* temporary */ .hw_csr_reg = ohci_hw_csr_reg, }; Modified: branches/linux-2.4/ieee1394-ioctl.h ============================================================================== --- branches/linux-2.4/ieee1394-ioctl.h (original) +++ branches/linux-2.4/ieee1394-ioctl.h 2003-02-28 19:24:52.000000000 -0500 @@ -68,4 +68,38 @@ #define VIDEO1394_IOC_LISTEN_POLL_BUFFER \ _IOWR('#', 0x18, struct video1394_wait) + +/* Raw1394's ISO interface */ +#define RAW1394_IOC_ISO_XMIT_INIT \ + _IOW ('#', 0x1a, struct raw1394_iso_status) +#define RAW1394_IOC_ISO_RECV_INIT \ + _IOWR('#', 0x1b, struct raw1394_iso_status) +#define RAW1394_IOC_ISO_RECV_START \ + _IOC (_IOC_WRITE, '#', 0x1c, sizeof(int) * 3) +#define RAW1394_IOC_ISO_XMIT_START \ + _IOC (_IOC_WRITE, '#', 0x1d, sizeof(int) * 2) +#define RAW1394_IOC_ISO_XMIT_RECV_STOP \ + _IO ('#', 0x1e) +#define RAW1394_IOC_ISO_GET_STATUS \ + _IOR ('#', 0x1f, struct raw1394_iso_status) +#define RAW1394_IOC_ISO_SHUTDOWN \ + _IO ('#', 0x20) +#define RAW1394_IOC_ISO_QUEUE_ACTIVITY \ + _IO ('#', 0x21) +#define RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL \ + _IOW ('#', 0x22, unsigned char) +#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL \ + _IOW ('#', 0x23, unsigned char) +#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK \ + _IOW ('#', 0x24, __u64) +#define RAW1394_IOC_ISO_RECV_PACKETS \ + _IOW ('#', 0x25, struct raw1394_iso_packets) +#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS \ + _IOW ('#', 0x26, unsigned int) +#define RAW1394_IOC_ISO_XMIT_PACKETS \ + _IOW ('#', 0x27, struct raw1394_iso_packets) +#define RAW1394_IOC_ISO_XMIT_SYNC \ + _IO ('#', 0x28) + + #endif /* __IEEE1394_IOCTL_H */ Modified: branches/linux-2.4/raw1394.c ============================================================================== --- branches/linux-2.4/raw1394.c (original) +++ branches/linux-2.4/raw1394.c 2003-02-28 19:24:52.000000000 -0500 @@ -46,9 +46,10 @@ #include "ieee1394_core.h" #include "hosts.h" #include "highlevel.h" +#include "iso.h" #include "ieee1394_transactions.h" #include "raw1394.h" - +#include "raw1394-private.h" #if BITS_PER_LONG == 64 #define int2ptr(x) ((void *)x) @@ -90,10 +91,10 @@ static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store, u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags); static struct hpsb_address_ops arm_ops = { - read: arm_read, - write: arm_write, - lock: arm_lock, - lock64: arm_lock64, + .read = arm_read, + .write = arm_write, + .lock = arm_lock, + .lock64 = arm_lock64, }; static void queue_complete_cb(struct pending_request *req); @@ -132,18 +133,25 @@ kfree(req); } +/* fi->reqlists_lock must be taken */ +static void __queue_complete_req(struct pending_request *req) +{ + struct file_info *fi = req->file_info; + list_del(&req->list); + list_add_tail(&req->list, &fi->req_complete); + + up(&fi->complete_sem); + wake_up_interruptible(&fi->poll_wait_complete); +} + static void queue_complete_req(struct pending_request *req) { unsigned long flags; struct file_info *fi = req->file_info; spin_lock_irqsave(&fi->reqlists_lock, flags); - list_del(&req->list); - list_add_tail(&req->list, &fi->req_complete); + __queue_complete_req(req); spin_unlock_irqrestore(&fi->reqlists_lock, flags); - - up(&fi->complete_sem); - wake_up_interruptible(&fi->poll_wait_complete); } static void queue_complete_cb(struct pending_request *req) @@ -2000,6 +2008,323 @@ return retval; } +/* rawiso operations */ + +/* check if any RAW1394_REQ_RAWISO_ACTIVITY event is already in the + * completion queue (reqlists_lock must be taken) */ +static inline int __rawiso_event_in_queue(struct file_info *fi) +{ + struct list_head *lh; + struct pending_request *req; + + list_for_each(lh, &fi->req_complete) { + req = list_entry(lh, struct pending_request, list); + if(req->req.type == RAW1394_REQ_RAWISO_ACTIVITY) { + return 1; + } + } + + return 0; +} + +/* put a RAWISO_ACTIVITY event in the queue, if one isn't there already */ +static void queue_rawiso_event(struct file_info *fi) +{ + unsigned long flags; + + spin_lock_irqsave(&fi->reqlists_lock, flags); + + /* only one ISO activity event may be in the queue */ + if(!__rawiso_event_in_queue(fi)) { + struct pending_request *req = __alloc_pending_request(SLAB_ATOMIC); + + if(req) { + req->file_info = fi; + req->req.type = RAW1394_REQ_RAWISO_ACTIVITY; + req->req.generation = get_hpsb_generation(fi->host); + __queue_complete_req(req); + } else { + /* on allocation failure, signal an overflow */ + if(fi->iso_handle) { + atomic_inc(&fi->iso_handle->overflows); + } + } + } + spin_unlock_irqrestore(&fi->reqlists_lock, flags); +} + +static void rawiso_activity_cb(struct hpsb_iso *iso) +{ + unsigned long flags; + struct list_head *lh; + struct host_info *hi; + + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(iso->host); + + if (hi != NULL) { + list_for_each(lh, &hi->file_info_list) { + struct file_info *fi = list_entry(lh, struct file_info, list); + if(fi->iso_handle == iso) + queue_rawiso_event(fi); + } + } + + spin_unlock_irqrestore(&host_info_lock, flags); +} + +/* helper function - gather all the kernel iso status bits for returning to user-space */ +static void raw1394_iso_fill_status(struct hpsb_iso *iso, struct raw1394_iso_status *stat) +{ + stat->config.data_buf_size = iso->buf_size; + stat->config.buf_packets = iso->buf_packets; + stat->config.channel = iso->channel; + stat->config.speed = iso->speed; + stat->config.irq_interval = iso->irq_interval; + stat->n_packets = hpsb_iso_n_ready(iso); + stat->overflows = atomic_read(&iso->overflows); + stat->xmit_cycle = iso->xmit_cycle; +} + +static int raw1394_iso_xmit_init(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_status stat; + + if(copy_from_user(&stat, uaddr, sizeof(stat))) + return -EFAULT; + + fi->iso_handle = hpsb_iso_xmit_init(fi->host, + stat.config.data_buf_size, + stat.config.buf_packets, + stat.config.channel, + stat.config.speed, + stat.config.irq_interval, + rawiso_activity_cb); + if(!fi->iso_handle) + return -ENOMEM; + + fi->iso_state = RAW1394_ISO_XMIT; + + raw1394_iso_fill_status(fi->iso_handle, &stat); + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; + + /* queue an event to get things started */ + rawiso_activity_cb(fi->iso_handle); + + return 0; +} + +static int raw1394_iso_recv_init(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_status stat; + + if(copy_from_user(&stat, uaddr, sizeof(stat))) + return -EFAULT; + + fi->iso_handle = hpsb_iso_recv_init(fi->host, + stat.config.data_buf_size, + stat.config.buf_packets, + stat.config.channel, + stat.config.irq_interval, + rawiso_activity_cb); + if(!fi->iso_handle) + return -ENOMEM; + + fi->iso_state = RAW1394_ISO_RECV; + + raw1394_iso_fill_status(fi->iso_handle, &stat); + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; + return 0; +} + +static int raw1394_iso_get_status(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_status stat; + struct hpsb_iso *iso = fi->iso_handle; + + raw1394_iso_fill_status(fi->iso_handle, &stat); + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; + + /* reset overflow counter */ + atomic_set(&iso->overflows, 0); + + return 0; +} + +/* copy N packet_infos out of the ringbuffer into user-supplied array */ +static int raw1394_iso_recv_packets(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_packets upackets; + unsigned int packet = fi->iso_handle->first_packet; + int i; + + if(copy_from_user(&upackets, uaddr, sizeof(upackets))) + return -EFAULT; + + if(upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle)) + return -EINVAL; + + /* ensure user-supplied buffer is accessible and big enough */ + if(verify_area(VERIFY_WRITE, upackets.infos, + upackets.n_packets * sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + /* copy the packet_infos out */ + for(i = 0; i < upackets.n_packets; i++) { + if(__copy_to_user(&upackets.infos[i], + &fi->iso_handle->infos[packet], + sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + packet = (packet + 1) % fi->iso_handle->buf_packets; + } + + return 0; +} + +/* copy N packet_infos from user to ringbuffer, and queue them for transmission */ +static int raw1394_iso_send_packets(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_packets upackets; + int i, rv; + + if(copy_from_user(&upackets, uaddr, sizeof(upackets))) + return -EFAULT; + + if(upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle)) + return -EINVAL; + + /* ensure user-supplied buffer is accessible and big enough */ + if(verify_area(VERIFY_READ, upackets.infos, + upackets.n_packets * sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + /* copy the infos structs in and queue the packets */ + for(i = 0; i < upackets.n_packets; i++) { + struct raw1394_iso_packet_info info; + + if(__copy_from_user(&info, &upackets.infos[i], + sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset, + info.len, info.tag, info.sy); + if(rv) + return rv; + } + + return 0; +} + +static void raw1394_iso_shutdown(struct file_info *fi) +{ + if(fi->iso_handle) + hpsb_iso_shutdown(fi->iso_handle); + + fi->iso_handle = NULL; + fi->iso_state = RAW1394_ISO_INACTIVE; +} + +/* mmap the rawiso xmit/recv buffer */ +static int raw1394_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct file_info *fi = file->private_data; + + if(fi->iso_state == RAW1394_ISO_INACTIVE) + return -EINVAL; + + return dma_region_mmap(&fi->iso_handle->data_buf, file, vma); +} + +/* ioctl is only used for rawiso operations */ +static int raw1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct file_info *fi = file->private_data; + + switch(fi->iso_state) { + case RAW1394_ISO_INACTIVE: + switch(cmd) { + case RAW1394_IOC_ISO_XMIT_INIT: + return raw1394_iso_xmit_init(fi, (void*) arg); + case RAW1394_IOC_ISO_RECV_INIT: + return raw1394_iso_recv_init(fi, (void*) arg); + default: + break; + } + break; + case RAW1394_ISO_RECV: + switch(cmd) { + case RAW1394_IOC_ISO_RECV_START: { + /* copy args from user-space */ + int args[3]; + if(copy_from_user(&args[0], (void*) arg, sizeof(args))) + return -EFAULT; + return hpsb_iso_recv_start(fi->iso_handle, args[0], args[1], args[2]); + } + case RAW1394_IOC_ISO_XMIT_RECV_STOP: + hpsb_iso_stop(fi->iso_handle); + return 0; + case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL: + return hpsb_iso_recv_listen_channel(fi->iso_handle, arg); + case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL: + return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg); + case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK: { + /* copy the u64 from user-space */ + u64 mask; + if(copy_from_user(&mask, (void*) arg, sizeof(mask))) + return -EFAULT; + return hpsb_iso_recv_set_channel_mask(fi->iso_handle, mask); + } + case RAW1394_IOC_ISO_GET_STATUS: + return raw1394_iso_get_status(fi, (void*) arg); + case RAW1394_IOC_ISO_RECV_PACKETS: + return raw1394_iso_recv_packets(fi, (void*) arg); + case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS: + return hpsb_iso_recv_release_packets(fi->iso_handle, arg); + case RAW1394_IOC_ISO_SHUTDOWN: + raw1394_iso_shutdown(fi); + return 0; + case RAW1394_IOC_ISO_QUEUE_ACTIVITY: + queue_rawiso_event(fi); + return 0; + } + break; + case RAW1394_ISO_XMIT: + switch(cmd) { + case RAW1394_IOC_ISO_XMIT_START: { + /* copy two ints from user-space */ + int args[2]; + if(copy_from_user(&args[0], (void*) arg, sizeof(args))) + return -EFAULT; + return hpsb_iso_xmit_start(fi->iso_handle, args[0], args[1]); + } + case RAW1394_IOC_ISO_XMIT_SYNC: + return hpsb_iso_xmit_sync(fi->iso_handle); + case RAW1394_IOC_ISO_XMIT_RECV_STOP: + hpsb_iso_stop(fi->iso_handle); + return 0; + case RAW1394_IOC_ISO_GET_STATUS: + return raw1394_iso_get_status(fi, (void*) arg); + case RAW1394_IOC_ISO_XMIT_PACKETS: + return raw1394_iso_send_packets(fi, (void*) arg); + case RAW1394_IOC_ISO_SHUTDOWN: + raw1394_iso_shutdown(fi); + return 0; + case RAW1394_IOC_ISO_QUEUE_ACTIVITY: + queue_rawiso_event(fi); + return 0; + } + break; + default: + break; + } + + return -EINVAL; +} + static unsigned int raw1394_poll(struct file *file, poll_table *pt) { struct file_info *fi = file->private_data; @@ -2060,6 +2385,9 @@ struct arm_addr *arm_addr = NULL; int another_host; + if(fi->iso_state != RAW1394_ISO_INACTIVE) + raw1394_iso_shutdown(fi); + for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { hpsb_unlisten_channel(hl_handle, fi->host, i); @@ -2121,7 +2449,7 @@ spin_unlock_irq(&host_info_lock); if (fail > 0) { printk(KERN_ERR "raw1394: during addr_list-release " - "error(s) occured \n"); + "error(s) occurred \n"); } while (!done) { @@ -2167,7 +2495,9 @@ static struct file_operations file_ops = { .owner = THIS_MODULE, .read = raw1394_read, - .write = raw1394_write, + .write = raw1394_write, + .mmap = raw1394_mmap, + .ioctl = raw1394_ioctl, .poll = raw1394_poll, .open = raw1394_open, .release = raw1394_release, Modified: branches/linux-2.4/raw1394.h ============================================================================== --- branches/linux-2.4/raw1394.h (original) +++ branches/linux-2.4/raw1394.h 2003-02-28 19:24:52.000000000 -0500 @@ -1,8 +1,7 @@ #ifndef IEEE1394_RAW1394_H #define IEEE1394_RAW1394_H -#define RAW1394_DEVICE_MAJOR 171 -#define RAW1394_DEVICE_NAME "raw1394" +/* header for the raw1394 API that is exported to user-space */ #define RAW1394_KERNELAPI_VERSION 4 @@ -36,10 +35,11 @@ #define RAW1394_REQ_PHYPACKET 500 /* kernel to user */ -#define RAW1394_REQ_BUS_RESET 10000 -#define RAW1394_REQ_ISO_RECEIVE 10001 -#define RAW1394_REQ_FCP_REQUEST 10002 -#define RAW1394_REQ_ARM 10003 +#define RAW1394_REQ_BUS_RESET 10000 +#define RAW1394_REQ_ISO_RECEIVE 10001 +#define RAW1394_REQ_FCP_REQUEST 10002 +#define RAW1394_REQ_ARM 10003 +#define RAW1394_REQ_RAWISO_ACTIVITY 10004 /* error codes */ #define RAW1394_ERROR_NONE 0 @@ -93,21 +93,21 @@ }; typedef struct arm_request { - nodeid_t destination_nodeid; - nodeid_t source_nodeid; - nodeaddr_t destination_offset; - u8 tlabel; - u8 tcode; - u_int8_t extended_transaction_code; - u_int32_t generation; - arm_length_t buffer_length; - byte_t *buffer; + __u16 destination_nodeid; + __u16 source_nodeid; + __u64 destination_offset; + __u8 tlabel; + __u8 tcode; + __u8 extended_transaction_code; + __u32 generation; + __u16 buffer_length; + __u8 *buffer; } *arm_request_t; typedef struct arm_response { - int response_code; - arm_length_t buffer_length; - byte_t *buffer; + __s32 response_code; + __u16 buffer_length; + __u8 *buffer; } *arm_response_t; typedef struct arm_request_response { @@ -115,68 +115,60 @@ struct arm_response *response; } *arm_request_response_t; -#ifdef __KERNEL__ +/* rawiso API */ +#include "ieee1394-ioctl.h" -struct iso_block_store { - atomic_t refcount; - size_t data_size; - quadlet_t data[0]; +/* per-packet metadata embedded in the ringbuffer */ +/* must be identical to hpsb_iso_packet_info in iso.h! */ +struct raw1394_iso_packet_info { + __u32 offset; + __u16 len; + __u16 cycle; /* recv only */ + __u8 channel; /* recv only */ + __u8 tag; + __u8 sy; }; -struct file_info { - struct list_head list; - - enum { opened, initialized, connected } state; - unsigned int protocol_version; - - struct hpsb_host *host; +/* argument for RAW1394_ISO_RECV/XMIT_PACKETS ioctls */ +struct raw1394_iso_packets { + __u32 n_packets; + struct raw1394_iso_packet_info *infos; +}; - struct list_head req_pending; - struct list_head req_complete; - struct semaphore complete_sem; - spinlock_t reqlists_lock; - wait_queue_head_t poll_wait_complete; +struct raw1394_iso_config { + /* size of packet data buffer, in bytes (will be rounded up to PAGE_SIZE) */ + __u32 data_buf_size; - struct list_head addr_list; + /* # of packets to buffer */ + __u32 buf_packets; - u8 *fcp_buffer; + /* iso channel (set to -1 for multi-channel recv) */ + __s32 channel; - u64 listen_channels; - quadlet_t *iso_buffer; - size_t iso_buffer_length; + /* xmit only - iso transmission speed */ + __u8 speed; - u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */ + /* max. latency of buffer, in packets (-1 if you don't care) */ + __s32 irq_interval; }; -struct arm_addr { - struct list_head addr_list; /* file_info list */ - u64 start, end; - u64 arm_tag; - u8 access_rights; - u8 notification_options; - u8 client_transactions; - u64 recvb; - u16 rec_length; - u8 *addr_space_buffer; /* accessed by read/write/lock */ -}; +/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */ +struct raw1394_iso_status { + /* current settings */ + struct raw1394_iso_config config; -struct pending_request { - struct list_head list; - struct file_info *file_info; - struct hpsb_packet *packet; - struct tq_struct tq; - struct iso_block_store *ibs; - quadlet_t *data; - int free_data; - struct raw1394_request req; -}; + /* number of packets waiting to be filled with data (ISO transmission) + or containing data received (ISO reception) */ + __u32 n_packets; -struct host_info { - struct list_head list; - struct hpsb_host *host; - struct list_head file_info_list; -}; + /* approximate number of packets dropped due to overflow or + underflow of the packet buffer (a value of zero guarantees + that no packets have been dropped) */ + __u32 overflows; -#endif /* __KERNEL__ */ + /* cycle number at which next packet will be transmitted; + -1 if not known */ + __s16 xmit_cycle; +}; #endif /* IEEE1394_RAW1394_H */ Added: branches/linux-2.4/raw1394-private.h ============================================================================== --- branches/linux-2.4/raw1394-private.h (original) +++ branches/linux-2.4/raw1394-private.h 2003-02-28 19:24:52.000000000 -0500 @@ -0,0 +1,79 @@ +#ifndef IEEE1394_RAW1394_PRIVATE_H +#define IEEE1394_RAW1394_PRIVATE_H + +/* header for definitions that are private to the raw1394 driver + and not visible to user-space */ + +#define RAW1394_DEVICE_MAJOR 171 +#define RAW1394_DEVICE_NAME "raw1394" + +struct iso_block_store { + atomic_t refcount; + size_t data_size; + quadlet_t data[0]; +}; + +enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0, + RAW1394_ISO_RECV = 1, + RAW1394_ISO_XMIT = 2 }; + +struct file_info { + struct list_head list; + + enum { opened, initialized, connected } state; + unsigned int protocol_version; + + struct hpsb_host *host; + + struct list_head req_pending; + struct list_head req_complete; + struct semaphore complete_sem; + spinlock_t reqlists_lock; + wait_queue_head_t poll_wait_complete; + + struct list_head addr_list; + + u8 *fcp_buffer; + + /* old ISO API */ + u64 listen_channels; + quadlet_t *iso_buffer; + size_t iso_buffer_length; + + u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */ + + /* new rawiso API */ + enum raw1394_iso_state iso_state; + struct hpsb_iso *iso_handle; +}; + +struct arm_addr { + struct list_head addr_list; /* file_info list */ + u64 start, end; + u64 arm_tag; + u8 access_rights; + u8 notification_options; + u8 client_transactions; + u64 recvb; + u16 rec_length; + u8 *addr_space_buffer; /* accessed by read/write/lock */ +}; + +struct pending_request { + struct list_head list; + struct file_info *file_info; + struct hpsb_packet *packet; + struct tq_struct tq; + struct iso_block_store *ibs; + quadlet_t *data; + int free_data; + struct raw1394_request req; +}; + +struct host_info { + struct list_head list; + struct hpsb_host *host; + struct list_head file_info_list; +}; + +#endif /* IEEE1394_RAW1394_PRIVATE_H */ Modified: branches/linux-2.4/Makefile ============================================================================== --- branches/linux-2.4/Makefile (original) +++ branches/linux-2.4/Makefile 2003-02-28 19:24:52.000000000 -0500 @@ -4,11 +4,11 @@ O_TARGET := ieee1394drv.o -export-objs := ieee1394_core.o ohci1394.o cmp.o +export-objs := ieee1394_core.o ohci1394.o cmp.o iso.o list-multi := ieee1394.o ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ - highlevel.o csr.o nodemgr.o dma.o + highlevel.o csr.o nodemgr.o dma.o iso.o obj-$(CONFIG_IEEE1394) += ieee1394.o obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o Modified: branches/linux-2.4/hosts.h ============================================================================== --- branches/linux-2.4/hosts.h (original) +++ branches/linux-2.4/hosts.h 2003-02-28 19:24:52.000000000 -0500 @@ -19,6 +19,7 @@ #define CSR_CONFIG_ROM_SIZE 0x100 struct hpsb_packet; +struct hpsb_iso; struct hpsb_host { struct list_head host_list; @@ -109,6 +110,31 @@ ISO_UNLISTEN_CHANNEL }; +enum isoctl_cmd { + /* rawiso API - see iso.h for the meanings of these commands + * INIT = allocate resources + * START = begin transmission/reception + * STOP = halt transmission/reception + * QUEUE/RELEASE = produce/consume packets + * SHUTDOWN = deallocate resources + */ + + XMIT_INIT, + XMIT_START, + XMIT_STOP, + XMIT_QUEUE, + XMIT_SHUTDOWN, + + RECV_INIT, + RECV_LISTEN_CHANNEL, /* multi-channel only */ + RECV_UNLISTEN_CHANNEL, /* multi-channel only */ + RECV_SET_CHANNEL_MASK, /* multi-channel only; arg is a *u64 */ + RECV_START, + RECV_STOP, + RECV_RELEASE, + RECV_SHUTDOWN, +}; + enum reset_types { /* 166 microsecond reset -- only type of reset available on non-1394a capable IEEE 1394 controllers */ @@ -146,6 +172,12 @@ */ int (*devctl) (struct hpsb_host *host, enum devctl_cmd command, int arg); + /* rawiso transmission/reception functions. Return 0 on success, -1 + * (or -EXXX errno code) on failure. If the low-level driver does not + * support the rawiso API, set isoctl to NULL. + */ + int (*isoctl) (struct hpsb_iso *iso, enum isoctl_cmd command, unsigned long arg); + /* This function is mainly to redirect local CSR reads/locks to the iso * management registers (bus manager id, bandwidth available, channels * available) to the hardware registers in OHCI. reg is 0,1,2,3 for bus Added: branches/linux-2.4/iso.c ============================================================================== --- branches/linux-2.4/iso.c (original) +++ branches/linux-2.4/iso.c 2003-02-28 19:24:52.000000000 -0500 @@ -0,0 +1,439 @@ +/* + * IEEE 1394 for Linux + * + * kernel ISO transmission/reception + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include <linux/slab.h> +#include "iso.h" + +void hpsb_iso_stop(struct hpsb_iso *iso) +{ + if(!iso->flags & HPSB_ISO_DRIVER_STARTED) + return; + + iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? + XMIT_STOP : RECV_STOP, 0); + iso->flags &= ~HPSB_ISO_DRIVER_STARTED; +} + +void hpsb_iso_shutdown(struct hpsb_iso *iso) +{ + if(iso->flags & HPSB_ISO_DRIVER_INIT) { + hpsb_iso_stop(iso); + iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? + XMIT_SHUTDOWN : RECV_SHUTDOWN, 0); + iso->flags &= ~HPSB_ISO_DRIVER_INIT; + } + + dma_region_free(&iso->data_buf); + kfree(iso->infos); + kfree(iso); +} + +static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_iso_type type, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int irq_interval, + void (*callback)(struct hpsb_iso*)) +{ + struct hpsb_iso *iso; + int dma_direction; + + /* make sure driver supports the ISO API */ + if(!host->driver->isoctl) { + printk(KERN_INFO "ieee1394: host driver '%s' does not support the rawiso API\n", + host->driver->name); + return NULL; + } + + /* sanitize parameters */ + + if(buf_packets < 2) + buf_packets = 2; + + if(irq_interval < 1 || irq_interval > buf_packets / 2) + irq_interval = buf_packets / 2; + + if(channel < -1 || channel >= 64) + return NULL; + + /* channel = -1 is OK for multi-channel recv but not for xmit */ + if(type == HPSB_ISO_XMIT && channel < 0) + return NULL; + + /* allocate and write the struct hpsb_iso */ + + iso = kmalloc(sizeof(*iso), SLAB_KERNEL); + if(!iso) + return NULL; + + /* allocate ringbuffer of packet descriptors */ + iso->infos = kmalloc(buf_packets * sizeof(struct hpsb_iso_packet_info), SLAB_KERNEL); + if(!iso->infos) + return NULL; + + iso->type = type; + iso->host = host; + iso->hostdata = NULL; + iso->callback = callback; + init_waitqueue_head(&iso->waitq); + iso->channel = channel; + iso->irq_interval = irq_interval; + dma_region_init(&iso->data_buf); + iso->buf_size = round_up_to_page(data_buf_size); + iso->buf_packets = buf_packets; + iso->pkt_dma = 0; + iso->first_packet = 0; + spin_lock_init(&iso->lock); + + if(iso->type == HPSB_ISO_XMIT) { + iso->n_ready_packets = iso->buf_packets; + dma_direction = PCI_DMA_TODEVICE; + } else { + iso->n_ready_packets = 0; + dma_direction = PCI_DMA_FROMDEVICE; + } + + atomic_set(&iso->overflows, 0); + iso->flags = 0; + iso->prebuffer = 0; + + /* allocate the packet buffer */ + if(dma_region_alloc(&iso->data_buf, iso->buf_size, host->pdev, dma_direction)) + goto err; + + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +int hpsb_iso_n_ready(struct hpsb_iso* iso) +{ + unsigned long flags; + int val; + + spin_lock_irqsave(&iso->lock, flags); + val = iso->n_ready_packets; + spin_unlock_irqrestore(&iso->lock, flags); + + return val; +} + + +struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int speed, + int irq_interval, + void (*callback)(struct hpsb_iso*)) +{ + struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT, + data_buf_size, buf_packets, + channel, irq_interval, callback); + if(!iso) + return NULL; + + iso->speed = speed; + + /* tell the driver to start working */ + if(host->driver->isoctl(iso, XMIT_INIT, 0)) + goto err; + + iso->flags |= HPSB_ISO_DRIVER_INIT; + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int irq_interval, + void (*callback)(struct hpsb_iso*)) +{ + struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV, + data_buf_size, buf_packets, + channel, irq_interval, callback); + if(!iso) + return NULL; + + /* tell the driver to start working */ + if(host->driver->isoctl(iso, RECV_INIT, 0)) + goto err; + + iso->flags |= HPSB_ISO_DRIVER_INIT; + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel) +{ + if(iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64) + return -EINVAL; + return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel); +} + +int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel) +{ + if(iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64) + return -EINVAL; + return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel); +} + +int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask) +{ + if(iso->type != HPSB_ISO_RECV || iso->channel != -1) + return -EINVAL; + return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK, (unsigned long) &mask); +} + +static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle) +{ + int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle); + if(retval) + return retval; + + iso->flags |= HPSB_ISO_DRIVER_STARTED; + return retval; +} + +int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer) +{ + if(iso->type != HPSB_ISO_XMIT) + return -1; + + if(iso->flags & HPSB_ISO_DRIVER_STARTED) + return 0; + + if(cycle < -1) + cycle = -1; + else if(cycle >= 8000) + cycle %= 8000; + + iso->xmit_cycle = cycle; + + if(prebuffer < 0) + prebuffer = iso->buf_packets; + else if(prebuffer == 0) + prebuffer = 1; + + if(prebuffer > iso->buf_packets) + prebuffer = iso->buf_packets; + + iso->prebuffer = prebuffer; + + /* remember the starting cycle; DMA will commence from xmit_queue_packets() + once enough packets have been buffered */ + iso->start_cycle = cycle; + + return 0; +} + +int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync) +{ + int retval = 0; + int isoctl_args[3]; + + if(iso->type != HPSB_ISO_RECV) + return -1; + + if(iso->flags & HPSB_ISO_DRIVER_STARTED) + return 0; + + if(cycle < -1) + cycle = -1; + else if(cycle >= 8000) + cycle %= 8000; + + isoctl_args[0] = cycle; + + if(tag_mask < 0) + /* match all tags */ + tag_mask = 0xF; + isoctl_args[1] = tag_mask; + + isoctl_args[2] = sync; + + retval = iso->host->driver->isoctl(iso, RECV_START, (unsigned long) &isoctl_args[0]); + if(retval) + return retval; + + iso->flags |= HPSB_ISO_DRIVER_STARTED; + return retval; +} + +/* check to make sure the user has not supplied bogus values of offset/len + that would cause the kernel to access memory outside the buffer */ + +static int hpsb_iso_check_offset_len(struct hpsb_iso *iso, + unsigned int offset, unsigned short len, + unsigned int *out_offset, unsigned short *out_len) +{ + if(offset >= iso->buf_size) + return -EFAULT; + + /* make sure the packet does not go beyond the end of the buffer */ + if(offset + len > iso->buf_size) + return -EFAULT; + + /* check for wrap-around */ + if(offset + len < offset) + return -EFAULT; + + /* now we can trust 'offset' and 'length' */ + *out_offset = offset; + *out_len = len; + + return 0; +} + + +int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy) +{ + struct hpsb_iso_packet_info *info; + unsigned long flags; + int rv; + + if(iso->type != HPSB_ISO_XMIT) + return -EINVAL; + + /* is there space in the buffer? */ + if(iso->n_ready_packets <= 0) { + return -EBUSY; + } + + info = &iso->infos[iso->first_packet]; + + /* check for bogus offset/length */ + if(hpsb_iso_check_offset_len(iso, offset, len, &info->offset, &info->len)) + return -EFAULT; + + info->tag = tag; + info->sy = sy; + + spin_lock_irqsave(&iso->lock, flags); + + rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long) info); + if(rv) + goto out; + + /* increment cursors */ + iso->first_packet = (iso->first_packet+1) % iso->buf_packets; + iso->xmit_cycle = (iso->xmit_cycle+1) % 8000; + iso->n_ready_packets--; + + if(iso->prebuffer != 0) { + iso->prebuffer--; + if(iso->prebuffer <= 0) { + iso->prebuffer = 0; + rv = do_iso_xmit_start(iso, iso->start_cycle); + } + } + +out: + spin_unlock_irqrestore(&iso->lock, flags); + return rv; +} + +int hpsb_iso_xmit_sync(struct hpsb_iso *iso) +{ + if(iso->type != HPSB_ISO_XMIT) + return -EINVAL; + + return wait_event_interruptible(iso->waitq, hpsb_iso_n_ready(iso) == iso->buf_packets); +} + +void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error) +{ + unsigned long flags; + spin_lock_irqsave(&iso->lock, flags); + + /* predict the cycle of the next packet to be queued */ + + /* jump ahead by the number of packets that are already buffered */ + cycle += iso->buf_packets - iso->n_ready_packets; + cycle %= 8000; + + iso->xmit_cycle = cycle; + iso->n_ready_packets++; + iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets; + + if(iso->n_ready_packets == iso->buf_packets || error != 0) { + /* the buffer has run empty! */ + atomic_inc(&iso->overflows); + } + + spin_unlock_irqrestore(&iso->lock, flags); +} + +void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, + u16 cycle, u8 channel, u8 tag, u8 sy) +{ + unsigned long flags; + spin_lock_irqsave(&iso->lock, flags); + + if(iso->n_ready_packets == iso->buf_packets) { + /* overflow! */ + atomic_inc(&iso->overflows); + } else { + struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma]; + info->offset = offset; + info->len = len; + info->cycle = cycle; + info->channel = channel; + info->tag = tag; + info->sy = sy; + + iso->pkt_dma = (iso->pkt_dma+1) % iso->buf_packets; + iso->n_ready_packets++; + } + + spin_unlock_irqrestore(&iso->lock, flags); +} + +int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) +{ + unsigned long flags; + unsigned int i; + int rv = 0; + + if(iso->type != HPSB_ISO_RECV) + return -1; + + spin_lock_irqsave(&iso->lock, flags); + for(i = 0; i < n_packets; i++) { + rv = iso->host->driver->isoctl(iso, RECV_RELEASE, + (unsigned long) &iso->infos[iso->first_packet]); + if(rv) + break; + + iso->first_packet = (iso->first_packet+1) % iso->buf_packets; + iso->n_ready_packets--; + } + spin_unlock_irqrestore(&iso->lock, flags); + return rv; +} + +void hpsb_iso_wake(struct hpsb_iso *iso) +{ + wake_up_interruptible(&iso->waitq); + + if(iso->callback) + iso->callback(iso); +} Modified: branches/linux-2.4/dv1394.c ============================================================================== --- branches/linux-2.4/dv1394.c (original) +++ branches/linux-2.4/dv1394.c 2003-02-28 19:24:53.000000000 -0500 @@ -138,7 +138,7 @@ (will cause undeflows if your machine is too slow!) */ -#define DV1394_DEBUG_LEVEL 1 +#define DV1394_DEBUG_LEVEL 0 /* for debugging use ONLY: allow more than one open() of the device */ /* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */ |
From: SVN U. <ben...@li...> - 2003-02-28 18:18:13
|
Author: bencollins Date: 2003-02-28 13:17:32 -0500 (Fri, 28 Feb 2003) New Revision: 807 Modified: branches/linux-2.4/eth1394.c Log: Workaround ARM's broken memcpy (which doesn't return void*). Patch from Bernard Leach. Modified: branches/linux-2.4/eth1394.c ============================================================================== --- branches/linux-2.4/eth1394.c (original) +++ branches/linux-2.4/eth1394.c 2003-02-28 13:17:33.000000000 -0500 @@ -206,7 +206,7 @@ unsigned char arp_data[2*(dev->addr_len+4)]; /* Copy the main data that we need */ - arp_ptr = memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data)); + memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data)); /* Extend the buffer enough for our new header */ skb_put (skb, sizeof (struct eth1394_arp) - @@ -214,7 +214,7 @@ #define PROCESS_MEMBER(ptr,val,len) \ memcpy (val, ptr, len); ptr += len - arp_ptr += arp1394->hw_addr_len; + arp_ptr = arp_data + arp1394->hw_addr_len; PROCESS_MEMBER (arp_ptr, &arp1394->sip, arp1394->ip_addr_len); arp_ptr += arp1394->hw_addr_len; PROCESS_MEMBER (arp_ptr, &arp1394->tip, arp1394->ip_addr_len); @@ -498,7 +498,7 @@ spin_unlock_irqrestore (&priv->lock, flags); #define PROCESS_MEMBER(ptr,val,len) \ - ptr = memcpy (ptr, val, len) + len + memcpy (ptr, val, len); ptr += len PROCESS_MEMBER (arp_ptr, src_hw, dev->addr_len); PROCESS_MEMBER (arp_ptr, &arp1394.sip, 4); PROCESS_MEMBER (arp_ptr, dest_hw, dev->addr_len); |
From: SVN U. <ben...@li...> - 2003-02-28 18:17:51
|
Author: bencollins Date: 2003-02-28 13:17:03 -0500 (Fri, 28 Feb 2003) New Revision: 806 Modified: trunk/eth1394.c Log: Workaround ARM's broken memcpy (which doesn't return void*). Patch from Bernard Leach. Modified: trunk/eth1394.c ============================================================================== --- trunk/eth1394.c (original) +++ trunk/eth1394.c 2003-02-28 13:17:04.000000000 -0500 @@ -221,7 +221,7 @@ unsigned char arp_data[2*(dev->addr_len+4)]; /* Copy the main data that we need */ - arp_ptr = memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data)); + memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data)); /* Extend the buffer enough for our new header */ skb_put (skb, sizeof (struct eth1394_arp) - @@ -229,7 +229,7 @@ #define PROCESS_MEMBER(ptr,val,len) \ memcpy (val, ptr, len); ptr += len - arp_ptr += arp1394->hw_addr_len; + arp_ptr = arp_data + arp1394->hw_addr_len; PROCESS_MEMBER (arp_ptr, &arp1394->sip, arp1394->ip_addr_len); arp_ptr += arp1394->hw_addr_len; PROCESS_MEMBER (arp_ptr, &arp1394->tip, arp1394->ip_addr_len); @@ -529,7 +529,7 @@ spin_unlock_irqrestore (&priv->lock, flags); #define PROCESS_MEMBER(ptr,val,len) \ - ptr = memcpy (ptr, val, len) + len + memcpy (ptr, val, len); ptr += len PROCESS_MEMBER (arp_ptr, src_hw, dev->addr_len); PROCESS_MEMBER (arp_ptr, &arp1394.sip, 4); PROCESS_MEMBER (arp_ptr, dest_hw, dev->addr_len); |
From: SVN U. <dm...@li...> - 2003-02-28 07:11:34
|
Author: dmaas Date: 2003-02-28 02:10:53 -0500 (Fri, 28 Feb 2003) New Revision: 805 Modified: trunk/dv1394.c Log: fix crash on rmmod dv1394 due to access of freed list element Modified: trunk/dv1394.c ============================================================================== --- trunk/dv1394.c (original) +++ trunk/dv1394.c 2003-02-28 02:10:54.000000000 -0500 @@ -2703,7 +2703,7 @@ struct ti_ohci *ohci; struct video_card *video = NULL; unsigned long flags; - struct list_head *lh; + struct list_head *lh, *templh; char buf[32]; int n; @@ -2717,7 +2717,7 @@ /* find the corresponding video_cards */ spin_lock_irqsave(&dv1394_cards_lock, flags); if(!list_empty(&dv1394_cards)) { - list_for_each(lh, &dv1394_cards) { + list_for_each_safe(lh, templh, &dv1394_cards) { video = list_entry(lh, struct video_card, list); if((video->id >> 2) == ohci->id) dv1394_un_init(video); |
From: SVN U. <dm...@li...> - 2003-02-28 07:10:05
|
Author: dmaas Date: 2003-02-28 02:09:09 -0500 (Fri, 28 Feb 2003) New Revision: 804 Modified: branches/linux-2.4/dv1394.c Log: fix crash on rmmod dv1394 due to access of freed list element Modified: branches/linux-2.4/dv1394.c ============================================================================== --- branches/linux-2.4/dv1394.c (original) +++ branches/linux-2.4/dv1394.c 2003-02-28 02:09:10.000000000 -0500 @@ -2678,7 +2678,7 @@ struct ti_ohci *ohci; struct video_card *video = NULL; unsigned long flags; - struct list_head *lh; + struct list_head *lh, *templh; char buf[32]; int n; @@ -2692,7 +2692,7 @@ /* find the corresponding video_cards */ spin_lock_irqsave(&dv1394_cards_lock, flags); if(!list_empty(&dv1394_cards)) { - list_for_each(lh, &dv1394_cards) { + list_for_each_safe(lh, templh, &dv1394_cards) { video = list_entry(lh, struct video_card, list); if((video->id >> 2) == ohci->id) dv1394_un_init(video); |
From: SVN U. <ben...@li...> - 2003-02-26 22:44:04
|
Author: bencollins Date: 2003-02-26 17:43:16 -0500 (Wed, 26 Feb 2003) New Revision: 803 Modified: trunk/nodemgr.c Log: Pass LONG_RESET_FORCE_ROOT to hpsb_reset_bus() if trying to gain IRM. Modified: trunk/nodemgr.c ============================================================================== --- trunk/nodemgr.c (original) +++ trunk/nodemgr.c 2003-02-26 17:43:17.000000000 -0500 @@ -1250,7 +1250,7 @@ /* The root node does not have a valid BROADCAST_CHANNEL * register and we do, so reset the bus with force_root set */ HPSB_INFO("Remote root is not IRM capable, resetting..."); - hpsb_reset_bus(host, 1); + hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT); return 0; } return 1; |
From: SVN U. <ben...@li...> - 2003-02-26 21:21:40
|
Author: bencollins Date: 2003-02-26 16:20:59 -0500 (Wed, 26 Feb 2003) New Revision: 802 Modified: trunk/nodemgr.c Log: Re-arrange knodemgrd logic a bit better. Modified: trunk/nodemgr.c ============================================================================== --- trunk/nodemgr.c (original) +++ trunk/nodemgr.c 2003-02-26 16:21:00.000000000 -0500 @@ -1269,10 +1269,14 @@ while (!down_interruptible(&hi->reset_sem) && !down_interruptible(&nodemgr_serialize)) { - nodemgr_node_probe(hi->host); + if (!nodemgr_check_root_capability(hi->host)) { + /* Do nothing, we are resetting */ + up(&nodemgr_serialize); + continue; + } - if (nodemgr_check_root_capability(hi->host)) - nodemgr_do_irm_duties(hi->host); + nodemgr_node_probe(hi->host); + nodemgr_do_irm_duties(hi->host); up(&nodemgr_serialize); } |
From: SVN U. <ben...@li...> - 2003-02-26 21:15:59
|
Author: bencollins Date: 2003-02-26 16:15:08 -0500 (Wed, 26 Feb 2003) New Revision: 801 Modified: trunk/eth1394.c trunk/eth1394.h trunk/ieee1394_core.c trunk/ieee1394_transactions.c trunk/ieee1394_transactions.h trunk/nodemgr.c trunk/ohci1394.c Log: Experimental GASP support patch from Steve Kinneberg. Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2003-02-26 16:15:10.000000000 -0500 @@ -396,9 +396,6 @@ /* irm_id is kept up to date by check_selfids() */ if (host->irm_id == host->node_id) { host->is_irm = 1; - host->is_busmgr = 1; - host->busmgr_id = host->node_id; - host->csr.bus_manager_id = host->node_id; } else { host->is_busmgr = 0; host->is_irm = 0; @@ -1248,6 +1245,7 @@ EXPORT_SYMBOL(hpsb_write); EXPORT_SYMBOL(hpsb_lock); EXPORT_SYMBOL(hpsb_lock64); +EXPORT_SYMBOL(hpsb_send_gasp); EXPORT_SYMBOL(hpsb_packet_success); /** highlevel.c **/ Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-26 16:15:10.000000000 -0500 @@ -31,9 +31,9 @@ * * Things implemented, but still in test phase: * . Iso Transmit + * . Async Stream Packets Transmit (Receive done via Iso interface) * * Things not implemented: - * . Async Stream Packets * . DMA error recovery * * Known bugs: @@ -649,18 +649,31 @@ } else { d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | (packet->header[0] & 0xFFFF); - 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]; + + 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]; + } packet_swab(d->prg_cpu[idx]->data, packet->tcode); } if (packet->data_size) { /* block transmit */ - d->prg_cpu[idx]->begin.control = - cpu_to_le32(DMA_CTL_OUTPUT_MORE | - DMA_CTL_IMMEDIATE | 0x10); + 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 | @@ -830,7 +843,7 @@ /* Decide whether we have an iso, a request, or a response packet */ if (packet->type == hpsb_raw) d = &ohci->at_req_context; - else if (packet->tcode == TCODE_ISO_DATA) { + else if ((packet->tcode == TCODE_ISO_DATA) && (packet->type == hpsb_iso)) { /* The legacy IT DMA context is initialized on first * use. However, the alloc cannot be run from * interrupt context, so we bail out if that is the @@ -856,7 +869,7 @@ } d = &ohci->it_legacy_context; - } else if (packet->tcode & 0x02) + } else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA)) d = &ohci->at_resp_context; else d = &ohci->at_req_context; @@ -1295,6 +1308,8 @@ u32 *prev_branch = NULL; for (blk = 0; blk < recv->nblocks; blk++) { + u32 control; + /* the DMA descriptor */ struct dma_cmd *cmd = &recv->block[blk]; @@ -1305,29 +1320,29 @@ unsigned long buf_offset = blk * recv->buf_stride; if (recv->dma_mode == BUFFER_FILL_MODE) { - cmd->control = 2 << 28; /* INPUT_MORE */ + control = 2 << 28; /* INPUT_MORE */ } else { - cmd->control = 3 << 28; /* INPUT_LAST */ + control = 3 << 28; /* INPUT_LAST */ } - cmd->control |= 8 << 24; /* s = 1, update xferStatus and resCount */ + 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) { - cmd->control |= 3 << 20; /* want interrupt */ + control |= 3 << 20; /* want interrupt */ } - cmd->control |= 3 << 18; /* enable branch to address */ - cmd->control |= recv->buf_stride; + control |= 3 << 18; /* enable branch to address */ + control |= recv->buf_stride; - cmd->address = dma_region_offset_to_bus(&iso->data_buf, buf_offset); + 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 = recv->buf_stride; + cmd->status = cpu_to_le32(recv->buf_stride); /* link the previous descriptor to this one */ if (prev_branch) { - *prev_branch = dma_prog_region_offset_to_bus(&recv->prog, prog_offset); - *prev_branch |= 1; /* set Z=1 */ + *prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1); } prev_branch = &cmd->branchAddress; @@ -1485,18 +1500,18 @@ /* 'next' becomes the new end of the DMA chain, so disable branch and enable interrupt */ next->branchAddress = 0; - next->control |= 3 << 20; + next->control |= cpu_to_le32(3 << 20); /* link prev to next */ - prev->branchAddress = dma_prog_region_offset_to_bus(&recv->prog, - sizeof(struct dma_cmd) * next_i) - | 1; /* Z=1 */ + 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 |= 3 << 20; /* enable interrupt */ + prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */ } else { - prev->control &= ~(3<<20); /* disable interrupt */ + prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */ } wmb(); @@ -1720,8 +1735,8 @@ struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma; /* check the DMA descriptor for new writes to xferStatus */ - u16 xferstatus = il->status >> 16; - u16 rescount = il->status & 0xFFFF; + u16 xferstatus = le32_to_cpu(il->status) >> 16; + u16 rescount = le32_to_cpu(il->status) & 0xFFFF; unsigned char event = xferstatus & 0x1F; @@ -1903,7 +1918,7 @@ 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 = cmd->output_last.status >> 16; + u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16; u8 event = xferstatus & 0x1F; if(!event) { @@ -1919,7 +1934,7 @@ wake = 1; /* parse cycle */ - cycle = cmd->output_last.status & 0x1FFF; + cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF; /* tell the subsystem the packet has gone out */ hpsb_iso_packet_sent(iso, cycle, event != 0x11); @@ -1972,7 +1987,7 @@ /* set up the OUTPUT_MORE_IMMEDIATE descriptor */ memset(next, 0, sizeof(struct iso_xmit_cmd)); - next->output_more_immediate.control = 0x02000008; + next->output_more_immediate.control = cpu_to_le32(0x02000008); /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */ @@ -1990,28 +2005,28 @@ next->iso_hdr[7] = len >> 8; /* set up the OUTPUT_LAST */ - next->output_last.control = 1 << 28; - next->output_last.control |= 1 << 27; /* update timeStamp */ - next->output_last.control |= 3 << 20; /* want interrupt */ - next->output_last.control |= 3 << 18; /* enable branch */ - next->output_last.control |= len; + 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 = dma_region_offset_to_bus(&iso->data_buf, offset); + 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 = - dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3; + prev->output_last.branchAddress = cpu_to_le32( + dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3); /* disable interrupt, unless required by the IRQ interval */ if(prev_i % iso->irq_interval) { - prev->output_last.control &= ~(3 << 20); /* no interrupt */ + prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */ } else { - prev->output_last.control |= 3 << 20; /* enable interrupt */ + prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */ } wmb(); Modified: trunk/ieee1394_transactions.c ============================================================================== --- trunk/ieee1394_transactions.c (original) +++ trunk/ieee1394_transactions.c 2003-02-26 16:15:10.000000000 -0500 @@ -98,6 +98,17 @@ packet->speed_code = SPEED_100; /* Force speed to be 100Mbps */ } +static void fill_async_stream_packet(struct hpsb_packet *packet, int length, + int channel, int tag, int sync) +{ + packet->header[0] = (length << 16) | (tag << 14) | (channel << 8) + | (TCODE_STREAM_DATA << 4) | sync; + + packet->header_size = 4; + packet->data_size = length; + packet->type = hpsb_async; + packet->tcode = TCODE_ISO_DATA; +} /** * hpsb_get_tlabel - allocate a transaction label @@ -495,7 +506,6 @@ } -/* We need a hpsb_lock64 function for the 64 bit equivalent. Probably. */ int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, int extcode, quadlet_t *data, quadlet_t arg) { @@ -558,3 +568,58 @@ return retval; } + +int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation, + quadlet_t *buffer, size_t length, u32 specifier_id, + unsigned int version) +{ +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + int i; +#endif + + struct hpsb_packet *packet; + int retval = 0; + u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8; + u8 specifier_id_lo = specifier_id & 0xff; + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_DEBUG("Send GASP: channel = %d, length = %d", channel, length); +#endif + + length += 8; + + packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0)); + if (!packet) + return -ENOMEM; + + if (length % 4) { + packet->data[length / 4] = 0; + } + + packet->host = host; + fill_async_stream_packet(packet, length, channel, 3, 0); + + packet->data[0] = cpu_to_be32((host->node_id << 16) | specifier_id_hi); + packet->data[1] = cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff)); + + memcpy(&(packet->data[2]), buffer, length - 4); + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_DEBUG("GASP: packet->header_size = %d", packet->header_size); + HPSB_DEBUG("GASP: packet->data_size = %d", packet->data_size); + + for(i=0; i<(packet->data_size/4); i++) + HPSB_DEBUG("GASP: data[%d]: 0x%08x", i*4, be32_to_cpu(packet->data[i])); +#endif + + packet->generation = generation; + + packet->no_waiter = 1; + + if (!hpsb_send_packet(packet)) { + free_hpsb_packet(packet); + retval = -EINVAL; + } + + return retval; +} Modified: trunk/ieee1394_transactions.h ============================================================================== --- trunk/ieee1394_transactions.h (original) +++ trunk/ieee1394_transactions.h 2003-02-26 16:15:10.000000000 -0500 @@ -55,5 +55,8 @@ u64 addr, int extcode, quadlet_t *data, quadlet_t arg); int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, int extcode, octlet_t *data, octlet_t arg); +int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation, + quadlet_t *buffer, size_t length, u32 specifier_id, + unsigned int version); #endif /* _IEEE1394_TRANSACTIONS_H */ Modified: trunk/nodemgr.c ============================================================================== --- trunk/nodemgr.c (original) +++ trunk/nodemgr.c 2003-02-26 16:15:10.000000000 -0500 @@ -1210,6 +1210,52 @@ return; } +/* Because we are a 1394a-2000 compliant IRM, we need to inform all the other + * nodes of the broadcast channel. (Really we're only setting the validity + * bit). */ +static void nodemgr_do_irm_duties(struct hpsb_host *host) +{ + quadlet_t bc; + + if (!host->is_irm) + return; + + host->csr.broadcast_channel |= 0x40000000; /* set validity bit */ + + bc = cpu_to_be32(host->csr.broadcast_channel); + + hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host), + (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL), + &bc, + sizeof(quadlet_t)); +} + +/* We need to ensure that if we are not the IRM, that the IRM node is capable of + * everything we can do, otherwise issue a bus reset and try to become the IRM + * ourselves. */ +static int nodemgr_check_root_capability(struct hpsb_host *host) +{ + quadlet_t bc; + int status; + + if (host->is_irm) + return 1; + + status = hpsb_read(host, LOCAL_BUS | (host->irm_id), + get_hpsb_generation(host), + (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL), + &bc, sizeof(quadlet_t)); + + if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) { + /* The root node does not have a valid BROADCAST_CHANNEL + * register and we do, so reset the bus with force_root set */ + HPSB_INFO("Remote root is not IRM capable, resetting..."); + hpsb_reset_bus(host, 1); + return 0; + } + return 1; +} + static int nodemgr_host_thread(void *__hi) { struct host_info *hi = (struct host_info *)__hi; @@ -1222,7 +1268,12 @@ * happens when we get a bus reset. */ while (!down_interruptible(&hi->reset_sem) && !down_interruptible(&nodemgr_serialize)) { + nodemgr_node_probe(hi->host); + + if (nodemgr_check_root_capability(hi->host)) + nodemgr_do_irm_duties(hi->host); + up(&nodemgr_serialize); } #ifdef CONFIG_IEEE1394_VERBOSEDEBUG Modified: trunk/eth1394.c ============================================================================== --- trunk/eth1394.c (original) +++ trunk/eth1394.c 2003-02-26 16:15:10.000000000 -0500 @@ -65,6 +65,7 @@ #include "ieee1394_transactions.h" #include "ieee1394.h" #include "highlevel.h" +#include "iso.h" #include "eth1394.h" #define ETH1394_PRINT_G(level, fmt, args...) \ @@ -101,6 +102,9 @@ MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)"); MODULE_LICENSE("GPL"); +static void ether1394_iso(struct hpsb_iso *iso); + + /* Find our host_info struct for a given host pointer. Must be called * under spinlock. */ static inline struct host_info *find_host_info (struct hpsb_host *host) @@ -178,15 +182,26 @@ * XXX: This is where we need to create a list of skb's for fragmented * packets. */ static inline void ether1394_encapsulate (struct sk_buff *skb, struct net_device *dev, - int proto) + int proto, struct packet_task *ptask) { union eth1394_hdr *hdr = (union eth1394_hdr *)skb_push (skb, hdr_type_len[ETH1394_HDR_LF_UF]); + hdr->words.word1 = 0; hdr->common.lf = ETH1394_HDR_LF_UF; hdr->words.word1 = htons(hdr->words.word1); hdr->uf.ether_type = proto; + /* Set the transmission type for the packet. Right now only ARP + * packets are sent via GASP. IP broadcast and IP multicast are not + * yet supported properly, they too should use GASP. */ + switch(proto) { + case __constant_htons(ETH_P_ARP): + ptask->tx_type = ETH1394_GASP; + break; + default: + ptask->tx_type = ETH1394_WRREQ; + } return; } @@ -280,6 +295,7 @@ unsigned long flags; struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; int phy_id = NODEID_TO_NODE(priv->host->node_id); + struct hpsb_host *host = priv->host; spin_lock_irqsave (&priv->lock, flags); @@ -289,20 +305,23 @@ memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi)); memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo)); + priv->bc_state = ETHER1394_BC_CHECK; + /* Register our limits now */ - ether1394_register_limits (phy_id, (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf, - priv->host->speed_map[(phy_id << 6) + phy_id], - (u64)(((u64)be32_to_cpu(priv->host->csr.rom[3]) << 32) | - be32_to_cpu(priv->host->csr.rom[4])), + ether1394_register_limits (phy_id, (be32_to_cpu(host->csr.rom[2]) >> 12) & 0xf, + host->speed_map[(phy_id << 6) + phy_id], + (u64)(((u64)be32_to_cpu(host->csr.rom[3]) << 32) | + be32_to_cpu(host->csr.rom[4])), ETHER1394_REGION_ADDR >> 32, ETHER1394_REGION_ADDR & 0xffffffff, priv); /* We'll use our max_rec as the default mtu */ if (set_mtu) - dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - sizeof (union eth1394_hdr); + dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - /* mtu = max_rec - */ + (sizeof (union eth1394_hdr) + 8); /* (hdr + GASP) */ /* Set our hardware address while we're at it */ - *(nodeid_t *)dev->dev_addr = htons (priv->host->node_id); + *(nodeid_t *)dev->dev_addr = htons (host->node_id); spin_unlock_irqrestore (&priv->lock, flags); } @@ -383,6 +402,15 @@ list_add_tail (&hi->list, &host_info_list); spin_unlock_irq (&host_info_lock); + /* Ignore validity in hopes that it will be set in the future. It'll + * check it on transmit. */ + priv->broadcast_channel = host->csr.broadcast_channel & 0x3f; + + priv->iso = hpsb_iso_recv_init(host, 8 * 4096, 8, priv->broadcast_channel, + 1, ether1394_iso); + if (priv->iso == NULL) { + priv->bc_state = ETHER1394_BC_CLOSED; + } return; out: @@ -396,11 +424,14 @@ /* Remove a card from our list */ static void ether1394_remove_host (struct hpsb_host *host) { + struct eth1394_priv *priv; struct host_info *hi; spin_lock_irq (&host_info_lock); hi = find_host_info (host); if (hi != NULL) { + priv = (struct eth1394_priv *)hi->dev->priv; + priv->bc_state = ETHER1394_BC_CLOSED; unregister_netdev (hi->dev); kfree (hi->dev); list_del (&hi->list); @@ -591,6 +622,104 @@ return RCODE_COMPLETE; } +static void ether1394_iso(struct hpsb_iso *iso) +{ + struct sk_buff *skb; + quadlet_t *data; + char *buf; + int flags; + struct net_device *dev = ether1394_find_dev(iso->host); + struct eth1394_priv *priv; + unsigned int len; + u32 specifier_id; + u16 source_id; + int i; + int nready; + + if (dev == NULL) { + ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %s\n", + iso->host->driver->name); + return; + } + + nready = hpsb_iso_n_ready(iso); + for(i = 0; i < nready; i++) { + struct hpsb_iso_packet_info *info = &iso->infos[iso->first_packet + i]; + data = (quadlet_t*) (iso->data_buf.kvirt + info->offset); + + /* skip over GASP header */ + buf = (char *)data + 8; + len = info->len - 8; + + specifier_id = (((be32_to_cpu(data[0]) & 0xffff) << 8) | + ((be32_to_cpu(data[1]) & 0xff000000) >> 24)); + source_id = be32_to_cpu(data[0]) >> 16; + + priv = (struct eth1394_priv *)dev->priv; + + if (info->channel != priv->broadcast_channel || + specifier_id != ETHER1394_GASP_SPECIFIER_ID) { + /* This packet is not for us */ + continue; + } + + /* A packet has been received by the ieee1394 bus. Build an skbuff + * around it so we can pass it to the high level network layer. */ + skb = dev_alloc_skb (len + dev->hard_header_len + 15); + if (!skb) { + HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n"); + priv->stats.rx_dropped++; + break; + } + + skb_reserve(skb, (dev->hard_header_len + 15) & ~15); + + memcpy (skb_put (skb, len), buf, len); + + /* Write metadata, and then pass to the receive level */ + skb->dev = dev; + skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ + + /* Parse the encapsulation header. This actually does the job of + * converting to an ethernet frame header, aswell as arp + * conversion if needed. ARP conversion is easier in this + * direction, since we are using ethernet as our backend. */ + skb->protocol = ether1394_parse_encap (skb, dev, source_id, + LOCAL_BUS | ALL_NODES); + + spin_lock_irqsave (&priv->lock, flags); + if (!skb->protocol) { + priv->stats.rx_errors++; + priv->stats.rx_dropped++; + dev_kfree_skb_any(skb); + goto bad_proto; + } + + netif_stop_queue(dev); + if (netif_rx (skb) == NET_RX_DROP) { + priv->stats.rx_errors++; + priv->stats.rx_dropped++; + goto bad_proto; + } + + /* Statistics */ + priv->stats.rx_packets++; + priv->stats.rx_bytes += skb->len; + + bad_proto: + spin_unlock_irqrestore (&priv->lock, flags); + } + + hpsb_iso_recv_release_packets(iso, i); + + netif_start_queue(dev); + + dev->last_rx = jiffies; + + return; +} + + /* This function is our scheduled write */ static void hpsb_write_sched (void *__ptask) { @@ -598,13 +727,26 @@ struct sk_buff *skb = ptask->skb; struct net_device *dev = ptask->skb->dev; struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; - unsigned long flags; + unsigned long flags; + int status; + + if (ptask->tx_type == ETH1394_GASP) { + status = hpsb_send_gasp(priv->host, priv->broadcast_channel, + get_hpsb_generation(priv->host), + (quadlet_t *)skb->data, skb->len, + ETHER1394_GASP_SPECIFIER_ID, + ETHER1394_GASP_VERSION); + } else { + status = hpsb_write(priv->host, ptask->dest_node, + get_hpsb_generation(priv->host), + ptask->addr, (quadlet_t *)skb->data, + skb->len); + } + /* Statistics */ spin_lock_irqsave (&priv->lock, flags); - if (!hpsb_write(priv->host, ptask->dest_node, - get_hpsb_generation(priv->host), - ptask->addr, (quadlet_t *)skb->data, skb->len)) { + if (!status) { priv->stats.tx_bytes += skb->len; priv->stats.tx_packets++; } else { @@ -636,6 +778,67 @@ struct packet_task *ptask = NULL; int ret = 0; + spin_lock_irqsave (&priv->lock, flags); + if (priv->bc_state == ETHER1394_BC_CLOSED) { + ETH1394_PRINT(KERN_ERR, dev->name, + "Cannot send packet, no broadcast channel available."); + ret = -EAGAIN; + goto fail; + } + + /* First time sending? Need a broadcast channel for ARP and for + * listening on */ + if (priv->bc_state == ETHER1394_BC_CHECK) { + quadlet_t bc; + + /* Get the local copy of the broadcast channel and check its + * validity (the IRM should validate it for us) */ + + bc = priv->host->csr.broadcast_channel; + + if ((bc & 0xc0000000) != 0xc0000000) { + /* broadcast channel not validated yet */ + ETH1394_PRINT(KERN_WARNING, dev->name, + "Error BROADCAST_CHANNEL register valid " + "bit not set, can't send IP traffic\n"); + hpsb_iso_shutdown(priv->iso); + priv->bc_state = ETHER1394_BC_CLOSED; + ret = -EAGAIN; + spin_unlock_irqrestore (&priv->lock, flags); + goto fail; + } + if (priv->broadcast_channel != (bc & 0x3f)) { + /* This really shouldn't be possible, but just in case + * the IEEE 1394 spec changes regarding broadcast + * channels in the future. */ + hpsb_iso_shutdown(priv->iso); + + priv->broadcast_channel = bc & 0x3f; + ETH1394_PRINT(KERN_WARNING, dev->name, + "Changing to broadcast channel %d...\n", + priv->broadcast_channel); + + priv->iso = hpsb_iso_recv_init(priv->host, 8 * 4096, + 8, priv->broadcast_channel, + 1, ether1394_iso); + if (priv->iso == NULL) { + ret = -EAGAIN; + goto fail; + } + } + if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) { + ETH1394_PRINT(KERN_ERR, dev->name, + "Could not start async reception\n"); + hpsb_iso_shutdown(priv->iso); + priv->bc_state = ETHER1394_BC_CLOSED; + ret = -EAGAIN; + spin_unlock_irqrestore (&priv->lock, flags); + goto fail; + } + priv->bc_state = ETHER1394_BC_OPENED; + } + spin_unlock_irqrestore (&priv->lock, flags); + if ((skb = skb_share_check (skb, kmflags)) == NULL) { ret = -ENOMEM; goto fail; @@ -654,8 +857,14 @@ if (proto == __constant_htons (ETH_P_ARP)) ether1394_arp_to_1394arp (skb, dev); + ptask = kmem_cache_alloc(packet_task_cache, kmflags); + if (ptask == NULL) { + ret = -ENOMEM; + goto fail; + } + /* Now add our encapsulation header */ - ether1394_encapsulate (skb, dev, proto); + ether1394_encapsulate (skb, dev, proto, ptask); /* TODO: The above encapsulate function needs to recognize when a * packet needs to be split for a specified node. It should create @@ -674,12 +883,6 @@ if (!addr) addr = ETHER1394_REGION_ADDR; - ptask = kmem_cache_alloc(packet_task_cache, kmflags); - if (ptask == NULL) { - ret = -ENOMEM; - goto fail; - } - ptask->skb = skb; ptask->addr = addr; ptask->dest_node = dest_node; @@ -702,7 +905,7 @@ netif_wake_queue (dev); spin_unlock_irqrestore (&priv->lock, flags); - return ret; + return 0; /* returning non-zero causes serious problems */ } /* Function for incoming 1394 packets */ @@ -738,6 +941,19 @@ static void __exit ether1394_exit_module (void) { + struct list_head *lh; + struct host_info *hi; + struct eth1394_priv *priv; + + lh = host_info_list.next; + while (lh != &host_info_list) { + hi = list_entry (lh, struct host_info, list); + priv = (struct eth1394_priv*)hi->dev->priv; + if (priv->bc_state != ETHER1394_BC_CLOSED) { + hpsb_iso_shutdown(priv->iso); + } + lh = lh->next; + } hpsb_unregister_highlevel (hl_handle); kmem_cache_destroy(packet_task_cache); } Modified: trunk/eth1394.h ============================================================================== --- trunk/eth1394.h (original) +++ trunk/eth1394.h 2003-02-26 16:15:10.000000000 -0500 @@ -30,9 +30,16 @@ #define ETHER1394_REGION_ADDR 0xfffff0200000ULL #define ETHER1394_REGION_ADDR_END (ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN) +/* GASP identifier numbers for IPv4 over IEEE 1394 */ +#define ETHER1394_GASP_SPECIFIER_ID 0x00005E +#define ETHER1394_GASP_VERSION 1 + /* Node set == 64 */ #define NODE_SET (ALL_NODES + 1) +enum eth1394_bc_states { ETHER1394_BC_CLOSED, ETHER1394_BC_OPENED, + ETHER1394_BC_CHECK }; + /* Private structure for our ethernet driver */ struct eth1394_priv { struct net_device_stats stats; /* Device stats */ @@ -43,6 +50,9 @@ u32 fifo_lo[ALL_NODES]; /* 32bit lo fifo offset per node */ u64 eui[ALL_NODES]; /* EUI-64 per node */ spinlock_t lock; /* Private lock */ + int broadcast_channel; /* Async stream Broadcast Channel */ + enum eth1394_bc_states bc_state; /* broadcast channel state */ + struct hpsb_iso *iso; /* Async stream recv handle */ }; struct host_info { @@ -51,12 +61,15 @@ struct net_device *dev; }; +typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type; + /* This is our task struct. It's used for the packet complete callback. */ struct packet_task { struct sk_buff *skb; /* Socket buffer we are sending */ nodeid_t dest_node; /* Destination of the packet */ u64 addr; /* Address */ struct hpsb_queue_struct tq; /* The task */ + eth1394_tx_type tx_type; /* Send data via GASP or Write Req. */ }; /* IP1394 headers */ |
From: SVN U. <ben...@li...> - 2003-02-26 06:47:21
|
Author: bencollins Date: 2003-02-26 01:46:26 -0500 (Wed, 26 Feb 2003) New Revision: 800 Modified: trunk/amdtp.c trunk/dv1394-private.h trunk/eth1394.c trunk/ohci1394.c trunk/ohci1394.h trunk/raw1394.c Log: English Teacher meets Programmer. More spelling fixes merged from Linus' tree. Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-26 01:46:27.000000000 -0500 @@ -827,7 +827,7 @@ return 0; } - /* Decide wether we have an iso, a request, or a response packet */ + /* Decide whether we have an iso, a request, or a response packet */ if (packet->type == hpsb_raw) d = &ohci->at_req_context; else if (packet->tcode == TCODE_ISO_DATA) { @@ -2266,7 +2266,7 @@ if (event & OHCI1394_cycleInconsistent) { /* We subscribe to the cycleInconsistent event only to * clear the corresponding event bit... otherwise, - * isochronous cycleMatch DMA wont work. */ + * isochronous cycleMatch DMA won't work. */ DBGMSG(ohci->id, "OHCI1394_cycleInconsistent"); event &= ~OHCI1394_cycleInconsistent; } @@ -2366,7 +2366,7 @@ if (!(node_id & 0x80000000)) { PRINT(KERN_ERR, ohci->id, "SelfID received, but NodeID invalid " - "(probably new bus reset occured): %08X", + "(probably new bus reset occurred): %08X", node_id); goto selfid_not_valid; } @@ -3530,7 +3530,7 @@ tasklet_init(&tasklet->tasklet, func, data); tasklet->type = type; /* We init the tasklet->link field, so we can list_del() it - * without worrying wether it was added to the list or not. */ + * without worrying whether it was added to the list or not. */ INIT_LIST_HEAD(&tasklet->link); } Modified: trunk/amdtp.c ============================================================================== --- trunk/amdtp.c (original) +++ trunk/amdtp.c 2003-02-26 01:46:27.000000000 -0500 @@ -230,7 +230,7 @@ /* The cycle_count and cycle_offset fields are used for the * synchronization timestamps (syt) in the cip header. They * are incremented by at least a cycle every time we put a - * time stamp in a packet. As we dont time stamp all + * time stamp in a packet. As we don't time stamp all * packages, cycle_count isn't updated in every cycle, and * sometimes it's incremented by 2. Thus, we have * cycle_count2, which is simply incremented by one with each @@ -750,7 +750,7 @@ /* This next addition should be modulo 8000 (0x1f40), * but we only use the lower 4 bits of cycle_count, so - * we dont need the modulo. */ + * we don't need the modulo. */ atomic_add(s->cycle_offset.integer / 3072, &s->cycle_count); s->cycle_offset.integer %= 3072; } Modified: trunk/dv1394-private.h ============================================================================== --- trunk/dv1394-private.h (original) +++ trunk/dv1394-private.h 2003-02-26 01:46:27.000000000 -0500 @@ -488,7 +488,7 @@ struct frame *frames[DV1394_MAX_FRAMES]; /* n_frames also serves as an indicator that this struct video_card is - intialized and ready to run DMA buffers */ + initialized and ready to run DMA buffers */ int n_frames; Modified: trunk/ohci1394.h ============================================================================== --- trunk/ohci1394.h (original) +++ trunk/ohci1394.h 2003-02-26 01:46:27.000000000 -0500 @@ -405,12 +405,12 @@ truncated */ #define EVT_OVERRUN 0x5 /* A recv FIFO overflowed on reception of ISO packet */ -#define EVT_DESCRIPTOR_READ 0x6 /* An unrecoverable error occured while host was +#define EVT_DESCRIPTOR_READ 0x6 /* An unrecoverable error occurred while host was reading a descriptor block */ -#define EVT_DATA_READ 0x7 /* An error occured while host controller was +#define EVT_DATA_READ 0x7 /* An error occurred while host controller was attempting to read from host memory in the data stage of descriptor processing */ -#define EVT_DATA_WRITE 0x8 /* An error occured while host controller was +#define EVT_DATA_WRITE 0x8 /* An error occurred while host controller was attempting to write either during the data stage of descriptor processing, or when processing a single 16-bit host memory write */ Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2003-02-26 01:46:27.000000000 -0500 @@ -2439,7 +2439,7 @@ spin_unlock_irq(&host_info_lock); if (fail > 0) { printk(KERN_ERR "raw1394: during addr_list-release " - "error(s) occured \n"); + "error(s) occurred \n"); } while (!done) { Modified: trunk/eth1394.c ============================================================================== --- trunk/eth1394.c (original) +++ trunk/eth1394.c 2003-02-26 01:46:28.000000000 -0500 @@ -663,7 +663,7 @@ * call to schedule our writes. */ /* XXX: Right now we accept that we don't exactly follow RFC. When - * we do, we will send ARP requests via GASP format, and so we wont + * we do, we will send ARP requests via GASP format, and so we won't * need this hack. */ spin_lock_irqsave (&priv->lock, flags); |
From: SVN U. <ben...@li...> - 2003-02-22 18:32:06
|
Author: bencollins Date: 2003-02-22 13:31:20 -0500 (Sat, 22 Feb 2003) New Revision: 799 Modified: trunk/raw1394.c Log: Speling correction. Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2003-02-22 13:31:21.000000000 -0500 @@ -238,7 +238,7 @@ list_del(&hi->list); host_count--; /* - FIXME: adressranges should be removed + FIXME: address ranges should be removed and fileinfo states should be initialized (including setting generation to internal-generation ...) |
From: SVN U. <ben...@li...> - 2003-02-22 08:15:42
|
Author: bencollins Date: 2003-02-22 03:15:01 -0500 (Sat, 22 Feb 2003) New Revision: 798 Modified: trunk/hosts.c trunk/hosts.h trunk/ohci1394.c trunk/pcilynx.c Log: Cleanup module ref counting. Patch from Christoph Hellwig. Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-22 03:15:02.000000000 -0500 @@ -966,16 +966,6 @@ dma_trm_reset(&ohci->at_resp_context); break; - case MODIFY_USAGE: - if (arg) { - if (try_module_get(THIS_MODULE)) - retval = 1; - } else { - module_put(THIS_MODULE); - retval = 1; - } - break; - case ISO_LISTEN_CHANNEL: { u64 mask; @@ -3202,6 +3192,7 @@ } static struct hpsb_host_driver ohci1394_driver = { + .owner = THIS_MODULE, .name = OHCI1394_DRIVER_NAME, .get_rom = ohci_get_rom, .transmit_packet = ohci_transmit, Modified: trunk/hosts.c ============================================================================== --- trunk/hosts.c (original) +++ trunk/hosts.c 2003-02-22 03:15:02.000000000 -0500 @@ -11,6 +11,7 @@ */ #include <linux/config.h> +#include <linux/module.h> #include <linux/types.h> #include <linux/list.h> #include <linux/init.h> @@ -69,8 +70,7 @@ spin_lock_irqsave(&hosts_lock, flags); list_for_each(lh, &hosts) { if (host == list_entry(lh, struct hpsb_host, host_list)) { - if (host->driver->devctl(host, MODIFY_USAGE, 1)) { - host->driver->devctl(host, MODIFY_USAGE, 1); + if (try_module_get(host->driver->owner)) { host->refcount++; retval = 1; } @@ -95,7 +95,7 @@ { unsigned long flags; - host->driver->devctl(host, MODIFY_USAGE, 0); + module_put(host->driver->owner); spin_lock_irqsave(&hosts_lock, flags); host->refcount--; Modified: trunk/hosts.h ============================================================================== --- trunk/hosts.h (original) +++ trunk/hosts.h 2003-02-22 03:15:02.000000000 -0500 @@ -92,12 +92,6 @@ * Return void. */ CANCEL_REQUESTS, - /* Decrease host usage count if arg == 0, increase otherwise. Return - * 1 for success, 0 for failure. Increase usage may fail if the driver - * is in the process of shutting itself down. Decrease usage can not - * fail. */ - MODIFY_USAGE, - /* Start or stop receiving isochronous channel in arg. Return void. * This acts as an optimization hint, hosts are not required not to * listen on unrequested channels. */ @@ -147,6 +141,7 @@ }; struct hpsb_host_driver { + struct module *owner; const char *name; /* This function must store a pointer to the configuration ROM into the Modified: trunk/pcilynx.c ============================================================================== --- trunk/pcilynx.c (original) +++ trunk/pcilynx.c 2003-02-22 03:15:02.000000000 -0500 @@ -801,17 +801,6 @@ break; - case MODIFY_USAGE: - if (arg) { - if (try_module_get(THIS_MODULE)) - retval = 1; - } else { - module_put(THIS_MODULE); - retval = 1; - } - - break; - case ISO_LISTEN_CHANNEL: spin_lock_irqsave(&lynx->iso_rcv.lock, flags); @@ -1904,6 +1893,7 @@ }; static struct hpsb_host_driver lynx_driver = { + .owner = THIS_MODULE, .name = PCILYNX_DRIVER_NAME, .get_rom = get_lynx_rom, .transmit_packet = lynx_transmit, |
From: SVN U. <ben...@li...> - 2003-02-22 04:39:45
|
Author: bencollins Date: 2003-02-21 23:39:07 -0500 (Fri, 21 Feb 2003) New Revision: 797 Modified: trunk/eth1394.c trunk/ieee1394_core.c trunk/ieee1394_types.h trunk/raw1394.c trunk/sbp2.c trunk/sbp2.h Log: Mainly this is sbp2's updates for hotplug scsi interface. THIS DOES NOT WORK WITH ANY AVAILABLE KERNEL. Hopefully 2.5.63 will have the required interfaces. Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2003-02-21 23:39:09.000000000 -0500 @@ -361,7 +361,7 @@ host->topology_map[host->selfid_count++] = sid; } else { HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d", - sid, (host->node_id & BUS_MASK) >> 6); + sid, NODEID_TO_BUS(host->node_id)); } } @@ -535,8 +535,8 @@ if (packet->type == hpsb_async && packet->node_id != ALL_NODES) { packet->speed_code = - host->speed_map[(host->node_id & NODE_MASK) * 64 - + (packet->node_id & NODE_MASK)]; + host->speed_map[NODEID_TO_NODE(host->node_id) * 64 + + NODEID_TO_NODE(packet->node_id)]; } #ifdef CONFIG_IEEE1394_VERBOSEDEBUG @@ -748,7 +748,7 @@ addr, 4, flags); if (!write_acked - && (((data[0] >> 16) & NODE_MASK) != NODE_MASK) + && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK) && (rcode >= 0)) { /* not a broadcast write, reply */ PREP_REPLY_PACKET(0); @@ -763,7 +763,7 @@ addr, data[3]>>16, flags); if (!write_acked - && (((data[0] >> 16) & NODE_MASK) != NODE_MASK) + && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK) && (rcode >= 0)) { /* not a broadcast write, reply */ PREP_REPLY_PACKET(0); Modified: trunk/raw1394.c ============================================================================== --- trunk/raw1394.c (original) +++ trunk/raw1394.c 2003-02-21 23:39:09.000000000 -0500 @@ -281,8 +281,8 @@ req->req.misc = (host->node_id << 16) | host->node_count; if (fi->protocol_version > 3) { - req->req.misc |= ((host->irm_id - & NODE_MASK) << 8); + req->req.misc |= (NODEID_TO_NODE(host->irm_id) + << 8); } queue_complete_req(req); @@ -571,8 +571,7 @@ req->req.misc = (fi->host->node_id << 16) | fi->host->node_count; if (fi->protocol_version > 3) { - req->req.misc |= - (fi->host->irm_id & NODE_MASK) << 8; + req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8; } } else { req->req.error = RAW1394_ERROR_INVALID_ARG; Modified: trunk/eth1394.c ============================================================================== --- trunk/eth1394.c (original) +++ trunk/eth1394.c 2003-02-21 23:39:09.000000000 -0500 @@ -199,7 +199,7 @@ { struct eth1394_priv *priv = (struct eth1394_priv *)(dev->priv); - u16 phy_id = priv->host->node_id & NODE_MASK; + u16 phy_id = NODEID_TO_NODE(priv->host->node_id); unsigned char *arp_ptr = (unsigned char *)skb->data; struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data; @@ -279,7 +279,7 @@ { unsigned long flags; struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; - int phy_id = priv->host->node_id & NODE_MASK; + int phy_id = NODEID_TO_NODE(priv->host->node_id); spin_lock_irqsave (&priv->lock, flags); @@ -480,7 +480,7 @@ * about the sending machine. */ if (hdr->uf.ether_type == __constant_htons (ETH_P_ARP)) { unsigned long flags; - u16 phy_id = srcid & NODE_MASK; + u16 phy_id = NODEID_TO_NODE(srcid); struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; struct eth1394_arp arp1394; @@ -667,8 +667,8 @@ * need this hack. */ spin_lock_irqsave (&priv->lock, flags); - addr = (u64)priv->fifo_hi[dest_node & NODE_MASK] << 32 | - priv->fifo_lo[dest_node & NODE_MASK]; + addr = (u64)priv->fifo_hi[NODEID_TO_NODE(dest_node)] << 32 | + priv->fifo_lo[NODEID_TO_NODE(dest_node)]; spin_unlock_irqrestore (&priv->lock, flags); if (!addr) Modified: trunk/sbp2.c ============================================================================== --- trunk/sbp2.c (original) +++ trunk/sbp2.c 2003-02-21 23:39:09.000000000 -0500 @@ -27,30 +27,6 @@ * driver. It also registers as a SCSI lower-level driver in order to accept * SCSI commands for transport using SBP-2. * - * - * Driver Loading: - * - * Currently, the SBP-2 driver is supported only as a module. Because the - * Linux SCSI stack is not Plug-N-Play aware, module load order is - * important. Assuming the SCSI core drivers are either built into the - * kernel or already loaded as modules, you should load the IEEE-1394 modules - * in the following order: - * - * ieee1394 (e.g. insmod ieee1394) - * ohci1394 (e.g. insmod ohci1394) - * sbp2 (e.g. insmod sbp2) - * - * The SBP-2 driver will attempt to discover any attached SBP-2 devices when first - * loaded, or after any IEEE-1394 bus reset (e.g. a hot-plug). It will then print - * out a debug message indicating if it was able to discover a SBP-2 device. - * - * Currently, the SBP-2 driver will catch any attached SBP-2 devices during the - * initial scsi bus scan (when the driver is first loaded). To add or remove - * SBP-2 devices "after" this initial scan (i.e. if you plug-in or un-plug a - * device after the SBP-2 driver is loaded), you must either use the scsi procfs - * add-single-device, remove-single-device, or a shell script such as - * rescan-scsi-bus.sh. - * * The easiest way to add/detect new SBP-2 devices is to run the shell script * rescan-scsi-bus.sh (or re-load the SBP-2 driver). This script may be * found at: @@ -136,14 +112,6 @@ * - Error Handling: SCSI aborts and bus reset requests are handled somewhat * but the code needs additional debugging. * - * - Module: The SBP-2 driver is currently only supported as a module. It would not take - * much work to allow it to be compiled into the kernel, but you'd have to - * add some init code to the kernel to support this... and modules are much - * more flexible anyway. ;-) - * - * - Hot-plugging: Interaction with the SCSI stack and support for hot-plugging could - * stand some improvement. - * * * History: * @@ -295,10 +263,11 @@ * 04/23/02 - Fix for Sony CD-ROM drives. Only send fetch agent reset to sbp2 device if it * returns the dead bit in status. Thanks to Chandan (ch...@to...) for this one. * 04/27/02 - Fix sbp2 login problem on SMP systems, enable real spinlocks by default. (JSG) - * 06/09/02 - Don't force 36-bute SCSI inquiry, but leave in a define for badly behaved devices. (JSG) + * 06/09/02 - Don't force 36-byte SCSI inquiry, but leave in a define for badly behaved devices. (JSG) * 02/04/03 - Fixed a SMP deadlock (don't hold sbp2_command_lock while calling sbp2scsi_complete_command). * Also save/restore irq flags in sbp2scsi_complete_command - Sancho Dauskardt <sd...@bd...> * 02/06/03 - Removed spinlock debugging; use kernel stuff instead (sda) + * 02/10/03 - Adopt to new hot-plug aware SCSI inferface (hc...@ls...) * */ @@ -497,6 +466,15 @@ * Globals */ +static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, + struct scsi_id_instance_data *scsi_id, + u32 status); + +static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, + struct scsi_id_instance_data *scsi_id, + u32 scsi_status, Scsi_Cmnd *SCpnt, + void (*done)(Scsi_Cmnd *)); + static Scsi_Host_Template scsi_driver_template; static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 }; @@ -822,7 +800,7 @@ { struct sbp2scsi_host_info *hi; - hi = (struct sbp2scsi_host_info *) command->Current_SCpnt->device->host->hostdata[0]; + hi = (struct sbp2scsi_host_info *)&command->Current_SCpnt->device->host->hostdata; if (hi == NULL) { printk(KERN_ERR "%s: hi == NULL\n", __FUNCTION__); @@ -871,59 +849,6 @@ * IEEE-1394 core driver stack related section *********************************************/ -/* - * This function is called at SCSI init in order to register our driver - * with the IEEE-1394 stack. - */ -int sbp2_init(void) -{ - SBP2_DEBUG("sbp2_init"); - - /* - * Register our high level driver with 1394 stack - */ - sbp2_hl_handle = hpsb_register_highlevel(SBP2_DEVICE_NAME, &sbp2_hl_ops); - - if (sbp2_hl_handle == NULL) { - SBP2_ERR("sbp2 failed to register with ieee1394 highlevel"); - return(-ENOMEM); - } - - /* - * Register our sbp2 status address space... - */ - hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS, - SBP2_STATUS_FIFO_ADDRESS + - SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1)); - - /* - * Handle data movement if physical dma is not enabled/supported on host controller - */ -#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA - hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL); -#endif - - hpsb_register_protocol(&sbp2_driver); - - return 0; -} - -/* - * This function is called from cleanup module, or during shut-down, in - * order to unregister our driver. - */ -void sbp2_cleanup(void) -{ - SBP2_DEBUG("sbp2_cleanup"); - - hpsb_unregister_protocol(&sbp2_driver); - - if (sbp2_hl_handle) { - hpsb_unregister_highlevel(sbp2_hl_handle); - sbp2_hl_handle = NULL; - } -} - static int sbp2_probe(struct unit_directory *ud) { struct sbp2scsi_host_info *hi; @@ -999,35 +924,44 @@ { struct sbp2scsi_host_info *hi; unsigned long flags; + struct Scsi_Host *scsi_host; SBP2_DEBUG("sbp2_add_host"); - /* Allocate some memory for our host info structure */ - hi = (struct sbp2scsi_host_info *)kmalloc(sizeof(struct sbp2scsi_host_info), - in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL); - - if (hi == NULL) { - SBP2_ERR("out of memory in sbp2_add_host"); + /* Register our host with the SCSI stack. */ + scsi_host = scsi_register (&scsi_driver_template, sizeof(struct sbp2scsi_host_info)); + if (!scsi_host) { + SBP2_ERR("failed to register scsi host"); return; } - /* Initialize some host stuff */ + hi = (struct sbp2scsi_host_info *)&scsi_host->hostdata; memset(hi, 0, sizeof(struct sbp2scsi_host_info)); + + hi->scsi_host = scsi_host; INIT_LIST_HEAD(&hi->list); hi->host = host; hi->sbp2_command_lock = SPIN_LOCK_UNLOCKED; + hi->scsi_host->max_id = SBP2SCSI_MAX_SCSI_IDS; spin_lock_irqsave(&sbp2_host_info_lock, flags); list_add_tail(&hi->list, &sbp2_host_info_list); spin_unlock_irqrestore(&sbp2_host_info_lock, flags); - /* Register our host with the SCSI stack. */ - hi->scsi_host = scsi_register (&scsi_driver_template, sizeof(void *)); - if (hi->scsi_host) { - hi->scsi_host->hostdata[0] = (unsigned long)hi; - hi->scsi_host->max_id = SBP2SCSI_MAX_SCSI_IDS; + /* + * XXX(hch): Hopefully the ieee1394 code will be converted + * to the driver model at some point. Until that happens + * we'll have to pass in NULL here. + */ + if (scsi_add_host(hi->scsi_host, NULL)) { + SBP2_ERR("failed to add scsi host"); + + spin_lock_irqsave(&sbp2_host_info_lock, flags); + list_del(&hi->list); + spin_unlock_irqrestore(&sbp2_host_info_lock, flags); + + scsi_unregister(hi->scsi_host); } - scsi_driver_template.present++; return; } @@ -1079,16 +1013,15 @@ SBP2_DEBUG("sbp2_remove_host"); spin_lock_irqsave(&sbp2_host_info_lock, flags); - hi = sbp2_find_host_info(host); - if (hi != NULL) { + if (hi) list_del(&hi->list); - kfree(hi); - } - else - SBP2_ERR("attempt to remove unknown host %p", host); - spin_unlock_irqrestore(&sbp2_host_info_lock, flags); + + if (hi) { + scsi_remove_host(hi->scsi_host); + scsi_unregister(hi->scsi_host); + } } /* @@ -1098,6 +1031,7 @@ static int sbp2_start_device(struct sbp2scsi_host_info *hi, struct unit_directory *ud) { struct scsi_id_instance_data *scsi_id = NULL; + struct scsi_device *sdev; struct node_entry *ne; int i; @@ -1203,7 +1137,7 @@ /* * Find an empty spot to stick our scsi id instance data. */ - for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) { + for (i = 0; i < hi->scsi_host->max_id; i++) { if (!hi->scsi_id[i]) { hi->scsi_id[i] = scsi_id; scsi_id->id = i; @@ -1224,7 +1158,7 @@ /* * Make sure we are not out of space */ - if (i == SBP2SCSI_MAX_SCSI_IDS) { + if (i == hi->scsi_host->max_id) { SBP2_ERR("No slots left for SBP-2 device"); sbp2_remove_device(hi, scsi_id); return -EBUSY; @@ -1256,6 +1190,13 @@ */ sbp2_max_speed_and_size(hi, scsi_id); + /* Add this device to the scsi layer now */ + sdev = scsi_add_device(hi->scsi_host, 0, scsi_id->id, 0); + if (IS_ERR(sdev)) { + SBP2_ERR("scsi_add_device failed"); + return PTR_ERR(sdev); + } + return 0; } @@ -1265,13 +1206,21 @@ static void sbp2_remove_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { + struct scsi_device *sdev = scsi_find_device(hi->scsi_host, 0, scsi_id->id, 0); + SBP2_DEBUG("sbp2_remove_device"); /* Complete any pending commands with selection timeout */ sbp2scsi_complete_all_commands(hi, scsi_id, DID_NO_CONNECT); - + + /* Remove it from the scsi layer now */ + if (scsi_remove_device(sdev)) + SBP2_ERR("scsi_remove_device failed"); + sbp2util_remove_command_orb_pool(scsi_id, hi); + hi->scsi_id[scsi_id->id] = NULL; + if (scsi_id->login_response) { pci_free_consistent(hi->host->pdev, sizeof(struct sbp2_login_response), @@ -1305,7 +1254,7 @@ } SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id); - hi->scsi_id[scsi_id->id] = NULL; + kfree(scsi_id); } @@ -1793,8 +1742,8 @@ SBP2_DEBUG("sbp2_max_speed_and_size"); /* Initial setting comes from the hosts speed map */ - scsi_id->speed_code = hi->host->speed_map[(hi->host->node_id & NODE_MASK) * 64 - + (scsi_id->ne->nodeid & NODE_MASK)]; + scsi_id->speed_code = hi->host->speed_map[NODEID_TO_NODE(hi->host->node_id) * 64 + + NODEID_TO_NODE(scsi_id->ne->nodeid)]; /* Bump down our speed if the user requested it */ if (scsi_id->speed_code > sbp2_max_speed) { @@ -2661,7 +2610,7 @@ /* * Pull our host info and scsi id instance data from the scsi command */ - hi = (struct sbp2scsi_host_info *) SCpnt->device->host->hostdata[0]; + hi = (struct sbp2scsi_host_info *) &SCpnt->device->host->hostdata; if (!hi) { SBP2_ERR("sbp2scsi_host_info is NULL - this is bad!"); @@ -2766,8 +2715,10 @@ * * This can be called in interrupt context. */ -static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 scsi_status, - Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, + struct scsi_id_instance_data *scsi_id, + u32 scsi_status, Scsi_Cmnd *SCpnt, + void (*done)(Scsi_Cmnd *)) { unsigned long flags; @@ -2888,7 +2839,7 @@ */ static int sbp2scsi_abort (Scsi_Cmnd *SCpnt) { - struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->device->host->hostdata[0]; + struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)&SCpnt->device->host->hostdata; struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->device->id]; struct sbp2_command_info *command; unsigned long flags; @@ -2938,7 +2889,7 @@ */ static int sbp2scsi_reset (Scsi_Cmnd *SCpnt) { - struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->device->host->hostdata[0]; + struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)&SCpnt->device->host->hostdata; struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->device->id]; SBP2_ERR("reset requested"); @@ -2951,32 +2902,6 @@ return(SUCCESS); } -/* - * Called by scsi stack after scsi driver is registered - */ -static int sbp2scsi_detect (Scsi_Host_Template *tpnt) -{ - SBP2_DEBUG("sbp2scsi_detect"); - - /* - * Call sbp2_init to register with the ieee1394 stack. This - * results in a callback to sbp2_add_host for each ieee1394 - * host controller currently registered, and for each of those - * we register a scsi host with the scsi stack. - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_unlock_irq(&io_request_lock); - sbp2_init(); - spin_lock_irq(&io_request_lock); -#else - sbp2_init(); -#endif - - /* We return the number of hosts registered. */ - return scsi_driver_template.present; -} - static const char *sbp2scsi_info (struct Scsi_Host *host) { return "SCSI emulation for for IEEE-1394 Storage Devices"; @@ -3065,7 +2990,6 @@ .proc_name = SBP2_DEVICE_NAME, .info = sbp2scsi_info, .proc_info = sbp2scsi_proc_info, - .detect = sbp2scsi_detect, .queuecommand = sbp2scsi_queuecommand, .eh_abort_handler = sbp2scsi_abort, .eh_device_reset_handler = sbp2scsi_reset, @@ -3097,23 +3021,36 @@ */ scsi_driver_template.max_sectors = sbp2_max_sectors; + /* - * Ideally we would register our scsi_driver_template with the - * scsi stack and after that register with the ieee1394 stack - * and process the add_host callbacks. However, the detect - * function in the scsi host template requires that we find at - * least one host, so we "nest" the registrations by calling - * sbp2_init from the detect function. - */ - scsi_driver_template.module = THIS_MODULE; - if (SCSI_REGISTER_HOST(&scsi_driver_template) || - !scsi_driver_template.present) { - SBP2_ERR("Please load the lower level IEEE-1394 driver " - "(e.g. ohci1394) before sbp2..."); - sbp2_cleanup(); - return -ENODEV; + * Register our high level driver with 1394 stack + */ + sbp2_hl_handle = hpsb_register_highlevel(SBP2_DEVICE_NAME, + &sbp2_hl_ops); + if (!sbp2_hl_handle) { + SBP2_ERR("sbp2 failed to register with ieee1394 highlevel"); + return(-ENOMEM); } + /* + * Register our sbp2 status address space... + */ + hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, + SBP2_STATUS_FIFO_ADDRESS, + SBP2_STATUS_FIFO_ADDRESS + + SBP2_STATUS_FIFO_ENTRY_TO_OFFSET( + SBP2SCSI_MAX_SCSI_IDS+1)); + + /* + * Handle data movement if physical dma is not enabled/supported + * on host controller + */ +#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA + hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops, + 0x0ULL, 0xfffffffcULL); +#endif + + hpsb_register_protocol(&sbp2_driver); return 0; } @@ -3121,17 +3058,9 @@ { SBP2_DEBUG("sbp2_module_exit"); - /* - * On module unload we unregister with the ieee1394 stack - * which results in remove_host callbacks for all ieee1394 - * host controllers. In the callbacks we unregister the - * corresponding scsi hosts. - */ - sbp2_cleanup(); - - if (SCSI_UNREGISTER_HOST(&scsi_driver_template)) - SBP2_ERR("sbp2_module_exit: couldn't unregister scsi driver"); - + hpsb_unregister_protocol(&sbp2_driver); + if (sbp2_hl_handle) + hpsb_unregister_highlevel(sbp2_hl_handle); } module_init(sbp2_module_init); Modified: trunk/sbp2.h ============================================================================== --- trunk/sbp2.h (original) +++ trunk/sbp2.h 2003-02-21 23:39:09.000000000 -0500 @@ -22,15 +22,6 @@ #ifndef SBP2_H #define SBP2_H -/* Some compatibility code */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#define SCSI_REGISTER_HOST(tmpl) scsi_register_module(MODULE_SCSI_HA, tmpl) -#define SCSI_UNREGISTER_HOST(tmpl) scsi_unregister_module(MODULE_SCSI_HA, tmpl) -#else -#define SCSI_REGISTER_HOST(tmpl) scsi_register_host(tmpl) -#define SCSI_UNREGISTER_HOST(tmpl) scsi_unregister_host(tmpl) -#endif - #define SBP2_DEVICE_NAME "sbp2" /* @@ -442,8 +433,6 @@ static void sbp2_add_host(struct hpsb_host *host); static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host); static void sbp2_remove_host(struct hpsb_host *host); -int sbp2_init(void); -void sbp2_cleanup(void); static int sbp2_probe(struct unit_directory *ud); static void sbp2_disconnect(struct unit_directory *ud); static void sbp2_update(struct unit_directory *ud); @@ -487,23 +476,4 @@ static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); -/* - * Scsi interface related prototypes - */ -static int sbp2scsi_detect (Scsi_Host_Template *tpnt); -static const char *sbp2scsi_info (struct Scsi_Host *host); -void sbp2scsi_setup(char *str, int *ints); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,44) -static int sbp2scsi_biosparam (struct scsi_device *sdev, struct block_device *dev, sector_t capacity, int geom[]); -#else -static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]); -#endif -static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); -static int sbp2scsi_reset (Scsi_Cmnd *SCpnt); -static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); -static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, - u32 status); -static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, - u32 scsi_status, Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); - #endif /* SBP2_H */ Modified: trunk/ieee1394_types.h ============================================================================== --- trunk/ieee1394_types.h (original) +++ trunk/ieee1394_types.h 2003-02-21 23:39:09.000000000 -0500 @@ -97,14 +97,17 @@ typedef u16 arm_length_t; #define BUS_MASK 0xffc0 +#define BUS_SHIFT 6 #define NODE_MASK 0x003f #define LOCAL_BUS 0xffc0 #define ALL_NODES 0x003f +#define NODEID_TO_BUS(nodeid) ((nodeid & BUS_MASK) >> BUS_SHIFT) +#define NODEID_TO_NODE(nodeid) (nodeid & NODE_MASK) + /* Can be used to consistently print a node/bus ID. */ -#define NODE_BUS_FMT "%02d:%04d" -#define NODE_BUS_ARGS(nodeid) \ - (nodeid & NODE_MASK), ((nodeid & BUS_MASK) >> 6) +#define NODE_BUS_FMT "%02d:%04d" +#define NODE_BUS_ARGS(nodeid) NODEID_TO_NODE(nodeid), NODEID_TO_BUS(nodeid) #define HPSB_PRINT(level, fmt, args...) printk(level "ieee1394: " fmt "\n" , ## args) |
From: SVN U. <ben...@li...> - 2003-02-22 04:37:14
|
Author: bencollins Date: 2003-02-21 23:36:38 -0500 (Fri, 21 Feb 2003) New Revision: 796 Modified: trunk/ieee1394-ioctl.h Log: Fix for rawiso compiles. Modified: trunk/ieee1394-ioctl.h ============================================================================== --- trunk/ieee1394-ioctl.h (original) +++ trunk/ieee1394-ioctl.h 2003-02-21 23:36:38.000000000 -0500 @@ -4,8 +4,8 @@ #ifndef __IEEE1394_IOCTL_H #define __IEEE1394_IOCTL_H -#include <asm/ioctl.h> -#include <asm/types.h> +#include <linux/ioctl.h> +#include <linux/types.h> /* AMDTP Gets 6 */ @@ -91,7 +91,7 @@ #define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL \ _IOW ('#', 0x23, unsigned char) #define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK \ - _IOW ('#', 0x24, u64) + _IOW ('#', 0x24, __u64) #define RAW1394_IOC_ISO_RECV_PACKETS \ _IOW ('#', 0x25, struct raw1394_iso_packets) #define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS \ |
From: SVN U. <ben...@li...> - 2003-02-18 04:09:02
|
Author: bencollins Date: 2003-02-17 23:08:25 -0500 (Mon, 17 Feb 2003) New Revision: 795 Modified: trunk/sbp2.c Log: New proc file for sbp2. More informative. Modified: trunk/sbp2.c ============================================================================== --- trunk/sbp2.c (original) +++ trunk/sbp2.c 2003-02-17 23:08:26.000000000 -0500 @@ -2952,39 +2952,6 @@ } /* - * Called by scsi stack to get bios parameters (used by fdisk, and at boot). - */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,43) -static int sbp2scsi_biosparam (struct scsi_device *sdev, - struct block_device *dev, sector_t capacity, int geom[]) -{ -#else -static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]) -{ - unsigned capacity = disk->capacity; -#endif - int heads, sectors, cylinders; - - SBP2_DEBUG("Request for bios parameters"); - - heads = 64; - sectors = 32; - cylinders = (int)capacity / (heads * sectors); - - if (cylinders > 1024) { - heads = 255; - sectors = 63; - cylinders = (int)capacity / (heads * sectors); - } - - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - - return(0); -} - -/* * Called by scsi stack after scsi driver is registered */ static int sbp2scsi_detect (Scsi_Host_Template *tpnt) @@ -3010,34 +2977,81 @@ return scsi_driver_template.present; } - -/* - * Called for contents of procfs - */ static const char *sbp2scsi_info (struct Scsi_Host *host) { - struct sbp2scsi_host_info *hi = sbp2_find_host_info_scsi(host); - static char info[1024]; + return "SCSI emulation for for IEEE-1394 Storage Devices"; +} + +/* Called for contents of procfs */ +#define SPRINTF(args...) \ + do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) +static int sbp2scsi_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +{ + Scsi_Device *scd; + struct Scsi_Host *host; + struct sbp2scsi_host_info *hi; + char *pos = buffer; + + /* if someone is sending us data, just throw it away */ + if (inout) + return length; + + host = scsi_host_hn_get(hostno); + if (!host) /* if we couldn't find it, we return an error */ + return -ESRCH; + + hi = sbp2_find_host_info_scsi(host); if (!hi) /* shouldn't happen, but... */ - return "IEEE-1394 SBP-2 protocol driver"; + return -ESRCH; - sprintf(info, "IEEE-1394 SBP-2 protocol driver (host: %s)\n%s\n" - "SBP-2 module load options:\n" - "- Max speed supported: %s\n" - "- Max sectors per I/O supported: %d\n" - "- Serialized I/O (debug): %s\n" - "- Exclusive login: %s", - hi->host->driver->name, - version, - hpsb_speedto_str[sbp2_max_speed], - sbp2_max_sectors, - sbp2_serialize_io ? "yes" : "no", - sbp2_exclusive_login ? "yes" : "no"); + SPRINTF("Host scsi%d : SBP-2 IEEE-1394 (%s)\n", hostno, + hi->host->driver->name); + SPRINTF("Driver version : %s\n", version); - return info; -} + SPRINTF("\nModule options :\n"); + SPRINTF(" sbp2_max_speed : %s\n", hpsb_speedto_str[sbp2_max_speed]); + SPRINTF(" sbp2_max_sectors : %d\n", sbp2_max_sectors); + SPRINTF(" sbp2_serialize_io : %s\n", sbp2_serialize_io ? "yes" : "no"); + SPRINTF(" sbp2_exclusive_login : %s\n", sbp2_exclusive_login ? "yes" : "no"); + + SPRINTF("\nAttached devices : %s\n", !list_empty(&host->my_devices) ? + "" : "none"); + + list_for_each_entry (scd, &host->my_devices, siblings) { + int i; + + SPRINTF(" [Channel: %02d, Id: %02d, Lun: %02d] ", scd->channel, + scd->id, scd->lun); + SPRINTF("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ? + scsi_device_types[(short) scd->type] : "Unknown device"); + + for (i = 0; (i < 8) && (scd->vendor[i] >= 0x20); i++) + SPRINTF("%c", scd->vendor[i]); + SPRINTF(" "); + + for (i = 0; (i < 16) && (scd->model[i] >= 0x20); i++) + SPRINTF("%c", scd->model[i]); + + SPRINTF("\n"); + } + + SPRINTF("\n"); + + /* release the reference count on this host */ + scsi_host_put(host); + /* Calculate start of next buffer, and return value. */ + *start = buffer + offset; + + if ((pos - buffer) < offset) + return (0); + else if ((pos - buffer - offset) < length) + return (pos - buffer - offset); + else + return (length); +} MODULE_AUTHOR("James Goodwin <ja...@fi...>"); MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver"); @@ -3046,25 +3060,24 @@ /* SCSI host template */ static Scsi_Host_Template scsi_driver_template = { - .name = "IEEE-1394 SBP-2 protocol driver", - .info = sbp2scsi_info, - .detect = sbp2scsi_detect, - .queuecommand = sbp2scsi_queuecommand, - .eh_abort_handler = sbp2scsi_abort, - .eh_device_reset_handler =sbp2scsi_reset, - .eh_bus_reset_handler = sbp2scsi_reset, - .eh_host_reset_handler =sbp2scsi_reset, - .bios_param = sbp2scsi_biosparam, - .this_id = -1, - .sg_tablesize = SG_ALL, - .use_clustering = ENABLE_CLUSTERING, - .cmd_per_lun = SBP2_MAX_CMDS_PER_LUN, - .can_queue = SBP2_MAX_SCSI_QUEUE, -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - .use_new_eh_code = TRUE, -#endif - .emulated = 1, - .proc_name = SBP2_DEVICE_NAME, + .module = THIS_MODULE, + .name = "SBP-2 IEEE-1394", + .proc_name = SBP2_DEVICE_NAME, + .info = sbp2scsi_info, + .proc_info = sbp2scsi_proc_info, + .detect = sbp2scsi_detect, + .queuecommand = sbp2scsi_queuecommand, + .eh_abort_handler = sbp2scsi_abort, + .eh_device_reset_handler = sbp2scsi_reset, + .eh_bus_reset_handler = sbp2scsi_reset, + .eh_host_reset_handler = sbp2scsi_reset, + .this_id = -1, + .sg_tablesize = SG_ALL, + .use_clustering = ENABLE_CLUSTERING, + .cmd_per_lun = SBP2_MAX_CMDS_PER_LUN, + .can_queue = SBP2_MAX_SCSI_QUEUE, + .emulated = 1, + .highmem_io = 1, }; static int sbp2_module_init(void) |
From: SVN U. <ben...@li...> - 2003-02-18 01:32:24
|
Author: bencollins Date: 2003-02-17 20:31:51 -0500 (Mon, 17 Feb 2003) New Revision: 794 Modified: trunk/ohci1394.c Log: Use ~0 for class mask. Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-17 20:31:52.000000000 -0500 @@ -3482,10 +3482,10 @@ static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = { { - .class = PCI_CLASS_FIREWIRE_OHCI, - .class_mask = 0x00ffffff, - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, + .class = PCI_CLASS_FIREWIRE_OHCI, + .class_mask = ~0, + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, |
From: SVN U. <ben...@li...> - 2003-02-18 01:29:50
|
Author: bencollins Date: 2003-02-17 20:29:16 -0500 (Mon, 17 Feb 2003) New Revision: 793 Modified: trunk/nodemgr.c Log: Merge change to call_usermodehelper(). Added final 0 argument. Modified: trunk/nodemgr.c ============================================================================== --- trunk/nodemgr.c (original) +++ trunk/nodemgr.c 2003-02-17 20:29:16.000000000 -0500 @@ -786,7 +786,7 @@ #ifdef CONFIG_IEEE1394_VERBOSEDEBUG HPSB_DEBUG("NodeMgr: %s %s %016Lx", argv[0], verb, (long long unsigned)ud->ne->guid); #endif - value = call_usermodehelper(argv[0], argv, envp); + value = call_usermodehelper(argv[0], argv, envp, 0); kfree(buf); kfree(envp); if (value != 0) |
From: SVN U. <ben...@li...> - 2003-02-17 15:08:02
|
Author: bencollins Date: 2003-02-17 10:07:29 -0500 (Mon, 17 Feb 2003) New Revision: 792 Modified: branches/linux-2.4/sbp2.c branches/linux-2.4/sbp2.h Log: Increase max outstanding commands default. Patch from Matthew Galgoci. Modified: branches/linux-2.4/sbp2.c ============================================================================== --- branches/linux-2.4/sbp2.c (original) +++ branches/linux-2.4/sbp2.c 2003-02-17 10:07:30.000000000 -0500 @@ -84,7 +84,7 @@ * sbp2_serialize_io - Serialize all I/O coming down from the scsi drivers * (0 = deserialized, 1 = serialized, default = 0) * sbp2_max_sectors, - Change max sectors per I/O supported (default = 255) - * sbp2_max_outstanding_cmds - Change max outstanding concurrent commands (default = 8) + * sbp2_max_outstanding_cmds - Change max outstanding concurrent commands (default = 64) * sbp2_max_cmds_per_lun - Change max concurrent commands per sbp2 device (default = 1) * sbp2_exclusive_login - Set to zero if you'd like to allow multiple hosts the ability * to log in at the same time. Sbp2 device must support this, @@ -402,7 +402,7 @@ * sbp2 devices attached (or if you need to do some debugging). */ MODULE_PARM(sbp2_max_outstanding_cmds,"i"); -MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 8)"); +MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 64)"); static int sbp2_max_outstanding_cmds = SBP2SCSI_MAX_OUTSTANDING_CMDS; /* Modified: branches/linux-2.4/sbp2.h ============================================================================== --- branches/linux-2.4/sbp2.h (original) +++ branches/linux-2.4/sbp2.h 2003-02-17 10:07:30.000000000 -0500 @@ -265,7 +265,7 @@ #define SBP2_CLUSTERING ENABLE_CLUSTERING #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 #define SBP2SCSI_MAX_SCSI_IDS 16 /* Max sbp2 device instances supported */ -#define SBP2SCSI_MAX_OUTSTANDING_CMDS 8 /* Max total outstanding sbp2 commands allowed at a time! */ +#define SBP2SCSI_MAX_OUTSTANDING_CMDS 64 /* Max total outstanding sbp2 commands allowed at a time! */ #define SBP2SCSI_MAX_CMDS_PER_LUN 1 /* Max outstanding sbp2 commands per device - tune as needed */ #define SBP2_MAX_SECTORS 255 /* Max sectors supported */ |
From: SVN U. <ben...@li...> - 2003-02-16 17:14:59
|
Author: bencollins Date: 2003-02-16 12:14:25 -0500 (Sun, 16 Feb 2003) New Revision: 791 Modified: trunk/dma.c Log: Patch from Linux-kernel Bugzilla. Fixes failure to compile by including mm.h. Modified: trunk/dma.c ============================================================================== --- trunk/dma.c (original) +++ trunk/dma.c 2003-02-16 12:14:26.000000000 -0500 @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/vmalloc.h> #include <linux/slab.h> +#include <linux/mm.h> #include "dma.h" /* dma_prog_region */ |
From: SVN U. <ben...@li...> - 2003-02-16 06:10:39
|
Author: bencollins Date: 2003-02-16 01:10:06 -0500 (Sun, 16 Feb 2003) New Revision: 790 Modified: trunk/ Log: Add *.mod.c to ignore list |
From: SVN U. <ben...@li...> - 2003-02-16 04:33:32
|
Author: bencollins Date: 2003-02-15 23:32:57 -0500 (Sat, 15 Feb 2003) New Revision: 789 Modified: trunk/amdtp.c trunk/dv1394.c trunk/video1394.c Log: Check return value of ioctl32 reg/unreg calls. Modified: trunk/amdtp.c ============================================================================== --- trunk/amdtp.c (original) +++ trunk/amdtp.c 2003-02-15 23:32:58.000000000 -0500 @@ -1264,8 +1264,11 @@ static int __init amdtp_init_module (void) { - if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_AMDTP, - THIS_MODULE, &amdtp_fops)) { + int ret; + + ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_AMDTP, + THIS_MODULE, &amdtp_fops); + if (ret) { HPSB_ERR("amdtp: unable to get minor device block"); return -EIO; } @@ -1279,10 +1282,12 @@ } #ifdef CONFIG_COMPAT - register_ioctl32_conversion(AMDTP_IOC_CHANNEL, NULL); - register_ioctl32_conversion(AMDTP_IOC_PLUG, NULL); - register_ioctl32_conversion(AMDTP_IOC_PING, NULL); - register_ioctl32_conversion(AMDTP_IOC_ZAP, NULL); + ret = register_ioctl32_conversion(AMDTP_IOC_CHANNEL, NULL); + ret |= register_ioctl32_conversion(AMDTP_IOC_PLUG, NULL); + ret |= register_ioctl32_conversion(AMDTP_IOC_PING, NULL); + ret |= register_ioctl32_conversion(AMDTP_IOC_ZAP, NULL); + if (ret) + HPSB_ERR("amdtp: Error registering ioctl32 translations"); #endif HPSB_INFO("Loaded AMDTP driver"); @@ -1293,10 +1298,14 @@ static void __exit amdtp_exit_module (void) { #ifdef CONFIG_COMPAT - unregister_ioctl32_conversion(AMDTP_IOC_CHANNEL); - unregister_ioctl32_conversion(AMDTP_IOC_PLUG); - unregister_ioctl32_conversion(AMDTP_IOC_PING); - unregister_ioctl32_conversion(AMDTP_IOC_ZAP); + int ret; + + ret = unregister_ioctl32_conversion(AMDTP_IOC_CHANNEL); + ret |= unregister_ioctl32_conversion(AMDTP_IOC_PLUG); + ret |= unregister_ioctl32_conversion(AMDTP_IOC_PING); + ret |= unregister_ioctl32_conversion(AMDTP_IOC_ZAP); + if (ret) + HPSB_ERR("amdtp: Error unregistering ioctl32 translations"); #endif hpsb_unregister_highlevel(amdtp_highlevel); Modified: trunk/video1394.c ============================================================================== --- trunk/video1394.c (original) +++ trunk/video1394.c 2003-02-15 23:32:58.000000000 -0500 @@ -1452,15 +1452,19 @@ static void __exit video1394_exit_module (void) { #ifdef CONFIG_COMPAT - unregister_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL); - unregister_ioctl32_conversion(VIDEO1394_IOC_UNLISTEN_CHANNEL); - unregister_ioctl32_conversion(VIDEO1394_IOC_TALK_CHANNEL); - unregister_ioctl32_conversion(VIDEO1394_IOC_UNTALK_CHANNEL); - unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER); - unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER); - unregister_ioctl32_conversion(VIDEO1394_IOC_TALK_QUEUE_BUFFER); - unregister_ioctl32_conversion(VIDEO1394_IOC32_TALK_WAIT_BUFFER); - unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_POLL_BUFFER); + int ret; + + ret = unregister_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL); + ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_UNLISTEN_CHANNEL); + ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_TALK_CHANNEL); + ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_UNTALK_CHANNEL); + ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER); + ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER); + ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_TALK_QUEUE_BUFFER); + ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_TALK_WAIT_BUFFER); + ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_POLL_BUFFER); + if (ret) + PRINT_G(KERN_INFO, "Error unregistering ioctl32 translations"); #endif hpsb_unregister_highlevel (hl_handle); @@ -1473,8 +1477,11 @@ static int __init video1394_init_module (void) { - if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394, - THIS_MODULE, &video1394_fops)) { + int ret; + + ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394, + THIS_MODULE, &video1394_fops); + if (ret) { PRINT_G(KERN_ERR, "video1394: unable to get minor device block"); return -EIO; } @@ -1491,22 +1498,24 @@ #ifdef CONFIG_COMPAT /* First the compatible ones */ - register_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL, NULL); - register_ioctl32_conversion(VIDEO1394_IOC_UNLISTEN_CHANNEL, NULL); - register_ioctl32_conversion(VIDEO1394_IOC_TALK_CHANNEL, NULL); - register_ioctl32_conversion(VIDEO1394_IOC_UNTALK_CHANNEL, NULL); + ret = register_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL, NULL); + ret |= register_ioctl32_conversion(VIDEO1394_IOC_UNLISTEN_CHANNEL, NULL); + ret |= register_ioctl32_conversion(VIDEO1394_IOC_TALK_CHANNEL, NULL); + ret |= register_ioctl32_conversion(VIDEO1394_IOC_UNTALK_CHANNEL, NULL); /* These need translation */ - register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER, + ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER, video1394_w_wait32); - register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER, + ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER, video1394_wr_wait32); - register_ioctl32_conversion(VIDEO1394_IOC_TALK_QUEUE_BUFFER, + ret |= register_ioctl32_conversion(VIDEO1394_IOC_TALK_QUEUE_BUFFER, video1394_queue_buf32); - register_ioctl32_conversion(VIDEO1394_IOC32_TALK_WAIT_BUFFER, + ret |= register_ioctl32_conversion(VIDEO1394_IOC32_TALK_WAIT_BUFFER, video1394_w_wait32); - register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_POLL_BUFFER, + ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_POLL_BUFFER, video1394_wr_wait32); + if (ret) + PRINT_G(KERN_INFO, "Error registering ioctl32 translations"); #endif PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module"); Modified: trunk/dv1394.c ============================================================================== --- trunk/dv1394.c (original) +++ trunk/dv1394.c 2003-02-15 23:32:58.000000000 -0500 @@ -3012,13 +3012,17 @@ static void __exit dv1394_exit_module(void) { #ifdef CONFIG_COMPAT - unregister_ioctl32_conversion(DV1394_IOC_SHUTDOWN); - unregister_ioctl32_conversion(DV1394_IOC_SUBMIT_FRAMES); - unregister_ioctl32_conversion(DV1394_IOC_WAIT_FRAMES); - unregister_ioctl32_conversion(DV1394_IOC_RECEIVE_FRAMES); - unregister_ioctl32_conversion(DV1394_IOC_START_RECEIVE); - unregister_ioctl32_conversion(DV1394_IOC32_INIT); - unregister_ioctl32_conversion(DV1394_IOC32_GET_STATUS); + int ret; + + ret = unregister_ioctl32_conversion(DV1394_IOC_SHUTDOWN); + ret |= unregister_ioctl32_conversion(DV1394_IOC_SUBMIT_FRAMES); + ret |= unregister_ioctl32_conversion(DV1394_IOC_WAIT_FRAMES); + ret |= unregister_ioctl32_conversion(DV1394_IOC_RECEIVE_FRAMES); + ret |= unregister_ioctl32_conversion(DV1394_IOC_START_RECEIVE); + ret |= unregister_ioctl32_conversion(DV1394_IOC32_INIT); + ret |= unregister_ioctl32_conversion(DV1394_IOC32_GET_STATUS); + if (ret) + printk(KERN_ERR "dv1394: Error unregistering ioctl32 translations\n"); #endif hpsb_unregister_highlevel (hl_handle); @@ -3033,14 +3037,18 @@ static int __init dv1394_init_module(void) { - if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_DV1394, - THIS_MODULE, &dv1394_fops)) { + int ret; + + ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_DV1394, + THIS_MODULE, &dv1394_fops); + if (ret) { printk(KERN_ERR "dv1394: unable to register character device\n"); return -EIO; } #ifdef CONFIG_DEVFS_FS - if (dv1394_devfs_add_dir("dv", NULL, NULL) < 0) { + ret = dv1394_devfs_add_dir("dv", NULL, NULL); + if (ret < 0) { printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/dv\n"); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); return -ENOMEM; @@ -3048,7 +3056,8 @@ #endif #ifdef CONFIG_PROC_FS - if (dv1394_procfs_add_dir("dv",NULL,NULL) < 0) { + ret = dv1394_procfs_add_dir("dv",NULL,NULL); + if (ret < 0) { printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv\n"); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); #ifdef CONFIG_DEVFS_FS @@ -3073,15 +3082,17 @@ #ifdef CONFIG_COMPAT /* First compatible ones */ - register_ioctl32_conversion(DV1394_IOC_SHUTDOWN, NULL); - register_ioctl32_conversion(DV1394_IOC_SUBMIT_FRAMES, NULL); - register_ioctl32_conversion(DV1394_IOC_WAIT_FRAMES, NULL); - register_ioctl32_conversion(DV1394_IOC_RECEIVE_FRAMES, NULL); - register_ioctl32_conversion(DV1394_IOC_START_RECEIVE, NULL); + ret = register_ioctl32_conversion(DV1394_IOC_SHUTDOWN, NULL); + ret |= register_ioctl32_conversion(DV1394_IOC_SUBMIT_FRAMES, NULL); + ret |= register_ioctl32_conversion(DV1394_IOC_WAIT_FRAMES, NULL); + ret |= register_ioctl32_conversion(DV1394_IOC_RECEIVE_FRAMES, NULL); + ret |= register_ioctl32_conversion(DV1394_IOC_START_RECEIVE, NULL); /* These need to be handled by translation */ - register_ioctl32_conversion(DV1394_IOC32_INIT, handle_dv1394_init); - register_ioctl32_conversion(DV1394_IOC32_GET_STATUS, handle_dv1394_get_status); + ret |= register_ioctl32_conversion(DV1394_IOC32_INIT, handle_dv1394_init); + ret |= register_ioctl32_conversion(DV1394_IOC32_GET_STATUS, handle_dv1394_get_status); + if (ret) + printk(KERN_ERR "dv1394: Error registering ioctl32 translations\n"); #endif return 0; |
From: SVN U. <ben...@li...> - 2003-02-16 04:18:21
|
Author: bencollins Date: 2003-02-15 23:17:39 -0500 (Sat, 15 Feb 2003) New Revision: 788 Modified: trunk/nodemgr.c Log: Merge patch for 2.5.61+bk daemonize change Modified: trunk/nodemgr.c ============================================================================== --- trunk/nodemgr.c (original) +++ trunk/nodemgr.c 2003-02-15 23:17:40.000000000 -0500 @@ -1215,9 +1215,8 @@ struct host_info *hi = (struct host_info *)__hi; /* No userlevel access needed */ - daemonize(); - - strcpy(current->comm, "knodemgrd"); + daemonize("knodemgrd"); + allow_signal(SIGTERM); /* Sit and wait for a signal to probe the nodes on the bus. This * happens when we get a bus reset. */ |
From: SVN U. <dm...@li...> - 2003-02-15 07:33:08
|
Author: dmaas Date: 2003-02-15 02:32:22 -0500 (Sat, 15 Feb 2003) New Revision: 787 Modified: branches/linux-2.4/dv1394-private.h branches/linux-2.4/dv1394.c Log: critical cleanups for dv1394 shutdown and interrupt handling to avoid crashes during shutdown Modified: branches/linux-2.4/dv1394-private.h ============================================================================== --- branches/linux-2.4/dv1394-private.h (original) +++ branches/linux-2.4/dv1394-private.h 2003-02-15 02:32:23.000000000 -0500 @@ -458,6 +458,10 @@ */ spinlock_t spinlock; + /* flag to prevent spurious interrupts (which OHCI seems to + generate a lot :) from accessing the struct */ + int dma_running; + /* 3) the sleeping semaphore 'sem' - this is used from process context only, to serialize various operations on the video_card. Even though only one @@ -571,7 +575,7 @@ static int do_dv1394_init(struct video_card *video, struct dv1394_init *init); static int do_dv1394_init_default(struct video_card *video); -static int do_dv1394_shutdown(struct video_card *video, int free_user_buf); +static void do_dv1394_shutdown(struct video_card *video, int free_user_buf); /* NTSC empty packet rate accurate to within 0.01%, Modified: branches/linux-2.4/dv1394.c ============================================================================== --- branches/linux-2.4/dv1394.c (original) +++ branches/linux-2.4/dv1394.c 2003-02-15 02:32:23.000000000 -0500 @@ -695,7 +695,7 @@ wmb(); #endif - + video->dma_running = 1; /* set the 'run' bit */ reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000); @@ -817,7 +817,9 @@ reg_write(video->ohci, video->ohci_IsoRcvCommandPtr, video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */ wmb(); - + + video->dma_running = 1; + /* run */ reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000); flush_pci_write(video->ohci); @@ -918,16 +920,16 @@ u64 chan_mask; int retval = -EINVAL; - debug_printk( "dv1394: initialising %d\n", video->id ); + debug_printk("dv1394: initialising %d\n", video->id); if(init->api_version != DV1394_API_VERSION) - goto err; + return -EINVAL; /* first sanitize all the parameters */ if( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) ) - goto err; + return -EINVAL; if( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) ) - goto err; + return -EINVAL; if( (init->syt_offset == 0) || (init->syt_offset > 50) ) /* default SYT offset is 3 cycles */ @@ -948,15 +950,15 @@ if(new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE); /* don't allow the user to allocate the DMA buffer more than once */ - if(video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) - goto err; - + if(video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) { + printk("dv1394: re-sizing the DMA buffer is not allowed\n"); + return -EINVAL; + } + /* shutdown the card if it's currently active */ /* (the card should not be reset if the parameters are screwy) */ - if( video_card_initialized(video) ) - do_dv1394_shutdown(video, 0); - + do_dv1394_shutdown(video, 0); /* try to claim the ISO channel */ spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); @@ -973,7 +975,6 @@ /* initialize misc. fields of video */ video->n_frames = init->n_frames; video->pal_or_ntsc = init->format; - video->cip_accum = 0; video->continuity_counter = 0; @@ -989,7 +990,6 @@ video->current_packet = -1; video->first_frame = 0; - if(video->pal_or_ntsc == DV1394_NTSC) { video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC; video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC; @@ -1002,14 +1002,8 @@ video->syt_offset = init->syt_offset; - /* find and claim DMA contexts on the OHCI card */ - /* XXX this should be the last step of initialization, since the interrupt - handler uses ohci_i*_ctx to indicate whether or not it is safe to touch - frames. I'm not making this change quite yet, since it would be better - to clean up the init/shutdown process first.*/ - if(video->ohci_it_ctx == -1) { ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT, it_tasklet_func, (unsigned long) video); @@ -1017,14 +1011,12 @@ if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) { printk(KERN_ERR "dv1394: could not find an available IT DMA context\n"); retval = -EBUSY; - goto err_ctx; - } - else { - video->ohci_it_ctx = video->it_tasklet.context; - debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx); + goto err; } + + video->ohci_it_ctx = video->it_tasklet.context; + debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx); } - if(video->ohci_ir_ctx == -1) { ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE, @@ -1033,14 +1025,11 @@ if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) { printk(KERN_ERR "dv1394: could not find an available IR DMA context\n"); retval = -EBUSY; - goto err_ctx; - } - else { - video->ohci_ir_ctx = video->ir_tasklet.context; - debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx); + goto err; } + video->ohci_ir_ctx = video->ir_tasklet.context; + debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx); } - /* allocate struct frames */ for(i = 0; i < init->n_frames; i++) { @@ -1049,7 +1038,7 @@ if(!video->frames[i]) { printk(KERN_ERR "dv1394: Cannot allocate frame structs\n"); retval = -ENOMEM; - goto err_frames; + goto err; } } @@ -1057,7 +1046,7 @@ /* allocate the ringbuffer */ retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE); if(retval) - goto err_frames; + goto err; video->dv_buf_size = new_buf_size; @@ -1079,7 +1068,7 @@ retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size, video->ohci->dev, PCI_DMA_FROMDEVICE); if(retval) - goto err_dv_buf; + goto err; debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n", video->n_frames*MAX_PACKETS, video->packet_buf.n_pages, @@ -1109,30 +1098,8 @@ return 0; - err_dv_buf: - dma_region_free(&video->dv_buf); - - err_frames: - for(i = 0; i < DV1394_MAX_FRAMES; i++) { - if(video->frames[i]) - frame_delete(video->frames[i]); - } - video->n_frames = 0; - - err_ctx: - if(video->ohci_it_ctx != -1) { - ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet); - video->ohci_it_ctx = -1; - } - if(video->ohci_ir_ctx != -1) { - ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet); - video->ohci_ir_ctx = -1; - } - - spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); - video->ohci->ISO_channel_usage &= ~chan_mask; - spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); - err: +err: + do_dv1394_shutdown(video, 1); return retval; } @@ -1160,10 +1127,15 @@ { unsigned long flags; int i; - + /* no interrupts */ spin_lock_irqsave(&video->spinlock, flags); + video->dma_running = 0; + + if( (video->ohci_it_ctx == -1) && (video->ohci_ir_ctx == -1) ) + goto out; + /* stop DMA if in progress */ if( (video->active_frame != -1) || (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) || @@ -1203,24 +1175,22 @@ } else debug_printk("dv1394: stop_dma: already stopped.\n"); - + +out: spin_unlock_irqrestore(&video->spinlock, flags); } -static int do_dv1394_shutdown(struct video_card *video, int free_dv_buf) +static void do_dv1394_shutdown(struct video_card *video, int free_dv_buf) { int i; - unsigned long flags; debug_printk("dv1394: shutdown...\n"); /* stop DMA if in progress */ stop_dma(video); - spin_lock_irqsave(&video->spinlock, flags); - /* release the DMA contexts */ if(video->ohci_it_ctx != -1) { video->ohci_IsoXmitContextControlSet = 0; @@ -1251,8 +1221,6 @@ video->ohci_ir_ctx = -1; } - spin_unlock_irqrestore(&video->spinlock, flags); - /* release the ISO channel */ if(video->channel != -1) { u64 chan_mask; @@ -1288,9 +1256,7 @@ dma_region_free(&video->packet_buf); video->packet_buf_size = 0; - debug_printk("dv1394: shutdown complete\n"); - - return 0; + debug_printk("dv1394: shutdown OK\n"); } /* @@ -1777,7 +1743,8 @@ } case DV1394_SHUTDOWN: case DV1394_IOC_SHUTDOWN: - ret = do_dv1394_shutdown(video, 0); + do_dv1394_shutdown(video, 0); + ret = 0; break; case DV1394_GET_STATUS: @@ -2147,6 +2114,9 @@ spin_lock(&video->spinlock); + if(!video->dma_running) + goto out; + irq_printk("ContextControl = %08x, CommandPtr = %08x\n", reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), reg_read(video->ohci, video->ohci_IsoXmitCommandPtr) @@ -2273,14 +2243,15 @@ } /* for(each frame) */ } - spin_unlock(&video->spinlock); - if(wake) { kill_fasync(&video->fasync, SIGIO, POLL_OUT); /* wake readers/writers/ioctl'ers */ wake_up_interruptible(&video->waitq); } + +out: + spin_unlock(&video->spinlock); } static void ir_tasklet_func(unsigned long data) @@ -2290,8 +2261,11 @@ spin_lock(&video->spinlock); - if( (video->ohci_ir_ctx != -1) - && (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) + if(!video->dma_running) + goto out; + + if( (video->ohci_ir_ctx != -1) && + (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { int sof=0; /* start-of-frame flag */ @@ -2431,14 +2405,15 @@ } /* receive interrupt */ - spin_unlock(&video->spinlock); - if(wake) { kill_fasync(&video->fasync, SIGIO, POLL_IN); /* wake readers/writers/ioctl'ers */ wake_up_interruptible(&video->waitq); } + +out: + spin_unlock(&video->spinlock); } static struct file_operations dv1394_fops= @@ -2652,6 +2627,7 @@ clear_bit(0, &video->open); spin_lock_init(&video->spinlock); + video->dma_running = 0; init_MUTEX(&video->sem); init_waitqueue_head(&video->waitq); video->fasync = NULL; @@ -2823,6 +2799,9 @@ spin_lock_irqsave(&video->spinlock, flags); + if(!video->dma_running) + goto out; + /* check IT context */ if(video->ohci_it_ctx != -1) { u32 ctx; @@ -2895,7 +2874,8 @@ reg_read(video->ohci, video->ohci_IsoRcvCommandPtr)); } } - + +out: spin_unlock_irqrestore(&video->spinlock, flags); /* wake readers/writers/ioctl'ers */ |