[Linux1394-cvslog] rev 516 - branches/config-rom-gen
Brought to you by:
aeb,
bencollins
From: SVN U. <ben...@us...> - 2002-07-15 16:36:52
|
Author: bencollins Date: Sun, 14 Jul 2002 11:57:20 -0400 New Revision: 516 Modified: branches/config-rom-gen/Config.in branches/config-rom-gen/amdtp.c branches/config-rom-gen/dv1394-private.h branches/config-rom-gen/dv1394.c branches/config-rom-gen/dv1394.h branches/config-rom-gen/hosts.c branches/config-rom-gen/hosts.h branches/config-rom-gen/ieee1394_core.h branches/config-rom-gen/ieee1394_transactions.c branches/config-rom-gen/nodemgr.c branches/config-rom-gen/ohci1394.c branches/config-rom-gen/ohci1394.h branches/config-rom-gen/pcilynx.c branches/config-rom-gen/pcilynx.h branches/config-rom-gen/sbp2.c branches/config-rom-gen/sbp2.h branches/config-rom-gen/video1394.c Log: Merge to rev 515 of trunk Modified: branches/config-rom-gen/dv1394.h ============================================================================== --- branches/config-rom-gen/dv1394.h (original) +++ branches/config-rom-gen/dv1394.h Mon Jul 15 12:36:16 2002 @@ -123,6 +123,67 @@ frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that it may transmit the new frames. + ERROR HANDLING + + An error (buffer underflow/overflow or a break in the DV stream due + to a 1394 bus reset) can be detected by checking the dropped_frames + field of struct dv1394_status (obtained through the + DV1394_GET_STATUS ioctl). + + The best way to recover from such an error is to re-initialize + dv1394, either by using the DV1394_INIT ioctl call, or closing the + file descriptor and opening it again. (note that you must unmap all + ringbuffer mappings when closing the file descriptor, or else + dv1394 will still be considered 'in use'). + + MAIN LOOP + + For maximum efficiency and robustness against bus errors, you are + advised to model the main loop of your application after the + following pseudo-code example: + + (checks of system call return values omitted for brevity; always + check return values in your code!) + + while( frames left ) { + + struct pollfd *pfd = ...; + + pfd->fd = dv1394_fd; + pfd->revents = 0; + pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive) + + (add other sources of I/O here) + + poll(pfd, 1, -1); (or select(); add a timeout if you want) + + if(pfd->revents) { + struct dv1394_status status; + + ioctl(dv1394_fd, DV1394_GET_STATUS, &status); + + if(status.dropped_frames > 0) { + reset_dv1394(); + } else { + for(int i = 0; i < status.n_clear_frames; i++) { + copy_DV_frame(); + } + } + } + } + + where copy_DV_frame() reads or writes on the dv1394 file descriptor + (read/write mode) or copies data to/from the mmap ringbuffer and + then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new + frames are availble (mmap mode). + + reset_dv1394() is called in the event of a buffer + underflow/overflow or a halt in the DV stream (e.g. due to a 1394 + bus reset). To guarantee recovery from the error, this function + should close the dv1394 file descriptor (and munmap() all + ringbuffer mappings, if you are using them), then re-open the + dv1394 device (and re-map the ringbuffer). + */ @@ -218,6 +279,13 @@ unsigned int syt_offset; }; +/* NOTE: you may only allocate the DV frame ringbuffer once each time + you open the dv1394 device. DV1394_INIT will fail if you call it a + second time with different 'n_frames' or 'format' arguments (which + would imply a different size for the ringbuffer). If you need a + different buffer size, simply close and re-open the device, then + initialize it with your new settings. */ + /* Q: What are cip_n and cip_d? */ /* @@ -262,8 +330,9 @@ ready to be filled with data */ unsigned int n_clear_frames; - /* how many times the DV output has underflowed - since the last call to DV1394_GET_STATUS */ + /* how many times the DV stream has underflowed, overflowed, + or otherwise encountered an error, since the previous call + to DV1394_GET_STATUS */ unsigned int dropped_frames; /* N.B. The dropped_frames counter is only a lower bound on the actual Modified: branches/config-rom-gen/ohci1394.c ============================================================================== --- branches/config-rom-gen/ohci1394.c (original) +++ branches/config-rom-gen/ohci1394.c Mon Jul 15 12:36:17 2002 @@ -37,7 +37,7 @@ * . DMA error recovery * * Known bugs: - * . Apple PowerBook detected but not working yet (still true?) + * . devctl BUS_RESET arg confusion (reset type or root holdoff?) */ /* @@ -77,12 +77,6 @@ * . Config ROM generation */ -/* Issues: - * - * - devctl BUS_RESET should treat arg as reset type - * - */ - #include <linux/config.h> #include <linux/kernel.h> #include <linux/list.h> @@ -228,7 +222,7 @@ spin_lock_irqsave (&ohci->phy_reg_lock, flags); - reg_write(ohci, OHCI1394_PhyControl, (((u16)addr << 8) & 0x00000f00) | 0x00008000); + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000); for (i = 0; i < OHCI_LOOP_COUNT; i++) { if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000) @@ -256,7 +250,7 @@ spin_lock_irqsave (&ohci->phy_reg_lock, flags); - reg_write(ohci, OHCI1394_PhyControl, 0x00004000 | (((u16)addr << 8) & 0x00000f00) | data); + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000); for (i = 0; i < OHCI_LOOP_COUNT; i++) { r = reg_read(ohci, OHCI1394_PhyControl); @@ -295,8 +289,6 @@ size_t size; quadlet_t q0, q1; - mdelay(10); - /* Check status of self-id reception */ if (ohci->selfid_swap) @@ -367,13 +359,6 @@ break; mdelay(1); } - - /* Now reenable LPS, since that's usually what we want after a - * softreset anyway. Wait 50msec to make sure we have full link - * enabled. */ - reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); - mdelay(50); - DBGMSG (ohci->id, "Soft reset finished"); } @@ -492,14 +477,42 @@ { quadlet_t buf; + /* Start off with a soft reset, to clear everything to a sane + * state. */ + ohci_soft_reset(ohci); + + /* Now enable LPS, which we need in order to start accessing + * most of the registers. In fact, on some cards (ALI M5251), + * accessing registers in the SClk domain without LPS enabled + * will lock up the machine. Wait 50msec to make sure we have + * full link enabled. */ + reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); + mdelay(50); + + /* Determine the number of available IR and IT contexts. */ + ohci->nb_iso_rcv_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); + DBGMSG(ohci->id, "%d iso receive contexts available", + ohci->nb_iso_rcv_ctx); + + ohci->nb_iso_xmit_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); + DBGMSG(ohci->id, "%d iso transmit contexts available", + ohci->nb_iso_xmit_ctx); + + /* Set the usage bits for non-existent contexts so they can't + * be allocated */ + ohci->ir_ctx_usage |= ~0 << ohci->nb_iso_rcv_ctx; + ohci->it_ctx_usage |= ~0 << ohci->nb_iso_xmit_ctx; + spin_lock_init(&ohci->phy_reg_lock); spin_lock_init(&ohci->event_lock); /* Put some defaults to these undefined bus options */ buf = reg_read(ohci, OHCI1394_BusOptions); - buf |= 0x60000000; /* Enable CMC and ISC */ + buf |= 0xE0000000; /* Enable IRMC, CMC and ISC */ buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */ - buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */ + buf &= ~0x18000000; /* Disable PMC and BMC */ reg_write(ohci, OHCI1394_BusOptions, buf); /* Set the bus number */ @@ -511,8 +524,10 @@ /* Clear link control register */ reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); - /* Enable cycle timer and cycle master */ + /* Enable cycle timer and cycle master and set the IRM + * contender bit in our self ID packets. */ reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000); + set_phy_reg_mask(ohci, 4, 0xc0); /* Clear interrupt registers */ reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); @@ -614,7 +629,7 @@ ((((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), + pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE, ohci->max_packet_size); } @@ -2043,7 +2058,7 @@ struct hpsb_host *host; struct ti_ohci *ohci; /* shortcut to currently handled device */ - unsigned long ohci_base, ohci_len; + unsigned long ohci_base; int i; if (version_printed++ == 0) @@ -2061,6 +2076,7 @@ ohci->id = card_id_counter++; ohci->dev = dev; ohci->host = host; + ohci->init_state = OHCI_INIT_ALLOC_HOST; host->pdev = dev; pci_set_drvdata(dev, ohci); @@ -2076,76 +2092,54 @@ * zero. Should this work? Obviously it's not defined what these * registers will read when they aren't supported. Bleh! */ if (dev->vendor == PCI_VENDOR_ID_APPLE && - dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { - ohci->no_swap_incoming = 1; - ohci->selfid_swap = 0; + dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { + ohci->no_swap_incoming = 1; + ohci->selfid_swap = 0; } else ohci->selfid_swap = 1; #endif - /* csr_config rom allocation */ - ohci->csr_config_rom_cpu = - pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, - &ohci->csr_config_rom_bus); - OHCI_DMA_ALLOC("consistent csr_config_rom"); - if (ohci->csr_config_rom_cpu == NULL) - FAIL(-ENOMEM, "Failed to allocate buffer config rom"); - - + /* We hardwire the MMIO length, since some CardBus adaptors + * fail to report the right length. Anyway, the ohci spec + * clearly says it's 2kb, so this shouldn't be a problem. */ ohci_base = pci_resource_start(dev, 0); - ohci_len = pci_resource_len(dev, 0); - - if (!request_mem_region (ohci_base, ohci_len, OHCI1394_DRIVER_NAME)) - FAIL(-ENOMEM, "MMIO resource (0x%lx@0x%lx) unavailable, aborting.", - ohci_base, ohci_len); - - ohci->registers = ioremap(ohci_base, ohci_len); + if (pci_resource_len(dev, 0) != OHCI1394_REGISTER_SIZE) + PRINT(KERN_WARNING, ohci->id, "Unexpected PCI resource length of %lx!", + pci_resource_len(dev, 0)); + + /* Seems PCMCIA handles this internally. Not sure why. Seems + * pretty bogus to force a driver to special case this. */ +#ifndef PCMCIA + if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME)) + FAIL(-ENOMEM, "MMIO resource (0x%lx - 0x%lx) unavailable", + ohci_base, ohci_base + OHCI1394_REGISTER_SIZE); +#endif + ohci->init_state = OHCI_INIT_HAVE_MEM_REGION; + ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE); if (ohci->registers == NULL) FAIL(-ENXIO, "Failed to remap registers - card not accessible"); - + ohci->init_state = OHCI_INIT_HAVE_IOMAPPING; DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", ohci->registers); + /* csr_config rom allocation */ + ohci->csr_config_rom_cpu = + pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, + &ohci->csr_config_rom_bus); + OHCI_DMA_ALLOC("consistent csr_config_rom"); + if (ohci->csr_config_rom_cpu == NULL) + FAIL(-ENOMEM, "Failed to allocate buffer config rom"); + ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER; - /* Start off with a softreset, to clear everything to a sane - * state. This will also set Link Power State (LPS), which we - * need in order to start accessing most of the registers. */ - ohci_soft_reset(ohci); - - /* determinte the number of available IR and IT contexts right away, - because they need to be known for alloc_dma_*_ctx() */ - ohci->nb_iso_rcv_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); - DBGMSG(ohci->id, "%d iso receive contexts available", - ohci->nb_iso_rcv_ctx); - - ohci->ir_ctx_usage = 0; - - /* set the usage bits for non-existent contexts so they can't be allocated */ - for(i = ohci->nb_iso_rcv_ctx; i < sizeof(ohci->ir_ctx_usage)*8; i++) - __set_bit(i, &ohci->ir_ctx_usage); - - ohci->nb_iso_xmit_ctx = - get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); - DBGMSG(ohci->id, "%d iso transmit contexts available", - ohci->nb_iso_xmit_ctx); - - ohci->it_ctx_usage = 0; - - /* set the usage bits for non-existent contexts so they can't be allocated */ - for(i = ohci->nb_iso_xmit_ctx; i < sizeof(ohci->it_ctx_usage)*8; i++) - __set_bit(i, &ohci->it_ctx_usage); - - - /* - * self-id dma buffer allocation - */ + /* self-id dma buffer allocation */ ohci->selfid_buf_cpu = pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, &ohci->selfid_buf_bus); OHCI_DMA_ALLOC("consistent selfid_buf"); + if (ohci->selfid_buf_cpu == NULL) FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets"); + ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER; if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff) PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on " @@ -2155,6 +2149,7 @@ /* No self-id errors at startup */ ohci->self_id_errors = 0; + ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE; /* AR DMA request context allocation */ ohci->ar_req_context = alloc_dma_rcv_ctx(ohci, DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC, @@ -2189,6 +2184,9 @@ if (ohci->at_resp_context == NULL) FAIL(-ENOMEM, "Failed to allocate AT Resp context"); + ohci->ir_ctx_usage = 0; + ohci->it_ctx_usage = 0; + /* IR DMA context */ ohci->ir_context = alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, 0, IR_NUM_DESC, @@ -2219,10 +2217,12 @@ OHCI1394_DRIVER_NAME, ohci)) FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq); + ohci->init_state = OHCI_INIT_HAVE_IRQ; ohci_initialize(ohci); /* Tell the highlevel this host is ready */ hpsb_add_host(host); + ohci->init_state = OHCI_INIT_DONE; return 0; #undef FAIL @@ -2231,73 +2231,62 @@ static void ohci1394_pci_remove(struct pci_dev *pdev) { struct ti_ohci *ohci; - quadlet_t buf; ohci = pci_get_drvdata(pdev); if (!ohci) return; - if (ohci->host) + switch (ohci->init_state) { + case OHCI_INIT_DONE: hpsb_remove_host(ohci->host); - /* Soft reset before we start */ - ohci_soft_reset(ohci); - - /* Free AR dma */ - free_dma_rcv_ctx(&ohci->ar_req_context); - free_dma_rcv_ctx(&ohci->ar_resp_context); - - /* Free AT dma */ - free_dma_trm_ctx(&ohci->at_req_context); - free_dma_trm_ctx(&ohci->at_resp_context); - - /* Free IR dma */ - free_dma_rcv_ctx(&ohci->ir_context); - - /* 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); + case OHCI_INIT_HAVE_IRQ: + /* Soft reset before we start - this disables + * interrupts and clears linkEnable and LPS. */ + ohci_soft_reset(ohci); + free_irq(ohci->dev->irq, ohci); + + case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE: + /* Free AR dma */ + free_dma_rcv_ctx(&ohci->ar_req_context); + free_dma_rcv_ctx(&ohci->ar_resp_context); + + /* Free AT dma */ + free_dma_trm_ctx(&ohci->at_req_context); + free_dma_trm_ctx(&ohci->at_resp_context); - /* Free self-id buffer */ - if (ohci->selfid_buf_cpu) { + /* Free IR dma */ + free_dma_rcv_ctx(&ohci->ir_context); + + /* Free IT dma */ + free_dma_trm_ctx(&ohci->it_context); + + case OHCI_INIT_HAVE_SELFID_BUFFER: pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, ohci->selfid_buf_cpu, ohci->selfid_buf_bus); OHCI_DMA_FREE("consistent selfid_buf"); - } - - /* Free config rom */ - if (ohci->csr_config_rom_cpu) { + + case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER: pci_free_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, - ohci->csr_config_rom_cpu, + ohci->csr_config_rom_cpu, ohci->csr_config_rom_bus); OHCI_DMA_FREE("consistent csr_config_rom"); - } - - /* 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) + case OHCI_INIT_HAVE_IOMAPPING: iounmap(ohci->registers); - release_mem_region (pci_resource_start(ohci->dev, 0), - pci_resource_len(ohci->dev, 0)); + case OHCI_INIT_HAVE_MEM_REGION: +#ifndef PCMCIA + release_mem_region(pci_resource_start(ohci->dev, 0), + OHCI1394_REGISTER_SIZE); +#endif #ifdef CONFIG_ALL_PPC - /* On UniNorth, power down the cable and turn off the - * chip clock when the module is removed to save power - * on laptops. Turning it back ON is done by the arch - * code when pci_enable_device() is called - */ + /* On UniNorth, power down the cable and turn off the chip + * clock when the module is removed to save power on + * laptops. Turning it back ON is done by the arch code when + * pci_enable_device() is called */ { struct device_node* of_node; @@ -2309,8 +2298,10 @@ } #endif /* CONFIG_ALL_PPC */ - pci_set_drvdata(ohci->dev, NULL); - hpsb_unref_host(ohci->host); + case OHCI_INIT_ALLOC_HOST: + pci_set_drvdata(ohci->dev, NULL); + hpsb_unref_host(ohci->host); + } } #define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) Modified: branches/config-rom-gen/amdtp.c ============================================================================== --- branches/config-rom-gen/amdtp.c (original) +++ branches/config-rom-gen/amdtp.c Mon Jul 15 12:36:19 2002 @@ -1110,7 +1110,7 @@ static int __init amdtp_init_module (void) { - if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL, + if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_AMDTP, THIS_MODULE, &amdtp_fops)) { HPSB_ERR("amdtp: unable to get minor device block"); return -EIO; @@ -1120,7 +1120,7 @@ &amdtp_highlevel_ops); if (amdtp_highlevel == NULL) { HPSB_ERR("amdtp: unable to register highlevel ops"); - ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP); return -EIO; } @@ -1132,7 +1132,7 @@ static void __exit amdtp_exit_module (void) { hpsb_unregister_highlevel(amdtp_highlevel); - ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP); HPSB_INFO("Unloaded AMDTP driver"); } Modified: branches/config-rom-gen/ieee1394_core.h ============================================================================== --- branches/config-rom-gen/ieee1394_core.h (original) +++ branches/config-rom-gen/ieee1394_core.h Mon Jul 15 12:36:20 2002 @@ -182,6 +182,7 @@ #define IEEE1394_MINOR_BLOCK_RAW1394 0 #define IEEE1394_MINOR_BLOCK_VIDEO1394 1 #define IEEE1394_MINOR_BLOCK_DV1394 2 +#define IEEE1394_MINOR_BLOCK_AMDTP 3 #define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15 /* return the index (within a minor number block) of a file */ Modified: branches/config-rom-gen/dv1394-private.h ============================================================================== --- branches/config-rom-gen/dv1394-private.h (original) +++ branches/config-rom-gen/dv1394-private.h Mon Jul 15 12:36:21 2002 @@ -460,7 +460,7 @@ This is a regular int, but use test_and_set_bit() (on bit zero) for atomicity. */ - int open; + unsigned long open; /* 2) the spinlock - this provides mutual exclusion between the interrupt Modified: branches/config-rom-gen/ohci1394.h ============================================================================== --- branches/config-rom-gen/ohci1394.h (original) +++ branches/config-rom-gen/ohci1394.h Mon Jul 15 12:36:21 2002 @@ -21,6 +21,8 @@ #ifndef _OHCI1394_H #define _OHCI1394_H +#include <asm/io.h> + #include "ieee1394_types.h" #include <asm/io.h> @@ -144,7 +146,16 @@ struct pci_dev *dev; - u32 state; + enum { + OHCI_INIT_ALLOC_HOST, + OHCI_INIT_HAVE_MEM_REGION, + OHCI_INIT_HAVE_IOMAPPING, + OHCI_INIT_HAVE_CONFIG_ROM_BUFFER, + OHCI_INIT_HAVE_SELFID_BUFFER, + OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE, + OHCI_INIT_HAVE_IRQ, + OHCI_INIT_DONE, + } init_state; /* remapped memory spaces */ void *registers; Modified: branches/config-rom-gen/ieee1394_transactions.c ============================================================================== --- branches/config-rom-gen/ieee1394_transactions.c (original) +++ branches/config-rom-gen/ieee1394_transactions.c Mon Jul 15 12:36:22 2002 @@ -169,8 +169,9 @@ */ int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait) { - int tlabel; + int tlabel = 0; unsigned long flags; + int found_tlabel = 0; if (wait) { down(&host->tlabel_count); @@ -180,15 +181,18 @@ spin_lock_irqsave(&host->tlabel_lock, flags); - if (host->tlabel_pool[0] != ~0) { - tlabel = ffz(host->tlabel_pool[0]); - host->tlabel_pool[0] |= 1 << tlabel; - } else { - tlabel = ffz(host->tlabel_pool[1]); - host->tlabel_pool[1] |= 1 << tlabel; - tlabel += 32; + while (!found_tlabel) { + tlabel = host->tlabel_current; + if (tlabel < 32 && !(host->tlabel_pool[0] & 1 << tlabel)) { + host->tlabel_pool[0] |= 1 << tlabel; + found_tlabel = 1; + } else if (!(host->tlabel_pool[1] & 1 << (tlabel - 32))) { + host->tlabel_pool[1] |= 1 << (tlabel - 32); + found_tlabel = 1; + } + host->tlabel_current = (host->tlabel_current + 1) % 64; } - + spin_unlock_irqrestore(&host->tlabel_lock, flags); return tlabel; Modified: branches/config-rom-gen/nodemgr.c ============================================================================== --- branches/config-rom-gen/nodemgr.c (original) +++ branches/config-rom-gen/nodemgr.c Mon Jul 15 12:36:23 2002 @@ -178,7 +178,7 @@ for (i = 0; i < 3; i++) { ret = hpsb_read(host, nodeid, generation, address, quad, 4); - if (ret != -EAGAIN) + if (!ret) break; } *quad = be32_to_cpu(*quad); @@ -962,12 +962,26 @@ HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT, NODE_BUS_ARGS(nodeid)); #endif + /* + * Must retry a few times if config rom read returns zero (how long?). Will + * not normally occur, but we should do the right thing. For example, with + * some sbp2 devices, the bridge chipset cannot return valid config rom reads + * immediately after power-on, since they need to detect the type of + * device attached (disk or CD-ROM). + */ + for (i = 0; i < 4; i++) { + if (nodemgr_read_quadlet(host, nodeid, generation, + addr, &buffer[0]) < 0) { + HPSB_ERR("ConfigROM quadlet transaction error for node " + NODE_BUS_FMT, NODE_BUS_ARGS(nodeid)); + return -1; + } + if (buffer[0]) + break; - if (nodemgr_read_quadlet(host, nodeid, generation, - addr, &buffer[0]) < 0) { - HPSB_ERR("ConfigROM quadlet transaction error for node " - NODE_BUS_FMT, NODE_BUS_ARGS(nodeid)); - return -1; + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout (HZ/4)) + return -1; } header_size = buffer[0] >> 24; @@ -1028,10 +1042,15 @@ return; if (buffer[1] != IEEE1394_BUSID_MAGIC) { - /* This isn't a 1394 device */ - HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device", - NODE_BUS_ARGS(nodeid)); - return; + /* This isn't a 1394 device, but we let it slide. There + * was a report of a device with broken firmware which + * reported '2394' instead of '1394', which is obviously a + * mistake. One would hope that a non-1394 device never + * gets connected to Firewire bus. If someone does, we + * shouldn't be held responsible, so we'll allow it with a + * warning. */ + HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]", + NODE_BUS_ARGS(nodeid), buffer[1]); } guid = ((u64)buffer[3] << 32) | buffer[4]; @@ -1080,11 +1099,11 @@ nodeid_t nodeid = LOCAL_BUS; unsigned int generation; - /* Pause for 1 second, to make sure things settle down. If + /* Pause for 1/4 second, to make sure things settle down. If * schedule_timeout returns non-zero, it means we caught a signal * and need to return. */ set_current_state(TASK_INTERRUPTIBLE); - if (schedule_timeout (HZ)) + if (schedule_timeout (HZ/4)) return; /* Now get the generation in which the node ID's we collect Modified: branches/config-rom-gen/hosts.c ============================================================================== --- branches/config-rom-gen/hosts.c (original) +++ branches/config-rom-gen/hosts.c Mon Jul 15 12:36:24 2002 @@ -124,7 +124,7 @@ h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL); if (!h) return NULL; - memset(h, 0, sizeof(struct hpsb_host)); + memset(h, 0, sizeof(struct hpsb_host) + extra); h->hostdata = h + 1; h->driver = drv; Modified: branches/config-rom-gen/hosts.h ============================================================================== --- branches/config-rom-gen/hosts.h (original) +++ branches/config-rom-gen/hosts.h Mon Jul 15 12:36:24 2002 @@ -31,6 +31,7 @@ u32 tlabel_pool[2]; struct semaphore tlabel_count; spinlock_t tlabel_lock; + u32 tlabel_current; unsigned char iso_listen_count[64]; Modified: branches/config-rom-gen/sbp2.c ============================================================================== --- branches/config-rom-gen/sbp2.c (original) +++ branches/config-rom-gen/sbp2.c Mon Jul 15 12:36:25 2002 @@ -86,6 +86,9 @@ * sbp2_max_sectors, - Change max sectors per I/O supported (default = 255) * sbp2_max_outstanding_cmds - Change max outstanding concurrent commands (default = 8) * sbp2_max_cmds_per_lun - Change max concurrent commands per sbp2 device (default = 1) + * sbp2_exclusive_login - Set to zero if you'd like to allow multiple hosts the ability + * to log in at the same time. Sbp2 device must support this, + * and you must know what you're doing (default = 1) * * (e.g. insmod sbp2 sbp2_serialize_io = 1) * @@ -135,11 +138,14 @@ * - Error Handling: SCSI aborts and bus reset requests are handled somewhat * but the code needs additional debugging. * - * - The SBP-2 driver is currently only supported as a module. It would not take + * - Module: The SBP-2 driver is currently only supported as a module. It would not take * much work to allow it to be compiled into the kernel, but you'd have to * add some init code to the kernel to support this... and modules are much * more flexible anyway. ;-) * + * - Hot-plugging: Interaction with the SCSI stack and support for hot-plugging could + * stand some improvement. + * * * History: * @@ -281,7 +287,7 @@ * (or handle linked commands well). * 04/21/02 - Added some additional debug capabilities: * * Able to handle phys dma requests directly, if host controller has phys - * dma disabled (e.g. insmod ohci1394 phys_dma=0). Undefine SBP2_HANDLE_PHYS_DMA + * dma disabled (e.g. insmod ohci1394 phys_dma=0). Undefine CONFIG_IEEE1394_SBP2_PHYS_DMA * if you'd like to disable sbp2 driver from registering for phys address range. * * New packet dump debug define (CONFIG_IEEE1394_SBP2_PACKET_DUMP) which allows * dumping of all sbp2 related packets sent and received. Especially effective @@ -289,7 +295,9 @@ * * Added new sbp2 module load option (sbp2_exclusive_login) for allowing * non-exclusive login to sbp2 device, for special multi-host applications. * 04/23/02 - Fix for Sony CD-ROM drives. Only send fetch agent reset to sbp2 device if it - * returns the dead bit in status. Thanks to Chandan (ch...@to...) for this one. + * returns the dead bit in status. Thanks to Chandan (ch...@to...) for this one. + * 04/27/02 - Fix sbp2 login problem on SMP systems, enable real spinlocks by default. (JSG) + * 06/09/02 - Don't force 36-bute SCSI inquiry, but leave in a define for badly behaved devices. (JSG) */ @@ -316,6 +324,7 @@ #include <asm/uaccess.h> #include <asm/io.h> #include <asm/byteorder.h> +#include <asm/atomic.h> #include <asm/system.h> #include <asm/io.h> #include <asm/scatterlist.h> @@ -341,7 +350,7 @@ #include "sbp2.h" static char version[] __devinitdata = - "$Revision: 1.0 $ James Goodwin <ja...@fi...>"; + "$Rev$ James Goodwin <ja...@fi...>"; /* * Module load parameter definitions @@ -406,7 +415,8 @@ * generally unsafe to have two hosts talking to a single sbp2 device at the same time (filesystem * coherency, etc.). If you're running an sbp2 device that supports multiple logins, and you're either * running read-only filesystems or some sort of special filesystem supporting multiple hosts, then - * set sbp2_exclusive_login to zero. + * set sbp2_exclusive_login to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four + * concurrent logins. */ MODULE_PARM(sbp2_exclusive_login,"i"); MODULE_PARM_DESC(sbp2_exclusive_login, "Exclusive login to sbp2 device (default = 1)"); @@ -482,10 +492,10 @@ #define SBP2_ERR(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args) /* - * Spinlock debugging stuff. I'm playing it safe until the driver has been - * debugged on SMP. (JSG) + * Spinlock debugging stuff. */ -/* #define SBP2_USE_REAL_SPINLOCKS */ +#define SBP2_USE_REAL_SPINLOCKS + #ifdef SBP2_USE_REAL_SPINLOCKS #define sbp2_spin_lock(lock, flags) spin_lock_irqsave(lock, flags) #define sbp2_spin_unlock(lock, flags) spin_unlock_irqrestore(lock, flags); @@ -496,11 +506,12 @@ #endif /* - * This is defined just to help with debugging. Functions handling phys dma are - * only used if host adapter is told not to use physical dma, or does not support - * physical dma. + * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on if your sbp2 device + * is not properly handling the SCSI inquiry command. This hack makes the inquiry look more + * like a typical MS Windows inquiry. */ -#define SBP2_HANDLE_PHYS_DMA + +/* #define SBP2_FORCE_36_BYTE_INQUIRY */ /* * Globals @@ -523,7 +534,7 @@ write: sbp2_handle_status_write }; -#ifdef SBP2_HANDLE_PHYS_DMA +#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA static struct hpsb_address_ops sbp2_physdma_ops = { read: sbp2_handle_physdma_read, write: sbp2_handle_physdma_write, @@ -612,6 +623,21 @@ #endif /* + * Goofy routine that basically does a down_timeout function. + */ +static int sbp2util_down_timeout(atomic_t *done, int timeout) +{ + int i; + + for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) { + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout(HZ/10)) /* 100ms */ + return(1); + } + return ((i > 0) ? 0:1); +} + +/* * This function is called to initially create a packet pool for use in * sbp2 I/O requests. This packet pool is used when sending out sbp2 * command and agent reset requests, and allows us to remove all @@ -739,7 +765,7 @@ hpsb_node_fill_packet(ne, packet); - packet->tlabel = get_tlabel(hi->host, packet->node_id, 1); + packet->tlabel = get_tlabel(hi->host, packet->node_id, 0); if (!data_size) { fill_async_writequad(packet, addr, data); @@ -1027,7 +1053,7 @@ /* * Handle data movement if physical dma is not enabled/supported on host controller */ -#ifdef SBP2_HANDLE_PHYS_DMA +#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL); #endif @@ -1322,7 +1348,7 @@ scsi_id->max_payload_size = sbp2_speedto_maxrec[SPEED_100]; ud->driver_data = scsi_id; - init_waitqueue_head(&scsi_id->sbp2_login_wait); + atomic_set(&scsi_id->sbp2_login_complete, 0); /* * Initialize structures needed for the command orb pool. @@ -1460,7 +1486,7 @@ kfree(scsi_id); } -#ifdef SBP2_HANDLE_PHYS_DMA +#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA /* * This function deals with physical dma write requests (for adapters that do not support * physical dma in hardware). Mostly just here for debugging... @@ -1506,7 +1532,7 @@ { return (((device_type == TYPE_DISK) || (device_type == TYPE_SDAD) || - (device_type == TYPE_ROM)) ? 0:1); + (device_type == TYPE_ROM)) ? 1:0); } /* @@ -1516,7 +1542,6 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { quadlet_t data[2]; - unsigned long flags; SBP2_DEBUG("sbp2_login_device"); @@ -1579,35 +1604,28 @@ data[1] = scsi_id->login_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); + atomic_set(&scsi_id->sbp2_login_complete, 0); + SBP2_DEBUG("sbp2_login_device: prepared to write"); hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8); SBP2_DEBUG("sbp2_login_device: written"); /* - * Wait for login status... but, only if the device has not - * already logged-in (some devices are fast) + * Wait for login status (up to 20 seconds)... */ - - save_flags(flags); - cli(); - /* 20 second timeout */ - if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) - sleep_on_timeout(&scsi_id->sbp2_login_wait, 20*HZ); - restore_flags(flags); - - SBP2_DEBUG("sbp2_login_device: initial check"); + if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 20*HZ)) { + SBP2_ERR("Error logging into SBP-2 device - login timed-out"); + return(-EIO); + } /* - * Match status to the login orb. If they do not match, it's - * probably because the login timed-out. + * Sanity. Make sure status returned matches login orb. */ if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) { SBP2_ERR("Error logging into SBP-2 device - login timed-out"); return(-EIO); } - SBP2_DEBUG("sbp2_login_device: second check"); - /* * Check status */ @@ -1689,10 +1707,12 @@ data[1] = scsi_id->logout_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); + atomic_set(&scsi_id->sbp2_login_complete, 0); + hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8); /* Wait for device to logout...1 second. */ - sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); + sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ); SBP2_INFO("Logged out of SBP-2 device"); @@ -1707,7 +1727,6 @@ static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { quadlet_t data[2]; - unsigned long flags; SBP2_DEBUG("sbp2_reconnect_device"); @@ -1752,22 +1771,20 @@ data[1] = scsi_id->reconnect_orb_dma; sbp2util_cpu_to_be32_buffer(data, 8); + atomic_set(&scsi_id->sbp2_login_complete, 0); + hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8); /* - * Wait for reconnect status... but, only if the device has not - * already reconnected (some devices are fast). + * Wait for reconnect status (up to 1 second)... */ - save_flags(flags); - cli(); - /* One second timout */ - if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) - sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); - restore_flags(flags); + if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ)) { + SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out"); + return(-EIO); + } /* - * Match status to the reconnect orb. If they do not match, it's - * probably because the reconnect timed-out. + * Sanity. Make sure status returned matches reconnect orb. */ if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) { SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out"); @@ -2381,11 +2398,14 @@ /* * The scsi stack sends down a request_bufflen which does not match the * length field in the scsi cdb. This causes some sbp2 devices to - * reject this inquiry command. Hack fix is to set both buff length and - * length field in cdb to 36. This gives best compatibility. + * reject this inquiry command. Fix the request_bufflen. */ if (*cmd == INQUIRY) { +#ifdef SBP2_FORCE_36_BYTE_INQUIRY request_bufflen = cmd[4] = 0x24; +#else + request_bufflen = cmd[4]; +#endif } /* @@ -2752,10 +2772,19 @@ scsi_id->last_orb = NULL; } + } else { + + /* + * It's probably a login/logout/reconnect status. + */ + if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) || + (scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) || + (scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) { + atomic_set(&scsi_id->sbp2_login_complete, 1); + } } sbp2_spin_unlock(&hi->sbp2_command_lock, flags); - wake_up(&scsi_id->sbp2_login_wait); return(RCODE_COMPLETE); } @@ -2988,9 +3017,9 @@ done (SCpnt); spin_unlock_irq(&io_request_lock); #else - spin_lock_irq(&hi->scsi_host->host_lock); + spin_lock_irq(hi->scsi_host->host_lock); done (SCpnt); - spin_unlock_irq(&hi->scsi_host->host_lock); + spin_unlock_irq(hi->scsi_host->host_lock); #endif return; Modified: branches/config-rom-gen/sbp2.h ============================================================================== --- branches/config-rom-gen/sbp2.h (original) +++ branches/config-rom-gen/sbp2.h Mon Jul 15 12:36:29 2002 @@ -398,9 +398,9 @@ u32 sbp2_firmware_revision; /* - * Wait queue used for logins, reconnects, logouts + * Variable used for logins, reconnects, logouts */ - wait_queue_head_t sbp2_login_wait; + atomic_t sbp2_login_complete; /* * Pool of command orbs, so we can have more than overlapped command per id @@ -500,10 +500,13 @@ struct unit_directory *ud); static void sbp2_remove_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); + +#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data, u64 addr, unsigned int length); static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data, u64 addr, unsigned int length); +#endif /* * SBP-2 protocol related prototypes Modified: branches/config-rom-gen/pcilynx.c ============================================================================== --- branches/config-rom-gen/pcilynx.c (original) +++ branches/config-rom-gen/pcilynx.c Mon Jul 15 12:36:30 2002 @@ -2,6 +2,7 @@ * ti_pcilynx.c - Texas Instruments PCILynx driver * Copyright (C) 1999,2000 Andreas Bombe <and...@mu...>, * Stephan Linz <li...@ma...> + * Manfred Weihs <we...@ic...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,6 +42,8 @@ #include "highlevel.h" #include "pcilynx.h" +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> /* print general (card independent) information */ #define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args) @@ -56,9 +59,85 @@ #endif +/* Module Parameters */ +MODULE_PARM(skip_eeprom,"i"); +MODULE_PARM_DESC(skip_eeprom, "Do not try to read bus info block from serial eeprom, but user generic one (default = 0)."); +static int skip_eeprom = 0; + + static struct hpsb_host_driver *lynx_driver; static unsigned int card_id; + + +/* + * I2C stuff + */ + +/* the i2c stuff was inspired by i2c-philips-par.c */ + +static void bit_setscl(void *data, int state) +{ + if (state) { + ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000040; + } else { + ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000040; + } + reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state); +} + +static void bit_setsda(void *data, int state) +{ + if (state) { + ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000010; + } else { + ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000010; + } + reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state); +} + +static int bit_getscl(void *data) +{ + return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000040; +} + +static int bit_getsda(void *data) +{ + return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000010; +} + +static int bit_reg(struct i2c_client *client) +{ + return 0; +} + +static int bit_unreg(struct i2c_client *client) +{ + return 0; +} + +static struct i2c_algo_bit_data bit_data = { + NULL, + bit_setsda, + bit_setscl, + bit_getsda, + bit_getscl, + 5, 5, 100, /* waits, timeout */ +}; + +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, +}; + + + /* * PCL handling functions. */ @@ -1232,6 +1311,11 @@ int i; int error; + /* needed for i2c communication with serial eeprom */ + struct i2c_adapter i2c_adapter; + struct i2c_algo_bit_data i2c_adapter_data; + + int got_valid_bus_info_block = 0; /* set to 1, if we were able to get a valid bus info block from serial eeprom */ error = -ENXIO; @@ -1492,6 +1576,94 @@ if (i != -1) set_phy_reg(lynx, 4, i | 0x40); } + + if (!skip_eeprom) + { + i2c_adapter = bit_ops; + i2c_adapter_data = bit_data; + i2c_adapter.algo_data = &i2c_adapter_data; + i2c_adapter_data.data = lynx; + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + PRINT(KERN_DEBUG, lynx->id,"original eeprom control: %d",reg_read(lynx,SERIAL_EEPROM_CONTROL)); +#endif + + /* reset hardware to sane state */ + lynx->i2c_driven_state = 0x00000070; + reg_write(lynx, SERIAL_EEPROM_CONTROL, lynx->i2c_driven_state); + + if (i2c_bit_add_bus(&i2c_adapter) < 0) + { + PRINT(KERN_ERR, lynx->id, "unable to register i2c"); + } + else + { + /* do i2c stuff */ + unsigned char i2c_cmd = 0x10; + struct i2c_msg msg[2] = { { 0x50, 0, 1, &i2c_cmd }, + { 0x50, I2C_M_RD, 20, (unsigned char*) lynx->config_rom } + }; + + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + union i2c_smbus_data data; + + if (i2c_smbus_xfer(&i2c_adapter, 80, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_BYTE,NULL)) + PRINT(KERN_ERR, lynx->id,"eeprom read start has failed"); + else + { + u16 addr; + for (addr=0x00; addr < 0x100; addr++) { + if (i2c_smbus_xfer(&i2c_adapter, 80, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE,& data)) { + PRINT(KERN_ERR, lynx->id, "unable to read i2c %x", addr); + break; + } + else + PRINT(KERN_DEBUG, lynx->id,"got serial eeprom data at %x: %x",addr, data.byte); + } + } +#endif + + /* we use i2c_transfer, because i2c_smbus_read_block_data does not work properly and we + do it more efficiently in one transaction rather then using several reads */ + if (i2c_transfer(&i2c_adapter, msg, 2) < 0) { + PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c"); + } else { +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + int i; +#endif + PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom"); + /* FIXME: probably we shoud rewrite the max_rec, max_ROM(1394a), generation(1394a) and link_spd(1394a) field + and recalculate the CRC */ + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + for (i=0; i < 5 ; i++) + PRINT(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x",i, be32_to_cpu(lynx->config_rom[i])); +#endif + + /* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */ + if (((be32_to_cpu(lynx->config_rom[0]) & 0xffff0000) == 0x04040000) && + (lynx->config_rom[1] == __constant_cpu_to_be32(0x31333934))) + { + PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from"); + got_valid_bus_info_block = 1; + } else { + PRINT(KERN_WARNING, lynx->id, "read something from serial eeprom, but it does not seem to be a valid bus info block"); + } + + } + + i2c_bit_del_bus(&i2c_adapter); + } + } + + if (got_valid_bus_info_block) { + memcpy(lynx->config_rom+5,lynx_csr_rom+5,sizeof(lynx_csr_rom)-20); + } else { + PRINT(KERN_INFO, lynx->id, "since we did not get a bus info block from serial eeprom, we use a generic one with a hard coded GUID"); + memcpy(lynx->config_rom,lynx_csr_rom,sizeof(lynx_csr_rom)); + } + hpsb_add_host(host); lynx->state = is_host; @@ -1503,7 +1675,8 @@ static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr) { - *ptr = lynx_csr_rom; + struct ti_lynx *lynx = host->hostdata; + *ptr = lynx->config_rom; return sizeof(lynx_csr_rom); } Modified: branches/config-rom-gen/video1394.c ============================================================================== --- branches/config-rom-gen/video1394.c (original) +++ branches/config-rom-gen/video1394.c Mon Jul 15 12:36:32 2002 @@ -168,86 +168,35 @@ /* Memory management functions */ /*******************************/ -#define MDEBUG(x) do { } while(0) /* Debug memory management */ - -/* [DaveM] I've recoded most of this so that: - * 1) It's easier to tell what is happening - * 2) It's more portable, especially for translating things - * out of vmalloc mapped areas in the kernel. - * 3) Less unnecessary translations happen. - * - * The code used to assume that the kernel vmalloc mappings - * existed in the page tables of every process, this is simply - * not guaranteed. We now use pgd_offset_k which is the - * defined way to get at the kernel page tables. - */ - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset_kernel(pmd, adr); - pte = *ptep; - if(pte_present(pte)) { - ret = (unsigned long) - page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); - return ret; -} - -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); - return ret; -} - static inline unsigned long kvirt_to_bus(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = virt_to_bus((void *)kva); - MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); - return ret; + return ret; } /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); return ret; } static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; - + unsigned long adr; + + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (mem) { @@ -256,8 +205,7 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -267,15 +215,14 @@ static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; - + unsigned long adr; + if (mem) { adr=(unsigned long) mem; - while (size > 0) + while ((long) size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -520,11 +467,11 @@ static void reset_ir_status(struct dma_iso_ctx *d, int n) { int i; - d->ir_prg[n][0].status = 4; - d->ir_prg[n][1].status = PAGE_SIZE-4; + d->ir_prg[n][0].status = cpu_to_le32(4); + d->ir_prg[n][1].status = cpu_to_le32(PAGE_SIZE-4); for (i=2;i<d->nb_cmd-1;i++) - d->ir_prg[n][i].status = PAGE_SIZE; - d->ir_prg[n][i].status = d->left_size; + d->ir_prg[n][i].status = cpu_to_le32(PAGE_SIZE); + d->ir_prg[n][i].status = cpu_to_le32(d->left_size); } static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags) @@ -534,38 +481,38 @@ int i; /* the first descriptor will read only 4 bytes */ - ir_prg[0].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_BRANCH | 4; + ir_prg[0].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_BRANCH | 4); /* set the sync flag */ if (flags & VIDEO1394_SYNC_FRAMES) - ir_prg[0].control |= DMA_CTL_WAIT; + ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT); - ir_prg[0].address = kvirt_to_bus(buf); - ir_prg[0].branchAddress = (virt_to_bus(&(ir_prg[1].control)) - & 0xfffffff0) | 0x1; + ir_prg[0].address = cpu_to_le32(kvirt_to_bus(buf)); + ir_prg[0].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[1].control)) + & 0xfffffff0) | 0x1); /* the second descriptor will read PAGE_SIZE-4 bytes */ - ir_prg[1].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_BRANCH | (PAGE_SIZE-4); - ir_prg[1].address = kvirt_to_bus(buf+4); - ir_prg[1].branchAddress = (virt_to_bus(&(ir_prg[2].control)) - & 0xfffffff0) | 0x1; + ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_BRANCH | (PAGE_SIZE-4)); + ir_prg[1].address = cpu_to_le32(kvirt_to_bus(buf+4)); + ir_prg[1].branchAddress = cpu_to_le32((virt_to_bus(&(ir_prg[2].control)) + & 0xfffffff0) | 0x1); for (i=2;i<d->nb_cmd-1;i++) { - ir_prg[i].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_BRANCH | PAGE_SIZE; - ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE); + ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_BRANCH | PAGE_SIZE); + ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE)); ir_prg[i].branchAddress = - (virt_to_bus(&(ir_prg[i+1].control)) - & 0xfffffff0) | 0x1; + cpu_to_le32((virt_to_bus(&(ir_prg[i+1].control)) + & 0xfffffff0) | 0x1); } /* the last descriptor will generate an interrupt */ - ir_prg[i].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | - DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size; - ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE); + ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | + DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size); + ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE)); } static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags) @@ -628,7 +575,7 @@ spin_lock(&d->lock); for (i=0;i<d->num_desc;i++) { - if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) { + if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) { reset_ir_status(d, i); d->buffer_status[i] = VIDEO1394_BUFFER_READY; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) @@ -664,7 +611,7 @@ buf[7] = timeStamp & 0xff; /* if first packet is empty packet, then put timestamp into the next full one too */ - if ( (d->it_prg[n][0].data[1] >>16) == 0x008) { + if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) { buf += d->packet_size; buf[6] = timeStamp >> 8; buf[7] = timeStamp & 0xff; @@ -683,7 +630,7 @@ buf[7] = timeStamp & 0xff; /* if first packet is empty packet, then put timestamp into the next full one too */ - if ( (d->it_prg[n][0].data[1] >>16) == 0x008) { + if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) { buf += d->packet_size; buf[6] = timeStamp >> 8; buf[7] = timeStamp & 0xff; @@ -707,7 +654,8 @@ spin_lock(&d->lock); for (i=0;i<d->num_desc;i++) { - if (d->it_prg[i][d->last_used_cmd[i]].end.status& 0xFFFF0000) { + if (d->it_prg[i][d->last_used_cmd[i]].end.status& + cpu_to_le32(0xFFFF0000)) { int next = d->next_buffer[i]; put_timestamp(ohci, d, next); d->it_prg[i][d->last_used_cmd[i]].end.status = 0; @@ -727,39 +675,40 @@ d->last_used_cmd[n] = d->nb_cmd - 1; for (i=0;i<d->nb_cmd;i++) { - it_prg[i].begin.control = DMA_CTL_OUTPUT_MORE | - DMA_CTL_IMMEDIATE | 8 ; + it_prg[i].begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE | + DMA_CTL_IMMEDIATE | 8) ; it_prg[i].begin.address = 0; it_prg[i].begin.status = 0; - it_prg[i].data[0] = + it_prg[i].data[0] = cpu_to_le32( (SPEED_100 << 16) | (/* tag */ 1 << 14) | (d->channel << 8) - | (TCODE_ISO_DATA << 4); - if (i==0) it_prg[i].data[0] |= sync_tag; - it_prg[i].data[1] = d->packet_size << 16; + | (TCODE_ISO_DATA << 4)); + if (i==0) it_prg[i].data[0] |= cpu_to_le32(sync_tag); + it_prg[i].data[1] = cpu_to_le32(d->packet_size << 16); it_prg[i].data[2] = 0; it_prg[i].data[3] = 0; - it_prg[i].end.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH; + it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | + DMA_CTL_BRANCH); it_prg[i].end.address = - kvirt_to_bus(buf+i*d->packet_size); + cpu_to_le32(kvirt_to_bus(buf+i*d->packet_size)); if (i<d->nb_cmd-1) { - it_prg[i].end.control |= d->packet_size; + it_prg[i].end.control |= cpu_to_le32(d->packet_size); it_prg[i].begin.branchAddress = - (virt_to_bus(&(it_prg[i+1].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) + & 0xfffffff0) | 0x3); it_prg[i].end.branchAddress = - (virt_to_bus(&(it_prg[i+1].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) + & 0xfffffff0) | 0x3); } else { /* the last prg generates an interrupt */ - it_prg[i].end.control |= DMA_CTL_UPDATE | - DMA_CTL_IRQ | d->left_size; + it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | + DMA_CTL_IRQ | d->left_size); /* the last prg doesn't branch */ it_prg[i].begin.branchAddress = 0; it_prg[i].end.branchAddress = 0; @@ -798,21 +747,21 @@ } else { size = packet_sizes[i]; } - it_prg[i].data[1] = size << 16; - it_prg[i].end.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH; + it_prg[i].data[1] = cpu_to_le32(size << 16); + it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH); if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) { - it_prg[i].end.control |= size; + it_prg[i].end.control |= cpu_to_le32(size); it_prg[i].begin.branchAddress = - (virt_to_bus(&(it_prg[i+1].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) + & 0xfffffff0) | 0x3); it_prg[i].end.branchAddress = - (virt_to_bus(&(it_prg[i+1].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) + & 0xfffffff0) | 0x3); } else { /* the last prg generates an interrupt */ - it_prg[i].end.control |= DMA_CTL_UPDATE | - DMA_CTL_IRQ | size; + it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | + DMA_CTL_IRQ | size); /* the last prg doesn't branch */ it_prg[i].begin.branchAddress = 0; it_prg[i].end.branchAddress = 0; @@ -1057,8 +1006,8 @@ if (d->last_buffer>=0) d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = - (virt_to_bus(&(d->ir_prg[v.buffer][0].control)) - & 0xfffffff0) | 0x1; + cpu_to_le32((virt_to_bus(&(d->ir_prg[v.buffer][0].control)) + & 0xfffffff0) | 0x1); d->last_buffer = v.buffer; @@ -1217,14 +1166,14 @@ d->it_prg[d->last_buffer] [ d->last_used_cmd[d->last_buffer] ].end.branchAddress = - (virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) + & 0xfffffff0) | 0x3); d->it_prg[d->last_buffer] [d->last_used_cmd[d->last_buffer] ].begin.branchAddress = - (virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) - & 0xfffffff0) | 0x3; + cpu_to_le32((virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) + & 0xfffffff0) | 0x3); d->next_buffer[d->last_buffer] = v.buffer; } d->last_buffer = v.buffer; Modified: branches/config-rom-gen/Config.in ============================================================================== --- branches/config-rom-gen/Config.in (original) +++ branches/config-rom-gen/Config.in Mon Jul 15 12:36:34 2002 @@ -9,22 +9,33 @@ if [ "$CONFIG_IEEE1394" != "n" ]; then comment "Device Drivers" - dep_tristate ' Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394 - if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then - bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM - bool ' Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS + + if [ "$CONFIG_I2C" = "n" -o "$CONFIG_I2C_ALGOBIT" = "n" ]; then + comment ' Texas Instruments PCILynx requires I2C bit-banging' + else + dep_tristate ' Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394 $CONFIG_I2C $CONFIG_I2C_ALGOBIT fi + + # Non-maintained pcilynx options + # if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then + # bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM + # bool ' Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS + # fi + dep_tristate ' OHCI-1394 support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394 comment "Protocol Drivers" dep_tristate ' OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394 dep_tristate ' SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394 + if [ "$CONFIG_IEEE1394_SBP2" != "n" ]; then + bool ' Enable Phys DMA support for SBP2 (Debug)' CONFIG_IEEE1394_SBP2_PHYS_DMA + fi dep_tristate ' Ethernet over 1394' CONFIG_IEEE1394_ETH1394 $CONFIG_IEEE1394 dep_tristate ' OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394 dep_tristate ' Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394 dep_tristate ' IEC61883-1 Plug support' CONFIG_IEEE1394_CMP $CONFIG_IEEE1394 - if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then + if [ "$CONFIG_IEEE1394_CMP" != "n" ]; then dep_tristate ' IEC61883-6 (Audio transmission) support' CONFIG_IEEE1394_AMDTP $CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394_CMP fi Modified: branches/config-rom-gen/dv1394.c ============================================================================== --- branches/config-rom-gen/dv1394.c (origi... [truncated message content] |