[Linux1394-cvslog] rev 720 - trunk
Brought to you by:
aeb,
bencollins
From: SVN U. <we...@li...> - 2002-12-22 14:51:21
|
Author: weihs Date: 2002-12-21 20:21:09 -0500 (Sat, 21 Dec 2002) New Revision: 720 Modified: trunk/pcilynx.c trunk/pcilynx.h Log: * Fix possible crash, if transmission of async packet is immediately followed by a bus reset and both events are handled by one singel interrupt. * Read transmission status from PCL rather than DMA channel status register (that is cleaner, avoids a race condition and allows a possible future extension to queue more than one packet in PCL at once) * Use correctly calculated CRCs in the configuration ROM image. Modified: trunk/pcilynx.c ============================================================================== --- trunk/pcilynx.c (original) +++ trunk/pcilynx.c 2002-12-22 09:50:49.000000000 -0500 @@ -27,6 +27,7 @@ * eeprom via i2c and storing it in config ROM * Reworked code for initiating bus resets * (long, short, with or without hold-off) + * Enhancements in async and iso send code */ #include <linux/config.h> @@ -476,7 +477,14 @@ struct hpsb_packet *packet; d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async); + if (!list_empty(&d->pcl_queue)) { + PRINT(KERN_ERR, lynx->id, "trying to queue a new packet in nonempty fifo"); + BUG(); + } + packet = driver_packet(d->queue.next); + list_del(&packet->driver_list); + list_add_tail(&packet->driver_list, &d->pcl_queue); d->header_dma = pci_map_single(lynx->dev, packet->header, packet->header_size, PCI_DMA_TODEVICE); @@ -490,6 +498,7 @@ pcl.next = PCL_NEXT_INVALID; pcl.async_error_next = PCL_NEXT_INVALID; + pcl.pcl_status = 0; #ifdef __BIG_ENDIAN pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size; #else @@ -556,7 +565,7 @@ spin_lock_irqsave(&d->queue_lock, flags); list_add_tail(&packet->driver_list, &d->queue); - if (d->queue.next == &packet->driver_list) + if (list_empty(&d->pcl_queue)) send_next(lynx, packet->type); spin_unlock_irqrestore(&d->queue_lock, flags); @@ -748,7 +757,44 @@ list_splice(&lynx->async.queue, &packet_list); INIT_LIST_HEAD(&lynx->async.queue); - spin_unlock_irqrestore(&lynx->async.queue_lock, flags); + if (list_empty(&lynx->async.pcl_queue)) { + spin_unlock_irqrestore(&lynx->async.queue_lock, flags); + PRINTD(KERN_DEBUG, lynx->id, "no async packet in PCL to cancel"); + } else { + struct ti_pcl pcl; + u32 ack; + struct hpsb_packet *packet; + + PRINT(KERN_INFO, lynx->id, "cancelling async packet, that was already in PCL"); + + get_pcl(lynx, lynx->async.pcl, &pcl); + + packet = driver_packet(lynx->async.pcl_queue.next); + list_del(&packet->driver_list); + + pci_unmap_single(lynx->dev, lynx->async.header_dma, + packet->header_size, PCI_DMA_TODEVICE); + if (packet->data_size) { + pci_unmap_single(lynx->dev, lynx->async.data_dma, + packet->data_size, PCI_DMA_TODEVICE); + } + + spin_unlock_irqrestore(&lynx->async.queue_lock, flags); + + if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { + if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { + ack = (pcl.pcl_status >> 15) & 0xf; + PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); + ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); + } else { + ack = (pcl.pcl_status >> 15) & 0xf; + } + } else { + PRINT(KERN_INFO, lynx->id, "async packet was not completed"); + ack = ACKX_ABORTED; + } + hpsb_packet_sent(host, packet, ack); + } while (!list_empty(&packet_list)) { packet = driver_packet(packet_list.next); @@ -1145,11 +1191,11 @@ linkint = reg_read(lynx, LINK_INT_STATUS); intmask = reg_read(lynx, PCI_INT_STATUS); + if (!(intmask & PCI_INT_INT_PEND)) return; + PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask, linkint); - if (!(intmask & PCI_INT_INT_PEND)) return; - reg_write(lynx, LINK_INT_STATUS, linkint); reg_write(lynx, PCI_INT_STATUS, intmask); @@ -1248,62 +1294,96 @@ } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) { - u32 ack; - struct hpsb_packet *packet; - + PRINTD(KERN_DEBUG, lynx->id, "async sent"); spin_lock(&lynx->async.queue_lock); - ack = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_SEND)); - - packet = driver_packet(lynx->async.queue.next); - list_del(&packet->driver_list); - - pci_unmap_single(lynx->dev, lynx->async.header_dma, - packet->header_size, PCI_DMA_TODEVICE); - if (packet->data_size) { - pci_unmap_single(lynx->dev, lynx->async.data_dma, - packet->data_size, PCI_DMA_TODEVICE); - } + if (list_empty(&lynx->async.pcl_queue)) { + spin_unlock(&lynx->async.queue_lock); + PRINT(KERN_WARNING, lynx->id, "async dma halted, but no queued packet (maybe it was cancelled)"); + } else { + struct ti_pcl pcl; + u32 ack; + struct hpsb_packet *packet; + + get_pcl(lynx, lynx->async.pcl, &pcl); + + packet = driver_packet(lynx->async.pcl_queue.next); + list_del(&packet->driver_list); + + pci_unmap_single(lynx->dev, lynx->async.header_dma, + packet->header_size, PCI_DMA_TODEVICE); + if (packet->data_size) { + pci_unmap_single(lynx->dev, lynx->async.data_dma, + packet->data_size, PCI_DMA_TODEVICE); + } - if (!list_empty(&lynx->async.queue)) { - send_next(lynx, hpsb_async); - } + if (!list_empty(&lynx->async.queue)) { + send_next(lynx, hpsb_async); + } - spin_unlock(&lynx->async.queue_lock); + spin_unlock(&lynx->async.queue_lock); - if (ack & DMA_CHAN_STAT_SPECIALACK) { - ack = (ack >> 15) & 0xf; - PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); - ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); - } else { - ack = (ack >> 15) & 0xf; + if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { + if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { + ack = (pcl.pcl_status >> 15) & 0xf; + PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); + ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); + } else { + ack = (pcl.pcl_status >> 15) & 0xf; + } + } else { + PRINT(KERN_INFO, lynx->id, "async packet was not completed"); + ack = ACKX_SEND_ERROR; + } + hpsb_packet_sent(host, packet, ack); } - - hpsb_packet_sent(host, packet, ack); } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) { - struct hpsb_packet *packet; - + PRINTD(KERN_DEBUG, lynx->id, "iso sent"); spin_lock(&lynx->iso_send.queue_lock); - packet = driver_packet(lynx->iso_send.queue.next); - list_del(&packet->driver_list); + if (list_empty(&lynx->iso_send.pcl_queue)) { + spin_unlock(&lynx->iso_send.queue_lock); + PRINT(KERN_ERR, lynx->id, "iso send dma halted, but no queued packet"); + } else { + struct ti_pcl pcl; + u32 ack; + struct hpsb_packet *packet; + + get_pcl(lynx, lynx->iso_send.pcl, &pcl); + + packet = driver_packet(lynx->iso_send.pcl_queue.next); + list_del(&packet->driver_list); + + pci_unmap_single(lynx->dev, lynx->iso_send.header_dma, + packet->header_size, PCI_DMA_TODEVICE); + if (packet->data_size) { + pci_unmap_single(lynx->dev, lynx->iso_send.data_dma, + packet->data_size, PCI_DMA_TODEVICE); + } - pci_unmap_single(lynx->dev, lynx->iso_send.header_dma, - packet->header_size, PCI_DMA_TODEVICE); - if (packet->data_size) { - pci_unmap_single(lynx->dev, lynx->iso_send.data_dma, - packet->data_size, PCI_DMA_TODEVICE); - } + if (!list_empty(&lynx->iso_send.queue)) { + send_next(lynx, hpsb_iso); + } - if (!list_empty(&lynx->iso_send.queue)) { - send_next(lynx, hpsb_iso); - } + spin_unlock(&lynx->iso_send.queue_lock); - spin_unlock(&lynx->iso_send.queue_lock); + if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) { + if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) { + ack = (pcl.pcl_status >> 15) & 0xf; + PRINTD(KERN_INFO, lynx->id, "special ack %d", ack); + ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR); + } else { + ack = (pcl.pcl_status >> 15) & 0xf; + } + } else { + PRINT(KERN_INFO, lynx->id, "iso send packet was not completed"); + ack = ACKX_SEND_ERROR; + } - hpsb_packet_sent(host, packet, ACK_COMPLETE); + hpsb_packet_sent(host, packet, ack); //FIXME: maybe we should just use ACK_COMPLETE and ACKX_SEND_ERROR + } } if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) { @@ -1605,7 +1685,9 @@ lynx->phy_reg0 = -1; INIT_LIST_HEAD(&lynx->async.queue); + INIT_LIST_HEAD(&lynx->async.pcl_queue); INIT_LIST_HEAD(&lynx->iso_send.queue); + INIT_LIST_HEAD(&lynx->iso_send.pcl_queue); pcl.next = pcl_bus(lynx, lynx->rcv_pcl); put_pcl(lynx, lynx->rcv_pcl_start, &pcl); Modified: trunk/pcilynx.h ============================================================================== --- trunk/pcilynx.h (original) +++ trunk/pcilynx.h 2002-12-22 09:50:49.000000000 -0500 @@ -95,6 +95,7 @@ struct lynx_send_data { pcl_t pcl_start, pcl; struct list_head queue; + struct list_head pcl_queue; /* this queue contains at most one packet */ spinlock_t queue_lock; dma_addr_t header_dma, data_dma; int channel; @@ -514,13 +515,13 @@ static quadlet_t lynx_csr_rom[] = { /* bus info block offset (hex) */ - _(0x04040000), /* info/CRC length, CRC 400 */ + _(0x04046aaf), /* info/CRC length, CRC 400 */ _(0x31333934), /* 1394 magic number 404 */ _(0xf064a000), /* misc. settings 408 */ _(0x08002850), /* vendor ID, chip ID high 40c */ _(0x0000ffff), /* chip ID low 410 */ /* root directory */ - _(0x00090000), /* directory length, CRC 414 */ + _(0x00095778), /* directory length, CRC 414 */ _(0x03080028), /* vendor ID (Texas Instr.) 418 */ _(0x81000008), /* offset to textual ID 41c */ _(0x0c000200), /* node capabilities 420 */ @@ -530,8 +531,8 @@ _(0x81000014), /* offset to textual ID 430 */ _(0x09000000), /* node hardware version 434 */ _(0x81000018), /* offset to textual ID 438 */ - /* module vendor ID textual */ - _(0x00070000), /* CRC length, CRC 43c */ +/* module vendor ID textual */ + _(0x00070812), /* CRC length, CRC 43c */ _(0x00000000), /* 440 */ _(0x00000000), /* 444 */ _(0x54455841), /* "Texas Instruments" 448 */ @@ -540,25 +541,25 @@ _(0x4d454e54), /* 454 */ _(0x53000000), /* 458 */ /* node unique ID leaf */ - _(0x00020000), /* CRC length, CRC 45c */ + _(0x00022ead), /* CRC length, CRC 45c */ _(0x08002850), /* vendor ID, chip ID high 460 */ _(0x0000ffff), /* chip ID low 464 */ /* module dependent info */ - _(0x00050000), /* CRC length, CRC 468 */ + _(0x0005d837), /* CRC length, CRC 468 */ _(0x81000012), /* offset to module textual ID 46c */ _(0x81000017), /* textual descriptor 470 */ _(0x39010000), /* SRAM size 474 */ _(0x3a010000), /* AUXRAM size 478 */ _(0x3b000000), /* AUX device 47c */ /* module textual ID */ - _(0x00050000), /* CRC length, CRC 480 */ + _(0x000594df), /* CRC length, CRC 480 */ _(0x00000000), /* 484 */ _(0x00000000), /* 488 */ _(0x54534231), /* "TSB12LV21" 48c */ _(0x324c5632), /* 490 */ _(0x31000000), /* 494 */ /* part number */ - _(0x00060000), /* CRC length, CRC 498 */ + _(0x00068405), /* CRC length, CRC 498 */ _(0x00000000), /* 49c */ _(0x00000000), /* 4a0 */ _(0x39383036), /* "9806000-0001" 4a4 */ @@ -566,14 +567,14 @@ _(0x30303031), /* 4ac */ _(0x20000001), /* 4b0 */ /* module hardware version textual */ - _(0x00050000), /* CRC length, CRC 4b4 */ + _(0x00056501), /* CRC length, CRC 4b4 */ _(0x00000000), /* 4b8 */ _(0x00000000), /* 4bc */ _(0x5453424b), /* "TSBKPCITST" 4c0 */ _(0x50434954), /* 4c4 */ _(0x53540000), /* 4c8 */ /* node hardware version textual */ - _(0x00050000), /* CRC length, CRC 4d0 */ + _(0x0005d805), /* CRC length, CRC 4d0 */ _(0x00000000), /* 4d4 */ _(0x00000000), /* 4d8 */ _(0x54534232), /* "TSB21LV03" 4dc */ |