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
- Lines: 526
- Date:
2003-06-13 07:51:34.000000000 -0700
- Orig file:
linux-2.4.20/drivers/ieee1394/pcilynx.c
- Orig date:
2002-11-28 15:53:13.000000000 -0800
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)