patch-2.4.8 linux/drivers/ieee1394/ohci1394.c
Next file: linux/drivers/ieee1394/pcilynx.c
Previous file: linux/drivers/ieee1394/nodemgr.h
Back to the patch index
Back to the overall index
- Lines: 499
- Date:
Sun Jul 29 10:48:33 2001
- Orig file:
v2.4.7/linux/drivers/ieee1394/ohci1394.c
- Orig date:
Wed Jul 25 17:10:20 2001
diff -u --recursive --new-file v2.4.7/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
@@ -36,14 +36,8 @@
* . Async Stream Packets
* . DMA error recovery
*
- * Things to be fixed:
- * . Latency problems on UltraSPARC
- *
* Known bugs:
- * . SelfID are sometimes not received properly
- * if card is initialized with no other nodes
- * on the bus
- * . Apple PowerBook detected but not working yet
+ * . Apple PowerBook detected but not working yet (still true?)
*/
/*
@@ -277,10 +271,7 @@
size_t size;
quadlet_t q0, q1;
- /* SelfID handling seems much easier than for the aic5800 chip.
- All the self-id packets, including this devices own self-id,
- should be correctly arranged in the selfid buffer at this
- stage */
+ mdelay(10);
/* Check status of self-id reception */
@@ -320,7 +311,7 @@
}
if (q0 == ~q1) {
- PRINT(KERN_DEBUG, ohci->id, "SelfID packet 0x%x received", q0);
+ DBGMSG (ohci->id, "SelfID packet 0x%x received", q0);
hpsb_selfid_received(host, cpu_to_be32(q0));
if (((q0 & 0x3f000000) >> 24) == phyid)
DBGMSG (ohci->id, "SelfID for this node is 0x%08x", q0);
@@ -332,7 +323,7 @@
size -= 2;
}
- PRINT(KERN_DEBUG, ohci->id, "SelfID complete");
+ DBGMSG(ohci->id, "SelfID complete");
hpsb_selfid_complete(host, phyid, isroot);
return 0;
@@ -346,10 +337,10 @@
for (i = 0; i < OHCI_LOOP_COUNT; i++) {
if (reg_read(ohci, OHCI1394_HCControlSet) & 0x00010000)
break;
- mdelay(10);
+ mdelay(1);
}
- PRINT(KERN_DEBUG, ohci->id, "Soft reset finished");
+ DBGMSG (ohci->id, "Soft reset finished");
return 0;
}
@@ -458,41 +449,32 @@
return ctx;
}
+static void ohci_init_config_rom(struct ti_ohci *ohci);
+
/* Global initialization */
static int ohci_initialize(struct hpsb_host *host)
{
struct ti_ohci *ohci=host->hostdata;
int retval, i;
+ quadlet_t buf;
spin_lock_init(&ohci->phy_reg_lock);
spin_lock_init(&ohci->event_lock);
- /*
- * Tip by James Goodwin <jamesg@Filanet.com>:
- * We need to add delays after the soft reset, setting LPS, and
- * enabling our link. This might fixes the self-id reception
- * problem at initialization.
- */
-
/* Soft reset */
if ((retval = ohci_soft_reset(ohci)) < 0)
return retval;
- /*
- * Delay after soft reset to make sure everything has settled
- * down (sanity)
- */
- mdelay(10);
-
+ /* Put some defaults to these undefined bus options */
+ buf = reg_read(ohci, OHCI1394_BusOptions);
+ buf |= 0x60000000; /* Enable CMC and ISC */
+ buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
+ buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */
+ reg_write(ohci, OHCI1394_BusOptions, buf);
+
/* Set Link Power Status (LPS) */
reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
- /*
- * Delay after setting LPS in order to make sure link/phy
- * communication is established
- */
- mdelay(10);
-
/* Set the bus number */
reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
@@ -515,13 +497,15 @@
/* enable self-id dma */
reg_write(ohci, OHCI1394_LinkControlSet, 0x00000200);
- /* Set the configuration ROM mapping register */
+ /* Set the Config ROM mapping register */
reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
+ /* Initialize the Config ROM */
+ ohci_init_config_rom(ohci);
+
+ /* Now get our max packet size */
ohci->max_packet_size =
1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
- PRINT(KERN_DEBUG, ohci->id, "Max packet size = %d bytes",
- ohci->max_packet_size);
/* Don't accept phy packets into AR request context */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
@@ -622,6 +606,14 @@
/* Enable link */
reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
+ buf = reg_read(ohci, OHCI1394_Version);
+ PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d] MMIO=[%lx-%lx]"
+ " Max Packet=[%d]", ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
+ ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
+ pci_resource_start(ohci->dev, 0),
+ pci_resource_start(ohci->dev, 0) + pci_resource_len(ohci->dev, 0),
+ ohci->max_packet_size);
+
return 1;
}
@@ -884,7 +876,7 @@
switch (cmd) {
case RESET_BUS:
- PRINT (KERN_DEBUG, ohci->id, "Resetting bus on request%s",
+ DBGMSG(ohci->id, "Bus reset requested%s",
((host->attempt_root || attempt_root) ?
" and attempting to become root" : ""));
set_phy_reg_mask (ohci, 1, 0x40 | ((host->attempt_root || attempt_root) ?
@@ -1076,10 +1068,13 @@
struct hpsb_host *host = ohci->host;
int phyid = -1, isroot = 0, flags;
- /* Read the interrupt event register */
+ /* Read the interrupt event register. We don't clear the bus reset
+ * here. We wait till we get a selfid complete interrupt and clear
+ * it then, and _only_ then. */
spin_lock_irqsave(&ohci->event_lock, flags);
event = reg_read(ohci, OHCI1394_IntEventClear);
- reg_write(ohci, OHCI1394_IntEventClear, event);
+ reg_write(ohci, OHCI1394_IntEventClear,
+ event & ~(OHCI1394_selfIDComplete|OHCI1394_busReset));
spin_unlock_irqrestore(&ohci->event_lock, flags);
if (!event) return;
@@ -1093,15 +1088,12 @@
return;
}
- /* Someone wants a bus reset. Better watch what you wish for...
- *
- * XXX: Read 6.1.1 of the OHCI1394 spec. We need to take special
- * care with the BusReset Interrupt, before and until the SelfID
- * phase is over. This is why the SelfID phase sometimes fails for
- * this driver. */
+ /* Someone wants a bus reset. Better watch what you wish for... */
if (event & OHCI1394_busReset) {
if (!host->in_bus_reset) {
- PRINT(KERN_DEBUG, ohci->id, "Bus reset requested");
+ DBGMSG(ohci->id, "Bus reset requested%s",
+ ((host->attempt_root || attempt_root) ?
+ " and attempting to become root" : ""));
/* Wait for the AT fifo to be flushed */
dma_trm_reset(ohci->at_req_context);
@@ -1112,7 +1104,8 @@
ohci->NumBusResets++;
}
- event &= ~OHCI1394_busReset;
+ /* Mask out everything except selfid */
+ event &= OHCI1394_selfIDComplete;
}
/* XXX: We need a way to also queue the OHCI1394_reqTxComplete,
@@ -1219,7 +1212,7 @@
phyid = node_id & 0x0000003f;
isroot = (node_id & 0x40000000) != 0;
- PRINT(KERN_DEBUG, ohci->id,
+ DBGMSG(ohci->id,
"SelfID interrupt received "
"(phyid %d, %s)", phyid,
(isroot ? "root" : "not root"));
@@ -1249,6 +1242,12 @@
} else
PRINT(KERN_ERR, ohci->id,
"SelfID received outside of bus reset sequence");
+
+ /* Clear everything, it's a new day */
+ spin_lock_irqsave(&ohci->event_lock, flags);
+ reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
+ spin_unlock_irqrestore(&ohci->event_lock, flags);
+
event &= ~OHCI1394_selfIDComplete;
}
if (event & OHCI1394_phyRegRcvd) {
@@ -1260,6 +1259,9 @@
"Physical register received outside of bus reset sequence");
event &= ~OHCI1394_phyRegRcvd;
}
+
+ /* Make sure we handle everything, just in case we accidentally
+ * enabled an interrupt that we didn't write a handler for. */
if (event)
PRINT(KERN_ERR, ohci->id, "Unhandled interrupt(s) 0x%08x\n",
event);
@@ -1374,7 +1376,7 @@
spin_unlock_irqrestore(&d->lock, flags);
return;
}
-#if 0
+
if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status)
== d->buf_size) {
/* Other part of packet not written yet.
@@ -1387,7 +1389,7 @@
spin_unlock_irqrestore(&d->lock, flags);
return;
}
-#endif
+
split_left = length;
split_ptr = (char *)d->spb;
memcpy(split_ptr,buf_ptr,d->buf_size-offset);
@@ -1448,7 +1450,7 @@
hpsb_packet_received(ohci->host, d->spb,
length-4, ack);
}
-#if OHCI1394_DEBUG
+#ifdef OHCI1394_DEBUG
else
PRINT (KERN_DEBUG, ohci->id, "Got phy packet ctx=%d ... discarded",
d->ctx);
@@ -1837,41 +1839,47 @@
#define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32((key) << 24) | (val))
-#define cf_put_crc16(cr, unit) \
- (*(cr)->unitdir[unit].start = cpu_to_be32(((cr)->unitdir[unit].length << 16) | \
- ohci_crc16((cr)->unitdir[unit].start + 1, (cr)->unitdir[unit].length)))
-
-#define cf_unit_begin(cr, unit) \
-do { \
- if ((cr)->unitdir[unit].refer != NULL) { \
- *(cr)->unitdir[unit].refer |= \
- (cr)->data - (cr)->unitdir[unit].refer; \
- cf_put_crc16(cr, (cr)->unitdir[unit].refunit); \
- } \
- (cr)->unitnum = (unit); \
- (cr)->unitdir[unit].start = (cr)->data++; \
-} while (0)
+static inline void cf_put_crc16(struct config_rom_ptr *cr, int unit)
+{
+ *cr->unitdir[unit].start =
+ cpu_to_be32((cr->unitdir[unit].length << 16) |
+ ohci_crc16(cr->unitdir[unit].start + 1,
+ cr->unitdir[unit].length));
+}
-#define cf_put_refer(cr, key, unit) \
-do { \
- (cr)->unitdir[unit].refer = (cr)->data; \
- (cr)->unitdir[unit].refunit = (cr)->unitnum; \
- ((cr)->data++)[0] = cpu_to_be32((key) << 24); \
-} while(0)
+static inline void cf_unit_begin(struct config_rom_ptr *cr, int unit)
+{
+ if (cr->unitdir[unit].refer != NULL) {
+ *cr->unitdir[unit].refer |=
+ cr->data - cr->unitdir[unit].refer;
+ cf_put_crc16(cr, cr->unitdir[unit].refunit);
+ }
+ cr->unitnum = unit;
+ cr->unitdir[unit].start = cr->data++;
+}
-#define cf_unit_end(cr) \
-do { \
- (cr)->unitdir[(cr)->unitnum].length = (cr)->data - \
- ((cr)->unitdir[(cr)->unitnum].start + 1); \
- cf_put_crc16((cr), (cr)->unitnum); \
-} while(0)
+static inline void cf_put_refer(struct config_rom_ptr *cr, char key, int unit)
+{
+ cr->unitdir[unit].refer = cr->data;
+ cr->unitdir[unit].refunit = cr->unitnum;
+ (cr->data++)[0] = cpu_to_be32(key << 24);
+}
+
+static inline void cf_unit_end(struct config_rom_ptr *cr)
+{
+ cr->unitdir[cr->unitnum].length = cr->data -
+ (cr->unitdir[cr->unitnum].start + 1);
+ cf_put_crc16(cr, cr->unitnum);
+}
+
+/* End of NetBSD derived code. */
static void ohci_init_config_rom(struct ti_ohci *ohci)
{
struct config_rom_ptr cr;
memset(&cr, 0, sizeof(cr));
- memset (ohci->csr_config_rom_cpu, 0, sizeof (ohci->csr_config_rom_cpu));
+ memset(ohci->csr_config_rom_cpu, 0, sizeof (ohci->csr_config_rom_cpu));
cr.data = ohci->csr_config_rom_cpu;
@@ -1887,7 +1895,7 @@
reg_read(ohci, OHCI1394_GUIDLo));
/* IEEE P1212 suggests the initial ROM header CRC should only
- * cover the header itself (and not the entire ROM). Since we use
+ * cover the header itself (and not the entire ROM). Since we do
* this, then we can make our bus_info_len the same as the CRC
* length. */
ohci->csr_config_rom_cpu[0] |= cpu_to_be32(
@@ -1981,7 +1989,7 @@
if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
break;
- mdelay(10);
+ mdelay(1);
}
*data = reg_read(ohci, OHCI1394_CSRData);
@@ -1998,29 +2006,15 @@
return data;
}
-struct hpsb_host_template *get_ohci_template(void)
-{
- static struct hpsb_host_template tmpl;
- static int initialized = 0;
-
- if (!initialized) {
- memset (&tmpl, 0, sizeof (struct hpsb_host_template));
-
- /* Initialize by field names so that a template structure
- * reorganization does not influence this code. */
- tmpl.name = "ohci1394";
-
- tmpl.initialize_host = ohci_initialize;
- tmpl.release_host = ohci_remove;
- tmpl.get_rom = get_ohci_rom;
- tmpl.transmit_packet = ohci_transmit;
- tmpl.devctl = ohci_devctl;
- tmpl.hw_csr_reg = ohci_hw_csr_reg;
- initialized = 1;
- }
-
- return &tmpl;
-}
+static struct hpsb_host_template ohci_template = {
+ name: OHCI1394_DRIVER_NAME,
+ initialize_host: ohci_initialize,
+ release_host: ohci_remove,
+ get_rom: get_ohci_rom,
+ transmit_packet: ohci_transmit,
+ devctl: ohci_devctl,
+ hw_csr_reg: ohci_hw_csr_reg,
+};
static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_device_id *ent)
{
@@ -2040,7 +2034,7 @@
}
pci_set_master(dev);
- host = hpsb_get_host(get_ohci_template(), sizeof (struct ti_ohci));
+ host = hpsb_get_host(&ohci_template, sizeof (struct ti_ohci));
if (!host) {
PRINT_G(KERN_ERR, "Out of memory trying to allocate host structure");
return -ENOMEM;
@@ -2054,8 +2048,6 @@
ohci->host = host;
pci_set_drvdata(dev, ohci);
- PRINT(KERN_INFO, ohci->id, "OHCI (PCI) IEEE-1394 Controller");
-
/* We don't want hardware swapping */
pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
@@ -2173,14 +2165,10 @@
ohci->ISO_channel_usage = 0;
spin_lock_init(&ohci->IR_channel_lock);
- if (!request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
+ if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
OHCI1394_DRIVER_NAME, ohci))
- PRINT(KERN_DEBUG, ohci->id, "Allocated interrupt %d", dev->irq);
- else
FAIL("Failed to allocate shared interrupt %d", dev->irq);
- ohci_init_config_rom(ohci);
-
/* Tell the highlevel this host is ready */
highlevel_add_one_host (host);
@@ -2190,7 +2178,9 @@
static void remove_card(struct ti_ohci *ohci)
{
- /* Reset the board properly before leaving */
+ quadlet_t buf;
+
+ /* Soft reset before we start */
ohci_soft_reset(ohci);
/* Free AR dma */
@@ -2207,6 +2197,10 @@
/* Free IT dma */
free_dma_trm_ctx(&ohci->it_context);
+ /* Disable all interrupts */
+ reg_write(ohci, OHCI1394_IntMaskClear, 0x80000000);
+ free_irq(ohci->dev->irq, ohci);
+
/* Free self-id buffer */
if (ohci->selfid_buf_cpu) {
pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
@@ -2222,9 +2216,15 @@
ohci->csr_config_rom_bus);
OHCI_DMA_FREE("consistent csr_config_rom");
}
-
- /* Free the IRQ */
- free_irq(ohci->dev->irq, ohci);
+
+ /* Disable our bus options */
+ buf = reg_read(ohci, OHCI1394_BusOptions);
+ buf &= ~0xf8000000;
+ buf |= 0x00ff0000;
+ reg_write(ohci, OHCI1394_BusOptions, buf);
+
+ /* Clear LinkEnable and LPS */
+ reg_write(ohci, OHCI1394_HCControlClear, 0x000a0000);
if (ohci->registers)
iounmap(ohci->registers);
@@ -2398,7 +2398,7 @@
}
static struct pci_driver ohci1394_driver = {
- name: "ohci1394",
+ name: OHCI1394_DRIVER_NAME,
id_table: ohci1394_pci_tbl,
probe: ohci1394_add_one,
remove: ohci1394_remove_one,
@@ -2406,20 +2406,20 @@
static void __exit ohci1394_cleanup (void)
{
- hpsb_unregister_lowlevel(get_ohci_template());
+ hpsb_unregister_lowlevel(&ohci_template);
pci_unregister_driver(&ohci1394_driver);
}
static int __init ohci1394_init(void)
{
int ret;
- if (hpsb_register_lowlevel(get_ohci_template())) {
+ if (hpsb_register_lowlevel(&ohci_template)) {
PRINT_G(KERN_ERR, "Registering failed");
return -ENXIO;
}
if ((ret = pci_module_init(&ohci1394_driver))) {
PRINT_G(KERN_ERR, "PCI module init failed\n");
- hpsb_unregister_lowlevel(get_ohci_template());
+ hpsb_unregister_lowlevel(&ohci_template);
return ret;
}
return ret;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)