patch-2.4.19 linux-2.4.19/drivers/ieee1394/pcilynx.c
Next file: linux-2.4.19/drivers/ieee1394/pcilynx.h
Previous file: linux-2.4.19/drivers/ieee1394/ohci1394.h
Back to the patch index
Back to the overall index
- Lines: 1021
- Date:
Fri Aug 2 17:39:44 2002
- Orig file:
linux-2.4.18/drivers/ieee1394/pcilynx.c
- Orig date:
Fri Dec 21 09:41:54 2001
diff -urN linux-2.4.18/drivers/ieee1394/pcilynx.c linux-2.4.19/drivers/ieee1394/pcilynx.c
@@ -2,6 +2,7 @@
* ti_pcilynx.c - Texas Instruments PCILynx driver
* Copyright (C) 1999,2000 Andreas Bombe <andreas.bombe@munich.netsurf.de>,
* Stephan Linz <linz@mazet.de>
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
*
* 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,10 +42,8 @@
#include "highlevel.h"
#include "pcilynx.h"
-
-#if MAX_PCILYNX_CARDS > PCILYNX_MINOR_ROM_START
-#error Max number of cards is bigger than PCILYNX_MINOR_ROM_START - this does not work.
-#endif
+#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)
@@ -60,9 +59,84 @@
#endif
-static struct ti_lynx cards[MAX_PCILYNX_CARDS];
-static int num_of_cards = 0;
-static struct hpsb_host_template lynx_template;
+/* 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.
@@ -143,10 +217,6 @@
#endif
-static int add_card(struct pci_dev *dev, const struct pci_device_id *devid);
-static void remove_card(struct pci_dev *dev);
-
-
/***********************************
* IEEE-1394 functionality section *
@@ -161,8 +231,9 @@
unsigned long flags;
if (addr > 15) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": PHY register address %d out of range", addr);
+ PRINT(KERN_ERR, lynx->id,
+ "%s: PHY register address %d out of range",
+ __FUNCTION__, addr);
return -1;
}
@@ -173,8 +244,8 @@
retval = reg_read(lynx, LINK_PHY);
if (i > 10000) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": runaway loop, aborting");
+ PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting",
+ __FUNCTION__);
retval = -1;
break;
}
@@ -196,14 +267,14 @@
unsigned long flags;
if (addr > 15) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": PHY register address %d out of range", addr);
+ PRINT(KERN_ERR, lynx->id,
+ "%s: PHY register address %d out of range", __FUNCTION__, addr);
return -1;
}
if (val > 0xff) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": PHY register value %d out of range", val);
+ PRINT(KERN_ERR, lynx->id,
+ "%s: PHY register value %d out of range", __FUNCTION__, val);
return -1;
}
@@ -222,8 +293,8 @@
int reg;
if (page > 7) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": PHY page %d out of range", page);
+ PRINT(KERN_ERR, lynx->id,
+ "%s: PHY page %d out of range", __FUNCTION__, page);
return -1;
}
@@ -244,8 +315,8 @@
int reg;
if (port > 15) {
- PRINT(KERN_ERR, lynx->id, __FUNCTION__
- ": PHY port %d out of range", port);
+ PRINT(KERN_ERR, lynx->id,
+ "%s: PHY port %d out of range", __FUNCTION__, port);
return -1;
}
@@ -377,7 +448,7 @@
hpsb_selfid_complete(host, phyid, isroot);
- if (host->in_bus_reset) return;
+ if (host->in_bus_reset) return; /* in bus reset again */
if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER);
reg_set_bits(lynx, LINK_CONTROL,
@@ -440,160 +511,7 @@
}
-#if 0
-static int lynx_detect(struct hpsb_host_template *tmpl)
-{
- struct hpsb_host *host;
- int i;
-
- init_driver();
-
- for (i = 0; i < num_of_cards; i++) {
- host = hpsb_get_host(tmpl, 0);
- if (host == NULL) {
- /* simply don't init more after out of mem */
- return i;
- }
- host->hostdata = &cards[i];
- cards[i].host = host;
- }
-
- return num_of_cards;
-}
-#endif
-
-static int lynx_initialize(struct hpsb_host *host)
-{
- struct ti_lynx *lynx = host->hostdata;
- struct ti_pcl pcl;
- int i;
- u32 *pcli;
-
- lynx->selfid_size = -1;
- lynx->phy_reg0 = -1;
-
- lynx->async.queue = NULL;
-
- pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
- put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
-
- pcl.next = PCL_NEXT_INVALID;
- pcl.async_error_next = PCL_NEXT_INVALID;
-#ifdef __BIG_ENDIAN
- pcl.buffer[0].control = PCL_CMD_RCV | 16;
- pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-#else
- pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
- pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-#endif
- pcl.buffer[0].pointer = lynx->rcv_page_dma;
- pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
- put_pcl(lynx, lynx->rcv_pcl, &pcl);
-
- pcl.next = pcl_bus(lynx, lynx->async.pcl);
- pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
- put_pcl(lynx, lynx->async.pcl_start, &pcl);
-
- pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
- pcl.async_error_next = PCL_NEXT_INVALID;
- put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
-
- pcl.next = PCL_NEXT_INVALID;
- pcl.async_error_next = PCL_NEXT_INVALID;
- pcl.buffer[0].control = PCL_CMD_RCV | 4;
-#ifndef __BIG_ENDIAN
- pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
- pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
-
- for (i = 0; i < NUM_ISORCV_PCL; i++) {
- int page = i / ISORCV_PER_PAGE;
- int sec = i % ISORCV_PER_PAGE;
-
- pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page]
- + sec * MAX_ISORCV_SIZE;
- pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
- put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
- }
-
- pcli = (u32 *)&pcl;
- for (i = 0; i < NUM_ISORCV_PCL; i++) {
- pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
- }
- put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
-
- /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
- reg_write(lynx, FIFO_SIZES, 0x003030a0);
- /* 20 byte threshold before triggering PCI transfer */
- reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
- /* threshold on both send FIFOs before transmitting:
- FIFO size - cache line size - 1 */
- i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
- i = 0x30 - i - 1;
- reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
-
- reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
-
- reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
- | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET
- | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK
- | LINK_INT_SENT_REJECT | LINK_INT_TX_INVALID_TC
- | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW
- | LINK_INT_ATF_UNDERFLOW);
-
- reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
- reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
- reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
- DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
- | DMA_WORD1_CMP_MATCH_EXACT | DMA_WORD1_CMP_MATCH_BUS_BCAST
- | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
-
- run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
-
- reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
- reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
- reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
- reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
-
- run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
-
- reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
- | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN
- | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
- | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX);
-
- if (!lynx->phyic.reg_1394a) {
- /* attempt to enable contender bit -FIXME- would this work
- * elsewhere? */
- reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
- reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);
- } else {
- /* set the contender bit in the extended PHY register
- * set. (Should check that bis 0,1,2 (=0xE0) is set
- * in register 2?)
- */
- i = get_phy_reg(lynx, 4);
- if (i != -1) set_phy_reg(lynx, 4, i | 0x40);
- }
-
- return 1;
-}
-
-static void lynx_release(struct hpsb_host *host)
-{
- struct ti_lynx *lynx;
-
- if (host != NULL) {
- lynx = host->hostdata;
- remove_card(lynx->dev);
- } else {
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
- unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
-#endif
- }
-}
-
+/* called from subsystem core */
static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
{
struct ti_lynx *lynx = host->hostdata;
@@ -642,6 +560,8 @@
return 1;
}
+
+/* called from subsystem core */
static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
{
struct ti_lynx *lynx = host->hostdata;
@@ -666,9 +586,7 @@
arg |= (retval == -1 ? 63 : retval);
retval = 0;
- PRINT(KERN_INFO, lynx->id, "resetting bus on request%s",
- (host->attempt_root ? " and attempting to become root"
- : ""));
+ PRINT(KERN_INFO, lynx->id, "resetting bus on request");
lynx->selfid_size = -1;
lynx->phy_reg0 = -1;
@@ -721,6 +639,8 @@
} else {
MOD_DEC_USE_COUNT;
}
+
+ retval = 1;
break;
case ISO_LISTEN_CHANNEL:
@@ -773,13 +693,13 @@
static struct file_operations aux_ops = {
- OWNER_THIS_MODULE
- read: mem_read,
- write: mem_write,
- poll: aux_poll,
- llseek: mem_llseek,
- open: mem_open,
- release: mem_release,
+ .owner = THIS_MODULE,
+ .read = mem_read,
+ .write = mem_write,
+ .poll = aux_poll,
+ .llseek = mem_llseek,
+ .open = mem_open,
+ .release = mem_release,
};
@@ -794,46 +714,35 @@
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;
- V22_COMPAT_MOD_INC_USE_COUNT;
-
if (cid < PCILYNX_MINOR_AUX_START) {
/* just for completeness */
- V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENXIO;
} else if (cid < PCILYNX_MINOR_ROM_START) {
cid -= PCILYNX_MINOR_AUX_START;
- if (cid >= num_of_cards || !cards[cid].aux_port) {
- V22_COMPAT_MOD_DEC_USE_COUNT;
+ if (cid >= num_of_cards || !cards[cid].aux_port)
return -ENXIO;
- }
type = t_aux;
} else if (cid < PCILYNX_MINOR_RAM_START) {
cid -= PCILYNX_MINOR_ROM_START;
- if (cid >= num_of_cards || !cards[cid].local_rom) {
- V22_COMPAT_MOD_DEC_USE_COUNT;
+ if (cid >= num_of_cards || !cards[cid].local_rom)
return -ENXIO;
- }
type = t_rom;
} else {
/* WARNING: Know what you are doing when opening RAM.
* It is currently used inside the driver! */
cid -= PCILYNX_MINOR_RAM_START;
- if (cid >= num_of_cards || !cards[cid].local_ram) {
- V22_COMPAT_MOD_DEC_USE_COUNT;
+ if (cid >= num_of_cards || !cards[cid].local_ram)
return -ENXIO;
- }
type = t_ram;
}
md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL);
- if (md == NULL) {
- V22_COMPAT_MOD_DEC_USE_COUNT;
+ if (md == NULL)
return -ENOMEM;
- }
md->lynx = &cards[cid];
md->cid = cid;
@@ -859,11 +768,7 @@
static int mem_release(struct inode *inode, struct file *file)
{
- struct memdata *md = (struct memdata *)file->private_data;
-
- kfree(md);
-
- V22_COMPAT_MOD_DEC_USE_COUNT;
+ kfree(file->private_data);
return 0;
}
@@ -1010,8 +915,8 @@
membase = md->lynx->aux_port;
break;
default:
- panic("pcilynx%d: unsupported md->type %d in " __FUNCTION__,
- md->lynx->id, md->type);
+ panic("pcilynx%d: unsupported md->type %d in %s",
+ md->lynx->id, md->type, __FUNCTION__);
}
down(&md->lynx->mem_dma_mutex);
@@ -1291,6 +1196,7 @@
}
}
+
static void iso_rcv_bh(struct ti_lynx *lynx)
{
unsigned int idx;
@@ -1335,44 +1241,102 @@
}
+static void remove_card(struct pci_dev *dev)
+{
+ struct ti_lynx *lynx;
+ int i;
+
+ lynx = pci_get_drvdata(dev);
+ if (!lynx) return;
+ pci_set_drvdata(dev, NULL);
+
+ switch (lynx->state) {
+ case is_host:
+ reg_write(lynx, PCI_INT_ENABLE, 0);
+ hpsb_remove_host(lynx->host);
+ case have_intr:
+ reg_write(lynx, PCI_INT_ENABLE, 0);
+ free_irq(lynx->dev->irq, lynx);
+ case have_iomappings:
+ reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+ /* Fix buggy cards with autoboot pin not tied low: */
+ reg_write(lynx, DMA0_CHAN_CTRL, 0);
+ iounmap(lynx->registers);
+ iounmap(lynx->local_rom);
+ iounmap(lynx->local_ram);
+ iounmap(lynx->aux_port);
+ case have_1394_buffers:
+ for (i = 0; i < ISORCV_PAGES; i++) {
+ if (lynx->iso_rcv.page[i]) {
+ pci_free_consistent(lynx->dev, PAGE_SIZE,
+ lynx->iso_rcv.page[i],
+ lynx->iso_rcv.page_dma[i]);
+ }
+ }
+ pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
+ lynx->rcv_page_dma);
+ case have_aux_buf:
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+ pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,
+ lynx->mem_dma_buffer_dma);
+#endif
+ case have_pcl_mem:
+#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
+ pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
+ lynx->pcl_mem_dma);
+#endif
+ case clear:
+ /* do nothing - already freed */
+ ;
+ }
+
+ tasklet_kill(&lynx->iso_rcv.tq);
+ hpsb_unref_host(lynx->host);
+}
+
+
static int __devinit add_card(struct pci_dev *dev,
- const struct pci_device_id *devid)
+ const struct pci_device_id *devid_is_unused)
{
#define FAIL(fmt, args...) do { \
PRINT_G(KERN_ERR, fmt , ## args); \
- num_of_cards--; \
remove_card(dev); \
- return -1; \
+ return error; \
} while (0)
+ struct hpsb_host *host;
struct ti_lynx *lynx; /* shortcut to currently handled device */
- unsigned int i;
+ struct ti_pcl pcl;
+ u32 *pcli;
+ int i;
+ int error;
- if (num_of_cards == MAX_PCILYNX_CARDS) {
- PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
- "Adjust MAX_PCILYNX_CARDS in pcilynx.h.",
- MAX_PCILYNX_CARDS);
- return -1;
- }
+ /* 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 */
- lynx = &cards[num_of_cards++];
+ error = -ENXIO;
if (pci_set_dma_mask(dev, 0xffffffff))
- FAIL("DMA address limits not supported for PCILynx hardware %d",
- lynx->id);
+ FAIL("DMA address limits not supported for PCILynx hardware");
if (pci_enable_device(dev))
- FAIL("failed to enable PCILynx hardware %d", lynx->id);
+ FAIL("failed to enable PCILynx hardware");
pci_set_master(dev);
- lynx->host = hpsb_get_host(&lynx_template, 0);
- if (!lynx->host)
- FAIL("failed to allocate host structure");
-
- lynx->state = have_host_struct;
- lynx->host->hostdata = lynx;
- lynx->id = num_of_cards-1;
+ error = -ENOMEM;
+
+ host = hpsb_alloc_host(lynx_driver, sizeof(struct ti_lynx));
+ if (!host) FAIL("failed to allocate control structure memory");
+
+ lynx = host->hostdata;
+ lynx->id = card_id++;
lynx->dev = dev;
- lynx->host->pdev = dev;
+ lynx->state = clear;
+ lynx->host = host;
+ host->pdev = dev;
+ pci_set_drvdata(dev, lynx);
lynx->lock = SPIN_LOCK_UNLOCKED;
lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED;
@@ -1435,7 +1399,9 @@
}
#endif
- reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+ reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
+ /* Fix buggy cards with autoboot pin not tied low: */
+ reg_write(lynx, DMA0_CHAN_CTRL, 0);
if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ,
PCILYNX_DRIVER_NAME, lynx)) {
@@ -1502,131 +1468,239 @@
PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
}
- /* Tell the highlevel this host is ready */
- highlevel_add_one_host (lynx->host);
-
- return 0;
-#undef FAIL
-}
+ lynx->selfid_size = -1;
+ lynx->phy_reg0 = -1;
-static void remove_card(struct pci_dev *dev)
-{
- struct ti_lynx *lynx;
- int i;
+ lynx->async.queue = NULL;
- lynx = cards;
- while (lynx->dev != dev) lynx++;
+ pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
+ put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
- switch (lynx->state) {
- case have_intr:
- reg_write(lynx, PCI_INT_ENABLE, 0);
- free_irq(lynx->dev->irq, lynx);
- case have_iomappings:
- reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
- iounmap(lynx->registers);
- iounmap(lynx->local_rom);
- iounmap(lynx->local_ram);
- iounmap(lynx->aux_port);
- case have_1394_buffers:
- for (i = 0; i < ISORCV_PAGES; i++) {
- if (lynx->iso_rcv.page[i]) {
- pci_free_consistent(lynx->dev, PAGE_SIZE,
- lynx->iso_rcv.page[i],
- lynx->iso_rcv.page_dma[i]);
- }
- }
- pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
- lynx->rcv_page_dma);
- case have_aux_buf:
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
- pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,
- lynx->mem_dma_buffer_dma);
+ pcl.next = PCL_NEXT_INVALID;
+ pcl.async_error_next = PCL_NEXT_INVALID;
+#ifdef __BIG_ENDIAN
+ pcl.buffer[0].control = PCL_CMD_RCV | 16;
+ pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
+#else
+ pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
+ pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
#endif
- case have_pcl_mem:
-#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
- pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
- lynx->pcl_mem_dma);
+ pcl.buffer[0].pointer = lynx->rcv_page_dma;
+ pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
+ put_pcl(lynx, lynx->rcv_pcl, &pcl);
+
+ pcl.next = pcl_bus(lynx, lynx->async.pcl);
+ pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
+ put_pcl(lynx, lynx->async.pcl_start, &pcl);
+
+ pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
+ pcl.async_error_next = PCL_NEXT_INVALID;
+ put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
+
+ pcl.next = PCL_NEXT_INVALID;
+ pcl.async_error_next = PCL_NEXT_INVALID;
+ pcl.buffer[0].control = PCL_CMD_RCV | 4;
+#ifndef __BIG_ENDIAN
+ pcl.buffer[0].control |= PCL_BIGENDIAN;
#endif
- case have_host_struct:
- /* FIXME - verify host freeing */
- case clear:;
- /* do nothing - already freed */
+ pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
+
+ for (i = 0; i < NUM_ISORCV_PCL; i++) {
+ int page = i / ISORCV_PER_PAGE;
+ int sec = i % ISORCV_PER_PAGE;
+
+ pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page]
+ + sec * MAX_ISORCV_SIZE;
+ pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
+ put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
}
- tasklet_kill(&lynx->iso_rcv.tq);
+ pcli = (u32 *)&pcl;
+ for (i = 0; i < NUM_ISORCV_PCL; i++) {
+ pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
+ }
+ put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
- lynx->state = clear;
-}
+ /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
+ reg_write(lynx, FIFO_SIZES, 0x003030a0);
+ /* 20 byte threshold before triggering PCI transfer */
+ reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
+ /* threshold on both send FIFOs before transmitting:
+ FIFO size - cache line size - 1 */
+ i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
+ i = 0x30 - i - 1;
+ reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
-#if 0
-static int init_driver()
-{
- struct pci_dev *dev = NULL;
- int success = 0;
+ reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
- if (num_of_cards) {
- PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again");
- return 0;
+ reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
+ | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET
+ | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK
+ | LINK_INT_SENT_REJECT | LINK_INT_TX_INVALID_TC
+ | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW
+ | LINK_INT_ATF_UNDERFLOW);
+
+ reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
+ reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
+ reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
+ reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
+ DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
+ | DMA_WORD1_CMP_MATCH_EXACT | DMA_WORD1_CMP_MATCH_BUS_BCAST
+ | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
+
+ run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
+
+ reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
+ reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
+ reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
+ reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
+
+ run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
+
+ reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
+ | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN
+ | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
+ | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX);
+
+ if (!lynx->phyic.reg_1394a) {
+ /* attempt to enable contender bit -FIXME- would this work
+ * elsewhere? */
+ reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
+ reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);
+ } else {
+ /* set the contender bit in the extended PHY register
+ * set. (Should check that bis 0,1,2 (=0xE0) is set
+ * in register 2?)
+ */
+ i = get_phy_reg(lynx, 4);
+ if (i != -1) set_phy_reg(lynx, 4, i | 0x40);
}
- PRINT_G(KERN_INFO, "looking for PCILynx cards");
- while ((dev = pci_find_device(PCI_VENDOR_ID_TI,
- PCI_DEVICE_ID_TI_PCILYNX, dev))
- != NULL) {
- if (add_card(dev) == 0) {
- success = 1;
+ 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 (success == 0) {
- PRINT_G(KERN_WARNING, "no operable PCILynx cards found");
- return -ENXIO;
+ 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));
}
-#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
- if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
- PRINT_G(KERN_ERR, "allocation of char major number %d failed",
- PCILYNX_MAJOR);
- return -EBUSY;
- }
-#endif
+ hpsb_add_host(host);
+ lynx->state = is_host;
return 0;
+#undef FAIL
}
-#endif
+
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);
}
-static struct hpsb_host_template lynx_template = {
- name: PCILYNX_DRIVER_NAME,
- initialize_host: lynx_initialize,
- release_host: lynx_release,
- get_rom: get_lynx_rom,
- transmit_packet: lynx_transmit,
- devctl: lynx_devctl
-};
-
static struct pci_device_id pci_table[] __devinitdata = {
{
- vendor: PCI_VENDOR_ID_TI,
- device: PCI_DEVICE_ID_TI_PCILYNX,
- subvendor: PCI_ANY_ID,
- subdevice: PCI_ANY_ID,
+ .vendor = PCI_VENDOR_ID_TI,
+ .device = PCI_DEVICE_ID_TI_PCILYNX,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
},
{ } /* Terminating entry */
};
-static struct pci_driver lynx_pcidriver = {
- name: PCILYNX_DRIVER_NAME,
- id_table: pci_table,
- probe: add_card,
- remove: remove_card,
+static struct pci_driver lynx_pci_driver = {
+ .name = PCILYNX_DRIVER_NAME,
+ .id_table = pci_table,
+ .probe = add_card,
+ .remove = __devexit_p(remove_card),
+};
+
+static struct hpsb_host_operations lynx_ops = {
+ .get_rom = get_lynx_rom,
+ .transmit_packet = lynx_transmit,
+ .devctl = lynx_devctl,
};
MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");
@@ -1635,30 +1709,52 @@
MODULE_SUPPORTED_DEVICE("pcilynx");
MODULE_DEVICE_TABLE(pci, pci_table);
-static void __exit pcilynx_cleanup(void)
-{
- hpsb_unregister_lowlevel(&lynx_template);
- pci_unregister_driver(&lynx_pcidriver);
- PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");
-}
-
static int __init pcilynx_init(void)
{
int ret;
- if (hpsb_register_lowlevel(&lynx_template)) {
- PRINT_G(KERN_ERR, "registering failed");
- return -ENXIO;
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+ if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
+ PRINT_G(KERN_ERR, "allocation of char major number %d failed",
+ PCILYNX_MAJOR);
+ return -EBUSY;
+ }
+#endif
+
+ lynx_driver = hpsb_register_lowlevel(&lynx_ops, PCILYNX_DRIVER_NAME);
+ if (!lynx_driver) {
+ ret = -ENOMEM;
+ goto free_char_dev;
}
- ret = pci_module_init(&lynx_pcidriver);
+ ret = pci_module_init(&lynx_pci_driver);
if (ret < 0) {
PRINT_G(KERN_ERR, "PCI module init failed");
- hpsb_unregister_lowlevel(&lynx_template);
+ goto unregister_lowlevel;
}
+ return 0;
+
+ unregister_lowlevel:
+ hpsb_unregister_lowlevel(lynx_driver);
+ free_char_dev:
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+ unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
+#endif
+
return ret;
}
+static void __exit pcilynx_cleanup(void)
+{
+ pci_unregister_driver(&lynx_pci_driver);
+ hpsb_unregister_lowlevel(lynx_driver);
+
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+ unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
+#endif
+}
+
+
module_init(pcilynx_init);
module_exit(pcilynx_cleanup);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)