Thread: [Linux1394-cvslog] rev 721 - branches/linux-2.4
Brought to you by:
aeb,
bencollins
From: SVN U. <we...@li...> - 2002-12-22 14:51:24
|
Author: weihs Date: 2002-12-21 20:28:19 -0500 (Sat, 21 Dec 2002) New Revision: 721 Modified: branches/linux-2.4/pcilynx.c branches/linux-2.4/pcilynx.h Log: backport from trunk: Fix for a crash, when async transmission and bus reset are reported by one single interrupt. Correctly calculated CRCs in configuration ROM image. Correct interpretation of the argument, when resetting the bus on request. Modified: branches/linux-2.4/pcilynx.c ============================================================================== --- branches/linux-2.4/pcilynx.c (original) +++ branches/linux-2.4/pcilynx.c 2002-12-22 09:50:51.000000000 -0500 @@ -19,6 +19,17 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* + * Contributions: + * + * Manfred Weihs <we...@ic...> + * reading bus info block (containing GUID) from serial + * 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> #include <linux/kernel.h> #include <linux/slab.h> @@ -450,7 +461,7 @@ if (host->in_bus_reset) return; /* in bus reset again */ - if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); + if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); //FIXME: I do not think, we need this here reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_CYCTIMEREN); @@ -466,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); @@ -480,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 @@ -546,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); @@ -563,6 +582,7 @@ struct hpsb_packet *packet; LIST_HEAD(packet_list); unsigned long flags; + int phy_reg; switch (cmd) { case RESET_BUS: @@ -571,21 +591,47 @@ break; } - if (arg) { - arg = 3 << 6; - } else { - arg = 1 << 6; - } - - retval = get_phy_reg(lynx, 1); - arg |= (retval == -1 ? 63 : retval); - retval = 0; - - PRINT(KERN_INFO, lynx->id, "resetting bus on request"); + switch (arg) { + case SHORT_RESET: + if (lynx->phyic.reg_1394a) { + phy_reg = get_phy_reg(lynx, 5); + if (phy_reg == -1) { + PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); + retval = -1; + break; + } + phy_reg |= 0x40; + + PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset) on request"); + + lynx->selfid_size = -1; + lynx->phy_reg0 = -1; + set_phy_reg(lynx, 5, phy_reg); /* set ISBR */ + break; + } else { + PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy"); + /* fall through to long bus reset */ + } + case LONG_RESET: + phy_reg = get_phy_reg(lynx, 1); + if (phy_reg == -1) { + PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); + retval = -1; + break; + } + phy_reg |= 0x40; + + PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset) on request"); + + lynx->selfid_size = -1; + lynx->phy_reg0 = -1; + set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */ + break; + default: + PRINT(KERN_ERR, lynx->id, "unknown argument for reset_bus command %d", arg); + retval = -1; + } - lynx->selfid_size = -1; - lynx->phy_reg0 = -1; - set_phy_reg(lynx, 1, arg); break; case GET_CYCLE_COUNTER: @@ -618,7 +664,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); @@ -1015,11 +1098,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); @@ -1118,62 +1201,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)) { @@ -1475,7 +1592,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: branches/linux-2.4/pcilynx.h ============================================================================== --- branches/linux-2.4/pcilynx.h (original) +++ branches/linux-2.4/pcilynx.h 2002-12-22 09:50:51.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 */ |