patch-2.4.21 linux-2.4.21/drivers/ieee1394/pcilynx.c

Next file: linux-2.4.21/drivers/ieee1394/pcilynx.h
Previous file: linux-2.4.21/drivers/ieee1394/ohci1394.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/ieee1394/pcilynx.c linux-2.4.21/drivers/ieee1394/pcilynx.c
@@ -19,6 +19,17 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+/*
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        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>
@@ -117,23 +128,20 @@
 }
 
 static struct i2c_algo_bit_data bit_data = {
-	NULL,
-	bit_setsda,
-	bit_setscl,
-	bit_getsda,
-	bit_getscl,
-	5, 5, 100,		/*	waits, timeout */
+	.setsda			= bit_setsda,
+	.setscl			= bit_setscl,
+	.getsda			= bit_getsda,
+	.getscl			= bit_getscl,
+	.udelay			= 5,
+	.mdelay			= 5,
+	.timeout		= 100,
 }; 
 
 static struct i2c_adapter bit_ops = {
-	"PCILynx I2C adapter",
-	0xAA, //FIXME: probably we should get an id in i2c-id.h
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	bit_reg,
-	bit_unreg,
+	.id 			= 0xAA, //FIXME: probably we should get an id in i2c-id.h
+	.client_register	= bit_reg,
+	.client_unregister	= bit_unreg,
+	.name			= "PCILynx I2C",
 };
 
 
@@ -450,7 +458,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 +474,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 +495,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 +562,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 +579,7 @@
         struct hpsb_packet *packet;
 	LIST_HEAD(packet_list);
         unsigned long flags;
+	int phy_reg;
 
         switch (cmd) {
         case RESET_BUS:
@@ -571,21 +588,140 @@
                         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;
+		case SHORT_RESET_NO_FORCE_ROOT:
+			if (lynx->phyic.reg_1394a) {
+				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;
+				}
+				if (phy_reg & 0x80) {
+					phy_reg &= ~0x80;
+					set_phy_reg(lynx, 1, phy_reg); /* clear RHB */
+				}
+
+				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, no force_root) 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_NO_FORCE_ROOT:
+			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 &= ~0x80;
+			phy_reg |= 0x40;
+
+			PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, no force_root) on request");
+
+			lynx->selfid_size = -1;
+			lynx->phy_reg0 = -1;
+			set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */
+			break;
+		case SHORT_RESET_FORCE_ROOT:
+			if (lynx->phyic.reg_1394a) {
+				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;
+				}
+				if (!(phy_reg & 0x80)) {
+					phy_reg |= 0x80;
+					set_phy_reg(lynx, 1, phy_reg); /* set RHB */
+				}
+
+				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, force_root set) 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_FORCE_ROOT:
+			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 |= 0xc0;
+
+			PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, force_root set) on request");
+
+			lynx->selfid_size = -1;
+			lynx->phy_reg0 = -1;
+			set_phy_reg(lynx, 1, phy_reg); /* set IBR and RHB */
+			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 +754,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);
@@ -709,7 +882,7 @@
 
 static int mem_open(struct inode *inode, struct file *file)
 {
-        int cid = minor(inode->i_rdev);
+        int cid = MINOR(inode->i_rdev);
         enum { t_rom, t_aux, t_ram } type;
         struct memdata *md;
         
@@ -891,21 +1064,13 @@
         ssize_t retval;
         void *membase;
 
-	if (*offset != off)	/* Check for EOF before we trust wrap */
-		return 0;
-	
-	/* FIXME: Signed wrap is undefined in C - wants fixing up */
-	if (off + count > off)
-		return 0;
-		
-        if ((off + count) > PCILYNX_MAX_MEMORY + 1) {
-                count = PCILYNX_MAX_MEMORY + 1 - off;
+        if ((off + count) > PCILYNX_MAX_MEMORY+1) {
+                count = PCILYNX_MAX_MEMORY+1 - off;
         }
-        if (count == 0) {
-                return 0;
+        if (count == 0 || off > PCILYNX_MAX_MEMORY) {
+                return -ENOSPC;
         }
 
-
         switch (md->type) {
         case rom:
                 membase = md->lynx->local_rom;
@@ -1015,11 +1180,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 +1283,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 +1674,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);
@@ -1677,7 +1878,7 @@
 
 
 
-static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
+static size_t get_lynx_rom(struct hpsb_host *host, quadlet_t **ptr)
 {
         struct ti_lynx *lynx = host->hostdata;
         *ptr = lynx->config_rom;
@@ -1698,7 +1899,7 @@
         .name =     PCILYNX_DRIVER_NAME,
         .id_table = pci_table,
         .probe =    add_card,
-        .remove =   __devexit_p(remove_card),
+        .remove =   remove_card,
 };
 
 static struct hpsb_host_driver lynx_driver = {
@@ -1706,6 +1907,7 @@
         .get_rom =         get_lynx_rom,
         .transmit_packet = lynx_transmit,
         .devctl =          lynx_devctl,
+	.isoctl =          NULL,
 };
 
 MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)